arnaucube
arnaucube/miden-cryptoPublic Self-hosted repository
miden-crypto/src/merkle/mmr/accumulator.rs
src/merkle/mmr/accumulator.rsRaw
 1use super::{
 2    super::{RpoDigest, Vec, ZERO},
 3    Felt, MmrProof, Rpo256, Word,
 4};
 5
 6#[derive(Debug, Clone, PartialEq)]
 7#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
 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<RpoDigest>,
33}
34
35impl MmrPeaks {
36    /// Hashes the peaks.
37    ///
38    /// The procedure will:
39    /// - Flatten and pad the peaks to a vector of Felts.
40    /// - Hash the vector of Felts.
41    pub fn hash_peaks(&self) -> Word {
42        Rpo256::hash_elements(&self.flatten_and_pad_peaks()).into()
43    }
44
45    pub fn verify(&self, value: RpoDigest, opening: MmrProof) -> bool {
46        let root = &self.peaks[opening.peak_index()];
47        opening.merkle_path.verify(opening.relative_pos() as u64, value, root)
48    }
49
50    /// Flattens and pads the peaks to make hashing inside of the Miden VM easier.
51    ///
52    /// The procedure will:
53    /// - Flatten the vector of Words into a vector of Felts.
54    /// - Pad the peaks with ZERO to an even number of words, this removes the need to handle RPO
55    ///   padding.
56    /// - Pad the peaks to a minimum length of 16 words, which reduces the constant cost of
57    ///   hashing.
58    pub fn flatten_and_pad_peaks(&self) -> Vec<Felt> {
59        let num_peaks = self.peaks.len();
60
61        // To achieve the padding rules above we calculate the length of the final vector.
62        // This is calculated as the number of field elements. Each peak is 4 field elements.
63        // The length is calculated as follows:
64        // - If there are less than 16 peaks, the data is padded to 16 peaks and as such requires
65        //   64 field elements.
66        // - If there are more than 16 peaks and the number of peaks is odd, the data is padded to
67        //   an even number of peaks and as such requires `(num_peaks + 1) * 4` field elements.
68        // - If there are more than 16 peaks and the number of peaks is even, the data is not padded
69        //   and as such requires `num_peaks * 4` field elements.
70        let len = if num_peaks < 16 {
71            64
72        } else if num_peaks % 2 == 1 {
73            (num_peaks + 1) * 4
74        } else {
75            num_peaks * 4
76        };
77
78        let mut elements = Vec::with_capacity(len);
79        elements.extend_from_slice(
80            &self
81                .peaks
82                .as_slice()
83                .iter()
84                .map(|digest| digest.into())
85                .collect::<Vec<Word>>()
86                .concat(),
87        );
88        elements.resize(len, ZERO);
89        elements
90    }
91}