hbs_lms/hasher/
mod.rs

1use core::{
2    convert::TryFrom,
3    fmt::Debug,
4    ops::{Deref, DerefMut},
5};
6use digest::{FixedOutput, Update};
7use tinyvec::ArrayVec;
8
9use crate::constants::{winternitz_chain::*, MAX_HASH_SIZE};
10
11pub mod sha256;
12pub mod shake256;
13
14pub struct HashChainData {
15    data: ArrayVec<[u8; ITER_MAX_LEN]>,
16}
17
18impl Deref for HashChainData {
19    type Target = ArrayVec<[u8; ITER_MAX_LEN]>;
20
21    fn deref(&self) -> &Self::Target {
22        &self.data
23    }
24}
25
26impl DerefMut for HashChainData {
27    fn deref_mut(&mut self) -> &mut Self::Target {
28        &mut self.data
29    }
30}
31
32/**
33 *
34 * This trait is used inside the library to generate hashes. Default implementations are available with [`sha256::Sha256`] and [`shake256::Shake256`].
35 * It can be used to outsource calculations to hardware accelerators.
36 *
37 *
38 * Requires PartialEq, to use compare within the tests.
39 * This is required as long as this [issue](https://github.com/rust-lang/rust/issues/26925) is
40 * open.
41 * */
42pub trait HashChain:
43    Debug + Default + Clone + PartialEq + Send + Sync + FixedOutput + Update
44{
45    const OUTPUT_SIZE: u16;
46    const BLOCK_SIZE: u16;
47
48    fn finalize(self) -> ArrayVec<[u8; MAX_HASH_SIZE]>;
49    fn finalize_reset(&mut self) -> ArrayVec<[u8; MAX_HASH_SIZE]>;
50
51    fn prepare_hash_chain_data(
52        lms_tree_identifier: &[u8],
53        lms_leaf_identifier: &[u8],
54    ) -> HashChainData {
55        let mut hc_data = HashChainData {
56            data: ArrayVec::from_array_len(
57                [0u8; ITER_MAX_LEN],
58                iter_len(Self::OUTPUT_SIZE as usize),
59            ),
60        };
61        hc_data[ITER_I..ITER_Q].copy_from_slice(lms_tree_identifier);
62        hc_data[ITER_Q..ITER_K].copy_from_slice(lms_leaf_identifier);
63        hc_data
64    }
65
66    fn do_hash_chain(
67        &mut self,
68        hc_data: &mut HashChainData,
69        hash_chain_id: u16,
70        initial_value: &[u8],
71        from: usize,
72        to: usize,
73    ) -> ArrayVec<[u8; MAX_HASH_SIZE]> {
74        hc_data[ITER_K..ITER_J].copy_from_slice(&hash_chain_id.to_be_bytes());
75        hc_data[ITER_PREV..].copy_from_slice(initial_value);
76
77        self.do_actual_hash_chain(hc_data, from, to);
78
79        ArrayVec::try_from(&hc_data[ITER_PREV..]).unwrap()
80    }
81
82    fn do_actual_hash_chain(&mut self, hc_data: &mut HashChainData, from: usize, to: usize) {
83        for j in from..to {
84            hc_data[ITER_J] = j as u8;
85            // We assume that the hasher is fresh initialized on the first round
86            self.update(&hc_data.data);
87            let temp_hash = self.finalize_reset();
88            hc_data[ITER_PREV..].copy_from_slice(temp_hash.as_slice());
89        }
90    }
91}