From 445d1da7752b71208fdde253d516181c54556844 Mon Sep 17 00:00:00 2001 From: "adria0.eth" <5526331+adria0@users.noreply.github.com> Date: Tue, 25 Jun 2024 13:23:34 +0200 Subject: [PATCH] feat: deterministic tests (#349) --- .github/workflows/ci.yml | 7 +- halo2_debug/Cargo.toml | 8 + halo2_debug/src/lib.rs | 37 +++ halo2_frontend/Cargo.toml | 1 - halo2_proofs/Cargo.toml | 2 +- halo2_proofs/src/plonk/prover.rs | 1 - halo2_proofs/tests/compress_selectors.rs | 40 ++- halo2_proofs/tests/frontend_backend_split.rs | 275 +++++++++---------- halo2_proofs/tests/plonk_api.rs | 104 ++++--- halo2_proofs/tests/serialization.rs | 139 +++++----- halo2_proofs/tests/shuffle.rs | 29 +- halo2_proofs/tests/shuffle_api.rs | 61 ++-- halo2_proofs/tests/vector-ops-unblinded.rs | 21 +- p3_frontend/Cargo.toml | 1 + p3_frontend/tests/common/mod.rs | 19 +- 15 files changed, 409 insertions(+), 336 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d3d0ce27d0..5d92f02ffb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,10 +17,9 @@ jobs: os: [ubuntu-latest, windows-latest, macOS-latest] include: - feature_set: basic - features: batch,dev-graph,gadget-traces + features: --features batch,dev-graph,gadget-traces - feature_set: all - features: batch,dev-graph,gadget-traces,test-dev-graph,thread-safe-region,sanity-checks,circuit-params,lookup-any-sanity-checks - + features: --all-features steps: - uses: actions/checkout@v3 - uses: actions-rs/toolchain@v1 @@ -30,7 +29,7 @@ jobs: uses: actions-rs/cargo@v1 with: command: test - args: --verbose --release --workspace --no-default-features --features "${{ matrix.features }}" + args: --verbose --release --workspace --no-default-features ${{ matrix.features }} examples: name: Run the examples diff --git a/halo2_debug/Cargo.toml b/halo2_debug/Cargo.toml index d86ea3755b..3af6c761d5 100644 --- a/halo2_debug/Cargo.toml +++ b/halo2_debug/Cargo.toml @@ -25,3 +25,11 @@ ff = "0.13" halo2curves = { version = "0.6.1", default-features = false } num-bigint = "0.4.5" halo2_middleware = { path = "../halo2_middleware" } +tiny-keccak = { version = "2.0.2", features=["keccak"] } +hex = "0.4.3" +rand_core = "0.6.4" +rand_chacha = "0.3" +rayon = "1.8" + +[features] +vector-tests = [] \ No newline at end of file diff --git a/halo2_debug/src/lib.rs b/halo2_debug/src/lib.rs index 8754563b71..911e90e6df 100644 --- a/halo2_debug/src/lib.rs +++ b/halo2_debug/src/lib.rs @@ -1 +1,38 @@ +use rand_chacha::ChaCha20Rng; +use rand_core::SeedableRng; +use tiny_keccak::Hasher; + +pub fn test_rng() -> ChaCha20Rng { + ChaCha20Rng::seed_from_u64(0xdeadbeef) +} + +/// Gets the hex representation of the keccak hash of the input data +pub fn keccak_hex>(data: D) -> String { + let mut hash = [0u8; 32]; + let mut hasher = tiny_keccak::Keccak::v256(); + hasher.update(data.as_ref()); + hasher.finalize(&mut hash); + hex::encode(hash) +} + +/// When the feature `vector-tests` is enabled, executes the test in a single thread and checks the result against the expected value. +/// When the feature `vector-tests` is disabled, just executes the test. +pub fn test_result Vec + Send>(test: F, _expected: &str) -> Vec { + #[cfg(feature = "vector-tests")] + let result = rayon::ThreadPoolBuilder::new() + .num_threads(1) + .build() + .unwrap() + .install(|| { + let result = test(); + assert_eq!(_expected, keccak_hex(result.clone()),); + result + }); + + #[cfg(not(feature = "vector-tests"))] + let result = test(); + + result +} + pub mod display; diff --git a/halo2_frontend/Cargo.toml b/halo2_frontend/Cargo.toml index f9627bac28..1dd4a2a2db 100644 --- a/halo2_frontend/Cargo.toml +++ b/halo2_frontend/Cargo.toml @@ -60,7 +60,6 @@ bits = ["halo2curves/bits"] gadget-traces = ["backtrace"] thread-safe-region = [] circuit-params = [] -heap-profiling = [] cost-estimator = ["serde", "serde_derive"] derive_serde = ["halo2curves/derive_serde"] lookup-any-sanity-checks = [] diff --git a/halo2_proofs/Cargo.toml b/halo2_proofs/Cargo.toml index e84af4eafa..96f84d7bb2 100644 --- a/halo2_proofs/Cargo.toml +++ b/halo2_proofs/Cargo.toml @@ -82,9 +82,9 @@ thread-safe-region = ["halo2_frontend/thread-safe-region"] sanity-checks = ["halo2_backend/sanity-checks"] batch = ["rand_core/getrandom", "halo2_backend/batch"] circuit-params = ["halo2_frontend/circuit-params"] -heap-profiling = ["halo2_frontend/heap-profiling"] cost-estimator = ["halo2_frontend/cost-estimator"] derive_serde = ["halo2curves/derive_serde", "halo2_frontend/derive_serde", "halo2_backend/derive_serde"] +vector-tests = [] lookup-any-sanity-checks = ["halo2_frontend/lookup-any-sanity-checks"] [lib] diff --git a/halo2_proofs/src/plonk/prover.rs b/halo2_proofs/src/plonk/prover.rs index 21caf757fd..1c6a3a7e0b 100644 --- a/halo2_proofs/src/plonk/prover.rs +++ b/halo2_proofs/src/plonk/prover.rs @@ -69,7 +69,6 @@ where } Ok(prover.create_proof()?) } - /// This creates a proof for the provided `circuit` when given the public /// parameters `params` and the proving key [`ProvingKey`] that was /// generated previously for the same circuit. The provided `instances` diff --git a/halo2_proofs/tests/compress_selectors.rs b/halo2_proofs/tests/compress_selectors.rs index 5362757295..99cacab9ac 100644 --- a/halo2_proofs/tests/compress_selectors.rs +++ b/halo2_proofs/tests/compress_selectors.rs @@ -4,6 +4,7 @@ use std::marker::PhantomData; use ff::PrimeField; use halo2_debug::display::expr_disp_names; +use halo2_debug::{test_result, test_rng}; use halo2_frontend::circuit::compile_circuit; use halo2_frontend::plonk::Error; use halo2_proofs::circuit::{Cell, Layouter, SimpleFloorPlanner, Value}; @@ -23,22 +24,6 @@ use halo2_proofs::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG}; use halo2_proofs::poly::kzg::multiopen::{ProverSHPLONK, VerifierSHPLONK}; use halo2_proofs::poly::kzg::strategy::SingleStrategy; use halo2curves::bn256::{Bn256, Fr, G1Affine}; -use rand_core::block::BlockRng; -use rand_core::block::BlockRngCore; - -// One number generator, that can be used as a deterministic Rng, outputing fixed values. -pub struct OneNg {} - -impl BlockRngCore for OneNg { - type Item = u32; - type Results = [u32; 16]; - - fn generate(&mut self, results: &mut Self::Results) { - for elem in results.iter_mut() { - *elem = 1; - } - } -} #[derive(Debug, Clone)] struct MyCircuitConfig { @@ -351,7 +336,7 @@ impl Circuit for MyCircuit { fn test_mycircuit( vk_keygen_compress_selectors: bool, pk_keygen_compress_selectors: bool, -) -> Result<(), halo2_proofs::plonk::Error> { +) -> Result, halo2_proofs::plonk::Error> { let engine = PlonkEngineConfig::new() .set_curve::() .set_msm(H2cEngine::new()) @@ -363,8 +348,9 @@ fn test_mycircuit( constant: Fr::one(), }; + let mut rng = test_rng(); + // Setup - let mut rng = BlockRng::new(OneNg {}); let params = ParamsKZG::::setup(k, &mut rng); let verifier_params = params.verifier_params(); let vk = keygen_vk_custom(¶ms, &circuit, vk_keygen_compress_selectors)?; @@ -398,7 +384,9 @@ fn test_mycircuit( instances.as_slice(), &mut verifier_transcript, ) - .map_err(halo2_proofs::plonk::Error::Backend) + .map_err(halo2_proofs::plonk::Error::Backend)?; + + Ok(proof) } /* @@ -496,12 +484,20 @@ fn test_compress_gates() { } #[test] -fn test_success() { +fn test_success() -> Result<(), halo2_proofs::plonk::Error> { // vk & pk keygen both WITH compress - assert!(test_mycircuit(true, true).is_ok()); + test_result( + || test_mycircuit(true, true).expect("should pass"), + "8326140d1873a91630d439a8812d1f104667144e03e0cd5c59eb358ae5d1a4eb", + ); // vk & pk keygen both WITHOUT compress - assert!(test_mycircuit(false, false).is_ok()); + test_result( + || test_mycircuit(false, false).expect("should pass"), + "73dd4c3c9c51d55dc8cf68ca2b5d8acdb40ed44bc8a88d718325bc0023688f64", + ); + + Ok(()) } #[should_panic] diff --git a/halo2_proofs/tests/frontend_backend_split.rs b/halo2_proofs/tests/frontend_backend_split.rs index 5c965191b2..6238a13e33 100644 --- a/halo2_proofs/tests/frontend_backend_split.rs +++ b/halo2_proofs/tests/frontend_backend_split.rs @@ -1,10 +1,6 @@ #![allow(clippy::many_single_char_names)] #![allow(clippy::op_ref)] -#[cfg(feature = "heap-profiling")] -#[global_allocator] -static ALLOC: dhat::Alloc = dhat::Alloc; - use halo2_backend::{ plonk::{ keygen::{keygen_pk, keygen_vk}, @@ -15,6 +11,7 @@ use halo2_backend::{ Blake2bRead, Blake2bWrite, Challenge255, TranscriptReadBuffer, TranscriptWriterBuffer, }, }; +use halo2_debug::test_rng; use halo2_frontend::{ circuit::{ compile_circuit, AssignedCell, Layouter, Region, SimpleFloorPlanner, Value, @@ -470,22 +467,6 @@ use halo2_proofs::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG}; use halo2_proofs::poly::kzg::multiopen::{ProverSHPLONK, VerifierSHPLONK}; use halo2_proofs::poly::kzg::strategy::SingleStrategy; use halo2curves::bn256::{Bn256, Fr, G1Affine}; -use rand_core::block::BlockRng; -use rand_core::block::BlockRngCore; - -// One number generator, that can be used as a deterministic Rng, outputing fixed values. -struct OneNg {} - -impl BlockRngCore for OneNg { - type Item = u32; - type Results = [u32; 16]; - - fn generate(&mut self, results: &mut Self::Results) { - for elem in results.iter_mut() { - *elem = 1; - } - } -} #[test] fn test_mycircuit_mock() { @@ -504,130 +485,140 @@ const WIDTH_FACTOR: usize = 1; #[test] fn test_mycircuit_full_legacy() { - #[cfg(all(feature = "heap-profiling", not(coverage)))] - let _profiler = dhat::Profiler::new_heap(); - - use halo2_proofs::plonk::{ - create_proof, keygen_pk as keygen_pk_legacy, keygen_vk as keygen_vk_legacy, - }; - - let k = K; - let circuit: MyCircuit = MyCircuit::new(k, 42); - - // Setup - let mut rng = BlockRng::new(OneNg {}); - let params = ParamsKZG::::setup(k, &mut rng); - let start = Instant::now(); - let vk = keygen_vk_legacy(¶ms, &circuit).expect("keygen_vk should not fail"); - let pk = keygen_pk_legacy(¶ms, vk.clone(), &circuit).expect("keygen_pk should not fail"); - println!("Keygen: {:?}", start.elapsed()); - - // Proving - let instances = vec![circuit.instances()]; - - let start = Instant::now(); - let mut transcript = Blake2bWrite::<_, G1Affine, Challenge255<_>>::init(vec![]); - create_proof::, ProverSHPLONK<'_, Bn256>, _, _, _, _>( - ¶ms, - &pk, - &[circuit], - instances.as_slice(), - &mut rng, - &mut transcript, - ) - .expect("proof generation should not fail"); - let proof = transcript.finalize(); - println!("Prove: {:?}", start.elapsed()); - - // Verify - let start = Instant::now(); - let mut verifier_transcript = - Blake2bRead::<_, G1Affine, Challenge255<_>>::init(proof.as_slice()); - let verifier_params = params.verifier_params(); - let strategy = SingleStrategy::new(&verifier_params); - - verify_proof::, VerifierSHPLONK, _, _, _>( - &verifier_params, - &vk, - strategy, - instances.as_slice(), - &mut verifier_transcript, - ) - .expect("verify succeeds"); - println!("Verify: {:?}", start.elapsed()); + halo2_debug::test_result( + || { + use halo2_proofs::plonk::{ + create_proof, keygen_pk as keygen_pk_legacy, keygen_vk as keygen_vk_legacy, + }; + + let k = K; + let circuit: MyCircuit = MyCircuit::new(k, 42); + + // Setup + let mut rng = test_rng(); + let params = ParamsKZG::::setup(k, &mut rng); + let start = Instant::now(); + let vk = keygen_vk_legacy(¶ms, &circuit).expect("keygen_vk should not fail"); + let pk = + keygen_pk_legacy(¶ms, vk.clone(), &circuit).expect("keygen_pk should not fail"); + println!("Keygen: {:?}", start.elapsed()); + + // Proving + let instances = vec![circuit.instances()]; + + let start = Instant::now(); + let mut transcript = Blake2bWrite::<_, G1Affine, Challenge255<_>>::init(vec![]); + create_proof::, ProverSHPLONK<'_, Bn256>, _, _, _, _>( + ¶ms, + &pk, + &[circuit], + instances.as_slice(), + &mut rng, + &mut transcript, + ) + .expect("proof generation should not fail"); + let proof = transcript.finalize(); + println!("Prove: {:?}", start.elapsed()); + + // Verify + let start = Instant::now(); + let mut verifier_transcript = + Blake2bRead::<_, G1Affine, Challenge255<_>>::init(proof.as_slice()); + let verifier_params = params.verifier_params(); + let strategy = SingleStrategy::new(&verifier_params); + + verify_proof::, VerifierSHPLONK, _, _, _>( + &verifier_params, + &vk, + strategy, + instances.as_slice(), + &mut verifier_transcript, + ) + .expect("verify succeeds"); + println!("Verify: {:?}", start.elapsed()); + + proof + }, + "427e55eafeaafd9f4dfc7ec6f782ec7464251c749bb08e23efb663790c0419ed", + ); } #[test] fn test_mycircuit_full_split() { - use halo2_middleware::zal::impls::{H2cEngine, PlonkEngineConfig}; - - #[cfg(all(feature = "heap-profiling", not(coverage)))] - let _profiler = dhat::Profiler::new_heap(); - - let engine = PlonkEngineConfig::new() - .set_curve::() - .set_msm(H2cEngine::new()) - .build(); - let k = K; - let circuit: MyCircuit = MyCircuit::new(k, 42); - let (compiled_circuit, config, cs) = compile_circuit(k, &circuit, false).unwrap(); - - // Setup - let mut rng = BlockRng::new(OneNg {}); - let params = ParamsKZG::::setup(k, &mut rng); - let start = Instant::now(); - let vk = keygen_vk(¶ms, &compiled_circuit).expect("keygen_vk should not fail"); - let pk = keygen_pk(¶ms, vk.clone(), &compiled_circuit).expect("keygen_pk should not fail"); - println!("Keygen: {:?}", start.elapsed()); - drop(compiled_circuit); - - let instances = circuit.instances(); - // Proving - println!("Proving..."); - let start = Instant::now(); - let mut witness_calc = WitnessCalculator::new(k, &circuit, &config, &cs, &instances); - let mut transcript = Blake2bWrite::<_, G1Affine, Challenge255<_>>::init(vec![]); - let mut prover = ProverSingle::< - KZGCommitmentScheme, - ProverSHPLONK<'_, Bn256>, - _, - _, - _, - _, - >::new_with_engine( - engine, - ¶ms, - &pk, -instances.clone(), - &mut rng, - &mut transcript, - ) - .unwrap(); - let mut challenges = HashMap::new(); - for phase in 0..cs.phases().count() { - println!("phase {phase}"); - let witness = witness_calc.calc(phase as u8, &challenges).unwrap(); - challenges = prover.commit_phase(phase as u8, witness).unwrap(); - } - prover.create_proof().unwrap(); - let proof = transcript.finalize(); - println!("Prove: {:?}", start.elapsed()); - - // Verify - let start = Instant::now(); - println!("Verifying..."); - let mut verifier_transcript = - Blake2bRead::<_, G1Affine, Challenge255<_>>::init(proof.as_slice()); - let verifier_params = params.verifier_params(); - let strategy = SingleStrategy::new(&verifier_params); - - verify_proof_single::, VerifierSHPLONK, _, _, _>( - &verifier_params, - &vk, - strategy, - instances, - &mut verifier_transcript, - ) - .expect("verify succeeds"); - println!("Verify: {:?}", start.elapsed()); + halo2_debug::test_result( + || { + use halo2_middleware::zal::impls::{H2cEngine, PlonkEngineConfig}; + + let engine = PlonkEngineConfig::new() + .set_curve::() + .set_msm(H2cEngine::new()) + .build(); + let k = K; + let circuit: MyCircuit = MyCircuit::new(k, 42); + let (compiled_circuit, config, cs) = compile_circuit(k, &circuit, true).unwrap(); + + // Setup + let mut rng = test_rng(); + let params = ParamsKZG::::setup(k, &mut rng); + let start = Instant::now(); + let vk = keygen_vk(¶ms, &compiled_circuit).expect("keygen_vk should not fail"); + let pk = keygen_pk(¶ms, vk.clone(), &compiled_circuit) + .expect("keygen_pk should not fail"); + println!("Keygen: {:?}", start.elapsed()); + drop(compiled_circuit); + + let instances = circuit.instances(); + // Proving + println!("Proving..."); + let start = Instant::now(); + let mut witness_calc = WitnessCalculator::new(k, &circuit, &config, &cs, &instances); + let mut transcript = Blake2bWrite::<_, G1Affine, Challenge255<_>>::init(vec![]); + let mut prover = ProverSingle::< + KZGCommitmentScheme, + ProverSHPLONK<'_, Bn256>, + _, + _, + _, + _, + >::new_with_engine( + engine, + ¶ms, + &pk, + instances.clone(), + &mut rng, + &mut transcript, + ) + .unwrap(); + let mut challenges = HashMap::new(); + for phase in 0..cs.phases().count() { + println!("phase {phase}"); + let witness = witness_calc.calc(phase as u8, &challenges).unwrap(); + challenges = prover.commit_phase(phase as u8, witness).unwrap(); + } + prover.create_proof().unwrap(); + let proof = transcript.finalize(); + println!("Prove: {:?}", start.elapsed()); + + // Verify + let start = Instant::now(); + println!("Verifying..."); + let mut verifier_transcript = + Blake2bRead::<_, G1Affine, Challenge255<_>>::init(proof.as_slice()); + let verifier_params = params.verifier_params(); + let strategy = SingleStrategy::new(&verifier_params); + + verify_proof_single::, VerifierSHPLONK, _, _, _>( + &verifier_params, + &vk, + strategy, + instances, + &mut verifier_transcript, + ) + .expect("verify succeeds"); + println!("Verify: {:?}", start.elapsed()); + + proof + }, + "427e55eafeaafd9f4dfc7ec6f782ec7464251c749bb08e23efb663790c0419ed", + ); } diff --git a/halo2_proofs/tests/plonk_api.rs b/halo2_proofs/tests/plonk_api.rs index 9ddd6de68a..d454d0292b 100644 --- a/halo2_proofs/tests/plonk_api.rs +++ b/halo2_proofs/tests/plonk_api.rs @@ -3,6 +3,7 @@ use assert_matches::assert_matches; use ff::{FromUniformBytes, WithSmallOrderMulGroup}; +use halo2_debug::test_rng; use halo2_middleware::zal::{ impls::{PlonkEngine, PlonkEngineConfig}, traits::MsmAccel, @@ -22,7 +23,7 @@ use halo2_proofs::transcript::{ Blake2bRead, Blake2bWrite, Challenge255, EncodedChallenge, TranscriptReadBuffer, TranscriptWriterBuffer, }; -use rand_core::{OsRng, RngCore}; +use rand_core::RngCore; use std::marker::PhantomData; #[test] @@ -567,61 +568,78 @@ fn plonk_api() { } fn test_plonk_api_gwc() { - use halo2_proofs::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG}; - use halo2_proofs::poly::kzg::multiopen::{ProverGWC, VerifierGWC}; - use halo2_proofs::poly::kzg::strategy::AccumulatorStrategy; - use halo2curves::bn256::Bn256; + halo2_debug::test_result( + || { + use halo2_proofs::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG}; + use halo2_proofs::poly::kzg::multiopen::{ProverGWC, VerifierGWC}; + use halo2_proofs::poly::kzg::strategy::AccumulatorStrategy; + use halo2curves::bn256::Bn256; - type Scheme = KZGCommitmentScheme; - bad_keys!(Scheme); + type Scheme = KZGCommitmentScheme; - let params = ParamsKZG::::new(K); - let rng = OsRng; + bad_keys!(Scheme); - let pk = keygen::>(¶ms); + let mut rng = test_rng(); - let proof = create_proof::<_, ProverGWC<_>, _, _, Blake2bWrite<_, _, Challenge255<_>>>( - rng, ¶ms, &pk, - ); + let params = ParamsKZG::::setup(K, &mut rng); + let pk = keygen::>(¶ms); - let verifier_params = params.verifier_params(); + let proof = + create_proof::<_, ProverGWC<_>, _, _, Blake2bWrite<_, _, Challenge255<_>>>( + &mut rng, ¶ms, &pk, + ); - verify_proof::< - _, - VerifierGWC<_>, - _, - Blake2bRead<_, _, Challenge255<_>>, - AccumulatorStrategy<_>, - >(&verifier_params, pk.get_vk(), &proof[..]); + let verifier_params = params.verifier_params(); + + verify_proof::< + _, + VerifierGWC<_>, + _, + Blake2bRead<_, _, Challenge255<_>>, + AccumulatorStrategy<_>, + >(&verifier_params, pk.get_vk(), &proof[..]); + + proof + }, + "b749dfa90ac3bc3d45f994cc8bf527928a274c2225e4e87668eece79938e6d12", + ); } fn test_plonk_api_shplonk() { - use halo2_proofs::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG}; - use halo2_proofs::poly::kzg::multiopen::{ProverSHPLONK, VerifierSHPLONK}; - use halo2_proofs::poly::kzg::strategy::AccumulatorStrategy; - use halo2curves::bn256::Bn256; + halo2_debug::test_result( + || { + use halo2_proofs::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG}; + use halo2_proofs::poly::kzg::multiopen::{ProverSHPLONK, VerifierSHPLONK}; + use halo2_proofs::poly::kzg::strategy::AccumulatorStrategy; + use halo2curves::bn256::Bn256; - type Scheme = KZGCommitmentScheme; - bad_keys!(Scheme); + type Scheme = KZGCommitmentScheme; + bad_keys!(Scheme); - let params = ParamsKZG::::new(K); - let rng = OsRng; + let mut rng = test_rng(); + let params = ParamsKZG::::setup(K, &mut rng); - let pk = keygen::>(¶ms); + let pk = keygen::>(¶ms); - let proof = create_proof::<_, ProverSHPLONK<_>, _, _, Blake2bWrite<_, _, Challenge255<_>>>( - rng, ¶ms, &pk, - ); + let proof = + create_proof::<_, ProverSHPLONK<_>, _, _, Blake2bWrite<_, _, Challenge255<_>>>( + rng, ¶ms, &pk, + ); - let verifier_params = params.verifier_params(); + let verifier_params = params.verifier_params(); - verify_proof::< - _, - VerifierSHPLONK<_>, - _, - Blake2bRead<_, _, Challenge255<_>>, - AccumulatorStrategy<_>, - >(&verifier_params, pk.get_vk(), &proof[..]); + verify_proof::< + _, + VerifierSHPLONK<_>, + _, + Blake2bRead<_, _, Challenge255<_>>, + AccumulatorStrategy<_>, + >(&verifier_params, pk.get_vk(), &proof[..]); + + proof + }, + "284001f93f86a5d18ad9ebff6da81031e5ad9f799ea1dc2606271a6ff240fbd3", + ); } fn test_plonk_api_ipa() { @@ -633,13 +651,13 @@ fn plonk_api() { type Scheme = IPACommitmentScheme; bad_keys!(Scheme); + let mut rng = test_rng(); let params = ParamsIPA::::new(K); - let rng = OsRng; let pk = keygen::>(¶ms); let proof = create_proof::<_, ProverIPA<_>, _, _, Blake2bWrite<_, _, Challenge255<_>>>( - rng, ¶ms, &pk, + &mut rng, ¶ms, &pk, ); let verifier_params = params; diff --git a/halo2_proofs/tests/serialization.rs b/halo2_proofs/tests/serialization.rs index 93dfca7dff..54e350d7d6 100644 --- a/halo2_proofs/tests/serialization.rs +++ b/halo2_proofs/tests/serialization.rs @@ -4,6 +4,7 @@ use std::{ }; use ff::Field; +use halo2_debug::test_rng; use halo2_proofs::{ circuit::{Layouter, SimpleFloorPlanner, Value}, plonk::{ @@ -24,7 +25,6 @@ use halo2_proofs::{ SerdeFormat, }; use halo2curves::bn256::{Bn256, Fr, G1Affine}; -use rand_core::OsRng; #[derive(Clone, Copy)] struct StandardPlonkConfig { @@ -130,67 +130,78 @@ impl Circuit for StandardPlonk { #[test] fn test_serialization() { - let k = 4; - let circuit = StandardPlonk(Fr::random(OsRng)); - let params = ParamsKZG::::setup(k, OsRng); - let compress_selectors = true; - let vk = keygen_vk_custom(¶ms, &circuit, compress_selectors).expect("vk should not fail"); - let pk = keygen_pk(¶ms, vk, &circuit).expect("pk should not fail"); - - let f = File::create("serialization-test.pk").unwrap(); - let mut writer = BufWriter::new(f); - pk.write(&mut writer, SerdeFormat::RawBytes).unwrap(); - writer.flush().unwrap(); - - let f = File::open("serialization-test.pk").unwrap(); - let mut reader = BufReader::new(f); - #[allow(clippy::unit_arg)] - let pk = pk_read::( - &mut reader, - SerdeFormat::RawBytes, - k, - &circuit, - compress_selectors, - ) - .unwrap(); - - std::fs::remove_file("serialization-test.pk").unwrap(); - - let instances: Vec>> = vec![vec![vec![circuit.0]]]; - let mut transcript = Blake2bWrite::<_, _, Challenge255<_>>::init(vec![]); - create_proof::< - KZGCommitmentScheme, - ProverGWC<'_, Bn256>, - Challenge255, - _, - Blake2bWrite, G1Affine, Challenge255<_>>, - _, - >( - ¶ms, - &pk, - &[circuit], - instances.as_slice(), - OsRng, - &mut transcript, - ) - .expect("prover should not fail"); - let proof = transcript.finalize(); - - let verifier_params = params.verifier_params(); - let strategy = SingleStrategy::new(&verifier_params); - let mut transcript = Blake2bRead::<_, _, Challenge255<_>>::init(&proof[..]); - assert!(verify_proof::< - KZGCommitmentScheme, - VerifierGWC, - Challenge255, - Blake2bRead<&[u8], G1Affine, Challenge255>, - SingleStrategy, - >( - &verifier_params, - pk.get_vk(), - strategy, - instances.as_slice(), - &mut transcript - ) - .is_ok()); + halo2_debug::test_result( + || { + let k = 4; + + let mut rng = test_rng(); + + let circuit = StandardPlonk(Fr::random(&mut rng)); + let params = ParamsKZG::::setup(k, &mut rng); + let compress_selectors = true; + let vk = keygen_vk_custom(¶ms, &circuit, compress_selectors) + .expect("vk should not fail"); + let pk = keygen_pk(¶ms, vk, &circuit).expect("pk should not fail"); + + let f = File::create("serialization-test.pk").unwrap(); + let mut writer = BufWriter::new(f); + pk.write(&mut writer, SerdeFormat::RawBytes).unwrap(); + writer.flush().unwrap(); + + let f = File::open("serialization-test.pk").unwrap(); + let mut reader = BufReader::new(f); + #[allow(clippy::unit_arg)] + let pk = pk_read::( + &mut reader, + SerdeFormat::RawBytes, + k, + &circuit, + compress_selectors, + ) + .unwrap(); + + std::fs::remove_file("serialization-test.pk").unwrap(); + + let instances: Vec>> = vec![vec![vec![circuit.0]]]; + let mut transcript = Blake2bWrite::<_, _, Challenge255<_>>::init(vec![]); + create_proof::< + KZGCommitmentScheme, + ProverGWC<'_, Bn256>, + Challenge255, + _, + Blake2bWrite, G1Affine, Challenge255<_>>, + _, + >( + ¶ms, + &pk, + &[circuit], + instances.as_slice(), + test_rng(), + &mut transcript, + ) + .expect("prover should not fail"); + let proof = transcript.finalize(); + + let verifier_params = params.verifier_params(); + let strategy = SingleStrategy::new(&verifier_params); + let mut transcript = Blake2bRead::<_, _, Challenge255<_>>::init(&proof[..]); + assert!(verify_proof::< + KZGCommitmentScheme, + VerifierGWC, + Challenge255, + Blake2bRead<&[u8], G1Affine, Challenge255>, + SingleStrategy, + >( + &verifier_params, + pk.get_vk(), + strategy, + instances.as_slice(), + &mut transcript + ) + .is_ok()); + + proof + }, + "0d3baeea90249588c3939dc2f64b071b24b7e4744c4ca8442fe4b2553aae9167", + ); } diff --git a/halo2_proofs/tests/shuffle.rs b/halo2_proofs/tests/shuffle.rs index 0b27a3509c..f74958bee8 100644 --- a/halo2_proofs/tests/shuffle.rs +++ b/halo2_proofs/tests/shuffle.rs @@ -1,4 +1,5 @@ use ff::{BatchInvert, FromUniformBytes}; +use halo2_debug::test_rng; use halo2_proofs::{ arithmetic::{CurveAffine, Field}, circuit::{floor_planner::V1, Layouter, Value}, @@ -18,7 +19,7 @@ use halo2_proofs::{ Blake2bRead, Blake2bWrite, Challenge255, TranscriptReadBuffer, TranscriptWriterBuffer, }, }; -use rand_core::{OsRng, RngCore}; +use rand_core::RngCore; use std::iter; fn rand_2d_array(rng: &mut R) -> [[F; H]; W] { @@ -273,9 +274,12 @@ fn test_prover( k: u32, circuit: MyCircuit, expected: bool, -) where +) -> Vec +where C::Scalar: FromUniformBytes<64>, { + let rng = test_rng(); + let params = ParamsIPA::::new(k); let vk = keygen_vk(¶ms, &circuit).unwrap(); let pk = keygen_pk(¶ms, vk, &circuit).unwrap(); @@ -288,7 +292,7 @@ fn test_prover( &pk, &[circuit], &[vec![]], - OsRng, + rng, &mut transcript, ) .expect("proof generation should not fail"); @@ -312,6 +316,8 @@ fn test_prover( }; assert_eq!(accepted, expected); + + proof } #[test] @@ -320,12 +326,14 @@ fn test_shuffle() { const H: usize = 32; const K: u32 = 8; - let circuit = &MyCircuit::<_, W, H>::rand(&mut OsRng); + let circuit = &MyCircuit::<_, W, H>::rand(&mut test_rng()); - { - test_mock_prover(K, circuit.clone(), Ok(())); - test_prover::(K, circuit.clone(), true); - } + test_mock_prover(K, circuit.clone(), Ok(())); + + halo2_debug::test_result( + || test_prover::(K, circuit.clone(), true), + "8526b66a372eaeccb687c21daf358d4fdb1c9d2b7e81470317c472634c5c1470", + ); #[cfg(not(feature = "sanity-checks"))] { @@ -348,6 +356,9 @@ fn test_shuffle() { }, )]), ); - test_prover::(K, circuit, false); + halo2_debug::test_result( + || test_prover::(K, circuit.clone(), false), + "27ad558ee60a6675911b87a0df5de49d7c9b5673d723bb05a9811aa33bf486d1", + ); } } diff --git a/halo2_proofs/tests/shuffle_api.rs b/halo2_proofs/tests/shuffle_api.rs index a5c1167081..7dc8d73bc5 100644 --- a/halo2_proofs/tests/shuffle_api.rs +++ b/halo2_proofs/tests/shuffle_api.rs @@ -1,6 +1,8 @@ use std::{marker::PhantomData, vec}; use ff::FromUniformBytes; +use halo2_debug::test_rng; +use halo2_proofs::poly::commitment::ParamsProver; use halo2_proofs::{ arithmetic::Field, circuit::{Layouter, SimpleFloorPlanner, Value}, @@ -10,7 +12,6 @@ use halo2_proofs::{ }, poly::Rotation, poly::{ - commitment::ParamsProver, ipa::{ commitment::{IPACommitmentScheme, ParamsIPA}, multiopen::{ProverIPA, VerifierIPA}, @@ -23,7 +24,6 @@ use halo2_proofs::{ }, }; use halo2curves::{pasta::EqAffine, CurveAffine}; -use rand_core::OsRng; struct ShuffleChip { config: ShuffleConfig, @@ -148,10 +148,12 @@ impl Circuit for MyCircuit { } } -fn test_prover(k: u32, circuit: MyCircuit, expected: bool) +fn test_prover(k: u32, circuit: MyCircuit, expected: bool) -> Vec where C::Scalar: FromUniformBytes<64>, { + let rng = test_rng(); + let params = ParamsIPA::::new(k); let vk = keygen_vk(¶ms, &circuit).unwrap(); let pk = keygen_pk(¶ms, vk, &circuit).unwrap(); @@ -164,7 +166,7 @@ where &pk, &[circuit], &[vec![]], - OsRng, + rng, &mut transcript, ) .expect("proof generation should not fail"); @@ -188,30 +190,37 @@ where }; assert_eq!(accepted, expected); + + proof } #[test] fn test_shuffle_api() { - use halo2_proofs::dev::MockProver; - use halo2curves::pasta::Fp; - const K: u32 = 4; - let input_0 = [1, 2, 4, 1] - .map(|e: u64| Value::known(Fp::from(e))) - .to_vec(); - let input_1 = [10, 20, 40, 10].map(Fp::from).to_vec(); - let shuffle_0 = [4, 1, 1, 2] - .map(|e: u64| Value::known(Fp::from(e))) - .to_vec(); - let shuffle_1 = [40, 10, 10, 20] - .map(|e: u64| Value::known(Fp::from(e))) - .to_vec(); - let circuit = MyCircuit { - input_0, - input_1, - shuffle_0, - shuffle_1, - }; - let prover = MockProver::run(K, &circuit, vec![]).unwrap(); - prover.assert_satisfied(); - test_prover::(K, circuit, true); + halo2_debug::test_result( + || { + use halo2_proofs::dev::MockProver; + use halo2curves::pasta::Fp; + const K: u32 = 4; + let input_0 = [1, 2, 4, 1] + .map(|e: u64| Value::known(Fp::from(e))) + .to_vec(); + let input_1 = [10, 20, 40, 10].map(Fp::from).to_vec(); + let shuffle_0 = [4, 1, 1, 2] + .map(|e: u64| Value::known(Fp::from(e))) + .to_vec(); + let shuffle_1 = [40, 10, 10, 20] + .map(|e: u64| Value::known(Fp::from(e))) + .to_vec(); + let circuit = MyCircuit { + input_0, + input_1, + shuffle_0, + shuffle_1, + }; + let prover = MockProver::run(K, &circuit, vec![]).unwrap(); + prover.assert_satisfied(); + test_prover::(K, circuit, true) + }, + "54f4fec1776178aadf8816754d7877f1de685e0ffb5b6af4db20f557d87550d6", + ); } diff --git a/halo2_proofs/tests/vector-ops-unblinded.rs b/halo2_proofs/tests/vector-ops-unblinded.rs index 73aa58ab69..6a3f54a4a9 100644 --- a/halo2_proofs/tests/vector-ops-unblinded.rs +++ b/halo2_proofs/tests/vector-ops-unblinded.rs @@ -4,6 +4,7 @@ use std::marker::PhantomData; use ff::FromUniformBytes; +use halo2_debug::test_rng; use halo2_proofs::{ arithmetic::{CurveAffine, Field}, circuit::{AssignedCell, Chip, Layouter, Region, SimpleFloorPlanner, Value}, @@ -21,7 +22,6 @@ use halo2_proofs::{ Blake2bRead, Blake2bWrite, Challenge255, TranscriptReadBuffer, TranscriptWriterBuffer, }, }; -use rand_core::OsRng; // ANCHOR: instructions trait NumericInstructions: Chip { @@ -360,7 +360,7 @@ impl NumericInstructions for AddChip { } } -#[derive(Default)] +#[derive(Default, Clone)] struct MulCircuit { a: Vec>, b: Vec>, @@ -413,7 +413,7 @@ impl Circuit for MulCircuit { } // ANCHOR_END: circuit -#[derive(Default)] +#[derive(Default, Clone)] struct AddCircuit { a: Vec>, b: Vec>, @@ -475,6 +475,8 @@ fn test_prover( where C::Scalar: FromUniformBytes<64>, { + let rng = test_rng(); + let params = ParamsIPA::::new(k); let vk = keygen_vk(¶ms, &circuit).unwrap(); let pk = keygen_pk(¶ms, vk, &circuit).unwrap(); @@ -488,7 +490,7 @@ where &pk, &[circuit], &instances, - OsRng, + rng, &mut transcript, ) .expect("proof generation should not fail"); @@ -545,9 +547,16 @@ fn test_vector_ops_unbinded() { }; // the commitments will be the first columns of the proof transcript so we can compare them easily - let proof_1 = test_prover::(k, mul_circuit, true, c_mul); + let proof_1 = halo2_debug::test_result( + || test_prover::(k, mul_circuit.clone(), true, c_mul.clone()), + "1f726eaddd926057e6c2aa8a364d1b4192da27f53c38c9f21d8924ef3eb0f0ab", + ); + // the commitments will be the first columns of the proof transcript so we can compare them easily - let proof_2 = test_prover::(k, add_circuit, true, c_add); + let proof_2 = halo2_debug::test_result( + || test_prover::(k, add_circuit.clone(), true, c_add.clone()), + "a42eb2f3e4761e6588bfd8db7e7035ead1cc1331017b6b09a7b75ddfbefefc58", + ); // the commitments will be the first columns of the proof transcript so we can compare them easily // here we compare the first 10 bytes of the commitments diff --git a/p3_frontend/Cargo.toml b/p3_frontend/Cargo.toml index 409783ea76..7a7e1972ca 100644 --- a/p3_frontend/Cargo.toml +++ b/p3_frontend/Cargo.toml @@ -23,6 +23,7 @@ p3-matrix = { git = "https://github.com/Plonky3/Plonky3", rev = "7b5b8a6" } p3-field = { git = "https://github.com/Plonky3/Plonky3", rev = "7b5b8a6" } p3-uni-stark = { git = "https://github.com/Plonky3/Plonky3", rev = "7b5b8a6" } halo2_middleware = { path = "../halo2_middleware" } +halo2_debug = { path = "../halo2_debug" } serde = { version = "1.0", default-features = false, features = ["derive", "alloc"] } num-bigint = { version = "0.4.3", default-features = false } diff --git a/p3_frontend/tests/common/mod.rs b/p3_frontend/tests/common/mod.rs index a7182f36f7..d762b5f2d5 100644 --- a/p3_frontend/tests/common/mod.rs +++ b/p3_frontend/tests/common/mod.rs @@ -11,6 +11,7 @@ use halo2_backend::{ Blake2bRead, Blake2bWrite, Challenge255, TranscriptReadBuffer, TranscriptWriterBuffer, }, }; +use halo2_debug::test_rng; use halo2_middleware::circuit::CompiledCircuit; use halo2_middleware::zal::impls::H2cEngine; use halo2curves::bn256::{Bn256, Fr, G1Affine}; @@ -20,24 +21,8 @@ use p3_frontend::{ CompileParams, FWrap, SymbolicAirBuilder, }; use p3_matrix::dense::RowMajorMatrix; -use rand_core::block::BlockRng; -use rand_core::block::BlockRngCore; use std::time::Instant; -// One number generator. Can be used as a deterministic Rng, outputing fixed values continuously. -pub(crate) struct OneNg {} - -impl BlockRngCore for OneNg { - type Item = u32; - type Results = [u32; 16]; - - fn generate(&mut self, results: &mut Self::Results) { - for elem in results.iter_mut() { - *elem = 1; - } - } -} - #[allow(clippy::type_complexity)] pub(crate) fn compile_witgen( air: A, @@ -76,7 +61,7 @@ pub(crate) fn setup_prove_verify( witness: Vec>>, ) { // Setup - let mut rng = BlockRng::new(OneNg {}); + let mut rng = test_rng(); let params = ParamsKZG::::setup(k, &mut rng); let verifier_params = params.verifier_params(); let start = Instant::now();