arnaucube
arnaucube/miden-cryptoPublic Self-hosted repository
miden-crypto/src/merkle/mmr/accumulator.rs
src/merkle/mmr/accumulator.rsRaw
 1use super::{
 2    super::Vec,
 3    super::{WORD_SIZE, ZERO},
 4    MmrProof, Rpo256, Word,
 5};
 6
 7#[derive(Debug, Clone, PartialEq)]
 8pub struct MmrPeaks {
 9    /// The number of leaves is used to differentiate accumulators that have the same number of
10    /// peaks. This happens because the number of peaks goes up-and-down as the structure is used
11    /// causing existing trees to be merged and new ones to be created. As an example, every time
12    /// the MMR has a power-of-two number of leaves there is a single peak.
13    ///
14    /// Every tree in the MMR forest has a distinct power-of-two size, this means only the right
15    /// most tree can have an odd number of elements (e.g. `1`). Additionally this means that the bits in
16    /// `num_leaves` conveniently encode the size of each individual tree.
17    ///
18    /// Examples:
19    ///
20    ///    - With 5 leaves, the binary `0b101`. The number of set bits is equal the number
21    ///      of peaks, in this case there are 2 peaks. The 0-indexed least-significant position of
22    ///      the bit determines the number of elements of a tree, so the rightmost tree has `2**0`
23    ///      elements and the left most has `2**2`.
24    ///    - With 12 leaves, the binary is `0b1100`, this case also has 2 peaks, the
25    ///      leftmost tree has `2**3=8` elements, and the right most has `2**2=4` elements.
26    pub num_leaves: usize,
27
28    /// All the peaks of every tree in the MMR forest. The peaks are always ordered by number of
29    /// leaves, starting from the peak with most children, to the one with least.
30    ///
31    /// Invariant: The length of `peaks` must be equal to the number of true bits in `num_leaves`.
32    pub peaks: Vec<Word>,
33}
34
35impl MmrPeaks {
36    /// Hashes the peaks.
37    ///
38    /// The hashing is optimized to work with the Miden VM, the procedure will:
39    ///
40    /// - Pad the peaks with ZERO to an even number of words, this removes the need to handle RPO padding.
41    /// - Pad the peaks to a minimum length of 16 words, which reduces the constant cost of
42    ///   hashing.
43    pub fn hash_peaks(&self) -> Word {
44        let mut copy = self.peaks.clone();
45
46        if copy.len() < 16 {
47            copy.resize(16, [ZERO; WORD_SIZE])
48        } else if copy.len() % 2 == 1 {
49            copy.push([ZERO; WORD_SIZE])
50        }
51
52        Rpo256::hash_elements(&copy.as_slice().concat()).into()
53    }
54
55    pub fn verify(&self, value: Word, opening: MmrProof) -> bool {
56        let root = &self.peaks[opening.peak_index()];
57        opening
58            .merkle_path
59            .verify(opening.relative_pos() as u64, value, root)
60    }
61}