sync
This commit is contained in:
commit
1b2234c51a
2
.cargo/config
Normal file
2
.cargo/config
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
[build]
|
||||||
|
target = "x86_64-unknown-linux-musl"
|
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/target
|
75
Cargo.lock
generated
Normal file
75
Cargo.lock
generated
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "drive"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"rand",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getrandom"
|
||||||
|
version = "0.2.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"wasi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.126"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ppv-lite86"
|
||||||
|
version = "0.2.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.8.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"rand_chacha",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_chacha"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||||
|
dependencies = [
|
||||||
|
"ppv-lite86",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.6.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.10.2+wasi-snapshot-preview1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
|
13
Cargo.toml
Normal file
13
Cargo.toml
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
[package]
|
||||||
|
name = "drive"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
rand = "0.8.5"
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
panic = "abort"
|
||||||
|
|
7
Makefile
Normal file
7
Makefile
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
|
||||||
|
.PHONY: solve
|
||||||
|
|
||||||
|
default: solve
|
||||||
|
|
||||||
|
solve:
|
||||||
|
nasm -o solve/solve solve/solve.s
|
BIN
solve/solve
Normal file
BIN
solve/solve
Normal file
Binary file not shown.
81
solve/solve.s
Normal file
81
solve/solve.s
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
; vim: ft=nasm
|
||||||
|
%macro i_nop 0
|
||||||
|
db 0x00
|
||||||
|
%endmacro
|
||||||
|
%define np i_nop
|
||||||
|
|
||||||
|
|
||||||
|
%macro i_halt 1
|
||||||
|
db 0x01
|
||||||
|
db %1
|
||||||
|
%endmacro
|
||||||
|
%define ht i_halt
|
||||||
|
|
||||||
|
; load <mem> <value>
|
||||||
|
%macro i_load 2
|
||||||
|
db 0x10
|
||||||
|
db %1
|
||||||
|
db %2
|
||||||
|
%endmacro
|
||||||
|
%define ld i_load
|
||||||
|
|
||||||
|
; send <device> <mem>
|
||||||
|
%macro i_send 2
|
||||||
|
db 0x20
|
||||||
|
db %1
|
||||||
|
db %2
|
||||||
|
%endmacro
|
||||||
|
%define sd i_send
|
||||||
|
|
||||||
|
; get <mem> <device>
|
||||||
|
%macro i_get 2
|
||||||
|
db 0x21
|
||||||
|
db %1
|
||||||
|
db %2
|
||||||
|
%endmacro
|
||||||
|
%define gt i_get
|
||||||
|
|
||||||
|
|
||||||
|
; jlt <a>, <b>, <loc>
|
||||||
|
; a < b
|
||||||
|
%macro i_less 3
|
||||||
|
db 0x50
|
||||||
|
db %1
|
||||||
|
db %2
|
||||||
|
db %3
|
||||||
|
%endmacro
|
||||||
|
%define jl i_less
|
||||||
|
|
||||||
|
|
||||||
|
; jle <a>, <b>, <loc>
|
||||||
|
; a <= b
|
||||||
|
%macro i_leq 3
|
||||||
|
db 0x51
|
||||||
|
db %1
|
||||||
|
db %2
|
||||||
|
db %3
|
||||||
|
%endmacro
|
||||||
|
%define le i_leq
|
||||||
|
|
||||||
|
%define inp 0
|
||||||
|
%define disp 1
|
||||||
|
%define arith 2
|
||||||
|
%define tape 3
|
||||||
|
|
||||||
|
|
||||||
|
gt 0x00, inp
|
||||||
|
gt 0x01, inp
|
||||||
|
gt 0x02, inp
|
||||||
|
gt 0x03, inp
|
||||||
|
; [a, b, c, d] -> mem
|
||||||
|
sd tape, 0x00
|
||||||
|
sd tape, 0x01
|
||||||
|
sd tape, 0x02
|
||||||
|
sd tape, 0x03
|
||||||
|
; {a, b, c, d}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
sd disp, 0x00
|
||||||
|
sd disp, 0x01
|
||||||
|
|
84
src/device.rs
Normal file
84
src/device.rs
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
use std::io::Read;
|
||||||
|
use std::io::Write;
|
||||||
|
|
||||||
|
pub trait Device {
|
||||||
|
fn get_byte(&mut self) -> u8;
|
||||||
|
fn send_byte(&mut self, byte: u8);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub struct Reader<'a> {
|
||||||
|
pub reader: &'a mut dyn Read,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl Device for Reader<'_> {
|
||||||
|
fn get_byte(&mut self) -> u8 {
|
||||||
|
self.reader.bytes().next().and_then(|result| result.ok()).map(|byte| byte as u8).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_byte(&mut self, _byte: u8) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Tape {
|
||||||
|
pub tape: [u8; 25000],
|
||||||
|
pub index: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Device for Tape {
|
||||||
|
fn get_byte(&mut self) -> u8 {
|
||||||
|
let i = self.tape[self.index];
|
||||||
|
if self.index == 0 {
|
||||||
|
self.index = 25000;
|
||||||
|
}
|
||||||
|
self.index -= 1;
|
||||||
|
self.index %= 25000;
|
||||||
|
i
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_byte(&mut self, byte: u8) {
|
||||||
|
self.tape[self.index] = byte;
|
||||||
|
self.index += 1;
|
||||||
|
self.index %= 25000;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Writer<'a> {
|
||||||
|
pub writer: &'a mut dyn Write,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Device for Writer<'_> {
|
||||||
|
fn get_byte(&mut self) -> u8 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_byte(&mut self, byte: u8) {
|
||||||
|
self.writer.write_all(&[byte]).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Arithmetic {
|
||||||
|
pub buffer: [u8; 3],
|
||||||
|
pub index: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Device for Arithmetic {
|
||||||
|
fn get_byte(&mut self) -> u8 {
|
||||||
|
match self.buffer[2] {
|
||||||
|
1 => self.buffer[0] + self.buffer[1],
|
||||||
|
2 => self.buffer[0] - self.buffer[1],
|
||||||
|
3 => self.buffer[0] ^ self.buffer[1],
|
||||||
|
_ => 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_byte(&mut self, byte: u8) {
|
||||||
|
self.buffer[self.index] = byte;
|
||||||
|
self.index += 1;
|
||||||
|
self.index %= 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
65
src/main.rs
Normal file
65
src/main.rs
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
mod device;
|
||||||
|
mod vm;
|
||||||
|
|
||||||
|
use device::{Reader, Arithmetic, Tape, Writer};
|
||||||
|
use std::io::Cursor;
|
||||||
|
use rand::prelude::random;
|
||||||
|
use std::io::Read;
|
||||||
|
use std::io;
|
||||||
|
use vm::{State, vm_run};
|
||||||
|
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
|
||||||
|
let program: Vec<u8> = io::stdin().bytes().map(|res| res.unwrap_or_else(|_| std::process::exit(1))).collect();
|
||||||
|
|
||||||
|
|
||||||
|
for _ in 0..10 {
|
||||||
|
let iv: [u8; 4] = random();
|
||||||
|
let mut input = Cursor::new(iv);
|
||||||
|
let mut output = Cursor::new(vec![0,0,0,0]);
|
||||||
|
|
||||||
|
let state = State {
|
||||||
|
ip: 0usize,
|
||||||
|
mem: [0; 4],
|
||||||
|
program: program.clone(),
|
||||||
|
devices: vec![Box::new(Reader { reader: &mut input } ),
|
||||||
|
Box::new(Writer { writer: &mut output } ),
|
||||||
|
Box::new(Arithmetic { buffer: [0; 3], index: 0usize }),
|
||||||
|
Box::new(Tape { tape: [0; 25000], index: 0usize }),]
|
||||||
|
};
|
||||||
|
vm_run(state);
|
||||||
|
let ov: [u8; 4] = output.into_inner().try_into().unwrap();
|
||||||
|
println!("{:?}", iv);
|
||||||
|
println!("{:?}", encrypt(iv));
|
||||||
|
println!("{:?}", ov);
|
||||||
|
if ov != encrypt(iv) {
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn encrypt(block: [u8; 4]) -> [u8; 4] {
|
||||||
|
let mut block = block;
|
||||||
|
|
||||||
|
let (i, _) = block[0].overflowing_add(block[3]);
|
||||||
|
block[1] ^= i;
|
||||||
|
let (i, _) = block[1].overflowing_add(block[0]);
|
||||||
|
block[2] ^= i;
|
||||||
|
let (i, _) = block[2].overflowing_add(block[1]);
|
||||||
|
block[3] ^= i;
|
||||||
|
let (i, _) = block[3].overflowing_add(block[2]);
|
||||||
|
block[0] ^= i;
|
||||||
|
|
||||||
|
for _ in 0..block[3] {
|
||||||
|
let (mul, _) = block[2].overflowing_mul(block[0]);
|
||||||
|
let (sum, _) = mul.overflowing_add(block[1]);
|
||||||
|
block[0] = sum % block[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
block
|
||||||
|
}
|
120
src/vm.rs
Normal file
120
src/vm.rs
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
use crate::device::Device;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct State<'a> {
|
||||||
|
pub ip: usize,
|
||||||
|
pub mem: [u8; 4],
|
||||||
|
pub program: Vec<u8>,
|
||||||
|
pub devices: Vec<Box<dyn Device + 'a>>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl State<'_> {
|
||||||
|
#[inline(never)]
|
||||||
|
fn next_byte(&mut self) -> u8 {
|
||||||
|
let result = self.program[self.ip];
|
||||||
|
self.ip += 1;
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(never)]
|
||||||
|
fn next_word(&mut self) -> u16 {
|
||||||
|
let result = (u16::from(self.program[self.ip]) << 8) | u16::from(self.program[self.ip + 1]);
|
||||||
|
self.ip += 2;
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(never)]
|
||||||
|
fn next_dword(&mut self) -> u32 {
|
||||||
|
let result = (u32::from(self.program[self.ip]) << 24) |
|
||||||
|
(u32::from(self.program[self.ip + 1]) << 16) |
|
||||||
|
(u32::from(self.program[self.ip + 2]) << 8) |
|
||||||
|
(u32::from(self.program[self.ip + 3]));
|
||||||
|
self.ip += 4;
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub enum Opcode {
|
||||||
|
Nop,
|
||||||
|
Halt,
|
||||||
|
Load,
|
||||||
|
r#Send,
|
||||||
|
Get,
|
||||||
|
Less,
|
||||||
|
LessEq,
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl From<u8> for Opcode {
|
||||||
|
fn from(v: u8) -> Self {
|
||||||
|
match v {
|
||||||
|
0x00 => Opcode::Nop,
|
||||||
|
0x01 => Opcode::Halt,
|
||||||
|
0x10 => Opcode::Load,
|
||||||
|
0x20 => Opcode::r#Send,
|
||||||
|
0x21 => Opcode::Get,
|
||||||
|
0x50 => Opcode::Less,
|
||||||
|
0x51 => Opcode::LessEq,
|
||||||
|
_ => Opcode::Halt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn vm_run(mut state: State) -> i32 {
|
||||||
|
loop {
|
||||||
|
if state.ip >= state.program.len() {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
match Opcode::from(state.program[state.ip]) {
|
||||||
|
Opcode::Nop => {
|
||||||
|
state.ip += 1;
|
||||||
|
}
|
||||||
|
Opcode::Halt => {
|
||||||
|
state.ip += 1;
|
||||||
|
let ret = state.next_byte();
|
||||||
|
return ret as i32;
|
||||||
|
}
|
||||||
|
Opcode::Load => {
|
||||||
|
state.ip += 1;
|
||||||
|
let location = state.next_byte() as usize;
|
||||||
|
let value = state.next_byte();
|
||||||
|
state.mem[location] = value;
|
||||||
|
}
|
||||||
|
Opcode::r#Send => {
|
||||||
|
state.ip += 1;
|
||||||
|
let device = state.next_byte() as usize;
|
||||||
|
let mem = state.mem[state.next_byte() as usize];
|
||||||
|
state.devices[device].send_byte(mem);
|
||||||
|
}
|
||||||
|
Opcode::Get => {
|
||||||
|
state.ip += 1;
|
||||||
|
let mem = state.next_byte() as usize;
|
||||||
|
let device = state.next_byte() as usize;
|
||||||
|
state.mem[mem] = state.devices[device].get_byte();
|
||||||
|
}
|
||||||
|
Opcode::Less => {
|
||||||
|
state.ip += 1;
|
||||||
|
let mem1 = state.mem[state.next_byte() as usize];
|
||||||
|
let mem2 = state.mem[state.next_byte() as usize];
|
||||||
|
let jump = state.next_byte() as usize;
|
||||||
|
if mem1 < mem2 {
|
||||||
|
state.ip = jump;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Opcode::LessEq => {
|
||||||
|
state.ip += 1;
|
||||||
|
let mem1 = state.mem[state.next_byte() as usize];
|
||||||
|
let mem2 = state.mem[state.next_byte() as usize];
|
||||||
|
let jump = state.next_byte() as usize;
|
||||||
|
if mem1 <= mem2 {
|
||||||
|
state.ip = jump;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user