arnaucube
arnaucube/miden-cryptoPublic Self-hosted repository
miden-crypto/src/merkle/mmr/peaks.rs
src/merkle/mmr/peaks.rsRaw
  1use super::{super::ZERO, Felt, MmrError, MmrProof, Rpo256, RpoDigest, Word};
  2use alloc::vec::Vec;
  3
  4// MMR PEAKS
  5// ================================================================================================
  6
  7#[derive(Debug, Clone, PartialEq, Eq)]
  8#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
  9pub struct MmrPeaks {
 10    /// The number of leaves is used to differentiate MMRs that have the same number of peaks. This
 11    /// happens because the number of peaks goes up-and-down as the structure is used causing
 12    /// existing trees to be merged and new ones to be created. As an example, every time the MMR
 13    /// has a power-of-two number of leaves there is a single peak.
 14    ///
 15    /// Every tree in the MMR forest has a distinct power-of-two size, this means only the right-
 16    /// most tree can have an odd number of elements (e.g. `1`). Additionally this means that the
 17    /// bits in `num_leaves` conveniently encode the size of each individual tree.
 18    ///
 19    /// Examples:
 20    ///
 21    ///    - With 5 leaves, the binary `0b101`. The number of set bits is equal the number
 22    ///      of peaks, in this case there are 2 peaks. The 0-indexed least-significant position of
 23    ///      the bit determines the number of elements of a tree, so the rightmost tree has `2**0`
 24    ///      elements and the left most has `2**2`.
 25    ///    - With 12 leaves, the binary is `0b1100`, this case also has 2 peaks, the
 26    ///      leftmost tree has `2**3=8` elements, and the right most has `2**2=4` elements.
 27    num_leaves: usize,
 28
 29    /// All the peaks of every tree in the MMR forest. The peaks are always ordered by number of
 30    /// leaves, starting from the peak with most children, to the one with least.
 31    ///
 32    /// Invariant: The length of `peaks` must be equal to the number of true bits in `num_leaves`.
 33    peaks: Vec<RpoDigest>,
 34}
 35
 36impl MmrPeaks {
 37    // CONSTRUCTOR
 38    // --------------------------------------------------------------------------------------------
 39
 40    /// Returns new [MmrPeaks] instantiated from the provided vector of peaks and the number of
 41    /// leaves in the underlying MMR.
 42    ///
 43    /// # Errors
 44    /// Returns an error if the number of leaves and the number of peaks are inconsistent.
 45    pub fn new(num_leaves: usize, peaks: Vec<RpoDigest>) -> Result<Self, MmrError> {
 46        if num_leaves.count_ones() as usize != peaks.len() {
 47            return Err(MmrError::InvalidPeaks);
 48        }
 49
 50        Ok(Self { num_leaves, peaks })
 51    }
 52
 53    // ACCESSORS
 54    // --------------------------------------------------------------------------------------------
 55
 56    /// Returns a count of leaves in the underlying MMR.
 57    pub fn num_leaves(&self) -> usize {
 58        self.num_leaves
 59    }
 60
 61    /// Returns the number of peaks of the underlying MMR.
 62    pub fn num_peaks(&self) -> usize {
 63        self.peaks.len()
 64    }
 65
 66    /// Returns the list of peaks of the underlying MMR.
 67    pub fn peaks(&self) -> &[RpoDigest] {
 68        &self.peaks
 69    }
 70
 71    /// Converts this [MmrPeaks] into its components: number of leaves and a vector of peaks of
 72    /// the underlying MMR.
 73    pub fn into_parts(self) -> (usize, Vec<RpoDigest>) {
 74        (self.num_leaves, self.peaks)
 75    }
 76
 77    /// Hashes the peaks.
 78    ///
 79    /// The procedure will:
 80    /// - Flatten and pad the peaks to a vector of Felts.
 81    /// - Hash the vector of Felts.
 82    pub fn hash_peaks(&self) -> RpoDigest {
 83        Rpo256::hash_elements(&self.flatten_and_pad_peaks())
 84    }
 85
 86    pub fn verify(&self, value: RpoDigest, opening: MmrProof) -> bool {
 87        let root = &self.peaks[opening.peak_index()];
 88        opening.merkle_path.verify(opening.relative_pos() as u64, value, root)
 89    }
 90
 91    /// Flattens and pads the peaks to make hashing inside of the Miden VM easier.
 92    ///
 93    /// The procedure will:
 94    /// - Flatten the vector of Words into a vector of Felts.
 95    /// - Pad the peaks with ZERO to an even number of words, this removes the need to handle RPO
 96    ///   padding.
 97    /// - Pad the peaks to a minimum length of 16 words, which reduces the constant cost of
 98    ///   hashing.
 99    pub fn flatten_and_pad_peaks(&self) -> Vec<Felt> {
100        let num_peaks = self.peaks.len();
101
102        // To achieve the padding rules above we calculate the length of the final vector.
103        // This is calculated as the number of field elements. Each peak is 4 field elements.
104        // The length is calculated as follows:
105        // - If there are less than 16 peaks, the data is padded to 16 peaks and as such requires
106        //   64 field elements.
107        // - If there are more than 16 peaks and the number of peaks is odd, the data is padded to
108        //   an even number of peaks and as such requires `(num_peaks + 1) * 4` field elements.
109        // - If there are more than 16 peaks and the number of peaks is even, the data is not padded
110        //   and as such requires `num_peaks * 4` field elements.
111        let len = if num_peaks < 16 {
112            64
113        } else if num_peaks % 2 == 1 {
114            (num_peaks + 1) * 4
115        } else {
116            num_peaks * 4
117        };
118
119        let mut elements = Vec::with_capacity(len);
120        elements.extend_from_slice(
121            &self
122                .peaks
123                .as_slice()
124                .iter()
125                .map(|digest| digest.into())
126                .collect::<Vec<Word>>()
127                .concat(),
128        );
129        elements.resize(len, ZERO);
130        elements
131    }
132}
133
134impl From<MmrPeaks> for Vec<RpoDigest> {
135    fn from(peaks: MmrPeaks) -> Self {
136        peaks.peaks
137    }
138}