diff --git a/src/merkle/index.rs b/src/merkle/index.rs index ff717ec..e9d5e0e 100644 --- a/src/merkle/index.rs +++ b/src/merkle/index.rs @@ -1,4 +1,4 @@ -use core::fmt::Display; +use core::{fmt::Display, num::NonZero}; use super::{Felt, MerkleError, RpoDigest}; use crate::utils::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable}; @@ -72,6 +72,41 @@ impl NodeIndex { Self::new(depth, value) } + /// Converts a scalar representation of a depth/value pair to a [`NodeIndex`]. + /// + /// This is the inverse operation of [`NodeIndex::to_scalar_index()`]. As `1` represents the + /// root node, `index` cannot be zero. + /// + /// # Errors + /// Returns the same errors under the same conditions as [`NodeIndex::new()`]. + /// + /// # Panics + /// Panics if the depth indicated by `index` does not fit in a [`u8`], or if the row-value + /// indicated by `index` does not fit in a [`u64`]. + pub const fn from_scalar_index(index: NonZero) -> Result { + let index = index.get() - 1; + + if index == 0 { + return Ok(Self { depth: 0, value: 0 }); + } + + let depth = { + let depth = u128::ilog2(index); + assert!(depth <= u8::MAX as u32); + depth as u8 + }; + + let max_value_for_depth = (1 << depth) - 1; + + let value = { + let value = index - max_value_for_depth; + assert!(value <= u64::MAX as u128); + value as u64 + }; + + Self::new(depth, value) + } + /// Creates a new node index pointing to the root of the tree. pub const fn root() -> Self { Self { depth: 0, value: 0 }