From ca6689ced5496ecdca3d9ea3b680ba5a3c3db4c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Tr=C4=85d?= Date: Tue, 11 Feb 2025 14:12:33 +0100 Subject: [PATCH] Add tests for proof compression with bon-rs (#853) * Add tests for proof compression with bon-rs * cargo vet --- Cargo.lock | 73 +++++++++++++++++++-- Cargo.toml | 1 + supply-chain/config.toml | 8 +++ supply-chain/imports.lock | 101 +++++++++++++++++++++++++++++ tests/common/mod.rs | 105 +++++++++++-------------------- tests/validate_proof_with_age.rs | 58 ++++++----------- tests/validate_proofs.rs | 89 +++++++++++++------------- 7 files changed, 279 insertions(+), 156 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3af7e34c..9d0b8bde 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1228,6 +1228,31 @@ dependencies = [ "serde_with", ] +[[package]] +name = "bon" +version = "3.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe7acc34ff59877422326db7d6f2d845a582b16396b6b08194942bf34c6528ab" +dependencies = [ + "bon-macros", + "rustversion", +] + +[[package]] +name = "bon-macros" +version = "3.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4159dd617a7fbc9be6a692fe69dc2954f8e6bb6bb5e4d7578467441390d77fd0" +dependencies = [ + "darling 0.20.10", + "ident_case", + "prettyplease", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.79", +] + [[package]] name = "bs58" version = "0.5.1" @@ -1857,8 +1882,18 @@ version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.13.4", + "darling_macro 0.13.4", +] + +[[package]] +name = "darling" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core 0.20.10", + "darling_macro 0.20.10", ] [[package]] @@ -1875,17 +1910,42 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.11.1", + "syn 2.0.79", +] + [[package]] name = "darling_macro" version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" dependencies = [ - "darling_core", + "darling_core 0.13.4", "quote", "syn 1.0.109", ] +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core 0.20.10", + "quote", + "syn 2.0.79", +] + [[package]] name = "data-encoding" version = "2.6.0" @@ -4577,9 +4637,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.87" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" dependencies = [ "unicode-ident", ] @@ -5669,7 +5729,7 @@ version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" dependencies = [ - "darling", + "darling 0.13.4", "proc-macro2", "quote", "syn 1.0.109", @@ -5750,6 +5810,7 @@ dependencies = [ "async-trait", "axum 0.7.7", "axum-server", + "bon", "bytes", "chrono", "clap", diff --git a/Cargo.toml b/Cargo.toml index f3d6be46..5d24910d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ axum = "0.7.7" axum-server = "0.7.1" tower-http = { version = "0.6.1", features = ["catch-panic"] } bytes = "1.4.0" +bon = "3" chrono = { version = "0.4.19", features = ["serde"] } clap = { version = "4.0", features = ["derive", "env"] } telemetry-batteries = { git = "https://github.com/worldcoin/telemetry-batteries.git", rev = "901ea26e478c81e10d5d4355ac628ab7b15afca7" } diff --git a/supply-chain/config.toml b/supply-chain/config.toml index 3897b040..c0b3e0a6 100644 --- a/supply-chain/config.toml +++ b/supply-chain/config.toml @@ -321,6 +321,14 @@ criteria = "safe-to-deploy" version = "1.42.0-rc.3" criteria = "safe-to-deploy" +[[exemptions.bon]] +version = "3.3.2" +criteria = "safe-to-deploy" + +[[exemptions.bon-macros]] +version = "3.3.2" +criteria = "safe-to-deploy" + [[exemptions.bs58]] version = "0.5.0" criteria = "safe-to-deploy" diff --git a/supply-chain/imports.lock b/supply-chain/imports.lock index 637a9b90..731f4a42 100644 --- a/supply-chain/imports.lock +++ b/supply-chain/imports.lock @@ -1611,6 +1611,35 @@ delta = "1.0.86 -> 1.0.87" notes = "No new unsafe interactions." aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT" +[[audits.google.audits.proc-macro2]] +who = "Liza Burakova , expected_failure: Option<&str>, + #[builder(default)] compressed: bool, ) { - test_verify_proof_inner( - uri, - client, - root, - signal_hash, - nullifier_hash, - external_nullifier_hash, - proof, - None, - expected_failure, - ) - .await -} + let body = if compressed { + let proof = semaphore_rs::protocol::compression::compress_proof(proof) + .expect("Failed to compress proof"); -#[allow(clippy::too_many_arguments)] -#[instrument(skip_all)] -pub async fn test_verify_proof_with_age( - uri: &str, - client: &Client, - root: Field, - signal_hash: Field, - nullifier_hash: Field, - external_nullifier_hash: Field, - proof: protocol::Proof, - max_root_age_seconds: i64, - expected_failure: Option<&str>, -) { - test_verify_proof_inner( - uri, - client, - root, - signal_hash, - nullifier_hash, - external_nullifier_hash, - proof, - Some(max_root_age_seconds), - expected_failure, - ) - .await -} + serde_json::to_string(&VerifyCompressedSemaphoreProofRequest { + root, + signal_hash, + nullifier_hash, + external_nullifier_hash, + proof, + }) + .expect("Cannot serialize VerifySemaphoreProofRequest") + } else { + serde_json::to_string(&VerifySemaphoreProofRequest { + root, + signal_hash, + nullifier_hash, + external_nullifier_hash, + proof, + }) + .expect("Cannot serialize VerifySemaphoreProofRequest") + }; -#[allow(clippy::too_many_arguments)] -#[instrument(skip_all)] -async fn test_verify_proof_inner( - uri: &str, - client: &Client, - root: Field, - signal_hash: Field, - nullifier_hash: Field, - external_nullifier_hash: Field, - proof: protocol::Proof, - max_root_age_seconds: Option, - expected_failure: Option<&str>, -) { - let body = construct_verify_proof_body( - root, - signal_hash, - nullifier_hash, - external_nullifier_hash, - proof, - ); + let body = Body::from(body); - let uri = match max_root_age_seconds { - Some(max_root_age_seconds) => { - format!("{uri}/verifySemaphoreProof?maxRootAgeSeconds={max_root_age_seconds}") - } - None => format!("{uri}/verifySemaphoreProof"), + let mut uri = if compressed { + format!("{uri}/verifyCompressedSemaphoreProof") + } else { + format!("{uri}/verifySemaphoreProof") }; + if let Some(max_root_age) = max_root_age_seconds { + uri = format!("{uri}?maxRootAgeSeconds={max_root_age}"); + } + let response = client .request(Method::POST, uri) .header("Content-Type", "application/json") diff --git a/tests/validate_proof_with_age.rs b/tests/validate_proof_with_age.rs index 506a5716..f2b9059b 100644 --- a/tests/validate_proof_with_age.rs +++ b/tests/validate_proof_with_age.rs @@ -4,8 +4,6 @@ use std::time::Instant; use common::prelude::*; -use crate::common::test_verify_proof_with_age; - #[tokio::test] async fn validate_proof_with_age_onchain() -> anyhow::Result<()> { validate_proof_with_age(false).await @@ -106,19 +104,17 @@ async fn validate_proof_with_age(offchain_mode_enabled: bool) -> anyhow::Result< // Wait so the proof is at least 2 seconds old tokio::time::sleep(Duration::from_secs(2)).await; + let test_builder = test_verify_proof_builder() + .uri(&uri) + .client(&client) + .root(root) + .signal_hash(signal_hash) + .nullifier_hash(nullifier_hash) + .external_nullifier_hash(external_nullifier_hash) + .proof(proof); + // Proof will be older than 2 seconds, but it's the latest root - test_verify_proof_with_age( - &uri, - &client, - root, - signal_hash, - nullifier_hash, - external_nullifier_hash, - proof, - 2, - None, - ) - .await; + test_builder.clone().max_root_age_seconds(2).call().await; // Insert the 2nd identity to produce new root test_insert_identity(&uri, &client, &mut ref_tree, &test_leaves, 1).await; @@ -127,18 +123,12 @@ async fn validate_proof_with_age(offchain_mode_enabled: bool) -> anyhow::Result< tokio::time::sleep(Duration::from_secs(sleep_duration_seconds)).await; // Now the old proof root is too old (definitely older than 2 seconds) - test_verify_proof_with_age( - &uri, - &client, - root, - signal_hash, - nullifier_hash, - external_nullifier_hash, - proof, - 2, - Some("Root provided in semaphore proof is too old."), - ) - .await; + test_builder + .clone() + .max_root_age_seconds(2) + .expected_failure("Root provided in semaphore proof is too old.") + .call() + .await; let max_age_of_proof = (Instant::now() - time_of_identity_insertion).as_secs() + 2; assert!( @@ -147,18 +137,10 @@ async fn validate_proof_with_age(offchain_mode_enabled: bool) -> anyhow::Result< ); // Test proof which is new enough - test_verify_proof_with_age( - &uri, - &client, - root, - signal_hash, - nullifier_hash, - external_nullifier_hash, - proof, - max_age_of_proof as i64, - None, - ) - .await; + test_builder + .max_root_age_seconds(max_age_of_proof as i64) + .call() + .await; // Shutdown the app properly for the final time shutdown.shutdown(); diff --git a/tests/validate_proofs.rs b/tests/validate_proofs.rs index ed750aad..51dca00f 100644 --- a/tests/validate_proofs.rs +++ b/tests/validate_proofs.rs @@ -106,17 +106,17 @@ async fn validate_proofs(offchain_mode_enabled: bool) -> anyhow::Result<()> { let proof = proof_task.await.unwrap(); - test_verify_proof( - &uri, - &client, - root, - signal_hash, - nullifier_hash, - external_nullifier_hash, - proof, - None, - ) - .await; + let test_builder = test_verify_proof_builder() + .uri(&uri) + .client(&client) + .root(root) + .signal_hash(signal_hash) + .nullifier_hash(nullifier_hash) + .external_nullifier_hash(external_nullifier_hash) + .proof(proof); + + test_builder.clone().call().await; + test_builder.clone().compressed(false).call().await; test_inclusion_proof( &mock_chain, @@ -147,17 +147,18 @@ async fn validate_proofs(offchain_mode_enabled: bool) -> anyhow::Result<()> { let invalid_nullifier_hash = generate_nullifier_hash(&IDENTITIES[1], external_nullifier_hash); - test_verify_proof( - &uri, - &client, - root, - signal_hash, - invalid_nullifier_hash, - external_nullifier_hash, - proof, - Some("invalid semaphore proof"), - ) - .await; + // TODO:: Reuse the main builder once https://github.com/elastio/bon/issues/149 is stabilized + test_verify_proof_builder() + .uri(&uri) + .client(&client) + .root(root) + .signal_hash(signal_hash) + .nullifier_hash(invalid_nullifier_hash) + .external_nullifier_hash(external_nullifier_hash) + .proof(proof) + .expected_failure("invalid semaphore proof") + .call() + .await; if !offchain_mode_enabled { test_verify_proof_on_chain( @@ -187,17 +188,17 @@ async fn validate_proofs(offchain_mode_enabled: bool) -> anyhow::Result<()> { ) .unwrap(); - test_verify_proof( - &uri, - &client, - root, - signal_hash, - new_nullifier_hash, - external_nullifier_hash, - new_proof, - Some("invalid semaphore proof"), - ) - .await; + test_verify_proof_builder() + .uri(&uri) + .client(&client) + .root(root) + .signal_hash(signal_hash) + .nullifier_hash(new_nullifier_hash) + .external_nullifier_hash(external_nullifier_hash) + .proof(new_proof) + .expected_failure("invalid semaphore proof") + .call() + .await; if !offchain_mode_enabled { test_verify_proof_on_chain( @@ -216,17 +217,17 @@ async fn validate_proofs(offchain_mode_enabled: bool) -> anyhow::Result<()> { let new_root = ref_tree.root(); - test_verify_proof( - &uri, - &client, - new_root, - signal_hash, - new_nullifier_hash, - external_nullifier_hash, - new_proof, - Some("invalid root"), - ) - .await; + test_verify_proof_builder() + .uri(&uri) + .client(&client) + .root(new_root) + .signal_hash(signal_hash) + .nullifier_hash(new_nullifier_hash) + .external_nullifier_hash(external_nullifier_hash) + .proof(new_proof) + .expected_failure("invalid root") + .call() + .await; if !offchain_mode_enabled { test_verify_proof_on_chain(