Skip to content

Commit

Permalink
Add C Hash function wrappers
Browse files Browse the repository at this point in the history
  • Loading branch information
yogh333 committed Feb 20, 2024
1 parent f18c53a commit 14739bf
Show file tree
Hide file tree
Showing 8 changed files with 807 additions and 11 deletions.
135 changes: 135 additions & 0 deletions ledger_device_sdk/src/hash.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
use ledger_secure_sdk_sys::{
cx_hash_final, cx_hash_get_size, cx_hash_no_throw, cx_hash_t, cx_hash_update,
CX_INVALID_PARAMETER, CX_LAST, CX_OK,
};

mod blake2;
mod ripemd;
mod sha2;
mod sha3;

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum HashError {
InvalidParameter,
InvalidOutputLength,
InternalError,
}

impl From<u32> for HashError {
fn from(x: u32) -> HashError {
match x {
CX_INVALID_PARAMETER => HashError::InvalidParameter,
_ => HashError::InternalError,
}
}
}

impl From<HashError> for u32 {
fn from(e: HashError) -> u32 {
e as u32
}
}

pub trait HashInit: Sized {
fn as_ctx_mut(&mut self) -> &mut cx_hash_t;
fn as_ctx(&self) -> &cx_hash_t;
fn new() -> Self;
fn get_size(&mut self) -> usize {
unsafe { cx_hash_get_size(self.as_ctx()) }
}
fn hash(mut self, input: &[u8], output: &mut [u8]) -> Result<(), HashError> {
let output_size = self.get_size();
if output_size > output.len() {
return Err(HashError::InvalidOutputLength);
}

let err = unsafe {
cx_hash_no_throw(
self.as_ctx_mut(),
CX_LAST,
input.as_ptr(),
input.len(),
output.as_mut_ptr(),
output.len(),
)
};
if err != CX_OK {
Err(err.into())
} else {
Ok(())
}
}
fn update(&mut self, input: &[u8]) -> Result<(), HashError> {
let err = unsafe { cx_hash_update(self.as_ctx_mut(), input.as_ptr(), input.len()) };
if err != CX_OK {
Err(err.into())
} else {
Ok(())
}
}
fn finalize(mut self, output: &mut [u8]) -> Result<(), HashError> {
let output_size = self.get_size();
if output_size > output.len() {
return Err(HashError::InvalidOutputLength);
}

let err = unsafe { cx_hash_final(self.as_ctx_mut(), output.as_mut_ptr()) };
if err != CX_OK {
Err(err.into())
} else {
Ok(())
}
}
}

#[cfg(test)]
mod tests {
use crate::assert_eq_err as assert_eq;
use crate::hash::sha2::Sha2_256;
use crate::hash::sha3::*;
use crate::hash::HashInit;
use crate::testing::TestType;
use testmacro::test_item as test;

const TEST_HASH: &[u8; 29] = b"Not your keys, not your coins";

#[test]
fn test_hash() {
let mut keccak = Keccak256::new();

let mut output: [u8; 32] = [0u8; 32];

let ouput_size = keccak.get_size();
assert_eq!(ouput_size, 32);

let _ = keccak.hash(TEST_HASH, &mut output);

let expected = [
0x1f, 0x20, 0x7c, 0xd9, 0xfd, 0x9f, 0x0b, 0x09, 0xb0, 0x04, 0x93, 0x6c, 0xa5, 0xe0,
0xd3, 0x1b, 0xa1, 0x6c, 0xd6, 0x14, 0x53, 0xaa, 0x28, 0x7e, 0x65, 0xaa, 0x88, 0x25,
0x3c, 0xdc, 0x1c, 0x94,
];
assert_eq!(&output, &expected);
}

#[test]
fn test_sha2_update() {
let mut hasher = Sha2_256::new();

let mut output: [u8; 32] = [0u8; 32];

let ouput_size = hasher.get_size();
assert_eq!(ouput_size, 32);

let _ = hasher.update(TEST_HASH);

let _ = hasher.finalize(&mut output);

let expected = [
0x52, 0x49, 0x2e, 0x81, 0x92, 0x16, 0xf3, 0x6b, 0x74, 0x7d, 0xd5, 0xda, 0x70, 0x3a,
0x26, 0x60, 0x14, 0x34, 0x60, 0x42, 0x42, 0xfa, 0xb2, 0x7e, 0x85, 0x51, 0xe7, 0x82,
0xa5, 0x11, 0x13, 0x40,
];
assert_eq!(&output, &expected);
}
}
138 changes: 138 additions & 0 deletions ledger_device_sdk/src/hash/blake2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
use super::HashInit;
use ledger_secure_sdk_sys::{cx_blake2b_init_no_throw, cx_blake2b_t, cx_hash_t};

#[derive(Default)]
#[allow(non_camel_case_types)]
pub struct Blake2b_256 {
ctx: cx_blake2b_t,
}

impl HashInit for Blake2b_256 {
fn as_ctx_mut(&mut self) -> &mut cx_hash_t {
&mut self.ctx.header
}

fn as_ctx(&self) -> &cx_hash_t {
&self.ctx.header
}

fn new() -> Self {
let mut ctx: Blake2b_256 = Default::default();
let _err = unsafe { cx_blake2b_init_no_throw(&mut ctx.ctx, 256) };
ctx
}
}

#[derive(Default)]
#[allow(non_camel_case_types)]
pub struct Blake2b_384 {
ctx: cx_blake2b_t,
}

impl HashInit for Blake2b_384 {
fn as_ctx_mut(&mut self) -> &mut cx_hash_t {
&mut self.ctx.header
}

fn as_ctx(&self) -> &cx_hash_t {
&self.ctx.header
}

fn new() -> Self {
let mut ctx: Blake2b_384 = Default::default();
let _err = unsafe { cx_blake2b_init_no_throw(&mut ctx.ctx, 384) };
ctx
}
}

#[derive(Default)]
#[allow(non_camel_case_types)]
pub struct Blake2b_512 {
ctx: cx_blake2b_t,
}

impl HashInit for Blake2b_512 {
fn as_ctx_mut(&mut self) -> &mut cx_hash_t {
&mut self.ctx.header
}

fn as_ctx(&self) -> &cx_hash_t {
&self.ctx.header
}

fn new() -> Self {
let mut ctx: Blake2b_512 = Default::default();
let _err = unsafe { cx_blake2b_init_no_throw(&mut ctx.ctx, 512) };
ctx
}
}

#[cfg(test)]
mod tests {
use crate::assert_eq_err as assert_eq;
use crate::hash::blake2::*;
use crate::testing::TestType;
use testmacro::test_item as test;

const TEST_HASH: &[u8; 29] = b"Not your keys, not your coins";

#[test]
fn test_hash_blake2b256() {
let mut blake2 = Blake2b_256::new();

let mut output: [u8; 32] = [0u8; 32];

let ouput_size = blake2.get_size();
assert_eq!(ouput_size, 32);

let _ = blake2.hash(TEST_HASH, &mut output);

let expected = [
0xcd, 0xa6, 0x49, 0x8e, 0x2f, 0x89, 0x71, 0xe8, 0x4e, 0xd5, 0x68, 0x2e, 0x3d, 0x47,
0x9c, 0xcc, 0x2c, 0xce, 0x7f, 0x37, 0xac, 0x92, 0x9c, 0xa0, 0xb0, 0x41, 0xb2, 0xdd,
0x06, 0xa9, 0xf3, 0xcb,
];
assert_eq!(&output, &expected);
}

#[test]
fn test_hash_blake2b384() {
let mut blake2 = Blake2b_384::new();

let mut output: [u8; 48] = [0u8; 48];

let ouput_size = blake2.get_size();
assert_eq!(ouput_size, 48);

let _ = blake2.hash(TEST_HASH, &mut output);

let expected = [
0x5f, 0x03, 0x04, 0x77, 0x92, 0x5e, 0x91, 0x29, 0xf9, 0xb8, 0xef, 0xf9, 0x88, 0x29,
0x04, 0xf4, 0x4f, 0x65, 0x3b, 0xef, 0xf8, 0x21, 0xca, 0x48, 0x68, 0xa7, 0xbe, 0x46,
0x1c, 0x45, 0x82, 0xb3, 0x3d, 0xd7, 0x7b, 0x9e, 0x91, 0x9a, 0xfe, 0x1c, 0x3b, 0xed,
0x4b, 0x8f, 0x3c, 0x5d, 0xde, 0x53,
];
assert_eq!(&output, &expected);
}

#[test]
fn test_hash_blake2b512() {
let mut blake2 = Blake2b_512::new();

let mut output: [u8; 64] = [0u8; 64];

let ouput_size = blake2.get_size();
assert_eq!(ouput_size, 64);

let _ = blake2.hash(TEST_HASH, &mut output);

let expected = [
0xc2, 0xe0, 0xfe, 0x8c, 0xb7, 0x83, 0x43, 0x7c, 0x8f, 0x36, 0x89, 0x48, 0xc4, 0x7a,
0x9c, 0x7c, 0x27, 0xa3, 0xb5, 0x98, 0x7a, 0x2d, 0x1b, 0x3b, 0xab, 0x48, 0x3d, 0xd6,
0xf6, 0x4c, 0xd1, 0x20, 0x7d, 0x72, 0x62, 0xb5, 0x35, 0xfe, 0x3f, 0x86, 0xad, 0x0c,
0x5f, 0x33, 0x4e, 0x55, 0x07, 0x64, 0x49, 0x7c, 0x11, 0xd5, 0xbd, 0x6a, 0x44, 0x2a,
0x9c, 0x2e, 0x6a, 0xab, 0xf9, 0x31, 0xc0, 0xab,
];
assert_eq!(&output, &expected);
}
}
51 changes: 51 additions & 0 deletions ledger_device_sdk/src/hash/ripemd.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
use super::HashInit;
use ledger_secure_sdk_sys::{cx_hash_t, cx_ripemd160_init_no_throw, cx_ripemd160_t};

#[derive(Default)]
pub struct Ripemd160 {
ctx: cx_ripemd160_t,
}

impl HashInit for Ripemd160 {
fn as_ctx_mut(&mut self) -> &mut cx_hash_t {
&mut self.ctx.header
}

fn as_ctx(&self) -> &cx_hash_t {
&self.ctx.header
}

fn new() -> Self {
let mut ctx: Ripemd160 = Default::default();
let _err = unsafe { cx_ripemd160_init_no_throw(&mut ctx.ctx) };
ctx
}
}

#[cfg(test)]
mod tests {
use crate::assert_eq_err as assert_eq;
use crate::hash::ripemd::*;
use crate::testing::TestType;
use testmacro::test_item as test;

const TEST_HASH: &[u8; 29] = b"Not your keys, not your coins";

#[test]
fn test_hash_ripemd160() {
let mut ripemd = Ripemd160::new();

let mut output: [u8; 20] = [0u8; 20];

let ouput_size = ripemd.get_size();
assert_eq!(ouput_size, 20);

let _ = ripemd.hash(TEST_HASH, &mut output);

let expected = [
0x75, 0x0f, 0x75, 0x73, 0x6a, 0x34, 0xac, 0x02, 0xd0, 0x72, 0xec, 0x2a, 0xf5, 0xf7,
0x1d, 0x16, 0xc2, 0x6f, 0x63, 0x23,
];
assert_eq!(&output, &expected);
}
}
Loading

0 comments on commit 14739bf

Please sign in to comment.