light_indexed_array/
array.rs

1use std::{cmp::Ordering, fmt::Debug, marker::PhantomData};
2
3use light_hasher::{bigint::bigint_to_be_bytes_array, Hasher};
4use num_bigint::BigUint;
5use num_traits::{CheckedAdd, CheckedSub, ToBytes, Unsigned, Zero};
6
7use crate::{changelog::RawIndexedElement, errors::IndexedArrayError};
8
9#[derive(Clone, Debug, Default)]
10pub struct IndexedElement<I>
11where
12    I: CheckedAdd + CheckedSub + Copy + Clone + PartialOrd + ToBytes + TryFrom<usize> + Unsigned,
13    I: Into<usize>,
14{
15    pub index: I,
16    pub value: BigUint,
17    pub next_index: I,
18}
19
20impl<I> From<RawIndexedElement<I>> for IndexedElement<I>
21where
22    I: CheckedAdd + CheckedSub + Copy + Clone + PartialOrd + ToBytes + TryFrom<usize> + Unsigned,
23    I: Into<usize>,
24{
25    fn from(value: RawIndexedElement<I>) -> Self {
26        IndexedElement {
27            index: value.index,
28            value: BigUint::from_bytes_be(&value.value),
29            next_index: value.next_index,
30        }
31    }
32}
33
34impl<I> PartialEq for IndexedElement<I>
35where
36    I: CheckedAdd + CheckedSub + Copy + Clone + PartialOrd + ToBytes + TryFrom<usize> + Unsigned,
37    I: Into<usize>,
38{
39    fn eq(&self, other: &Self) -> bool {
40        self.value == other.value
41            && self.index == other.index
42            && self.next_index == other.next_index
43    }
44}
45
46impl<I> Eq for IndexedElement<I>
47where
48    I: CheckedAdd + CheckedSub + Copy + Clone + PartialOrd + ToBytes + TryFrom<usize> + Unsigned,
49    I: Into<usize>,
50{
51}
52
53impl<I> PartialOrd for IndexedElement<I>
54where
55    I: CheckedAdd + CheckedSub + Copy + Clone + PartialOrd + ToBytes + TryFrom<usize> + Unsigned,
56    I: Into<usize>,
57{
58    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
59        Some(self.cmp(other))
60    }
61}
62
63impl<I> Ord for IndexedElement<I>
64where
65    I: CheckedAdd + CheckedSub + Copy + Clone + PartialOrd + ToBytes + TryFrom<usize> + Unsigned,
66    I: Into<usize>,
67{
68    fn cmp(&self, other: &Self) -> Ordering {
69        self.value.cmp(&other.value)
70    }
71}
72
73impl<I> IndexedElement<I>
74where
75    I: CheckedAdd + CheckedSub + Copy + Clone + PartialOrd + ToBytes + TryFrom<usize> + Unsigned,
76    I: Into<usize>,
77{
78    pub fn index(&self) -> usize {
79        self.index.into()
80    }
81
82    pub fn next_index(&self) -> usize {
83        self.next_index.into()
84    }
85
86    pub fn hash<H>(&self, next_value: &BigUint) -> Result<[u8; 32], IndexedArrayError>
87    where
88        H: Hasher,
89    {
90        let hash = H::hashv(&[
91            bigint_to_be_bytes_array::<32>(&self.value)?.as_ref(),
92            bigint_to_be_bytes_array::<32>(next_value)?.as_ref(),
93        ])?;
94
95        Ok(hash)
96    }
97
98    pub fn update_from_raw_element(&mut self, raw_element: &RawIndexedElement<I>) {
99        self.index = raw_element.index;
100        self.value = BigUint::from_bytes_be(&raw_element.value);
101        self.next_index = raw_element.next_index;
102    }
103}
104
105#[derive(Clone, Debug)]
106pub struct IndexedElementBundle<I>
107where
108    I: CheckedAdd + CheckedSub + Copy + Clone + PartialOrd + ToBytes + TryFrom<usize> + Unsigned,
109    I: Into<usize>,
110{
111    pub new_low_element: IndexedElement<I>,
112    pub new_element: IndexedElement<I>,
113    pub new_element_next_value: BigUint,
114}
115
116#[derive(Clone, Debug)]
117pub struct IndexedArray<H, I>
118where
119    H: Hasher,
120    I: CheckedAdd + CheckedSub + Copy + Clone + PartialOrd + ToBytes + TryFrom<usize> + Unsigned,
121    I: Into<usize>,
122{
123    pub elements: Vec<IndexedElement<I>>,
124    pub current_node_index: I,
125    pub highest_element_index: I,
126    pub highest_value: BigUint,
127
128    _hasher: PhantomData<H>,
129}
130
131impl<H, I> Default for IndexedArray<H, I>
132where
133    H: Hasher,
134    I: CheckedAdd + CheckedSub + Copy + Clone + PartialOrd + ToBytes + TryFrom<usize> + Unsigned,
135    I: Into<usize>,
136{
137    fn default() -> Self {
138        Self {
139            elements: vec![IndexedElement {
140                index: I::zero(),
141                value: BigUint::zero(),
142                next_index: I::zero(),
143            }],
144            current_node_index: I::zero(),
145            highest_element_index: I::zero(),
146            highest_value: BigUint::zero(),
147            _hasher: PhantomData,
148        }
149    }
150}
151
152impl<H, I> IndexedArray<H, I>
153where
154    H: Hasher,
155    I: CheckedAdd + CheckedSub + Copy + Clone + PartialOrd + ToBytes + TryFrom<usize> + Unsigned,
156    I: Into<usize>,
157{
158    pub fn new(value: BigUint, next_value: BigUint) -> Self {
159        Self {
160            current_node_index: I::zero(),
161            highest_element_index: I::zero(),
162            highest_value: next_value,
163            elements: vec![IndexedElement {
164                index: I::zero(),
165                value,
166                next_index: I::zero(),
167            }],
168            _hasher: PhantomData,
169        }
170    }
171    pub fn get(&self, index: usize) -> Option<&IndexedElement<I>> {
172        self.elements.get(index)
173    }
174
175    pub fn len(&self) -> usize {
176        self.current_node_index.into()
177    }
178
179    pub fn is_empty(&self) -> bool {
180        self.current_node_index == I::zero()
181    }
182
183    pub fn iter(&self) -> IndexingArrayIter<H, I> {
184        IndexingArrayIter {
185            indexing_array: self,
186            front: 0,
187            back: self.current_node_index.into(),
188        }
189    }
190
191    pub fn find_element(&self, value: &BigUint) -> Option<&IndexedElement<I>> {
192        self.elements[..self.len() + 1]
193            .iter()
194            .find(|&node| node.value == *value)
195    }
196
197    /// Returns the index of the low element for the given `value`, which is
198    /// not yet the part of the array.
199    ///
200    /// Low element is the greatest element which still has lower value than
201    /// the provided one.
202    ///
203    /// Low elements are used in non-membership proofs.
204    pub fn find_low_element_index_for_nonexistent(
205        &self,
206        value: &BigUint,
207    ) -> Result<I, IndexedArrayError> {
208        // Try to find element whose next element is higher than the provided
209        // value.
210        for (i, node) in self.elements.iter().enumerate() {
211            if node.value == *value {
212                return Err(IndexedArrayError::ElementAlreadyExists);
213            }
214            if self.elements[node.next_index()].value > *value && node.value < *value {
215                return i.try_into().map_err(|_| IndexedArrayError::IntegerOverflow);
216            }
217        }
218        // If no such element was found, it means that our value is going to be
219        // the greatest in the array. This means that the currently greatest
220        // element is going to be the low element of our value.
221        Ok(self.highest_element_index)
222    }
223
224    /// Returns the:
225    ///
226    /// * Low element for the given value.
227    /// * Next value for that low element.
228    ///
229    /// For the given `value`, which is not yet the part of the array.
230    ///
231    /// Low element is the greatest element which still has lower value than
232    /// the provided one.
233    ///
234    /// Low elements are used in non-membership proofs.
235    pub fn find_low_element_for_nonexistent(
236        &self,
237        value: &BigUint,
238    ) -> Result<(IndexedElement<I>, BigUint), IndexedArrayError> {
239        let low_element_index = self.find_low_element_index_for_nonexistent(value)?;
240        let low_element = self.elements[low_element_index.into()].clone();
241        let next_value = if low_element.next_index == I::zero() {
242            self.highest_value.clone()
243        } else {
244            self.elements[low_element.next_index.into()].value.clone()
245        };
246        Ok((low_element.clone(), next_value))
247    }
248
249    /// Returns the index of the low element for the given `value`, which is
250    /// already the part of the array.
251    ///
252    /// Low element is the greatest element which still has lower value than
253    /// the provided one.
254    ///
255    /// Low elements are used in non-membership proofs.
256    pub fn find_low_element_index_for_existent(
257        &self,
258        value: &BigUint,
259    ) -> Result<I, IndexedArrayError> {
260        for (i, node) in self.elements[..self.len() + 1].iter().enumerate() {
261            if self.elements[node.next_index.into()].value == *value {
262                let i = i
263                    .try_into()
264                    .map_err(|_| IndexedArrayError::IntegerOverflow)?;
265                return Ok(i);
266            }
267        }
268        Err(IndexedArrayError::ElementDoesNotExist)
269    }
270
271    /// Returns the low element for the given `value`, which is already the
272    /// part of the array.
273    ///
274    /// Low element is the greatest element which still has lower value than
275    /// the provided one.
276    ///
277    /// Low elements are used in non-membership proofs.
278    pub fn find_low_element_for_existent(
279        &self,
280        value: &BigUint,
281    ) -> Result<IndexedElement<I>, IndexedArrayError> {
282        let low_element_index = self.find_low_element_index_for_existent(value)?;
283        let low_element = self.elements[low_element_index.into()].clone();
284        Ok(low_element)
285    }
286
287    /// Returns the hash of the given element. That hash consists of:
288    ///
289    /// * The value of the given element.
290    /// * The `next_index` of the given element.
291    /// * The value of the element pointed by `next_index`.
292    pub fn hash_element(&self, index: I) -> Result<[u8; 32], IndexedArrayError> {
293        let element = self
294            .elements
295            .get(index.into())
296            .ok_or(IndexedArrayError::IndexHigherThanMax)?;
297        let next_element = self
298            .elements
299            .get(element.next_index.into())
300            .ok_or(IndexedArrayError::IndexHigherThanMax)?;
301        element.hash::<H>(&next_element.value)
302    }
303
304    /// Returns an updated low element and a new element, created based on the
305    /// provided `low_element_index` and `value`.
306    pub fn new_element_with_low_element_index(
307        &self,
308        low_element_index: I,
309        value: &BigUint,
310    ) -> Result<IndexedElementBundle<I>, IndexedArrayError> {
311        let mut new_low_element = self.elements[low_element_index.into()].clone();
312
313        let new_element_index = self
314            .current_node_index
315            .checked_add(&I::one())
316            .ok_or(IndexedArrayError::IntegerOverflow)?;
317        let new_element = IndexedElement {
318            index: new_element_index,
319            value: value.clone(),
320            next_index: new_low_element.next_index,
321        };
322
323        new_low_element.next_index = new_element_index;
324
325        let new_element_next_value = if new_element.next_index == I::zero() {
326            self.highest_value.clone()
327        } else {
328            self.elements[new_element.next_index.into()].value.clone()
329        };
330
331        Ok(IndexedElementBundle {
332            new_low_element,
333            new_element,
334            new_element_next_value,
335        })
336    }
337
338    pub fn new_element(
339        &self,
340        value: &BigUint,
341    ) -> Result<IndexedElementBundle<I>, IndexedArrayError> {
342        let low_element_index = self.find_low_element_index_for_nonexistent(value)?;
343        let element = self.new_element_with_low_element_index(low_element_index, value)?;
344
345        Ok(element)
346    }
347
348    /// Appends the given `value` to the indexing array.
349    pub fn append_with_low_element_index(
350        &mut self,
351        low_element_index: I,
352        value: &BigUint,
353    ) -> Result<IndexedElementBundle<I>, IndexedArrayError> {
354        // TOD0: add length check, and add field to with tree height here
355
356        let old_low_element = &self.elements[low_element_index.into()];
357
358        // Check that the `value` belongs to the range of `old_low_element`.
359        if old_low_element.next_index == I::zero() {
360            // In this case, the `old_low_element` is the greatest element.
361            // The value of `new_element` needs to be greater than the value of
362            // `old_low_element` (and therefore, be the greatest).
363            if value <= &old_low_element.value {
364                return Err(IndexedArrayError::LowElementGreaterOrEqualToNewElement);
365            }
366        } else {
367            // The value of `new_element` needs to be greater than the value of
368            // `old_low_element` (and therefore, be the greatest).
369            if value <= &old_low_element.value {
370                return Err(IndexedArrayError::LowElementGreaterOrEqualToNewElement);
371            }
372            // The value of `new_element` needs to be lower than the value of
373            // next element pointed by `old_low_element`.
374            if value >= &self.elements[old_low_element.next_index.into()].value {
375                return Err(IndexedArrayError::NewElementGreaterOrEqualToNextElement);
376            }
377        }
378
379        // Create new node.
380        let new_element_bundle =
381            self.new_element_with_low_element_index(low_element_index, value)?;
382
383        // If the old low element wasn't pointing to any element, it means that:
384        //
385        // * It used to be the highest element.
386        // * Our new element, which we are appending, is going the be the
387        //   highest element.
388        //
389        // Therefore, we need to save the new element index as the highest
390        // index.
391        if old_low_element.next_index == I::zero() {
392            self.highest_element_index = new_element_bundle.new_element.index;
393        }
394
395        // Insert new node.
396        self.current_node_index = new_element_bundle.new_element.index;
397        self.elements.push(new_element_bundle.new_element.clone());
398
399        // Update low element.
400        self.elements[low_element_index.into()] = new_element_bundle.new_low_element.clone();
401
402        Ok(new_element_bundle)
403    }
404
405    pub fn append(
406        &mut self,
407        value: &BigUint,
408    ) -> Result<IndexedElementBundle<I>, IndexedArrayError> {
409        let low_element_index = self.find_low_element_index_for_nonexistent(value)?;
410        self.append_with_low_element_index(low_element_index, value)
411    }
412
413    pub fn lowest(&self) -> Option<IndexedElement<I>> {
414        if self.current_node_index < I::one() {
415            None
416        } else {
417            self.elements.get(1).cloned()
418        }
419    }
420}
421
422pub struct IndexingArrayIter<'a, H, I>
423where
424    H: Hasher,
425    I: CheckedAdd + CheckedSub + Copy + Clone + PartialOrd + ToBytes + TryFrom<usize> + Unsigned,
426    I: Into<usize>,
427{
428    indexing_array: &'a IndexedArray<H, I>,
429    front: usize,
430    back: usize,
431}
432
433impl<'a, H, I> Iterator for IndexingArrayIter<'a, H, I>
434where
435    H: Hasher,
436    I: CheckedAdd + CheckedSub + Copy + Clone + PartialOrd + ToBytes + TryFrom<usize> + Unsigned,
437    I: Into<usize>,
438{
439    type Item = &'a IndexedElement<I>;
440
441    fn next(&mut self) -> Option<Self::Item> {
442        if self.front <= self.back {
443            let result = self.indexing_array.elements.get(self.front);
444            self.front += 1;
445            result
446        } else {
447            None
448        }
449    }
450}
451
452impl<H, I> DoubleEndedIterator for IndexingArrayIter<'_, H, I>
453where
454    H: Hasher,
455    I: CheckedAdd + CheckedSub + Copy + Clone + PartialOrd + ToBytes + TryFrom<usize> + Unsigned,
456    I: Into<usize>,
457{
458    fn next_back(&mut self) -> Option<Self::Item> {
459        if self.back >= self.front {
460            let result = self.indexing_array.elements.get(self.back);
461            self.back -= 1;
462            result
463        } else {
464            None
465        }
466    }
467}