Skip to content

Commit 0eab47e

Browse files
refactor(aggregation_mode): migrate merkle tree to lambdaworks (#1911)
Co-authored-by: JuArce <[email protected]>
1 parent 0a6419f commit 0eab47e

File tree

18 files changed

+599
-161
lines changed

18 files changed

+599
-161
lines changed

aggregation_mode/Cargo.lock

Lines changed: 11 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

aggregation_mode/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ tokio = { version = "1", features = ["time"]}
1616
sha3 = "0.10.8"
1717
reqwest = { version = "0.12" }
1818
ciborium = "=0.2.2"
19+
lambdaworks-crypto = { git = "https://github.com/lambdaclass/lambdaworks.git", rev = "5f8f2cfcc8a1a22f77e8dff2d581f1166eefb80b", features = ["serde"]}
1920
# Necessary for the VerificationData type
2021
aligned-sdk = { path = "../batcher/aligned-sdk/" }
2122
# zkvms

aggregation_mode/aggregation_programs/Cargo.lock

Lines changed: 112 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

aggregation_mode/aggregation_programs/risc0/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ serde_json = "1.0.117"
1010
# Unstable feature is necessary for tiny-keccak patch, see: https://dev.risczero.com/api/zkvm/precompiles#stability
1111
risc0-zkvm = { git = "https://github.com/risc0/risc0", tag="v2.0.0", default-features = false, features = ["unstable", "std"] }
1212
tiny-keccak = { version = "2.0.2", features = ["keccak"] }
13+
lambdaworks-crypto = { git = "https://github.com/lambdaclass/lambdaworks.git", rev = "5f8f2cfcc8a1a22f77e8dff2d581f1166eefb80b", features = ["serde"]}
1314

1415
[lib]
1516
path = "./src/lib.rs"

aggregation_mode/aggregation_programs/risc0/src/lib.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use lambdaworks_crypto::merkle_tree::traits::IsMerkleTreeBackend;
12
use serde::{Deserialize, Serialize};
23
use tiny_keccak::{Hasher, Keccak};
34

@@ -21,6 +22,35 @@ impl Risc0ImageIdAndPubInputs {
2122
}
2223
}
2324

25+
// Note: this MerkleTreeBackend is defined in three locations
26+
// - aggregation_mode/src/aggregators/mod.rs
27+
// - aggregation_mode/src/aggregators/risc0_aggregator.rs
28+
// - aggregation_mode/src/aggregators/sp1_aggregator.rs
29+
// All 3 implementations should match
30+
// The definition on aggregator/mod.rs supports taking proofs from both Risc0 and SP1,
31+
// Additionally, a version that takes the leaves as already hashed data is defined on:
32+
// - batcher/aligned-sdk/src/sdk/aggregation.rs
33+
// This one is used in the SDK since,
34+
// the user may not have access to the proofs that he didn't submit
35+
impl IsMerkleTreeBackend for Risc0ImageIdAndPubInputs {
36+
type Data = Risc0ImageIdAndPubInputs;
37+
type Node = [u8; 32];
38+
39+
fn hash_data(leaf: &Self::Data) -> Self::Node {
40+
leaf.commitment()
41+
}
42+
43+
fn hash_new_parent(child_1: &Self::Node, child_2: &Self::Node) -> Self::Node {
44+
let mut hasher = Keccak::v256();
45+
hasher.update(child_1);
46+
hasher.update(child_2);
47+
48+
let mut hash = [0u8; 32];
49+
hasher.finalize(&mut hash);
50+
hash
51+
}
52+
}
53+
2454
#[derive(Serialize, Deserialize)]
2555
pub struct Input {
2656
pub proofs_image_id_and_pub_inputs: Vec<Risc0ImageIdAndPubInputs>,
Lines changed: 4 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,11 @@
11
#![no_main]
22

3+
use lambdaworks_crypto::merkle_tree::merkle::MerkleTree;
34
use risc0_aggregation_program::{Input, Risc0ImageIdAndPubInputs};
45
use risc0_zkvm::guest::env;
5-
use tiny_keccak::{Hasher, Keccak};
66

77
risc0_zkvm::guest::entry!(main);
88

9-
fn combine_hashes(hash_a: &[u8; 32], hash_b: &[u8; 32]) -> [u8; 32] {
10-
let mut hasher = Keccak::v256();
11-
hasher.update(hash_a);
12-
hasher.update(hash_b);
13-
14-
let mut hash = [0u8; 32];
15-
hasher.finalize(&mut hash);
16-
hash
17-
}
18-
19-
/// Computes the merkle root for the given proofs
20-
fn compute_merkle_root(proofs: &[Risc0ImageIdAndPubInputs]) -> [u8; 32] {
21-
let mut leaves: Vec<[u8; 32]> = proofs
22-
.chunks(2)
23-
.map(|chunk| match chunk {
24-
[a, b] => combine_hashes(&a.commitment(), &b.commitment()),
25-
[a] => combine_hashes(&a.commitment(), &a.commitment()),
26-
_ => panic!("Unexpected chunk leaves"),
27-
})
28-
.collect();
29-
30-
while leaves.len() > 1 {
31-
leaves = leaves
32-
.chunks(2)
33-
.map(|chunk| match chunk {
34-
[a, b] => combine_hashes(&a, &b),
35-
[a] => combine_hashes(&a, &a),
36-
_ => panic!("Unexpected chunk size in leaves"),
37-
})
38-
.collect()
39-
}
40-
41-
leaves[0]
42-
}
43-
449
fn main() {
4510
let input = env::read::<Input>();
4611

@@ -52,7 +17,8 @@ fn main() {
5217
env::verify(image_id.clone(), &public_inputs).expect("proof to be verified correctly");
5318
}
5419

55-
let merkle_root = compute_merkle_root(&input.proofs_image_id_and_pub_inputs);
20+
let merkle_tree: MerkleTree<Risc0ImageIdAndPubInputs> =
21+
MerkleTree::build(&input.proofs_image_id_and_pub_inputs).unwrap();
5622

57-
env::commit_slice(&merkle_root);
23+
env::commit_slice(&merkle_tree.root);
5824
}

aggregation_mode/aggregation_programs/sp1/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ sha2 = { git = "https://github.com/sp1-patches/RustCrypto-hashes", tag = "sha2-v
1010
sha3 = { git = "https://github.com/sp1-patches/RustCrypto-hashes", tag = "sha3-v0.10.8-patch-v1" }
1111
serde = { version = "1.0.203", features = ["derive"] }
1212
serde_json = "1.0.117"
13+
lambdaworks-crypto = { git = "https://github.com/lambdaclass/lambdaworks.git", rev = "5f8f2cfcc8a1a22f77e8dff2d581f1166eefb80b", features = ["serde"]}
1314

1415
[lib]
1516
path = "./src/lib.rs"

aggregation_mode/aggregation_programs/sp1/src/lib.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use lambdaworks_crypto::merkle_tree::traits::IsMerkleTreeBackend;
12
use serde::{Deserialize, Serialize};
23
use sha3::{Digest, Keccak256};
34

@@ -18,6 +19,32 @@ impl SP1VkAndPubInputs {
1819
}
1920
}
2021

22+
// Note: this MerkleTreeBackend is defined in three locations
23+
// - aggregation_mode/src/aggregators/mod.rs
24+
// - aggregation_mode/src/aggregators/risc0_aggregator.rs and
25+
// - aggregation_mode/src/aggregators/sp1_aggregator.rs
26+
// All 3 implementations should match
27+
// The definition on aggregator/mod.rs supports taking proofs from both Risc0 and SP1,
28+
// Additionally, a version that takes the leaves as already hashed data is defined on:
29+
// - batcher/aligned-sdk/src/sdk/aggregation.rs
30+
// This one is used in the SDK since
31+
// the user may not have access to the proofs that they didn't submit
32+
impl IsMerkleTreeBackend for SP1VkAndPubInputs {
33+
type Data = SP1VkAndPubInputs;
34+
type Node = [u8; 32];
35+
36+
fn hash_data(leaf: &Self::Data) -> Self::Node {
37+
leaf.hash()
38+
}
39+
40+
fn hash_new_parent(child_1: &Self::Node, child_2: &Self::Node) -> Self::Node {
41+
let mut hasher = Keccak256::new();
42+
hasher.update(child_1);
43+
hasher.update(child_2);
44+
hasher.finalize().into()
45+
}
46+
}
47+
2148
#[derive(Serialize, Deserialize)]
2249
pub struct Input {
2350
pub proofs_vk_and_pub_inputs: Vec<SP1VkAndPubInputs>,

0 commit comments

Comments
 (0)