This commit is contained in:
EvilMuffinHa 2022-06-11 17:12:06 -04:00
commit 1b2234c51a
10 changed files with 448 additions and 0 deletions

2
.cargo/config Normal file
View File

@ -0,0 +1,2 @@
[build]
target = "x86_64-unknown-linux-musl"

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target

75
Cargo.lock generated Normal file
View 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
View 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
View File

@ -0,0 +1,7 @@
.PHONY: solve
default: solve
solve:
nasm -o solve/solve solve/solve.s

BIN
solve/solve Normal file

Binary file not shown.

81
solve/solve.s Normal file
View 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
View 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
View 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
View 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;
}
}
}
}
}