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