use crate::nh;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Key32(pub [u8; 32]);
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Key64(pub [u8; 64]);
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Key128(pub [u8; 128]);
impl From<[u8; 32]> for Key32 {
fn from(value: [u8; 32]) -> Self {
Self(value)
}
}
impl From<[u8; 64]> for Key64 {
fn from(value: [u8; 64]) -> Self {
Self(value)
}
}
impl From<[u8; 128]> for Key128 {
fn from(value: [u8; 128]) -> Self {
Self(value)
}
}
impl AsRef<[u8; 32]> for Key32 {
fn as_ref(&self) -> &[u8; 32] {
&self.0
}
}
pub type Key = Key32;
pub(crate) fn to_material(key: &impl MasterKey) -> [u8; 32] {
key.to_material()
}
pub trait MasterKey {
fn to_material(&self) -> [u8; 32];
}
impl MasterKey for Key32 {
#[inline]
fn to_material(&self) -> [u8; 32] {
self.0
}
}
impl MasterKey for Key64 {
fn to_material(&self) -> [u8; 32] {
fold_key_words(&self.0)
}
}
impl MasterKey for Key128 {
fn to_material(&self) -> [u8; 32] {
fold_key_words(&self.0)
}
}
impl MasterKey for [u8; 32] {
#[inline]
fn to_material(&self) -> [u8; 32] {
*self
}
}
fn fold_key_words(key: &[u8]) -> [u8; 32] {
debug_assert!(key.len() >= 32 && key.len().is_multiple_of(8));
let words: alloc::vec::Vec<u64> = key
.chunks_exact(8)
.map(|chunk| u64::from_le_bytes(chunk.try_into().unwrap()))
.collect();
let seeds = [words[0], words[1], words[2], words[3]];
let mut out = [0u64; 4];
for (i, word) in words.iter().enumerate().skip(4) {
let lane = i & 3;
out[lane] = nh::hash_word_into(out[lane], *word, seeds[(i + 1) & 3]);
}
let mut material = [0u8; 32];
for (i, word) in out.iter().enumerate() {
material[i * 8..(i + 1) * 8].copy_from_slice(&word.to_le_bytes());
}
material
}