diff --git a/aggregation_mode/Cargo.lock b/aggregation_mode/Cargo.lock index 5d007dc89b..ff66359b2a 100644 --- a/aggregation_mode/Cargo.lock +++ b/aggregation_mode/Cargo.lock @@ -4719,10 +4719,12 @@ dependencies = [ [[package]] name = "lambdaworks-crypto" -version = "0.10.0" -source = "git+https://github.com/lambdaclass/lambdaworks.git?rev=efd46f0b0aea3aa95d94bba7de86cb96611b40d3#efd46f0b0aea3aa95d94bba7de86cb96611b40d3" +version = "0.12.0" +source = "git+https://github.com/lambdaclass/lambdaworks.git?rev=5f8f2cfcc8a1a22f77e8dff2d581f1166eefb80b#5f8f2cfcc8a1a22f77e8dff2d581f1166eefb80b" dependencies = [ "lambdaworks-math", + "rand 0.8.5", + "rand_chacha 0.3.1", "serde", "sha2 0.10.8 (registry+https://github.com/rust-lang/crates.io-index)", "sha3 0.10.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4730,9 +4732,11 @@ dependencies = [ [[package]] name = "lambdaworks-math" -version = "0.10.0" -source = "git+https://github.com/lambdaclass/lambdaworks.git?rev=efd46f0b0aea3aa95d94bba7de86cb96611b40d3#efd46f0b0aea3aa95d94bba7de86cb96611b40d3" +version = "0.12.0" +source = "git+https://github.com/lambdaclass/lambdaworks.git?rev=5f8f2cfcc8a1a22f77e8dff2d581f1166eefb80b#5f8f2cfcc8a1a22f77e8dff2d581f1166eefb80b" dependencies = [ + "getrandom 0.2.15", + "rand 0.8.5", "serde", "serde_json", ] @@ -6190,6 +6194,7 @@ dependencies = [ "bincode", "c-kzg", "ciborium", + "lambdaworks-crypto", "reqwest 0.12.15", "risc0-build", "risc0-ethereum-contracts", @@ -7208,6 +7213,7 @@ dependencies = [ name = "risc0_aggregation_program" version = "0.1.0" dependencies = [ + "lambdaworks-crypto", "risc0-zkvm 2.0.0", "serde", "serde_json", @@ -8484,6 +8490,7 @@ dependencies = [ name = "sp1_aggregation_program" version = "0.1.0" dependencies = [ + "lambdaworks-crypto", "serde", "serde_json", "sha2 0.10.8 (git+https://github.com/sp1-patches/RustCrypto-hashes?tag=sha2-v0.10.8-patch-v1)", diff --git a/aggregation_mode/Cargo.toml b/aggregation_mode/Cargo.toml index f52e8b9f7f..af5ee562ee 100644 --- a/aggregation_mode/Cargo.toml +++ b/aggregation_mode/Cargo.toml @@ -17,6 +17,7 @@ tokio = { version = "1", features = ["time"]} sha3 = "0.10.8" reqwest = { version = "0.12" } ciborium = "=0.2.2" +lambdaworks-crypto = { git = "https://github.com/lambdaclass/lambdaworks.git", rev = "5f8f2cfcc8a1a22f77e8dff2d581f1166eefb80b", features = ["serde"]} # Necessary for the VerificationData type aligned-sdk = { path = "../batcher/aligned-sdk/" } # zkvms diff --git a/aggregation_mode/aggregation_programs/Cargo.lock b/aggregation_mode/aggregation_programs/Cargo.lock index 474a6da85b..3eeff9dc76 100644 --- a/aggregation_mode/aggregation_programs/Cargo.lock +++ b/aggregation_mode/aggregation_programs/Cargo.lock @@ -326,6 +326,12 @@ dependencies = [ "syn 2.0.100", ] +[[package]] +name = "bumpalo" +version = "3.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" + [[package]] name = "bytemuck" version = "1.22.0" @@ -596,8 +602,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", ] [[package]] @@ -661,6 +669,16 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + [[package]] name = "keccak" version = "0.1.5" @@ -670,6 +688,30 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "lambdaworks-crypto" +version = "0.12.0" +source = "git+https://github.com/lambdaclass/lambdaworks.git?rev=5f8f2cfcc8a1a22f77e8dff2d581f1166eefb80b#5f8f2cfcc8a1a22f77e8dff2d581f1166eefb80b" +dependencies = [ + "lambdaworks-math", + "rand", + "rand_chacha", + "serde", + "sha2 0.10.8 (registry+https://github.com/rust-lang/crates.io-index)", + "sha3 0.10.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "lambdaworks-math" +version = "0.12.0" +source = "git+https://github.com/lambdaclass/lambdaworks.git?rev=5f8f2cfcc8a1a22f77e8dff2d581f1166eefb80b#5f8f2cfcc8a1a22f77e8dff2d581f1166eefb80b" +dependencies = [ + "getrandom", + "rand", + "serde", + "serde_json", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -1161,6 +1203,7 @@ dependencies = [ name = "risc0_aggregation_program" version = "0.1.0" dependencies = [ + "lambdaworks-crypto", "risc0-zkvm", "serde", "serde_json", @@ -1245,6 +1288,16 @@ dependencies = [ "digest", ] +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest", + "keccak", +] + [[package]] name = "sha3" version = "0.10.8" @@ -1305,10 +1358,11 @@ dependencies = [ name = "sp1_aggregation_program" version = "0.1.0" dependencies = [ + "lambdaworks-crypto", "serde", "serde_json", "sha2 0.10.8 (git+https://github.com/sp1-patches/RustCrypto-hashes?tag=sha2-v0.10.8-patch-v1)", - "sha3", + "sha3 0.10.8 (git+https://github.com/sp1-patches/RustCrypto-hashes?tag=sha3-v0.10.8-patch-v1)", "sp1-zkvm", ] @@ -1459,6 +1513,63 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn 2.0.100", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + [[package]] name = "winnow" version = "0.7.6" diff --git a/aggregation_mode/aggregation_programs/risc0/Cargo.toml b/aggregation_mode/aggregation_programs/risc0/Cargo.toml index d347adbae8..263863c00c 100644 --- a/aggregation_mode/aggregation_programs/risc0/Cargo.toml +++ b/aggregation_mode/aggregation_programs/risc0/Cargo.toml @@ -10,6 +10,7 @@ serde_json = "1.0.117" # Unstable feature is necessary for tiny-keccak patch, see: https://dev.risczero.com/api/zkvm/precompiles#stability risc0-zkvm = { git = "https://github.com/risc0/risc0", tag="v2.0.0", default-features = false, features = ["unstable", "std"] } tiny-keccak = { version = "2.0.2", features = ["keccak"] } +lambdaworks-crypto = { git = "https://github.com/lambdaclass/lambdaworks.git", rev = "5f8f2cfcc8a1a22f77e8dff2d581f1166eefb80b", features = ["serde"]} [lib] path = "./src/lib.rs" diff --git a/aggregation_mode/aggregation_programs/risc0/src/lib.rs b/aggregation_mode/aggregation_programs/risc0/src/lib.rs index 8599eb859f..20c9a38b28 100644 --- a/aggregation_mode/aggregation_programs/risc0/src/lib.rs +++ b/aggregation_mode/aggregation_programs/risc0/src/lib.rs @@ -1,3 +1,4 @@ +use lambdaworks_crypto::merkle_tree::traits::IsMerkleTreeBackend; use serde::{Deserialize, Serialize}; use tiny_keccak::{Hasher, Keccak}; @@ -21,6 +22,35 @@ impl Risc0ImageIdAndPubInputs { } } +// Note: this MerkleTreeBackend is defined in three locations +// - aggregation_mode/src/aggregators/mod.rs +// - aggregation_mode/src/aggregators/risc0_aggregator.rs +// - aggregation_mode/src/aggregators/sp1_aggregator.rs +// All 3 implementations should match +// The definition on aggregator/mod.rs supports taking proofs from both Risc0 and SP1, +// Additionally, a version that takes the leaves as already hashed data is defined on: +// - batcher/aligned-sdk/src/sdk/aggregation.rs +// This one is used in the SDK since, +// the user may not have access to the proofs that he didn't submit +impl IsMerkleTreeBackend for Risc0ImageIdAndPubInputs { + type Data = Risc0ImageIdAndPubInputs; + type Node = [u8; 32]; + + fn hash_data(leaf: &Self::Data) -> Self::Node { + leaf.commitment() + } + + fn hash_new_parent(child_1: &Self::Node, child_2: &Self::Node) -> Self::Node { + let mut hasher = Keccak::v256(); + hasher.update(child_1); + hasher.update(child_2); + + let mut hash = [0u8; 32]; + hasher.finalize(&mut hash); + hash + } +} + #[derive(Serialize, Deserialize)] pub struct Input { pub proofs_image_id_and_pub_inputs: Vec, diff --git a/aggregation_mode/aggregation_programs/risc0/src/main.rs b/aggregation_mode/aggregation_programs/risc0/src/main.rs index 02264f2b74..7797adab78 100644 --- a/aggregation_mode/aggregation_programs/risc0/src/main.rs +++ b/aggregation_mode/aggregation_programs/risc0/src/main.rs @@ -1,46 +1,11 @@ #![no_main] +use lambdaworks_crypto::merkle_tree::merkle::MerkleTree; use risc0_aggregation_program::{Input, Risc0ImageIdAndPubInputs}; use risc0_zkvm::guest::env; -use tiny_keccak::{Hasher, Keccak}; risc0_zkvm::guest::entry!(main); -fn combine_hashes(hash_a: &[u8; 32], hash_b: &[u8; 32]) -> [u8; 32] { - let mut hasher = Keccak::v256(); - hasher.update(hash_a); - hasher.update(hash_b); - - let mut hash = [0u8; 32]; - hasher.finalize(&mut hash); - hash -} - -/// Computes the merkle root for the given proofs -fn compute_merkle_root(proofs: &[Risc0ImageIdAndPubInputs]) -> [u8; 32] { - let mut leaves: Vec<[u8; 32]> = proofs - .chunks(2) - .map(|chunk| match chunk { - [a, b] => combine_hashes(&a.commitment(), &b.commitment()), - [a] => combine_hashes(&a.commitment(), &a.commitment()), - _ => panic!("Unexpected chunk leaves"), - }) - .collect(); - - while leaves.len() > 1 { - leaves = leaves - .chunks(2) - .map(|chunk| match chunk { - [a, b] => combine_hashes(&a, &b), - [a] => combine_hashes(&a, &a), - _ => panic!("Unexpected chunk size in leaves"), - }) - .collect() - } - - leaves[0] -} - fn main() { let input = env::read::(); @@ -52,7 +17,8 @@ fn main() { env::verify(image_id.clone(), &public_inputs).expect("proof to be verified correctly"); } - let merkle_root = compute_merkle_root(&input.proofs_image_id_and_pub_inputs); + let merkle_tree: MerkleTree = + MerkleTree::build(&input.proofs_image_id_and_pub_inputs).unwrap(); - env::commit_slice(&merkle_root); + env::commit_slice(&merkle_tree.root); } diff --git a/aggregation_mode/aggregation_programs/sp1/Cargo.toml b/aggregation_mode/aggregation_programs/sp1/Cargo.toml index 72f8c52534..b96f33b756 100644 --- a/aggregation_mode/aggregation_programs/sp1/Cargo.toml +++ b/aggregation_mode/aggregation_programs/sp1/Cargo.toml @@ -10,6 +10,7 @@ sha2 = { git = "https://github.com/sp1-patches/RustCrypto-hashes", tag = "sha2-v sha3 = { git = "https://github.com/sp1-patches/RustCrypto-hashes", tag = "sha3-v0.10.8-patch-v1" } serde = { version = "1.0.203", features = ["derive"] } serde_json = "1.0.117" +lambdaworks-crypto = { git = "https://github.com/lambdaclass/lambdaworks.git", rev = "5f8f2cfcc8a1a22f77e8dff2d581f1166eefb80b", features = ["serde"]} [lib] path = "./src/lib.rs" diff --git a/aggregation_mode/aggregation_programs/sp1/src/lib.rs b/aggregation_mode/aggregation_programs/sp1/src/lib.rs index d1c683c6cd..7fbc285ca3 100644 --- a/aggregation_mode/aggregation_programs/sp1/src/lib.rs +++ b/aggregation_mode/aggregation_programs/sp1/src/lib.rs @@ -1,3 +1,4 @@ +use lambdaworks_crypto::merkle_tree::traits::IsMerkleTreeBackend; use serde::{Deserialize, Serialize}; use sha3::{Digest, Keccak256}; @@ -18,6 +19,32 @@ impl SP1VkAndPubInputs { } } +// Note: this MerkleTreeBackend is defined in three locations +// - aggregation_mode/src/aggregators/mod.rs +// - aggregation_mode/src/aggregators/risc0_aggregator.rs and +// - aggregation_mode/src/aggregators/sp1_aggregator.rs +// All 3 implementations should match +// The definition on aggregator/mod.rs supports taking proofs from both Risc0 and SP1, +// Additionally, a version that takes the leaves as already hashed data is defined on: +// - batcher/aligned-sdk/src/sdk/aggregation.rs +// This one is used in the SDK since +// the user may not have access to the proofs that they didn't submit +impl IsMerkleTreeBackend for SP1VkAndPubInputs { + type Data = SP1VkAndPubInputs; + type Node = [u8; 32]; + + fn hash_data(leaf: &Self::Data) -> Self::Node { + leaf.hash() + } + + fn hash_new_parent(child_1: &Self::Node, child_2: &Self::Node) -> Self::Node { + let mut hasher = Keccak256::new(); + hasher.update(child_1); + hasher.update(child_2); + hasher.finalize().into() + } +} + #[derive(Serialize, Deserialize)] pub struct Input { pub proofs_vk_and_pub_inputs: Vec, diff --git a/aggregation_mode/aggregation_programs/sp1/src/main.rs b/aggregation_mode/aggregation_programs/sp1/src/main.rs index 2c638e3276..9b66ce2e1c 100644 --- a/aggregation_mode/aggregation_programs/sp1/src/main.rs +++ b/aggregation_mode/aggregation_programs/sp1/src/main.rs @@ -1,42 +1,11 @@ #![no_main] sp1_zkvm::entrypoint!(main); +use lambdaworks_crypto::merkle_tree::merkle::MerkleTree; use sha2::{Digest, Sha256}; use sha3::Keccak256; use sp1_aggregation_program::{Input, SP1VkAndPubInputs}; -fn combine_hashes(hash_a: &[u8; 32], hash_b: &[u8; 32]) -> [u8; 32] { - let mut hasher = Keccak256::new(); - hasher.update(hash_a); - hasher.update(hash_b); - hasher.finalize().into() -} - -/// Computes the merkle root for the given proofs using the vk -fn compute_merkle_root(proofs: &[SP1VkAndPubInputs]) -> [u8; 32] { - let mut leaves: Vec<[u8; 32]> = proofs - .chunks(2) - .map(|chunk| match chunk { - [a, b] => combine_hashes(&a.hash(), &b.hash()), - [a] => combine_hashes(&a.hash(), &a.hash()), - _ => panic!("Unexpected chunk leaves"), - }) - .collect(); - - while leaves.len() > 1 { - leaves = leaves - .chunks(2) - .map(|chunk| match chunk { - [a, b] => combine_hashes(&a, &b), - [a] => combine_hashes(&a, &a), - _ => panic!("Unexpected chunk size in leaves"), - }) - .collect() - } - - leaves[0] -} - pub fn main() { let input = sp1_zkvm::io::read::(); @@ -48,7 +17,8 @@ pub fn main() { sp1_zkvm::lib::verify::verify_sp1_proof(&vkey, &public_values_digest.into()); } - let merkle_root = compute_merkle_root(&input.proofs_vk_and_pub_inputs); + let merkle_tree: MerkleTree = + MerkleTree::build(&input.proofs_vk_and_pub_inputs).unwrap(); - sp1_zkvm::io::commit_slice(&merkle_root); + sp1_zkvm::io::commit_slice(&merkle_tree.root); } diff --git a/aggregation_mode/src/aggregators/mod.rs b/aggregation_mode/src/aggregators/mod.rs index 3e777f3771..a549568970 100644 --- a/aggregation_mode/src/aggregators/mod.rs +++ b/aggregation_mode/src/aggregators/mod.rs @@ -3,9 +3,11 @@ pub mod sp1_aggregator; use std::fmt::Display; +use lambdaworks_crypto::merkle_tree::traits::IsMerkleTreeBackend; use risc0_aggregator::{ AlignedRisc0VerificationError, Risc0AggregationError, Risc0ProofReceiptAndImageId, }; +use sha3::{Digest, Keccak256}; use sp1_aggregator::{ AlignedSP1VerificationError, SP1AggregationError, SP1ProofWithPubValuesAndElf, }; @@ -123,6 +125,39 @@ impl AlignedProof { } } +/// Merkle tree commitment for aligned proofs. +/// +/// Each leaf node (representing a proof) is committed by hashing: +/// — The program id: the verification key hash in SP1 or the image ID in RISC Zero +/// — Public inputs. +/// +/// Intermediate nodes in the tree are formed by computing the keccak pairs of child nodes. +// Note: this MerkleTreeBackend is defined in three locations +// - aggregation_mode/src/aggregators/mod.rs +// - aggregation_mode/src/aggregators/risc0_aggregator.rs +// - aggregation_mode/src/aggregators/sp1_aggregator.rs +// All 3 implementations should match +// The definition on aggregator/mod.rs supports taking proofs from both Risc0 and SP1, +// Additionally, a version that takes the leaves as already hashed data is defined on: +// - batcher/aligned-sdk/src/sdk/aggregation.rs +// This one is used in the SDK since, +// the user may not have access to the proofs that he didn't submit +impl IsMerkleTreeBackend for AlignedProof { + type Data = AlignedProof; + type Node = [u8; 32]; + + fn hash_data(leaf: &Self::Data) -> Self::Node { + leaf.commitment() + } + + fn hash_new_parent(child_1: &Self::Node, child_2: &Self::Node) -> Self::Node { + let mut hasher = Keccak256::new(); + hasher.update(child_1); + hasher.update(child_2); + hasher.finalize().into() + } +} + #[derive(Debug)] pub enum AlignedVerificationError { Sp1(AlignedSP1VerificationError), diff --git a/aggregation_mode/src/backend/merkle_tree.rs b/aggregation_mode/src/backend/merkle_tree.rs index b72dac5b50..6aaa46b50a 100644 --- a/aggregation_mode/src/backend/merkle_tree.rs +++ b/aggregation_mode/src/backend/merkle_tree.rs @@ -1,29 +1,12 @@ use crate::aggregators::AlignedProof; -use sha3::{Digest, Keccak256}; - -pub fn combine_hashes(hash_a: &[u8; 32], hash_b: &[u8; 32]) -> [u8; 32] { - let mut hasher = Keccak256::new(); - hasher.update(hash_a); - hasher.update(hash_b); - hasher.finalize().into() -} +use lambdaworks_crypto::merkle_tree::merkle::MerkleTree; /// Returns (merkle_root, leaves) -pub fn compute_proofs_merkle_root(proofs: &[AlignedProof]) -> ([u8; 32], Vec<[u8; 32]>) { +pub fn compute_proofs_merkle_root( + proofs: &[AlignedProof], +) -> Option<(MerkleTree, Vec<[u8; 32]>)> { + let merkle_tree: MerkleTree = MerkleTree::build(proofs)?; let leaves: Vec<[u8; 32]> = proofs.iter().map(|proof| proof.commitment()).collect(); - let mut root = leaves.clone(); - - while root.len() > 1 { - root = root - .chunks(2) - .map(|chunk| match chunk { - [a, b] => combine_hashes(a, b), - [a] => combine_hashes(a, a), - _ => panic!("Unexpected chunk size in leaves"), - }) - .collect() - } - - (root[0], leaves) + Some((merkle_tree, leaves)) } diff --git a/aggregation_mode/src/backend/mod.rs b/aggregation_mode/src/backend/mod.rs index f120892a60..2ae85c9cec 100644 --- a/aggregation_mode/src/backend/mod.rs +++ b/aggregation_mode/src/backend/mod.rs @@ -35,6 +35,7 @@ pub enum AggregatedProofSubmissionError { ReceiptError(PendingTransactionError), FetchingProofs(ProofsFetcherError), ZKVMAggregation(ProofAggregationError), + BuildingMerkleRoot, MerkleRootMisMatch, } @@ -105,7 +106,9 @@ impl ProofAggregator { } info!("Proofs fetched, constructing merkle root..."); - let (merkle_root, leaves) = compute_proofs_merkle_root(&proofs); + let (merkle_tree, leaves) = compute_proofs_merkle_root(&proofs) + .ok_or(AggregatedProofSubmissionError::BuildingMerkleRoot)?; + let merkle_root = merkle_tree.root; info!("Merkle root constructed: 0x{}", hex::encode(merkle_root)); info!("Starting proof aggregation program..."); diff --git a/batcher/Cargo.lock b/batcher/Cargo.lock index 50a3ca0f55..fe3f655620 100644 --- a/batcher/Cargo.lock +++ b/batcher/Cargo.lock @@ -79,7 +79,7 @@ dependencies = [ "env_logger", "ethers", "futures-util", - "lambdaworks-crypto", + "lambdaworks-crypto 0.10.0", "log", "rpassword", "serde", @@ -108,7 +108,7 @@ dependencies = [ "ethers", "futures-util", "hex", - "lambdaworks-crypto", + "lambdaworks-crypto 0.12.0", "log", "once_cell", "priority-queue", @@ -134,7 +134,7 @@ dependencies = [ "ethers", "futures-util", "hex", - "lambdaworks-crypto", + "lambdaworks-crypto 0.12.0", "log", "reqwest 0.12.15", "serde", @@ -4609,7 +4609,20 @@ name = "lambdaworks-crypto" version = "0.10.0" source = "git+https://github.com/lambdaclass/lambdaworks.git?rev=efd46f0b0aea3aa95d94bba7de86cb96611b40d3#efd46f0b0aea3aa95d94bba7de86cb96611b40d3" dependencies = [ - "lambdaworks-math", + "lambdaworks-math 0.10.0", + "serde", + "sha2", + "sha3", +] + +[[package]] +name = "lambdaworks-crypto" +version = "0.12.0" +source = "git+https://github.com/lambdaclass/lambdaworks.git?rev=5f8f2cfcc8a1a22f77e8dff2d581f1166eefb80b#5f8f2cfcc8a1a22f77e8dff2d581f1166eefb80b" +dependencies = [ + "lambdaworks-math 0.12.0", + "rand 0.8.5", + "rand_chacha 0.3.1", "serde", "sha2", "sha3", @@ -4624,6 +4637,17 @@ dependencies = [ "serde_json", ] +[[package]] +name = "lambdaworks-math" +version = "0.12.0" +source = "git+https://github.com/lambdaclass/lambdaworks.git?rev=5f8f2cfcc8a1a22f77e8dff2d581f1166eefb80b#5f8f2cfcc8a1a22f77e8dff2d581f1166eefb80b" +dependencies = [ + "getrandom 0.2.15", + "rand 0.8.5", + "serde", + "serde_json", +] + [[package]] name = "lazy-regex" version = "3.4.1" diff --git a/batcher/aligned-batcher/Cargo.toml b/batcher/aligned-batcher/Cargo.toml index 145f87d6e7..703c2c321e 100644 --- a/batcher/aligned-batcher/Cargo.toml +++ b/batcher/aligned-batcher/Cargo.toml @@ -20,7 +20,7 @@ hex = "0.4.3" dotenvy = "0.15.0" anyhow = "1.0.83" ethers = { version = "2.0", features = ["ws", "rustls"] } -lambdaworks-crypto = { git = "https://github.com/lambdaclass/lambdaworks.git", rev = "efd46f0b0aea3aa95d94bba7de86cb96611b40d3", features = ["serde"] } +lambdaworks-crypto = { git = "https://github.com/lambdaclass/lambdaworks.git", rev = "5f8f2cfcc8a1a22f77e8dff2d581f1166eefb80b", features = ["serde"] } serde_yaml = "0.9.34" sp1-sdk = { git = "https://github.com/succinctlabs/sp1.git", rev = "v4.1.7" } risc0-zkvm = { git = "https://github.com/risc0/risc0", tag = "v2.0.0" } diff --git a/batcher/aligned-sdk/Cargo.toml b/batcher/aligned-sdk/Cargo.toml index 20df5fb31e..964be4a4e9 100644 --- a/batcher/aligned-sdk/Cargo.toml +++ b/batcher/aligned-sdk/Cargo.toml @@ -17,7 +17,7 @@ tokio = { version = "1.37.0", features = [ "rt-multi-thread", "sync", ] } -lambdaworks-crypto = { git = "https://github.com/lambdaclass/lambdaworks.git", rev = "efd46f0b0aea3aa95d94bba7de86cb96611b40d3", features = ["serde"] } +lambdaworks-crypto = { git = "https://github.com/lambdaclass/lambdaworks.git", rev = "5f8f2cfcc8a1a22f77e8dff2d581f1166eefb80b", features = ["serde"]} serde = { version = "1.0.201", features = ["derive"] } sha3 = { version = "0.10.8" } url = "2.5.0" diff --git a/batcher/aligned-sdk/src/sdk/aggregation.rs b/batcher/aligned-sdk/src/sdk/aggregation.rs index 552611d532..bfb3def124 100644 --- a/batcher/aligned-sdk/src/sdk/aggregation.rs +++ b/batcher/aligned-sdk/src/sdk/aggregation.rs @@ -6,6 +6,7 @@ use ethers::{ providers::{Http, Middleware, Provider}, types::Filter, }; +use lambdaworks_crypto::merkle_tree::{merkle::MerkleTree, traits::IsMerkleTreeBackend}; use sha3::{Digest, Keccak256}; /// How much to go back from current block if from_block is not provided @@ -46,6 +47,37 @@ impl AggregationModeVerificationData { } } +// We use a newtype wrapper around `[u8; 32]` because Rust's orphan rule +// prevents implementing a foreign trait (`IsMerkleTreeBackend`) for a foreign type (`[u8; 32]`). +#[derive(Default, Debug, PartialEq, Eq)] +pub struct Hash32([u8; 32]); + +// Note: +// We define a version of the backend that takes the leaves as hashed data +// since the user may not have access to the proofs that he didn't submit +// The original MerkleTreeBackend is defined in three locations +// - aggregation_mode/src/aggregators/mod.rs +// - aggregation_mode/src/aggregators/risc0_aggregator.rs +// - aggregation_mode/src/aggregators/sp1_aggregator.rs +// The definition on aggregator/mod.rs supports taking proofs from both Risc0 and SP1 +// Hashes of all implementations should match +impl IsMerkleTreeBackend for Hash32 { + type Data = Hash32; + type Node = [u8; 32]; + + /// We don't have to hash the data, as the blob already contains the proof commitments (which represent the merkle leaves) + fn hash_data(leaf: &Self::Data) -> Self::Node { + leaf.0 + } + + fn hash_new_parent(child_1: &Self::Node, child_2: &Self::Node) -> Self::Node { + let mut hasher = Keccak256::new(); + hasher.update(child_1); + hasher.update(child_2); + hasher.finalize().into() + } +} + #[derive(Debug)] pub enum ProofVerificationAggModeError { ProvingSystemNotSupportedInAggMode, @@ -158,10 +190,16 @@ pub async fn is_proof_verified_in_aggregation_mode( let blob_bytes = hex::decode(blob_data.blob.replace("0x", "")).expect("A valid hex encoded data"); - let proof_commitments = decoded_blob(blob_bytes); + let proof_commitments: Vec = decoded_blob(blob_bytes) + .iter() + .map(|p| Hash32(*p)) + .collect(); + let Some(merkle_tree) = MerkleTree::::build(&proof_commitments) else { + continue; + }; - if proof_commitments.contains(&verification_data.commitment()) { - return if verify_blob_merkle_root(proof_commitments, merkle_root) { + if proof_commitments.contains(&Hash32(verification_data.commitment())) { + return if merkle_tree.root == merkle_root { Ok(merkle_root) } else { Err(ProofVerificationAggModeError::UnmatchedBlobAndEventMerkleRoot) @@ -206,25 +244,3 @@ fn decoded_blob(blob_data: Vec) -> Vec<[u8; 32]> { proof_hashes } - -pub fn combine_hashes(hash_a: &[u8; 32], hash_b: &[u8; 32]) -> [u8; 32] { - let mut hasher = Keccak256::new(); - hasher.update(hash_a); - hasher.update(hash_b); - hasher.finalize().into() -} - -fn verify_blob_merkle_root(mut commitments: Vec<[u8; 32]>, merkle_root: [u8; 32]) -> bool { - while commitments.len() > 1 { - commitments = commitments - .chunks(2) - .map(|chunk| match chunk { - [a, b] => combine_hashes(a, b), - [a] => combine_hashes(a, a), - _ => panic!("Unexpected chunk size in leaves"), - }) - .collect() - } - - commitments[0] == merkle_root -} diff --git a/operator/merkle_tree/lib/Cargo.lock b/operator/merkle_tree/lib/Cargo.lock index c07c0a2630..eb9a224e07 100644 --- a/operator/merkle_tree/lib/Cargo.lock +++ b/operator/merkle_tree/lib/Cargo.lock @@ -58,6 +58,7 @@ dependencies = [ "hex", "lambdaworks-crypto", "log", + "reqwest 0.12.5", "serde", "serde_json", "serde_repr", @@ -104,6 +105,12 @@ dependencies = [ "rustc_version", ] +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "auto_impl" version = "1.2.0" @@ -154,6 +161,12 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "base64ct" version = "1.6.0" @@ -901,7 +914,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "reqwest", + "reqwest 0.11.27", "serde", "serde_json", "syn 2.0.65", @@ -963,7 +976,7 @@ checksum = "e79e5973c26d4baf0ce55520bd732314328cabe53193286671b47144145b9649" dependencies = [ "chrono", "ethers-core", - "reqwest", + "reqwest 0.11.27", "semver", "serde", "serde_json", @@ -988,7 +1001,7 @@ dependencies = [ "futures-locks", "futures-util", "instant", - "reqwest", + "reqwest 0.11.27", "serde", "serde_json", "thiserror", @@ -1021,7 +1034,7 @@ dependencies = [ "jsonwebtoken", "once_cell", "pin-project", - "reqwest", + "reqwest 0.11.27", "serde", "serde_json", "thiserror", @@ -1323,8 +1336,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", ] [[package]] @@ -1381,6 +1396,25 @@ dependencies = [ "tracing", ] +[[package]] +name = "h2" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9421a676d1b147b16b82c9225157dc629087ef8ec4d5e2960f9437a90dac0a5" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http 1.1.0", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "half" version = "2.4.1" @@ -1475,6 +1509,29 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http 1.1.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http 1.1.0", + "http-body 1.0.1", + "pin-project-lite", +] + [[package]] name = "httparse" version = "1.8.0" @@ -1497,9 +1554,9 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2", + "h2 0.3.26", "http 0.2.12", - "http-body", + "http-body 0.4.6", "httparse", "httpdate", "itoa", @@ -1511,6 +1568,26 @@ dependencies = [ "want", ] +[[package]] +name = "hyper" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "256fb8d4bd6413123cc9d91832d78325c48ff41677595be797d90f42969beae0" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "h2 0.4.10", + "http 1.1.0", + "http-body 1.0.1", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + [[package]] name = "hyper-rustls" version = "0.24.2" @@ -1519,10 +1596,63 @@ checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", "http 0.2.12", - "hyper", - "rustls", + "hyper 0.14.28", + "rustls 0.21.12", "tokio", - "tokio-rustls", + "tokio-rustls 0.24.1", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" +dependencies = [ + "futures-util", + "http 1.1.0", + "hyper 1.5.2", + "hyper-util", + "rustls 0.23.26", + "rustls-pki-types", + "tokio", + "tokio-rustls 0.26.2", + "tower-service", +] + +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper 1.5.2", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "hyper 1.5.2", + "pin-project-lite", + "socket2", + "tokio", + "tower", + "tower-service", + "tracing", ] [[package]] @@ -1715,10 +1845,12 @@ dependencies = [ [[package]] name = "lambdaworks-crypto" -version = "0.10.0" -source = "git+https://github.com/lambdaclass/lambdaworks.git?rev=efd46f0b0aea3aa95d94bba7de86cb96611b40d3#efd46f0b0aea3aa95d94bba7de86cb96611b40d3" +version = "0.12.0" +source = "git+https://github.com/lambdaclass/lambdaworks.git?rev=5f8f2cfcc8a1a22f77e8dff2d581f1166eefb80b#5f8f2cfcc8a1a22f77e8dff2d581f1166eefb80b" dependencies = [ "lambdaworks-math", + "rand", + "rand_chacha", "serde", "sha2", "sha3", @@ -1726,9 +1858,11 @@ dependencies = [ [[package]] name = "lambdaworks-math" -version = "0.10.0" -source = "git+https://github.com/lambdaclass/lambdaworks.git?rev=efd46f0b0aea3aa95d94bba7de86cb96611b40d3#efd46f0b0aea3aa95d94bba7de86cb96611b40d3" +version = "0.12.0" +source = "git+https://github.com/lambdaclass/lambdaworks.git?rev=5f8f2cfcc8a1a22f77e8dff2d581f1166eefb80b#5f8f2cfcc8a1a22f77e8dff2d581f1166eefb80b" dependencies = [ + "getrandom", + "rand", "serde", "serde_json", ] @@ -2452,11 +2586,11 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", - "h2", + "h2 0.3.26", "http 0.2.12", - "http-body", - "hyper", - "hyper-rustls", + "http-body 0.4.6", + "hyper 0.14.28", + "hyper-rustls 0.24.2", "ipnet", "js-sys", "log", @@ -2464,22 +2598,65 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls", - "rustls-pemfile", + "rustls 0.21.12", + "rustls-pemfile 1.0.4", "serde", "serde_json", "serde_urlencoded", - "sync_wrapper", + "sync_wrapper 0.1.2", "system-configuration", "tokio", - "tokio-rustls", + "tokio-rustls 0.24.1", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", "webpki-roots", - "winreg", + "winreg 0.50.0", +] + +[[package]] +name = "reqwest" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37" +dependencies = [ + "base64 0.22.1", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2 0.4.10", + "http 1.1.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.5.2", + "hyper-rustls 0.27.5", + "hyper-tls", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls-pemfile 2.2.0", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 1.0.2", + "system-configuration", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg 0.52.0", ] [[package]] @@ -2595,10 +2772,23 @@ checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", "ring 0.17.8", - "rustls-webpki", + "rustls-webpki 0.101.7", "sct", ] +[[package]] +name = "rustls" +version = "0.23.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df51b5869f3a441595eac5e8ff14d486ff285f7b8c0df8770e49c3b56351f0f0" +dependencies = [ + "once_cell", + "rustls-pki-types", + "rustls-webpki 0.103.1", + "subtle", + "zeroize", +] + [[package]] name = "rustls-pemfile" version = "1.0.4" @@ -2608,6 +2798,21 @@ dependencies = [ "base64 0.21.7", ] +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" + [[package]] name = "rustls-webpki" version = "0.101.7" @@ -2618,6 +2823,17 @@ dependencies = [ "untrusted 0.9.0", ] +[[package]] +name = "rustls-webpki" +version = "0.103.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03" +dependencies = [ + "ring 0.17.8", + "rustls-pki-types", + "untrusted 0.9.0", +] + [[package]] name = "rustversion" version = "1.0.17" @@ -3014,7 +3230,7 @@ dependencies = [ "fs2", "hex", "once_cell", - "reqwest", + "reqwest 0.11.27", "semver", "serde", "serde_json", @@ -3052,6 +3268,12 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" + [[package]] name = "system-configuration" version = "0.5.1" @@ -3221,7 +3443,17 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls", + "rustls 0.21.12", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" +dependencies = [ + "rustls 0.23.26", "tokio", ] @@ -3233,9 +3465,9 @@ checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" dependencies = [ "futures-util", "log", - "rustls", + "rustls 0.21.12", "tokio", - "tokio-rustls", + "tokio-rustls 0.24.1", "tungstenite 0.20.1", "webpki-roots", ] @@ -3312,6 +3544,27 @@ dependencies = [ "winnow 0.6.8", ] +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + [[package]] name = "tower-service" version = "0.3.2" @@ -3378,7 +3631,7 @@ dependencies = [ "httparse", "log", "rand", - "rustls", + "rustls 0.21.12", "sha1", "thiserror", "url", @@ -3817,6 +4070,16 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "winreg" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + [[package]] name = "ws_stream_wasm" version = "0.7.4" diff --git a/operator/merkle_tree/lib/Cargo.toml b/operator/merkle_tree/lib/Cargo.toml index ba5fe61126..3e019ea662 100644 --- a/operator/merkle_tree/lib/Cargo.toml +++ b/operator/merkle_tree/lib/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" serde = { version = "1.0.201", features = ["derive"] } serde_json = "1.0.117" bincode = "1.3.3" -lambdaworks-crypto = { git = "https://github.com/lambdaclass/lambdaworks.git", rev = "efd46f0b0aea3aa95d94bba7de86cb96611b40d3", features = ["serde"] } +lambdaworks-crypto = { git = "https://github.com/lambdaclass/lambdaworks.git", rev = "5f8f2cfcc8a1a22f77e8dff2d581f1166eefb80b", features = ["serde"] } hex = "0.4.3" sha3 = "0.10.8" aligned-sdk = { path = "../../../batcher/aligned-sdk" }