Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //! Proof of concept virtual machine with instructions in-line with memory
- //!
- //! TODO: Implement unions for lense and use that for handling everything correctly!
- //!
- //! The instructions are RISC with a few CISC commands to interact with the network and handle
- //! cryptography.
- //!
- //! Instruction set
- //! ---------------
- //!
- //! 0x0_ : Core VM management
- //!
- //! 0x00 Return up the stack
- //! 0x01 Define function : 0x__
- //! 0x02 Define variable : 0x__ len:u16
- //! 0x03* Slice into a memory region
- //!
- //! 0x0A Crypto_box: key, nonce, message, signature
- //! 0x0B Hexdump: region
- //!
- //! 0xA_ .. 0xE_
- //! : Pre-boot defined functions and statics
- //!
- //! 0xF_ : Runtime defined
- //!
- //! Implementation notes
- //! --------------------
- //!
- //! - The 0x0_ range may be used freely as *non-callable registers*
- //! - This is useful for slicing into memory regions
- extern crate rand;
- use rand::{ChaChaRng, SeedableRng, Rng};
- macro_rules! vec_no_copy {
- [$expr:expr; $n:expr] => {{
- let mut tmp = Vec::with_capacity($n);
- for _ in 0..$n {
- tmp.push($expr)
- }
- tmp
- }}
- }
- fn hex_dump(vec: &[u8]) {
- println!("Hexdump:");
- let mut m = 0;
- for bytes in vec.chunks(16) {
- let mut n = 0;
- println!("{:04x} {}", m * 16,
- bytes.iter()
- .map(|x| {
- n += 1;
- if n == 8 {
- format!("{:02x} ", x)
- } else {
- format!("{:02x}", x)
- }
- })
- .collect::<Vec<String>>()
- .join(" "));
- m += 1;
- }
- }
- pub struct State<'a> {
- state: &'a mut [u8],
- cursor: u16,
- registers: Vec<Reg<'a>>,
- chacha: ChaChaRng,
- stack: Vec<u16>,
- lock_flags: bool,
- }
- enum Reg<'a> {
- Exact(u16),
- Region(&'a mut [u8]),
- None,
- }
- impl<'a> Reg<'a> {
- fn get_region(&self) -> Result<&[u8], ()> {
- match *self {
- Reg::Region(ref r) => Ok(r),
- _ => Err(()),
- }
- }
- fn get_region_mut(&mut self) -> Result<&mut [u8], ()> {
- match *self {
- Reg::Region(ref mut r) => Ok(r),
- _ => Err(()),
- }
- }
- }
- impl<'a> State<'a> {
- fn with_program(prog: &'a mut [u8]) -> Self {
- State {
- state: prog,
- cursor: 0,
- registers: vec_no_copy![Reg::None; 0xFF],
- chacha: ChaChaRng::new_unseeded(),
- stack: Vec::new(),
- lock_flags: false,
- }
- }
- fn get_u8(&mut self) -> u8 {
- let ret = self.state[self.cursor as usize];
- self.cursor += 1;
- ret
- }
- fn get_u16(&mut self) -> u16 {
- let ret = &self.state[self.cursor as usize..self.cursor as usize + 2];
- self.cursor += 2;
- (ret[0] as u16) << 8 | ret[1] as u16
- }
- fn set_start(&mut self) {
- let reg = self.get_u8() as usize;
- self.registers[reg] = Reg::Exact(self.cursor);
- }
- fn seek(&mut self) {
- let pos = self.get_u8() as usize;
- match self.registers[pos] {
- Reg::Exact(c) => self.cursor = c,
- _ => unimplemented!(),
- }
- println!("Jump: {}", self.cursor)
- }
- fn set_region(&mut self) {
- assert!(self.cursor % 2 == 1, "Set_region must be aligned to 2 bytes! {}",
- self.cursor % 2);
- let (ins, len) = (self.get_u8() as usize, self.get_u16() as usize);
- self.registers[ins as usize] = Reg::Region(unsafe {
- ::std::slice::from_raw_parts_mut(
- (self.state.as_mut_ptr() as *mut u8).offset(self.cursor as isize),
- len)
- });
- self.cursor += len as u16;
- }
- // Should be implemented in the language itself
- fn crypt(&mut self) -> Result<(), ()> {
- let (key, nonce, range) = (self.get_u8() as usize,
- self.get_u8() as usize,
- self.get_u8() as usize);
- // TODO: use and update nonce
- {
- let key = try!(self.registers[key].get_region());
- assert!(key.len() == 32);
- self.chacha.reseed(unsafe {
- ::std::slice::from_raw_parts(key.as_ptr() as *const u32, 4)
- });
- }
- let range = try!(self.registers[range].get_region_mut());
- self.chacha.fill_bytes(range);
- Ok(())
- }
- // Lock memory flags and disable setting exec functions and interrupts
- fn boot(&mut self) {
- if !self.lock_flags {
- self.lock_flags = true;
- } else {
- println!("Guest attempted to boot, but it is already running");
- }
- }
- fn dump_region(&mut self) {
- let region = self.get_u8() as usize;
- if let Reg::Region(ref r) = self.registers[region] {
- hex_dump(r)
- }
- }
- fn tick(&mut self) {
- println!("Cursor: {}", self.cursor);
- match self.get_u8() {
- 0x00 => match self.stack.pop() {
- Some(c) => self.cursor = c,
- None => println!("Cannot return upwards!"),
- },
- // Set function : u8
- 0x01 => self.set_start(),
- // Set region : (u8, u16)
- 0x02 => self.set_region(),
- // Encrypt a region : (u8, u8)
- 0x0A => { self.crypt().map_err(|_| println!("Invalid key!")); },
- // Dump a selected region : u8
- 0x0B => self.dump_region(),
- // Nop
- 0xFF => {},
- n =>
- match self.registers[n as usize] {
- Reg::Region(ref r) => hex_dump(r),
- Reg::Exact(c) => self.cursor = c,
- Reg::None => println!("Undefined function: {}", n),
- }
- }
- }
- }
- impl<'a> Iterator for State<'a> {
- type Item = ();
- #[inline]
- fn next(&mut self) -> Option<Self::Item> {
- if (self.cursor as usize) < self.state.len() {
- Some(self.tick())
- } else {
- None
- }
- }
- }
- static mut Program: &'static mut [u64] = &mut [
- // Compiled program
- 0x1000A102FFA001FF, // nop, fn reset_nonce, nop, static nonce
- 0x0000000000000000, // nonce
- 0x0000000000000000, // nonce
- 0x2000A302FFA20100, // return, fn reset_key, nop, static key
- 0x0000000000000000, // key
- 0x0000000000000000, // key
- 0x0000000000000000, // key
- 0x0000000000000000, // key
- 0xA1A1A30AA3A1A30A, // crypt key, nonce, key. crypt key, nonce, nonce
- 0xFFA2A0A30BA10B00, // dump nonce, dump key, call reset_nonce, call reset_key, nop
- // 8 * 4 = 32 bytes of instructions
- // 8 * 6 = 48 bytes of memory (nonce and key)
- // 32 + 48 = 80 byte program
- // Hexdump:
- // 0000 ff 01 a0 ff 02 a1 00 10 00 00 00 00 00 00 00 00
- // 0010 00 00 00 00 00 00 00 00 00 01 a2 ff 02 a3 00 20
- // 0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- // 0030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- // 0040 0a a3 a1 a3 0a a3 a1 a1 00 0b a1 0b a3 a0 a2 ff
- // 0xFF, // Padding for fn 3 + ret offset correction
- // // Initialisation
- // // fn reset_nonce @ 0xA0 () {
- // 0x01, 0xA0, 0xFF,
- // // static mut nonce @ 0xA1 = [u8; 16];
- // 0x02, 0xA1, 0x00, 0x10,
- // // 16 byte nonce
- // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- // // return
- // 0x00,
- // // }
- // // fn init @ 0xA2 (mut nonce @ 0xA1) {
- // 0x01, 0xA2, 0xFF, // 0x01, 0xA1
- // // static mut key @ 0xA3 = [0u8; 32];
- // 0x02, 0xA3, 0x00, 0x20,
- // // 32 byte key
- // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- // // crypt(key, nonce, key)
- // 0x0A, 0xA3, 0xA1, 0xA3,
- // // crypt(key, nonce, nonce)
- // 0x0A, 0xA3, 0xA1, 0xA1,
- // // return
- // 0x00,
- // // }
- // // hex_dump(nonce)
- // 0x0B, 0xA1,
- // // hex_dump(key)
- // 0x0B, 0xA3,
- // // Define and initialise statics 'nonce' and 'key'
- // // reset_nonce()
- // 0xA0,
- // // init()
- // 0xA2, // dead code due to not actually having the stack return from reset_nonce
- ];
- #[test]
- fn print() {
- let program = unsafe {
- ::std::slice::from_raw_parts_mut(Program.as_mut_ptr() as *mut u8, Program.len() * 8)
- };
- let mut s = State::with_program(program);
- hex_dump(s.state);
- for _ in 0..14 {
- s.tick()
- // Profiling, debugging, etc?
- }
- hex_dump(s.state);
- unreachable!() // Debugging, dump the state
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement