Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(stdlib): SMT with foreign merkle_membership #1108

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[package]
authors = [""]
compiler_version = "0.1"

[dependencies]
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
leaf_index = 4
new_leaf1 = 1234
new_leaf2 = 5678
64 changes: 64 additions & 0 deletions crates/nargo_cli/tests/test_data/sparse_merkle_tree/src/main.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
use dep::std;
use dep::std::hash;
use dep::std::merkle;
use dep::std::merkle::smt::SparseMerkleTree;

fn main(
leaf_index: Field,
new_leaf1: Field,
new_leaf2: Field,
) -> pub [Field; 3] {
let default_value = 0xdead;
let hash_low = hash::pedersen([default_value, default_value])[0];
let hash_mid = hash::pedersen([hash_low, hash_low])[0];
let hash_high = hash::pedersen([hash_mid, hash_mid])[0];
let empty_root = hash::pedersen([hash_high, hash_high])[0];

// Remains the same since we're only testing mutations at a single index
let hash_path = [default_value, hash_low, hash_mid, hash_high];

let root_after_insert_leaf1 = merkle::compute_root_from_leaf(
new_leaf1,
leaf_index,
hash_path,
);
let root_after_replace_leaf1_with_leaf2 = merkle::compute_root_from_leaf(
new_leaf2,
leaf_index,
hash_path,
);

let smt = SparseMerkleTree { default_value };

smt.insert(
empty_root,
root_after_insert_leaf1,
new_leaf1,
leaf_index,
hash_path,
);

SparseMerkleTree::update(
root_after_insert_leaf1, // old_root
new_leaf1, // old leaf
root_after_replace_leaf1_with_leaf2, // new_root
new_leaf2,
leaf_index,
hash_path,
);

smt.delete(
root_after_replace_leaf1_with_leaf2, // old_root
new_leaf2, // old leaf
empty_root, // new root
leaf_index,
hash_path
);

[
empty_root,
root_after_insert_leaf1,
root_after_replace_leaf1_with_leaf2
]
}

8 changes: 4 additions & 4 deletions noir_stdlib/src/merkle.nr
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
mod smt;
// Regular merkle tree means a append-only merkle tree (Explain why this is the only way to have privacy and alternatives if you don't want it)

// Returns one if the leaf is in the tree
// and it is at the given index
// and the hashpath proves this
// Currently we assume that it is a binary tree, so depth k implies a width of 2^k
// Returns one if the leaf is in the tree at the given index and associated hashpath.
// Currently we assume that it is a binary tree, so depth k implies a width of 2^k.
// Futhermore, internal hashes are assumed to be taken as a pedersen x coordinate.
// XXX: In the future we can add an arity parameter
fn check_membership(_root : Field, _leaf : Field, _index : Field, _hash_path: [Field]) -> Field {
(compute_merkle_root(_leaf, _index, _hash_path) == _root) as Field
Expand Down
73 changes: 73 additions & 0 deletions noir_stdlib/src/merkle/smt.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
use crate::merkle;

struct SparseMerkleTree {
default_value: Field,
}

impl SparseMerkleTree {
// Constrains that the new leaf is located in the new tree at an index
// that previously held the default value in the old tree.
fn insert(self,
old_root: Field,
new_root: Field,
new_leaf: Field,
index: Field,
hash_path: [Field],
) {
SparseMerkleTree::update(
old_root,
self.default_value,
new_root,
new_leaf,
index,
hash_path,
);
}

// Constrains that the new tree holds the default value at the same
// index that the old tree held the old leaf.
fn delete(
self,
old_root: Field,
old_leaf: Field,
new_root: Field,
index: Field,
hash_path: [Field],
) {
SparseMerkleTree::update(
old_root,
old_leaf,
new_root,
self.default_value,
index,
hash_path,
);
}

// Constrains that the changed leaf's before and after values are
// consistent with the given merkle roots, and that the leaf at the
// specified index is the only difference between the trees.
fn update(
old_root: Field,
old_leaf: Field,
new_root: Field,
new_leaf: Field,
index: Field,
hash_path: [Field],
) {
// Constrain old leaf to be in old tree
constrain merkle::check_membership(
old_root,
old_leaf,
index,
hash_path,
) == 1;
// Constrain new leaf to be in new tree at same index
constrain merkle::check_membership(
new_root,
new_leaf,
index,
hash_path,
) == 1;
}
}