miden_crypto/merkle/mmr/
inorder.rs

1//! Index for nodes of a binary tree based on an in-order tree walk.
2//!
3//! In-order walks have the parent node index split its left and right subtrees. All the left
4//! children have indexes lower than the parent, meanwhile all the right subtree higher indexes.
5//! This property makes it is easy to compute changes to the index by adding or subtracting the
6//! leaves count.
7use core::num::NonZeroUsize;
8
9use winter_utils::{Deserializable, Serializable};
10
11// IN-ORDER INDEX
12// ================================================================================================
13
14/// Index of nodes in a perfectly balanced binary tree based on an in-order tree walk.
15#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
16pub struct InOrderIndex {
17    idx: usize,
18}
19
20impl InOrderIndex {
21    // CONSTRUCTORS
22    // --------------------------------------------------------------------------------------------
23
24    /// Returns a new [InOrderIndex] instantiated from the provided value.
25    pub fn new(idx: NonZeroUsize) -> InOrderIndex {
26        InOrderIndex { idx: idx.get() }
27    }
28
29    /// Return a new [InOrderIndex] instantiated from the specified leaf position.
30    ///
31    /// # Panics:
32    /// If `leaf` is higher than or equal to `usize::MAX / 2`.
33    pub fn from_leaf_pos(leaf: usize) -> InOrderIndex {
34        // Convert the position from 0-indexed to 1-indexed, since the bit manipulation in this
35        // implementation only works 1-indexed counting.
36        let pos = leaf + 1;
37        InOrderIndex { idx: pos * 2 - 1 }
38    }
39
40    // PUBLIC ACCESSORS
41    // --------------------------------------------------------------------------------------------
42
43    /// True if the index is pointing at a leaf.
44    ///
45    /// Every odd number represents a leaf.
46    pub fn is_leaf(&self) -> bool {
47        self.idx & 1 == 1
48    }
49
50    /// Returns true if this note is a left child of its parent.
51    pub fn is_left_child(&self) -> bool {
52        self.parent().left_child() == *self
53    }
54
55    /// Returns the level of the index.
56    ///
57    /// Starts at level zero for leaves and increases by one for each parent.
58    pub fn level(&self) -> u32 {
59        self.idx.trailing_zeros()
60    }
61
62    /// Returns the index of the left child.
63    ///
64    /// # Panics:
65    /// If the index corresponds to a leaf.
66    pub fn left_child(&self) -> InOrderIndex {
67        // The left child is itself a parent, with an index that splits its left/right subtrees. To
68        // go from the parent index to its left child, it is only necessary to subtract the count
69        // of elements on the child's right subtree + 1.
70        let els = 1 << (self.level() - 1);
71        InOrderIndex { idx: self.idx - els }
72    }
73
74    /// Returns the index of the right child.
75    ///
76    /// # Panics:
77    /// If the index corresponds to a leaf.
78    pub fn right_child(&self) -> InOrderIndex {
79        // To compute the index of the parent of the right subtree it is sufficient to add the size
80        // of its left subtree + 1.
81        let els = 1 << (self.level() - 1);
82        InOrderIndex { idx: self.idx + els }
83    }
84
85    /// Returns the index of the parent node.
86    pub fn parent(&self) -> InOrderIndex {
87        // If the current index corresponds to a node in a left tree, to go up a level it is
88        // required to add the number of nodes of the right sibling, analogously if the node is a
89        // right child, going up requires subtracting the number of nodes in its left subtree.
90        //
91        // Both of the above operations can be performed by bitwise manipulation. Below the mask
92        // sets the number of trailing zeros to be equal the new level of the index, and the bit
93        // marks the parent.
94        let target = self.level() + 1;
95        let bit = 1 << target;
96        let mask = bit - 1;
97        let idx = self.idx ^ (self.idx & mask);
98        InOrderIndex { idx: idx | bit }
99    }
100
101    /// Returns the index of the sibling node.
102    pub fn sibling(&self) -> InOrderIndex {
103        let parent = self.parent();
104        if *self > parent {
105            parent.left_child()
106        } else {
107            parent.right_child()
108        }
109    }
110
111    /// Returns the inner value of this [InOrderIndex].
112    pub fn inner(&self) -> u64 {
113        self.idx as u64
114    }
115}
116
117impl Serializable for InOrderIndex {
118    fn write_into<W: winter_utils::ByteWriter>(&self, target: &mut W) {
119        target.write_usize(self.idx);
120    }
121}
122
123impl Deserializable for InOrderIndex {
124    fn read_from<R: winter_utils::ByteReader>(
125        source: &mut R,
126    ) -> Result<Self, winter_utils::DeserializationError> {
127        let idx = source.read_usize()?;
128        Ok(InOrderIndex { idx })
129    }
130}
131
132// CONVERSIONS FROM IN-ORDER INDEX
133// ------------------------------------------------------------------------------------------------
134
135impl From<InOrderIndex> for u64 {
136    fn from(index: InOrderIndex) -> Self {
137        index.idx as u64
138    }
139}
140
141// TESTS
142// ================================================================================================
143
144#[cfg(test)]
145mod test {
146    use proptest::prelude::*;
147    use winter_utils::{Deserializable, Serializable};
148
149    use super::InOrderIndex;
150
151    proptest! {
152        #[test]
153        fn proptest_inorder_index_random(count in 1..1000usize) {
154            let left_pos = count * 2;
155            let right_pos = count * 2 + 1;
156
157            let left = InOrderIndex::from_leaf_pos(left_pos);
158            let right = InOrderIndex::from_leaf_pos(right_pos);
159
160            assert!(left.is_leaf());
161            assert!(right.is_leaf());
162            assert_eq!(left.parent(), right.parent());
163            assert_eq!(left.parent().right_child(), right);
164            assert_eq!(left, right.parent().left_child());
165            assert_eq!(left.sibling(), right);
166            assert_eq!(left, right.sibling());
167        }
168    }
169
170    #[test]
171    fn test_inorder_index_basic() {
172        let left = InOrderIndex::from_leaf_pos(0);
173        let right = InOrderIndex::from_leaf_pos(1);
174
175        assert!(left.is_leaf());
176        assert!(right.is_leaf());
177        assert_eq!(left.parent(), right.parent());
178        assert_eq!(left.parent().right_child(), right);
179        assert_eq!(left, right.parent().left_child());
180        assert_eq!(left.sibling(), right);
181        assert_eq!(left, right.sibling());
182    }
183
184    #[test]
185    fn test_inorder_index_serialization() {
186        let index = InOrderIndex::from_leaf_pos(5);
187        let bytes = index.to_bytes();
188        let index2 = InOrderIndex::read_from_bytes(&bytes).unwrap();
189        assert_eq!(index, index2);
190    }
191}