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