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: SMT Proofs (Inclusion and Exclusion) #648

Merged
merged 67 commits into from
Mar 12, 2024
Merged
Show file tree
Hide file tree
Changes from 63 commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
fda3e0a
SMT generate proof
bvrooman Dec 18, 2023
da38555
Passing test for proof
bvrooman Dec 18, 2023
d8dd367
Update merkle_tree.rs
bvrooman Dec 19, 2023
c4efe4f
Update tests
bvrooman Dec 19, 2023
5793c2b
WIP
bvrooman Dec 20, 2023
71f503f
Support inclusion and exclusion proofs
bvrooman Dec 22, 2023
c2e2f16
Update CHANGELOG.md
bvrooman Dec 22, 2023
7146ee0
Merge branch 'master' into bvrooman/feat/smt-proofs
bvrooman Dec 22, 2023
cbd627d
Clean up
bvrooman Dec 22, 2023
eeb8bd8
Clippy
bvrooman Dec 22, 2023
30df56f
Additional tests
bvrooman Dec 22, 2023
093dc4c
Remove superfluous code
bvrooman Dec 22, 2023
48f40a8
WIP
bvrooman Dec 22, 2023
39c2e90
debugging
bvrooman Dec 23, 2023
81a9f64
Fix proofs
bvrooman Dec 23, 2023
317f342
Clean up
bvrooman Dec 23, 2023
1094d61
Clean up
bvrooman Dec 23, 2023
3483e75
Clippy
bvrooman Dec 23, 2023
fc08309
use alloc
bvrooman Dec 23, 2023
0c50d9c
use alloc format
bvrooman Dec 23, 2023
00e021e
Clippy
bvrooman Dec 23, 2023
4d895d2
Clean up
bvrooman Dec 24, 2023
2cf6469
cosmetic
bvrooman Dec 24, 2023
90dbe51
Add test for empty tree
bvrooman Jan 15, 2024
98440e9
Merge branch 'master' into bvrooman/feat/smt-proofs
bvrooman Jan 15, 2024
24bde3e
Use proptest for random index
bvrooman Jan 16, 2024
fff3885
clippy
bvrooman Jan 16, 2024
786769a
Merge branch 'master' into bvrooman/feat/smt-proofs
xgreenx Jan 17, 2024
5f96a69
Replace enum with single struct
bvrooman Jan 29, 2024
a3895a0
Merge branch 'master' into bvrooman/feat/smt-proofs
bvrooman Jan 29, 2024
42c5733
Fix test name
bvrooman Jan 29, 2024
d421b00
Submit an example of the incorrect proof
xgreenx Jan 29, 2024
94c9aee
Merge remote-tracking branch 'origin/bvrooman/feat/smt-proofs' into b…
xgreenx Jan 29, 2024
286e36f
Missed change
bvrooman Jan 29, 2024
6f3fe1e
Merge branch 'bvrooman/feat/smt-proofs' of https://github.com/FuelLab…
bvrooman Jan 29, 2024
0ac82af
WIP - Update tests, proofs
bvrooman Feb 2, 2024
9cf4a06
WIP testing
bvrooman Feb 2, 2024
8afba49
WIP
bvrooman Mar 6, 2024
76ac41a
WIP
bvrooman Mar 6, 2024
07b6c52
All tests green
bvrooman Mar 6, 2024
7959a42
Simplify
bvrooman Mar 6, 2024
249d341
Update proof.rs
bvrooman Mar 6, 2024
e2fc674
Merge branch 'master' into bvrooman/feat/smt-proofs
bvrooman Mar 6, 2024
7c81df8
Update tests
bvrooman Mar 6, 2024
c2636eb
Clippy + no_std
bvrooman Mar 6, 2024
d44c7ab
Remove proptest regressions
bvrooman Mar 6, 2024
2c04eb1
Added a test with inclusion proof
xgreenx Mar 7, 2024
5632915
Added a test with inclusion proof
xgreenx Mar 7, 2024
346adf6
Check key
bvrooman Mar 7, 2024
5ca6979
Update
bvrooman Mar 7, 2024
bee8aa8
Delete sparse.txt
bvrooman Mar 7, 2024
7800cbe
Test and fix for placeholders
bvrooman Mar 7, 2024
b519be5
Clippy
bvrooman Mar 7, 2024
0977a79
Another test case
xgreenx Mar 7, 2024
ca6edbf
use debug_assert over assert
bvrooman Mar 8, 2024
a2ee4d8
Update proof.rs
bvrooman Mar 8, 2024
c1ad59b
Remove invalid test
bvrooman Mar 8, 2024
8251b01
Fix tests
bvrooman Mar 8, 2024
3aafeb5
Merge branch 'master' into bvrooman/feat/smt-proofs
bvrooman Mar 8, 2024
2506510
ExclusionLeaf
bvrooman Mar 8, 2024
faafe04
Clippy
bvrooman Mar 8, 2024
d67770a
Style
bvrooman Mar 8, 2024
9558729
Remove dbg
bvrooman Mar 9, 2024
e961cd8
Use enum for ExclusionLeaf
bvrooman Mar 11, 2024
124f183
dev: refactor smt node visibility (#696)
Mar 11, 2024
fa5d09c
Small nits from me=)
xgreenx Mar 11, 2024
b446631
Simplify proof check
bvrooman Mar 11, 2024
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]

### Added

- [#648](https://github.com/FuelLabs/fuel-vm/pull/648): Added support for generating proofs for Sparse Merkle Trees (SMTs) and proof verification. Proofs can be used to attest to the inclusion or exclusion of data from the set.

### Changed

#### Breaking
Expand Down
2 changes: 2 additions & 0 deletions fuel-merkle/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ criterion = { workspace = true }
datatest-stable = "0.1"
fuel-merkle-test-helpers = { path = "test-helpers" }
hex = "0.4"
proptest = "1.4"
proptest-derive = "0.4"
rand = "0.8"
serde_json = "1.0"
serde_yaml = "0.9"
Expand Down
4 changes: 2 additions & 2 deletions fuel-merkle/src/common/msb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ impl GetBit for u8 {

pub trait Msb {
fn get_bit_at_index_from_msb(&self, index: u32) -> Option<Bit>;
fn common_prefix_count(&self, other: &Self) -> u32;
fn common_prefix_count(&self, other: &[u8]) -> u32;
}

impl<const N: usize> Msb for [u8; N] {
Expand All @@ -38,7 +38,7 @@ impl<const N: usize> Msb for [u8; N] {
.and_then(|byte| byte.get_bit(byte_bit_index))
}

fn common_prefix_count(&self, other: &Self) -> u32 {
fn common_prefix_count(&self, other: &[u8]) -> u32 {
let mut count = 0;
for (byte1, byte2) in self.iter().zip(other.iter()) {
// For each pair of bytes, compute the similarity of each byte using
Expand Down
4 changes: 2 additions & 2 deletions fuel-merkle/src/common/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub trait Path {
}

pub trait ComparablePath {
fn common_path_length(&self, other: &Self) -> u32;
fn common_path_length(&self, other: &[u8]) -> u32;
}

impl<T> Path for T
Expand All @@ -38,7 +38,7 @@ impl<T> ComparablePath for T
where
T: Msb,
{
fn common_path_length(&self, other: &Self) -> u32 {
fn common_path_length(&self, other: &[u8]) -> u32 {
self.common_prefix_count(other)
}
}
67 changes: 35 additions & 32 deletions fuel-merkle/src/common/path_iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,12 @@ pub struct PathIter<T: ParentNode> {
impl<T> PathIter<T>
where
T: ParentNode + Clone,
T::Key: Clone,
{
pub fn new(root: &T, leaf_key: T::Key) -> Self {
pub fn new(root: &T, leaf_key: &T::Key) -> Self {
let initial = (Ok(root.clone()), Ok(root.clone()));

#[rustfmt::skip]
// The initial offset from the most significant bit (MSB).
//
// The offset from the MSB indicates which bit to read when deducing the
Expand All @@ -116,30 +118,30 @@ where
// With an 8-bit key and heights 1 through 7:
//
// Height Depth
// 7 0 127 Offset = Bits - Height =
// 8 - 7 = 1 / \
// 7 0 127 Offset = Bits - Height = 8 - 7 = 1
// / \
// / \
// ... ... ...
// / \
// / \
// 3 4 07 247 Offset = Bits - Height =
// 8 - 3 = 5 / \ / \
// 3 4 07 247 Offset = Bits - Height = 8 - 3 = 5
// / \ / \
// / \ ... \
// / \ \
// / \ \
// / \ \
// / \ \
// 2 5 03 11 251 Offset = Bits - Height =
// 8 - 2 = 6 / \ / \ / \
// 2 5 03 11 251 Offset = Bits - Height = 8 - 2 = 6
// / \ / \ / \
// / \ / \ ... \
// 1 6 01 05 09 13 253 Offset = Bits - Height =
// 8 - 1 = 7 / \ / \ / \ / \ / \
// 0 7 00 02 04 06 08 10 12 14 252 254
// 1 6 01 05 09 13 253 Offset = Bits - Height = 8 - 1 = 7
// / \ / \ / \ / \ / \
// 0 7 00 02 04 06 08 10 12 14 252 254
// 00 01 02 03 04 05 06 07 126 127
//
let initial_offset = T::key_size_in_bits() - root.height();
Self {
leaf_key,
leaf_key: leaf_key.clone(),
current: Some(initial),
current_offset: initial_offset,
}
Expand Down Expand Up @@ -187,14 +189,15 @@ where
}

pub trait AsPathIterator<T: ParentNode> {
fn as_path_iter(&self, leaf_key: T::Key) -> PathIter<T>;
fn as_path_iter(&self, leaf_key: &T::Key) -> PathIter<T>;
}

impl<T> AsPathIterator<T> for T
where
T: ParentNode + Clone,
T::Key: Clone,
{
fn as_path_iter(&self, leaf_key: T::Key) -> PathIter<T> {
fn as_path_iter(&self, leaf_key: &T::Key) -> PathIter<T> {
PathIter::new(self, leaf_key)
}
}
Expand Down Expand Up @@ -307,7 +310,7 @@ mod test {
{
let leaf = Node::from_leaf_index(0);
let (path, _): (Vec<TestNode>, Vec<TestNode>) = root
.as_path_iter(leaf.leaf_key())
.as_path_iter(&leaf.leaf_key())
.map(|(path, side)| (path.unwrap(), side.unwrap()))
.unzip();
let expected_path = vec![
Expand All @@ -322,7 +325,7 @@ mod test {
{
let leaf = Node::from_leaf_index(1);
let (path, _): (Vec<TestNode>, Vec<TestNode>) = root
.as_path_iter(leaf.leaf_key())
.as_path_iter(&leaf.leaf_key())
.map(|(path, side)| (path.unwrap(), side.unwrap()))
.unzip();
let expected_path = vec![
Expand All @@ -337,7 +340,7 @@ mod test {
{
let leaf = Node::from_leaf_index(2);
let (path, _): (Vec<TestNode>, Vec<TestNode>) = root
.as_path_iter(leaf.leaf_key())
.as_path_iter(&leaf.leaf_key())
.map(|(path, side)| (path.unwrap(), side.unwrap()))
.unzip();
let expected_path = vec![
Expand All @@ -352,7 +355,7 @@ mod test {
{
let leaf = Node::from_leaf_index(3);
let (path, _): (Vec<TestNode>, Vec<TestNode>) = root
.as_path_iter(leaf.leaf_key())
.as_path_iter(&leaf.leaf_key())
.map(|(path, side)| (path.unwrap(), side.unwrap()))
.unzip();
let expected_path = vec![
Expand All @@ -367,7 +370,7 @@ mod test {
{
let leaf = Node::from_leaf_index(4);
let (path, _): (Vec<TestNode>, Vec<TestNode>) = root
.as_path_iter(leaf.leaf_key())
.as_path_iter(&leaf.leaf_key())
.map(|(path, side)| (path.unwrap(), side.unwrap()))
.unzip();
let expected_path = vec![
Expand All @@ -382,7 +385,7 @@ mod test {
{
let leaf = Node::from_leaf_index(5);
let (path, _): (Vec<TestNode>, Vec<TestNode>) = root
.as_path_iter(leaf.leaf_key())
.as_path_iter(&leaf.leaf_key())
.map(|(path, side)| (path.unwrap(), side.unwrap()))
.unzip();
let expected_path = vec![
Expand All @@ -397,7 +400,7 @@ mod test {
{
let leaf = Node::from_leaf_index(6);
let (path, _): (Vec<TestNode>, Vec<TestNode>) = root
.as_path_iter(leaf.leaf_key())
.as_path_iter(&leaf.leaf_key())
.map(|(path, side)| (path.unwrap(), side.unwrap()))
.unzip();
let expected_path = vec![
Expand All @@ -412,7 +415,7 @@ mod test {
{
let leaf = Node::from_leaf_index(7);
let (path, _): (Vec<TestNode>, Vec<TestNode>) = root
.as_path_iter(leaf.leaf_key())
.as_path_iter(&leaf.leaf_key())
.map(|(path, side)| (path.unwrap(), side.unwrap()))
.unzip();
let expected_path = vec![
Expand Down Expand Up @@ -448,7 +451,7 @@ mod test {
{
let leaf = Node::from_leaf_index(0);
let (_, side): (Vec<TestNode>, Vec<TestNode>) = root
.as_path_iter(leaf.leaf_key())
.as_path_iter(&leaf.leaf_key())
.map(|(path, side)| (path.unwrap(), side.unwrap()))
.unzip();
let expected_side = vec![
Expand All @@ -463,7 +466,7 @@ mod test {
{
let leaf = Node::from_leaf_index(1);
let (_, side): (Vec<TestNode>, Vec<TestNode>) = root
.as_path_iter(leaf.leaf_key())
.as_path_iter(&leaf.leaf_key())
.map(|(path, side)| (path.unwrap(), side.unwrap()))
.unzip();
let expected_side = vec![
Expand All @@ -478,7 +481,7 @@ mod test {
{
let leaf = Node::from_leaf_index(2);
let (_, side): (Vec<TestNode>, Vec<TestNode>) = root
.as_path_iter(leaf.leaf_key())
.as_path_iter(&leaf.leaf_key())
.map(|(path, side)| (path.unwrap(), side.unwrap()))
.unzip();
let expected_side = vec![
Expand All @@ -493,7 +496,7 @@ mod test {
{
let leaf = Node::from_leaf_index(3);
let (_, side): (Vec<TestNode>, Vec<TestNode>) = root
.as_path_iter(leaf.leaf_key())
.as_path_iter(&leaf.leaf_key())
.map(|(path, side)| (path.unwrap(), side.unwrap()))
.unzip();
let expected_side = vec![
Expand All @@ -508,7 +511,7 @@ mod test {
{
let leaf = Node::from_leaf_index(4);
let (_, side): (Vec<TestNode>, Vec<TestNode>) = root
.as_path_iter(leaf.leaf_key())
.as_path_iter(&leaf.leaf_key())
.map(|(path, side)| (path.unwrap(), side.unwrap()))
.unzip();
let expected_side = vec![
Expand All @@ -523,7 +526,7 @@ mod test {
{
let leaf = Node::from_leaf_index(5);
let (_, side): (Vec<TestNode>, Vec<TestNode>) = root
.as_path_iter(leaf.leaf_key())
.as_path_iter(&leaf.leaf_key())
.map(|(path, side)| (path.unwrap(), side.unwrap()))
.unzip();
let expected_side = vec![
Expand All @@ -538,7 +541,7 @@ mod test {
{
let leaf = Node::from_leaf_index(6);
let (_, side): (Vec<TestNode>, Vec<TestNode>) = root
.as_path_iter(leaf.leaf_key())
.as_path_iter(&leaf.leaf_key())
.map(|(path, side)| (path.unwrap(), side.unwrap()))
.unzip();
let expected_side = vec![
Expand All @@ -553,7 +556,7 @@ mod test {
{
let leaf = Node::from_leaf_index(7);
let (_, side): (Vec<TestNode>, Vec<TestNode>) = root
.as_path_iter(leaf.leaf_key())
.as_path_iter(&leaf.leaf_key())
.map(|(path, side)| (path.unwrap(), side.unwrap()))
.unzip();
let expected_side = vec![
Expand All @@ -573,7 +576,7 @@ mod test {
let leaf = Node::from_leaf_index(4); // 0b0100

let (path, _): (Vec<TestNode>, Vec<TestNode>) = root
.as_path_iter(leaf.leaf_key())
.as_path_iter(&leaf.leaf_key())
.map(|(path, side)| (path.unwrap(), side.unwrap()))
.unzip();

Expand All @@ -594,7 +597,7 @@ mod test {
let leaf = Node::from_leaf_index(61); // 0b00111101

let (path, _): (Vec<TestNode>, Vec<TestNode>) = root
.as_path_iter(leaf.leaf_key())
.as_path_iter(&leaf.leaf_key())
.map(|(path, side)| (path.unwrap(), side.unwrap()))
.unzip();

Expand All @@ -619,7 +622,7 @@ mod test {
let leaf = Node::from_leaf_index(0);

let (path, side): (Vec<TestNode>, Vec<TestNode>) = root
.as_path_iter(leaf.leaf_key())
.as_path_iter(&leaf.leaf_key())
.map(|(path, side)| (path.unwrap(), side.unwrap()))
.unzip();

Expand Down
2 changes: 1 addition & 1 deletion fuel-merkle/src/common/position_path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ impl PositionPathIter {
Self {
rightmost_position: Position::from_leaf_index(leaves_count - 1),
current_side_node: None,
path_iter: root.as_path_iter(leaf.leaf_key()),
path_iter: root.as_path_iter(&leaf.leaf_key()),
}
}
}
Expand Down
1 change: 1 addition & 0 deletions fuel-merkle/src/sparse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pub use merkle_tree::{
};
pub use primitive::Primitive;
pub mod in_memory;
pub mod proof;

use crate::common::Bytes32;

Expand Down
5 changes: 5 additions & 0 deletions fuel-merkle/src/sparse/in_memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::{
sparse::{
self,
merkle_tree::MerkleTreeKey,
proof::Proof,
Primitive,
},
storage::{
Expand Down Expand Up @@ -177,6 +178,10 @@ impl MerkleTree {
pub fn root(&self) -> Bytes32 {
self.tree.root()
}

pub fn generate_proof(&self, key: &MerkleTreeKey) -> Option<Proof> {
self.tree.generate_proof(key).ok()
}
}

impl Default for MerkleTree {
Expand Down
Loading
Loading