extern crate alloc;
use alloc::boxed::Box;
use core::marker::PhantomData;
use libcrux_hacl_rs::streaming_types::error_code;
use crate::hacl::hash_blake2b::{
blake2_params, digest, index, malloc_raw, params_and_key, reset, reset_with_key, state_t,
update0,
};
use super::{
ConstDigestLen, ConstKeyLen, ConstKeyLenConstDigestLen, Dynamic, Error, LengthBounds,
SupportsKeyLen, SupportsOutLen,
};
const PARAM_LEN: usize = 16;
const MAX_LEN: usize = 64;
pub struct Blake2bBuilder<'a, T> {
key: T,
personal: &'a [u8; PARAM_LEN],
salt: &'a [u8; PARAM_LEN],
}
impl<'a> Blake2bBuilder<'a, &'a ()> {
pub fn new_unkeyed() -> Self {
Self {
key: &(),
personal: &[0; PARAM_LEN],
salt: &[0; PARAM_LEN],
}
}
pub fn build_var_digest_len(self, digest_length: u8) -> Result<Blake2b<ConstKeyLen<0>>, Error> {
if digest_length < 1 || digest_length as usize > MAX_LEN {
return Err(Error::InvalidDigestLength);
}
let key_length = 0;
let kk = index {
key_length,
digest_length,
last_node: false,
};
let params = blake2_params {
digest_length,
key_length,
fanout: 1,
depth: 1,
leaf_length: 0,
node_offset: 0,
node_depth: 0,
inner_length: 0,
salt: self.salt,
personal: self.personal,
};
let key = params_and_key {
fst: &[params],
snd: &[],
};
Ok(Blake2b {
state: malloc_raw(kk, key),
_phantom: PhantomData,
})
}
pub fn build_const_digest_len<const OUT_LEN: usize>(
self,
) -> Blake2b<ConstKeyLenConstDigestLen<0, OUT_LEN>>
where
Blake2b<LengthBounds>: SupportsOutLen<OUT_LEN>,
{
let digest_length = OUT_LEN as u8;
let key_length = 0;
let kk = index {
key_length,
digest_length,
last_node: false,
};
let params = blake2_params {
digest_length,
key_length,
fanout: 1,
depth: 1,
leaf_length: 0,
node_offset: 0,
node_depth: 0,
inner_length: 0,
salt: self.salt,
personal: self.personal,
};
let key = params_and_key {
fst: &[params],
snd: &[],
};
Blake2b {
state: malloc_raw(kk, key),
_phantom: PhantomData,
}
}
}
impl<'a, const KEY_LEN: usize> Blake2bBuilder<'a, &'a [u8; KEY_LEN]>
where
Blake2b<LengthBounds>: SupportsKeyLen<KEY_LEN>,
{
pub fn new_keyed_const(key: &'a [u8; KEY_LEN]) -> Self {
Self {
key,
personal: &[0; PARAM_LEN],
salt: &[0; PARAM_LEN],
}
}
pub fn build_var_digest_len(
self,
digest_length: u8,
) -> Result<Blake2b<ConstKeyLen<KEY_LEN>>, Error> {
if digest_length < 1 || digest_length as usize > MAX_LEN {
return Err(Error::InvalidDigestLength);
}
let key_length = KEY_LEN as u8;
let kk = index {
key_length,
digest_length,
last_node: false,
};
let params = blake2_params {
digest_length,
key_length,
fanout: 1,
depth: 1,
leaf_length: 0,
node_offset: 0,
node_depth: 0,
inner_length: 0,
salt: self.salt,
personal: self.personal,
};
let key = params_and_key {
fst: &[params],
snd: self.key,
};
Ok(Blake2b::<ConstKeyLen<KEY_LEN>> {
state: malloc_raw(kk, key),
_phantom: PhantomData,
})
}
pub fn build_const_digest_len<const OUT_LEN: usize>(
self,
) -> Blake2b<ConstKeyLenConstDigestLen<KEY_LEN, OUT_LEN>>
where
Blake2b<LengthBounds>: SupportsOutLen<OUT_LEN>,
{
let key_length = KEY_LEN as u8;
let digest_length = OUT_LEN as u8;
let kk = index {
key_length,
digest_length,
last_node: false,
};
let params = blake2_params {
digest_length,
key_length,
fanout: 1,
depth: 1,
leaf_length: 0,
node_offset: 0,
node_depth: 0,
inner_length: 0,
salt: self.salt,
personal: self.personal,
};
let key = params_and_key {
fst: &[params],
snd: self.key,
};
Blake2b::<ConstKeyLenConstDigestLen<KEY_LEN, OUT_LEN>> {
state: malloc_raw(kk, key),
_phantom: PhantomData,
}
}
}
impl<'a> Blake2bBuilder<'a, &'a [u8]> {
pub fn new_keyed_dynamic(key: &'a [u8]) -> Result<Self, Error> {
if key.len() > MAX_LEN {
return Err(Error::InvalidKeyLength);
}
Ok(Self {
key,
personal: &[0; PARAM_LEN],
salt: &[0; PARAM_LEN],
})
}
pub fn build_var_digest_len(self, digest_length: u8) -> Result<Blake2b<Dynamic>, Error> {
if digest_length < 1 || digest_length as usize > MAX_LEN {
return Err(Error::InvalidDigestLength);
}
let key_length = self.key.len() as u8;
let kk = index {
key_length,
digest_length,
last_node: false,
};
let params = blake2_params {
digest_length,
key_length,
fanout: 1,
depth: 1,
leaf_length: 0,
node_offset: 0,
node_depth: 0,
inner_length: 0,
salt: self.salt,
personal: self.personal,
};
let key = params_and_key {
fst: &[params],
snd: self.key,
};
Ok(Blake2b {
state: malloc_raw(kk, key),
_phantom: PhantomData,
})
}
pub fn build_const_digest_len<const OUT_LEN: usize>(self) -> Blake2b<ConstDigestLen<OUT_LEN>>
where
Blake2b<LengthBounds>: SupportsOutLen<OUT_LEN>,
{
let key_length = self.key.len() as u8;
let digest_length = OUT_LEN as u8;
let kk = index {
key_length,
digest_length,
last_node: false,
};
let params = blake2_params {
digest_length,
key_length,
fanout: 1,
depth: 1,
leaf_length: 0,
node_offset: 0,
node_depth: 0,
inner_length: 0,
salt: self.salt,
personal: self.personal,
};
let key = params_and_key {
fst: &[params],
snd: self.key,
};
Blake2b {
state: malloc_raw(kk, key),
_phantom: PhantomData,
}
}
}
impl<'a, T> Blake2bBuilder<'a, T> {
pub fn with_personalization(self, personal: &'a [u8; PARAM_LEN]) -> Self {
Self { personal, ..self }
}
pub fn with_salt(self, salt: &'a [u8; PARAM_LEN]) -> Self {
Self { salt, ..self }
}
}
pub struct Blake2b<T> {
state: Box<[state_t]>,
_phantom: PhantomData<T>,
}
impl<T> Blake2b<T> {
pub fn update(&mut self, chunk: &[u8]) -> Result<(), Error> {
if chunk.len() > (u32::MAX as usize) {
return Err(Error::InvalidChunkLength);
}
match update0(self.state.as_mut(), chunk, chunk.len() as u32) {
error_code::Success => Ok(()),
error_code::MaximumLengthExceeded => Err(Error::MaximumLengthExceeded),
_ => Err(Error::Unexpected),
}
}
}
impl<const KEY_LEN: usize> Blake2b<ConstKeyLen<KEY_LEN>> {
pub fn finalize(&self, dst: &mut [u8]) -> Result<usize, Error> {
let digest_len = self.state[0].block_state.snd;
if dst.len() < digest_len as usize {
return Err(Error::InvalidDigestLength);
}
Ok(digest(&self.state, dst) as usize)
}
}
impl Blake2b<Dynamic> {
pub fn finalize(&self, dst: &mut [u8]) -> Result<usize, Error> {
let digest_len = self.state[0].block_state.snd;
if dst.len() < digest_len as usize {
return Err(Error::InvalidDigestLength);
}
Ok(digest(&self.state, dst) as usize)
}
}
impl<const KEY_LEN: usize, const OUT_LEN: usize>
Blake2b<ConstKeyLenConstDigestLen<KEY_LEN, OUT_LEN>>
{
pub fn finalize(&self, dst: &mut [u8; OUT_LEN]) {
digest(&self.state, dst);
}
}
impl<const OUT_LEN: usize> Blake2b<ConstDigestLen<OUT_LEN>> {
pub fn finalize(&self, dst: &mut [u8; OUT_LEN]) {
digest(&self.state, dst);
}
}
impl<const KEY_LEN: usize, const OUT_LEN: usize>
Blake2b<ConstKeyLenConstDigestLen<KEY_LEN, OUT_LEN>>
{
pub fn reset_with_key(&mut self, key: &[u8; KEY_LEN]) {
reset_with_key(&mut self.state, key);
}
}
impl<const KEY_LEN: usize> Blake2b<ConstKeyLen<KEY_LEN>> {
pub fn reset_with_key(&mut self, key: &[u8; KEY_LEN]) {
reset_with_key(&mut self.state, key);
}
}
impl<const OUT_LEN: usize> Blake2b<ConstDigestLen<OUT_LEN>> {
pub fn reset_with_key(&mut self, key: &[u8]) -> Result<(), Error> {
if self.state.as_ref()[0].block_state.fst as usize != key.len() {
return Err(Error::InvalidKeyLength);
}
reset_with_key(&mut self.state, key);
Ok(())
}
}
impl Blake2b<Dynamic> {
pub fn reset_with_key(&mut self, key: &[u8]) -> Result<(), Error> {
if self.state[0].block_state.fst as usize != key.len() {
return Err(Error::InvalidKeyLength);
}
reset_with_key(&mut self.state, key);
Ok(())
}
}
impl Blake2b<ConstKeyLen<0>> {
pub fn reset(&mut self) {
reset(&mut self.state)
}
}
impl<const OUT_LEN: usize> Blake2b<ConstKeyLenConstDigestLen<0, OUT_LEN>> {
pub fn reset(&mut self) {
reset(&mut self.state)
}
}
impl<const OUT_LEN: usize> Blake2b<ConstDigestLen<OUT_LEN>> {
pub fn reset(&mut self) -> Result<(), Error> {
if self.state.as_ref()[0].block_state.fst != 0 {
return Err(Error::InvalidKeyLength);
}
reset(&mut self.state);
Ok(())
}
}
impl Blake2b<Dynamic> {
pub fn reset(&mut self) -> Result<(), Error> {
if self.state.as_ref()[0].block_state.fst != 0 {
return Err(Error::InvalidKeyLength);
}
reset(&mut self.state);
Ok(())
}
}