Skip to main content

miden_crypto/merkle/
index.rs

1use core::fmt::Display;
2
3use super::{Felt, MerkleError, Word};
4use crate::utils::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable};
5
6// NODE INDEX
7// ================================================================================================
8
9/// Address to an arbitrary node in a binary tree using level order form.
10///
11/// The position is represented by the pair `(depth, pos)`, where for a given depth `d` elements
12/// are numbered from $0..(2^d)-1$. Example:
13///
14/// ```text
15/// depth
16/// 0             0
17/// 1         0        1
18/// 2      0    1    2    3
19/// 3     0 1  2 3  4 5  6 7
20/// ```
21///
22/// The root is represented by the pair $(0, 0)$, its left child is $(1, 0)$ and its right child
23/// $(1, 1)$.
24#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
25pub struct NodeIndex {
26    depth: u8,
27    position: u64,
28}
29
30impl NodeIndex {
31    // CONSTRUCTORS
32    // --------------------------------------------------------------------------------------------
33
34    /// Creates a new node index.
35    ///
36    /// # Errors
37    /// Returns an error if:
38    /// - `depth` is greater than 64.
39    /// - `position` is greater than or equal to 2^{depth}.
40    pub const fn new(depth: u8, position: u64) -> Result<Self, MerkleError> {
41        if depth > 64 {
42            Err(MerkleError::DepthTooBig(depth as u64))
43        } else if (64 - position.leading_zeros()) > depth as u32 {
44            Err(MerkleError::InvalidNodeIndex { depth, position })
45        } else {
46            Ok(Self { depth, position })
47        }
48    }
49
50    /// Creates a new node index without checking its validity.
51    pub const fn new_unchecked(depth: u8, position: u64) -> Self {
52        debug_assert!(depth <= 64);
53        debug_assert!((64 - position.leading_zeros()) <= depth as u32);
54        Self { depth, position }
55    }
56
57    /// Creates a new node index for testing purposes.
58    ///
59    /// # Panics
60    /// Panics if the `position` is greater than or equal to 2^{depth}.
61    #[cfg(test)]
62    pub(super) fn make(depth: u8, position: u64) -> Self {
63        Self::new(depth, position).unwrap()
64    }
65
66    /// Creates a node index from a pair of field elements representing the depth and position.
67    ///
68    /// # Errors
69    /// Returns an error if:
70    /// - `depth` is greater than 64.
71    /// - `position` is greater than or equal to 2^{depth}.
72    pub fn from_elements(depth: &Felt, position: &Felt) -> Result<Self, MerkleError> {
73        let depth = depth.as_canonical_u64();
74        let depth = u8::try_from(depth).map_err(|_| MerkleError::DepthTooBig(depth))?;
75        let position = position.as_canonical_u64();
76        Self::new(depth, position)
77    }
78
79    /// Creates a new node index pointing to the root of the tree.
80    pub const fn root() -> Self {
81        Self { depth: 0, position: 0 }
82    }
83
84    /// Computes sibling index of the current node.
85    pub const fn sibling(mut self) -> Self {
86        self.position ^= 1;
87        self
88    }
89
90    /// Returns left child index of the current node.
91    pub const fn left_child(mut self) -> Self {
92        self.depth += 1;
93        self.position <<= 1;
94        self
95    }
96
97    /// Returns right child index of the current node.
98    pub const fn right_child(mut self) -> Self {
99        self.depth += 1;
100        self.position = (self.position << 1) + 1;
101        self
102    }
103
104    /// Returns the parent of the current node. This is the same as [`Self::move_up()`], but returns
105    /// a new value instead of mutating `self`.
106    pub const fn parent(mut self) -> Self {
107        self.depth = self.depth.saturating_sub(1);
108        self.position >>= 1;
109        self
110    }
111
112    // PROVIDERS
113    // --------------------------------------------------------------------------------------------
114
115    /// Builds a node to be used as input of a hash function when computing a Merkle path.
116    ///
117    /// Will evaluate the parity of the current instance to define the result.
118    pub const fn build_node(&self, slf: Word, sibling: Word) -> [Word; 2] {
119        if self.is_position_odd() {
120            [sibling, slf]
121        } else {
122            [slf, sibling]
123        }
124    }
125
126    /// Returns the scalar representation of the depth/position pair.
127    ///
128    /// It is computed as `2^depth + position`.
129    ///
130    /// # Errors
131    ///
132    /// - [`MerkleError::DepthTooBig`] if the depth is 64 or greater, as the resulting index would
133    ///   overflow.
134    pub const fn to_scalar_index(&self) -> Result<u64, MerkleError> {
135        if self.depth >= 64 {
136            return Err(MerkleError::DepthTooBig(self.depth as u64));
137        }
138        Ok((1u64 << self.depth as u64) + self.position)
139    }
140
141    /// Returns the depth of the current instance.
142    pub const fn depth(&self) -> u8 {
143        self.depth
144    }
145
146    /// Returns the position of this index within its depth layer.
147    pub const fn position(&self) -> u64 {
148        self.position
149    }
150
151    /// Returns `true` if the current instance points to a right sibling node.
152    pub const fn is_position_odd(&self) -> bool {
153        (self.position & 1) == 1
154    }
155
156    /// Returns `true` if the n-th node on the path points to a right child.
157    pub const fn is_nth_bit_odd(&self, n: u8) -> bool {
158        (self.position >> n) & 1 == 1
159    }
160
161    /// Returns `true` if the depth is `0`.
162    pub const fn is_root(&self) -> bool {
163        self.depth == 0
164    }
165
166    // STATE MUTATORS
167    // --------------------------------------------------------------------------------------------
168
169    /// Traverses one level towards the root, decrementing the depth by `1`.
170    pub fn move_up(&mut self) {
171        self.depth = self.depth.saturating_sub(1);
172        self.position >>= 1;
173    }
174
175    /// Traverses towards the root until the specified depth is reached.
176    ///
177    /// Assumes that the specified depth is smaller than the current depth.
178    pub fn move_up_to(&mut self, depth: u8) {
179        debug_assert!(depth < self.depth);
180        let delta = self.depth.saturating_sub(depth);
181        self.depth = self.depth.saturating_sub(delta);
182        self.position >>= delta as u32;
183    }
184
185    // ITERATORS
186    // --------------------------------------------------------------------------------------------
187
188    /// Return an iterator of the indices required for a Merkle proof of inclusion of a node at
189    /// `self`.
190    ///
191    /// This is *exclusive* on both ends: neither `self` nor the root index are included in the
192    /// returned iterator.
193    pub fn proof_indices(&self) -> impl ExactSizeIterator<Item = NodeIndex> + use<> {
194        ProofIter { next_index: self.sibling() }
195    }
196}
197
198impl Display for NodeIndex {
199    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
200        write!(f, "depth={}, position={}", self.depth, self.position)
201    }
202}
203
204impl Serializable for NodeIndex {
205    fn write_into<W: ByteWriter>(&self, target: &mut W) {
206        target.write_u8(self.depth);
207        target.write_u64(self.position);
208    }
209}
210
211impl Deserializable for NodeIndex {
212    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
213        let depth = source.read_u8()?;
214        let position = source.read_u64()?;
215        NodeIndex::new(depth, position)
216            .map_err(|_| DeserializationError::InvalidValue("Invalid index".into()))
217    }
218
219    fn min_serialized_size() -> usize {
220        // u8 (depth) + u64 (value)
221        9
222    }
223}
224
225/// Implementation for [`NodeIndex::proof_indices()`].
226#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)]
227struct ProofIter {
228    next_index: NodeIndex,
229}
230
231impl Iterator for ProofIter {
232    type Item = NodeIndex;
233
234    fn next(&mut self) -> Option<NodeIndex> {
235        if self.next_index.is_root() {
236            return None;
237        }
238
239        let index = self.next_index;
240        self.next_index = index.parent().sibling();
241
242        Some(index)
243    }
244
245    fn size_hint(&self) -> (usize, Option<usize>) {
246        let remaining = ExactSizeIterator::len(self);
247
248        (remaining, Some(remaining))
249    }
250}
251
252impl ExactSizeIterator for ProofIter {
253    fn len(&self) -> usize {
254        self.next_index.depth() as usize
255    }
256}
257
258#[cfg(test)]
259mod tests {
260    use assert_matches::assert_matches;
261    use proptest::prelude::*;
262
263    use super::*;
264
265    #[test]
266    fn test_node_index_position_too_high() {
267        assert_eq!(NodeIndex::new(0, 0).unwrap(), NodeIndex { depth: 0, position: 0 });
268        let err = NodeIndex::new(0, 1).unwrap_err();
269        assert_matches!(err, MerkleError::InvalidNodeIndex { depth: 0, position: 1 });
270
271        assert_eq!(NodeIndex::new(1, 1).unwrap(), NodeIndex { depth: 1, position: 1 });
272        let err = NodeIndex::new(1, 2).unwrap_err();
273        assert_matches!(err, MerkleError::InvalidNodeIndex { depth: 1, position: 2 });
274
275        assert_eq!(NodeIndex::new(2, 3).unwrap(), NodeIndex { depth: 2, position: 3 });
276        let err = NodeIndex::new(2, 4).unwrap_err();
277        assert_matches!(err, MerkleError::InvalidNodeIndex { depth: 2, position: 4 });
278
279        assert_eq!(NodeIndex::new(3, 7).unwrap(), NodeIndex { depth: 3, position: 7 });
280        let err = NodeIndex::new(3, 8).unwrap_err();
281        assert_matches!(err, MerkleError::InvalidNodeIndex { depth: 3, position: 8 });
282    }
283
284    #[test]
285    fn test_node_index_can_represent_depth_64() {
286        assert!(NodeIndex::new(64, u64::MAX).is_ok());
287    }
288
289    prop_compose! {
290        fn node_index()(position in 0..2u64.pow(u64::BITS - 1)) -> NodeIndex {
291            // unwrap never panics because the range of depth is 0..u64::BITS
292            let mut depth = position.ilog2() as u8;
293            if position > (1 << depth) { // round up
294                depth += 1;
295            }
296            NodeIndex::new(depth, position).unwrap()
297        }
298    }
299
300    proptest! {
301        #[test]
302        fn arbitrary_index_wont_panic_on_move_up(
303            mut index in node_index(),
304            count in prop::num::u8::ANY,
305        ) {
306            for _ in 0..count {
307                index.move_up();
308            }
309        }
310
311        #[test]
312        fn to_scalar_index_succeeds_for_depth_lt_64(depth in 0u8..64, position_bits in 0u64..u64::MAX) {
313            let position = if depth == 0 { 0 } else { position_bits % (1u64 << depth) };
314            let index = NodeIndex::new(depth, position).unwrap();
315            assert!(index.to_scalar_index().is_ok());
316        }
317    }
318
319    #[test]
320    fn test_to_scalar_index_depth_64_returns_error() {
321        let index = NodeIndex::new(64, 0).unwrap();
322        assert_matches!(index.to_scalar_index(), Err(MerkleError::DepthTooBig(64)));
323
324        let index = NodeIndex::new(64, u64::MAX).unwrap();
325        assert_matches!(index.to_scalar_index(), Err(MerkleError::DepthTooBig(64)));
326    }
327
328    #[test]
329    fn test_to_scalar_index_known_values() {
330        // Root's children: depth=1, pos=0 → scalar 2; depth=1, pos=1 → scalar 3
331        assert_eq!(NodeIndex::make(1, 0).to_scalar_index().unwrap(), 2);
332        assert_eq!(NodeIndex::make(1, 1).to_scalar_index().unwrap(), 3);
333
334        // depth=2: scalars 4,5,6,7
335        assert_eq!(NodeIndex::make(2, 0).to_scalar_index().unwrap(), 4);
336        assert_eq!(NodeIndex::make(2, 3).to_scalar_index().unwrap(), 7);
337
338        // depth=3: scalars 8..15
339        assert_eq!(NodeIndex::make(3, 0).to_scalar_index().unwrap(), 8);
340        assert_eq!(NodeIndex::make(3, 7).to_scalar_index().unwrap(), 15);
341    }
342
343    #[test]
344    fn test_to_scalar_index_depth_63_max_position() {
345        // 2^63 + (2^63 - 1) = 2^64 - 1 = u64::MAX
346        let index = NodeIndex::new(63, (1u64 << 63) - 1).unwrap();
347        assert_eq!(index.to_scalar_index().unwrap(), u64::MAX);
348    }
349
350    #[test]
351    fn test_to_scalar_index_boundary_depths() {
352        // depth 0 (root): scalar = 1 + 0 = 1
353        assert_eq!(NodeIndex::make(0, 0).to_scalar_index().unwrap(), 1);
354
355        // depth 62, position 0: scalar = 2^62
356        assert_eq!(NodeIndex::make(62, 0).to_scalar_index().unwrap(), 1u64 << 62);
357
358        // depth 63, position 0: scalar = 2^63
359        assert_eq!(NodeIndex::make(63, 0).to_scalar_index().unwrap(), 1u64 << 63);
360    }
361}