miden-crypto/src/merkle/mmr/accumulator.rs
src/merkle/mmr/accumulator.rsRaw
1use super::{super::Vec, super::ZERO, Felt, MmrProof, Rpo256, Word};
2
3#[derive(Debug, Clone, PartialEq)]
4pub struct MmrPeaks {
5 /// The number of leaves is used to differentiate accumulators that have the same number of
6 /// peaks. This happens because the number of peaks goes up-and-down as the structure is used
7 /// causing existing trees to be merged and new ones to be created. As an example, every time
8 /// the MMR has a power-of-two number of leaves there is a single peak.
9 ///
10 /// Every tree in the MMR forest has a distinct power-of-two size, this means only the right
11 /// most tree can have an odd number of elements (e.g. `1`). Additionally this means that the bits in
12 /// `num_leaves` conveniently encode the size of each individual tree.
13 ///
14 /// Examples:
15 ///
16 /// - With 5 leaves, the binary `0b101`. The number of set bits is equal the number
17 /// of peaks, in this case there are 2 peaks. The 0-indexed least-significant position of
18 /// the bit determines the number of elements of a tree, so the rightmost tree has `2**0`
19 /// elements and the left most has `2**2`.
20 /// - With 12 leaves, the binary is `0b1100`, this case also has 2 peaks, the
21 /// leftmost tree has `2**3=8` elements, and the right most has `2**2=4` elements.
22 pub num_leaves: usize,
23
24 /// All the peaks of every tree in the MMR forest. The peaks are always ordered by number of
25 /// leaves, starting from the peak with most children, to the one with least.
26 ///
27 /// Invariant: The length of `peaks` must be equal to the number of true bits in `num_leaves`.
28 pub peaks: Vec<Word>,
29}
30
31impl MmrPeaks {
32 /// Hashes the peaks.
33 ///
34 /// The procedure will:
35 /// - Flatten and pad the peaks to a vector of Felts.
36 /// - Hash the vector of Felts.
37 pub fn hash_peaks(&self) -> Word {
38 Rpo256::hash_elements(&self.flatten_and_pad_peaks()).into()
39 }
40
41 pub fn verify(&self, value: Word, opening: MmrProof) -> bool {
42 let root = &self.peaks[opening.peak_index()];
43 opening.merkle_path.verify(opening.relative_pos() as u64, value, root)
44 }
45
46 /// Flattens and pads the peaks to make hashing inside of the Miden VM easier.
47 ///
48 /// The procedure will:
49 /// - Flatten the vector of Words into a vector of Felts.
50 /// - Pad the peaks with ZERO to an even number of words, this removes the need to handle RPO
51 /// padding.
52 /// - Pad the peaks to a minimum length of 16 words, which reduces the constant cost of
53 /// hashing.
54 pub fn flatten_and_pad_peaks(&self) -> Vec<Felt> {
55 let num_peaks = self.peaks.len();
56
57 // To achieve the padding rules above we calculate the length of the final vector.
58 // This is calculated as the number of field elements. Each peak is 4 field elements.
59 // The length is calculated as follows:
60 // - If there are less than 16 peaks, the data is padded to 16 peaks and as such requires
61 // 64 field elements.
62 // - If there are more than 16 peaks and the number of peaks is odd, the data is padded to
63 // an even number of peaks and as such requires `(num_peaks + 1) * 4` field elements.
64 // - If there are more than 16 peaks and the number of peaks is even, the data is not padded
65 // and as such requires `num_peaks * 4` field elements.
66 let len = if num_peaks < 16 {
67 64
68 } else if num_peaks % 2 == 1 {
69 (num_peaks + 1) * 4
70 } else {
71 num_peaks * 4
72 };
73
74 let mut elements = Vec::with_capacity(len);
75 elements.extend_from_slice(&self.peaks.as_slice().concat());
76 elements.resize(len, ZERO);
77 elements
78 }
79}