Skip to content

Commit

Permalink
feat: implement tiered smt
Browse files Browse the repository at this point in the history
closes #36
  • Loading branch information
vlopes11 committed Feb 8, 2023
1 parent cf7011a commit b5b7395
Show file tree
Hide file tree
Showing 11 changed files with 1,792 additions and 16 deletions.
2 changes: 1 addition & 1 deletion src/hash/rpo/digest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use core::{cmp::Ordering, ops::Deref};
pub struct RpoDigest([Felt; DIGEST_SIZE]);

impl RpoDigest {
pub fn new(value: [Felt; DIGEST_SIZE]) -> Self {
pub const fn new(value: [Felt; DIGEST_SIZE]) -> Self {
Self(value)
}

Expand Down
40 changes: 38 additions & 2 deletions src/merkle/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::{
hash::rpo::{Rpo256, RpoDigest},
utils::collections::{BTreeMap, Vec},
Felt, Word, ZERO,
utils::collections::{vec, BTreeMap, Vec},
Felt, StarkField, Word, WORD_SIZE, ZERO,
};
use core::fmt;

Expand All @@ -11,9 +11,15 @@ pub use merkle_tree::MerkleTree;
mod merkle_path_set;
pub use merkle_path_set::MerklePathSet;

mod path;
pub use path::MerklePath;

mod simple_smt;
pub use simple_smt::SimpleSmt;

mod tiered_smt;
pub use tiered_smt::TieredSmt;

// ERRORS
// ================================================================================================

Expand Down Expand Up @@ -63,3 +69,33 @@ impl std::error::Error for MerkleError {}
const fn int_to_node(value: u64) -> Word {
[Felt::new(value), ZERO, ZERO, ZERO]
}

/// Computes a set of sub-trees of an empty merkle tree.
///
/// The returned vector is indexed by the depth and will contain the correspondent hash.
fn empty_merkle_subtrees<T>(depth: u8) -> Vec<T>
where
T: From<RpoDigest>,
{
(0..depth as u16 + 1)
.scan(RpoDigest::default(), |state, _| {
let value = *state;
*state = Rpo256::merge(&[value, value]);
Some(value)
})
.collect::<Vec<_>>()
.into_iter()
.rev()
.map(T::from)
.collect()
}

#[test]
fn empty_merkle_subtrees_is_calculated_correctly() {
let null = empty_merkle_subtrees(u8::MAX);
let mut root = RpoDigest::default();
for _ in 0..u8::MAX {
root = Rpo256::merge(&[root, root]);
}
assert_eq!(root, null[0]);
}
71 changes: 71 additions & 0 deletions src/merkle/path.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
use super::{vec, Rpo256, Vec, Word};
use core::ops::Deref;

// MERKLE PATH
// ================================================================================================

/// A merkle path container, composed of a sequence of nodes of a Merkle tree.
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct MerklePath {
nodes: Vec<Word>,
}

impl MerklePath {
// CONSTRUCTORS
// --------------------------------------------------------------------------------------------

/// Creates a new Merkle path from a list of nodes.
pub fn new(nodes: Vec<Word>) -> Self {
Self { nodes }
}

// PROVIDERS
// --------------------------------------------------------------------------------------------

/// Returns the depth in which this Merkle path proof is valid.
pub fn depth(&self) -> u8 {
self.nodes.len() as u8
}

/// Verify the Merkle opening proof towards the provided root.
///
/// It will assert `input` exists on a Merkle tree, indexed by `index` for an arbitrary depth.
pub fn verify(&self, mut index: u64, input: Word, root: &Word) -> bool {
let computed = self.nodes.iter().copied().fold(input, |node, sibling| {
// build the input node, considering the parity of the current index.
let is_right_sibling = (index & 1) == 1;
let input = if is_right_sibling {
[sibling.into(), node.into()]
} else {
[node.into(), sibling.into()]
};
// compute the node and move to the next iteration.
index >>= 1;
Rpo256::merge(&input).into()
});
root == &computed
}
}

impl Deref for MerklePath {
type Target = [Word];

fn deref(&self) -> &Self::Target {
&self.nodes
}
}

impl FromIterator<Word> for MerklePath {
fn from_iter<T: IntoIterator<Item = Word>>(iter: T) -> Self {
Self::new(iter.into_iter().collect())
}
}

impl IntoIterator for MerklePath {
type Item = Word;
type IntoIter = vec::IntoIter<Word>;

fn into_iter(self) -> Self::IntoIter {
self.nodes.into_iter()
}
}
15 changes: 2 additions & 13 deletions src/merkle/simple_smt/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::{BTreeMap, MerkleError, Rpo256, RpoDigest, Vec, Word};
use super::{empty_merkle_subtrees, BTreeMap, MerkleError, Rpo256, RpoDigest, Vec, Word};

#[cfg(test)]
mod tests;
Expand Down Expand Up @@ -204,18 +204,7 @@ impl Store {
fn new(depth: u32) -> (Self, Word) {
let branches = BTreeMap::new();
let leaves = BTreeMap::new();

// Construct empty node digests for each layer of the tree
let empty_hashes: Vec<RpoDigest> = (0..depth + 1)
.scan(Word::default().into(), |state, _| {
let value = *state;
*state = Rpo256::merge(&[value, value]);
Some(value)
})
.collect::<Vec<_>>()
.into_iter()
.rev()
.collect();
let empty_hashes = empty_merkle_subtrees::<RpoDigest>(depth as u8);

let root = empty_hashes[0].into();
let store = Self {
Expand Down
Loading

0 comments on commit b5b7395

Please sign in to comment.