Merge #178

178: Add support for running HMAC operations r=alistair23 a=alistair23

This PR adds the HMAC driver and a HMAC example.

Co-authored-by: Alistair Francis <alistair.francis@wdc.com>
diff --git a/examples/hmac.rs b/examples/hmac.rs
new file mode 100644
index 0000000..97184f7
--- /dev/null
+++ b/examples/hmac.rs
@@ -0,0 +1,55 @@
+#![no_std]
+
+use core::fmt::Write;
+use libtock::hmac::{HmacDataBuffer, HmacDestBuffer, HmacKeyBuffer};
+use libtock::result::TockResult;
+use libtock::syscalls;
+
+#[libtock::main]
+async fn main() -> TockResult<()> {
+    let mut drivers = libtock::retrieve_drivers()?;
+    let mut console = drivers.console.create_console();
+    writeln!(console, "Starting HMAC example")?;
+    let hmac_driver = drivers.hmac.init_driver()?;
+
+    writeln!(console, "Loading in 0 key")?;
+    let mut key_buffer = HmacKeyBuffer::default();
+    let _key_buffer = hmac_driver.init_key_buffer(&mut key_buffer)?;
+    writeln!(console, "  done")?;
+
+    writeln!(console, "Creating data buffer")?;
+    let mut data_buffer = HmacDataBuffer::default();
+    let data: &[u8; 72] =
+        b"A language empowering everyone to build reliable and efficient software.";
+
+    for (i, d) in data.iter().enumerate() {
+        data_buffer.buffer[i] = *d;
+    }
+    let _data_buffer = hmac_driver.init_data_buffer(&mut data_buffer)?;
+    writeln!(console, "  done")?;
+
+    writeln!(console, "Creating dest buffer")?;
+    let mut dest_buffer = HmacDestBuffer::default();
+    let dest_buffer = hmac_driver.init_dest_buffer(&mut dest_buffer)?;
+    writeln!(console, "  done")?;
+
+    let mut temp_buffer = [0; libtock::hmac::DEST_BUFFER_SIZE];
+
+    writeln!(console, "Setting callback and running")?;
+    let mut callback = |_result, _digest| {
+        writeln!(console, "HMAC Complete, printing digest").unwrap();
+        dest_buffer.read_bytes(&mut temp_buffer[..]);
+
+        for buf in temp_buffer.iter().take(libtock::hmac::DEST_BUFFER_SIZE) {
+            write!(console, "{:x}", *buf).unwrap();
+        }
+    };
+
+    let _subscription = hmac_driver.subscribe(&mut callback)?;
+
+    hmac_driver.run()?;
+
+    loop {
+        unsafe { syscalls::raw::yieldk() };
+    }
+}
diff --git a/src/drivers.rs b/src/drivers.rs
index 185f6ea..bd7f45b 100644
--- a/src/drivers.rs
+++ b/src/drivers.rs
@@ -2,6 +2,7 @@
 use crate::buttons::ButtonsDriverFactory;
 use crate::console::ConsoleDriver;
 use crate::gpio::GpioDriverFactory;
+use crate::hmac::HmacDriverFactory;
 use crate::leds::LedsDriverFactory;
 use crate::result::OtherError;
 use crate::result::TockError;
@@ -23,6 +24,7 @@
     pub leds: LedsDriverFactory,
     pub timer: DriverContext,
     pub gpio: GpioDriverFactory,
+    pub hmac: HmacDriverFactory,
     pub temperature: TemperatureDriverFactory,
     pub buttons: ButtonsDriverFactory,
     pub adc: AdcDriverFactory,
@@ -71,6 +73,7 @@
         active_timer: Cell::new(None),
     },
     gpio: GpioDriverFactory,
+    hmac: HmacDriverFactory,
     temperature: TemperatureDriverFactory,
     rng: RngDriver,
     ambient_light_sensor: AmbientLightSensor,
diff --git a/src/hmac.rs b/src/hmac.rs
new file mode 100644
index 0000000..e5475cc
--- /dev/null
+++ b/src/hmac.rs
@@ -0,0 +1,123 @@
+use crate::callback::CallbackSubscription;
+use crate::callback::Consumer;
+use crate::result::TockResult;
+use crate::syscalls;
+use core::marker::PhantomData;
+use libtock_core::shared_memory::SharedMemory;
+
+const DRIVER_NUMBER: usize = 0x40003;
+
+pub const KEY_BUFFER_SIZE: usize = 32;
+pub const DATA_BUFFER_SIZE: usize = 256;
+pub const DEST_BUFFER_SIZE: usize = 32;
+
+mod command_nr {
+    pub const SET_ALGORITHM: usize = 0;
+    pub const RUN: usize = 1;
+}
+
+mod subscribe_nr {
+    pub const SUBSCRIBE_CALLBACK: usize = 0;
+}
+
+mod allow_nr {
+    pub const KEY: usize = 0;
+    pub const DATA: usize = 1;
+    pub const DEST: usize = 2;
+}
+
+#[non_exhaustive]
+pub struct HmacDriverFactory;
+
+impl HmacDriverFactory {
+    pub fn init_driver(&mut self) -> TockResult<HmacDriver> {
+        let hmac = HmacDriver {
+            lifetime: PhantomData,
+        };
+        Ok(hmac)
+    }
+}
+
+struct HmacEventConsumer;
+
+impl<CB: FnMut(usize, usize)> Consumer<CB> for HmacEventConsumer {
+    fn consume(callback: &mut CB, result: usize, digest: usize, _: usize) {
+        callback(result, digest);
+    }
+}
+
+pub struct HmacKeyBuffer {
+    buffer: [u8; KEY_BUFFER_SIZE],
+}
+
+impl Default for HmacKeyBuffer {
+    fn default() -> Self {
+        HmacKeyBuffer {
+            buffer: [0; KEY_BUFFER_SIZE],
+        }
+    }
+}
+
+pub struct HmacDataBuffer {
+    pub buffer: [u8; DATA_BUFFER_SIZE],
+}
+
+impl Default for HmacDataBuffer {
+    fn default() -> Self {
+        HmacDataBuffer {
+            buffer: [0; DATA_BUFFER_SIZE],
+        }
+    }
+}
+
+pub struct HmacDestBuffer {
+    buffer: [u8; DEST_BUFFER_SIZE],
+}
+
+impl Default for HmacDestBuffer {
+    fn default() -> Self {
+        HmacDestBuffer {
+            buffer: [0; DEST_BUFFER_SIZE],
+        }
+    }
+}
+
+pub struct HmacDriver<'a> {
+    lifetime: PhantomData<&'a ()>,
+}
+
+impl<'a> HmacDriver<'a> {
+    pub fn init_key_buffer(&self, buffer: &'a mut HmacKeyBuffer) -> TockResult<SharedMemory> {
+        syscalls::allow(DRIVER_NUMBER, allow_nr::KEY, &mut buffer.buffer).map_err(Into::into)
+    }
+
+    pub fn init_data_buffer(&self, buffer: &'a mut HmacDataBuffer) -> TockResult<SharedMemory> {
+        syscalls::allow(DRIVER_NUMBER, allow_nr::DATA, &mut buffer.buffer).map_err(Into::into)
+    }
+
+    pub fn init_dest_buffer(&self, buffer: &'a mut HmacDestBuffer) -> TockResult<SharedMemory> {
+        syscalls::allow(DRIVER_NUMBER, allow_nr::DEST, &mut buffer.buffer).map_err(Into::into)
+    }
+
+    pub fn subscribe<CB: FnMut(usize, usize) -> () + FnMut(usize, usize)>(
+        &self,
+        callback: &'a mut CB,
+    ) -> TockResult<CallbackSubscription> {
+        syscalls::subscribe::<HmacEventConsumer, _>(
+            DRIVER_NUMBER,
+            subscribe_nr::SUBSCRIBE_CALLBACK,
+            callback,
+        )
+        .map_err(Into::into)
+    }
+
+    pub fn set_algorithm(&self, hash: usize) -> TockResult<()> {
+        syscalls::command(DRIVER_NUMBER, command_nr::SET_ALGORITHM, hash, 0)?;
+        Ok(())
+    }
+
+    pub fn run(&self) -> TockResult<()> {
+        syscalls::command(DRIVER_NUMBER, command_nr::RUN, 0, 0)?;
+        Ok(())
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 152e223..eb13b94 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -11,6 +11,7 @@
 pub mod executor;
 pub mod futures;
 pub mod gpio;
+pub mod hmac;
 pub mod leds;
 pub mod result;
 pub mod rng;