1use std::sync::Arc;
2
3use byteorder::{ByteOrder, LittleEndian};
4use tiny_keccak::{CShake, Hasher as _, Kmac};
5
6use super::nhpoly1305;
7
8const KMAC_KEY_BYTES: usize = 32;
9const KEY_BYTES: usize = KMAC_KEY_BYTES + nhpoly1305::NHPOLY_KEY_BYTES;
10
11pub const OUTPUT_BYTES: usize = 32;
13
14pub const SEED_BYTES: usize = 32;
16
17pub const MIN_SEED_BYTES: usize = 16;
19
20#[derive(Clone, Debug, PartialEq, Eq)]
22pub struct Key(Vec<u8>);
23
24struct HashInner {
25 key: Key,
26 st_kmac: Kmac,
27}
28
29#[derive(Clone)]
31pub struct Hasher {
32 inner: Arc<HashInner>,
33}
34
35impl Hasher {
36 pub fn hash(&self, msg: &[u8]) -> Vec<u8> {
38 let nhpoly_key = &self.inner.key.0[32..];
39 debug_assert_eq!(nhpoly_key.len(), nhpoly1305::NHPOLY_KEY_BYTES);
40 let st_nhpoly = nhpoly1305::Hasher::new(nhpoly_key);
41 let mut poly = [0u8; 16];
42 st_nhpoly.hash(&mut poly, msg);
43
44 let mut msg_len_u8 = [0u8; 8];
45 LittleEndian::write_u64(&mut msg_len_u8, msg.len() as u64);
46
47 let mut st_kmac = self.inner.st_kmac.clone();
48 st_kmac.update(&msg_len_u8);
49 st_kmac.update(&poly);
50 let mut h = vec![0u8; 32];
51 st_kmac.finalize(&mut h);
52 h
53 }
54
55 pub fn new(key: Key, personalization: Option<&[u8]>) -> Hasher {
62 debug_assert_eq!(key.0.len(), KEY_BYTES);
63 let kmac_key = &key.0[..KMAC_KEY_BYTES];
64 let st_kmac = Kmac::v128(kmac_key, personalization.unwrap_or_default());
65 Hasher {
66 inner: Arc::new(HashInner { key, st_kmac }),
67 }
68 }
69}
70
71impl Key {
72 pub fn from_seed(seed: &[u8], personalization: Option<&[u8]>) -> Key {
79 if seed.len() < MIN_SEED_BYTES {
80 panic!("Seed is too short");
81 }
82 let mut st_cshake = CShake::v128(b"sthash key", personalization.unwrap_or_default());
83 st_cshake.update(seed);
84 let mut key = vec![0; KEY_BYTES];
85 st_cshake.finalize(&mut key);
86 Key(key)
87 }
88}