From 325bab113a735aac869902dd9fad26c1ae8e613e Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Wed, 12 Oct 2022 17:43:50 +0200 Subject: [PATCH 01/31] test --- plonky2/src/fri/mod.rs | 2 +- plonky2/src/plonk/circuit_builder.rs | 2 +- plonky2/src/plonk/circuit_data.rs | 2 +- plonky2/src/plonk/recursive_verifier.rs | 42 +++++++++++++++++++++++++ 4 files changed, 45 insertions(+), 3 deletions(-) diff --git a/plonky2/src/fri/mod.rs b/plonky2/src/fri/mod.rs index 87c4c2aa..d362420e 100644 --- a/plonky2/src/fri/mod.rs +++ b/plonky2/src/fri/mod.rs @@ -54,7 +54,7 @@ impl FriConfig { /// FRI parameters, including generated parameters which are specific to an instance size, in /// contrast to `FriConfig` which is user-specified and independent of instance size. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct FriParams { /// User-specified FRI configuration. pub config: FriConfig, diff --git a/plonky2/src/plonk/circuit_builder.rs b/plonky2/src/plonk/circuit_builder.rs index bfa012da..3a2cccb0 100644 --- a/plonky2/src/plonk/circuit_builder.rs +++ b/plonky2/src/plonk/circuit_builder.rs @@ -50,7 +50,7 @@ pub struct CircuitBuilder, const D: usize> { pub config: CircuitConfig, /// The types of gates used in this circuit. - gates: HashSet>, + pub(crate) gates: HashSet>, /// The concrete placement of each gate. pub(crate) gate_instances: Vec>, diff --git a/plonky2/src/plonk/circuit_data.rs b/plonky2/src/plonk/circuit_data.rs index 7e69ef31..879ed6d3 100644 --- a/plonky2/src/plonk/circuit_data.rs +++ b/plonky2/src/plonk/circuit_data.rs @@ -263,7 +263,7 @@ pub struct VerifierOnlyCircuitData, const D: usize> { } /// Circuit data required by both the prover and the verifier. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct CommonCircuitData< F: RichField + Extendable, C: GenericConfig, diff --git a/plonky2/src/plonk/recursive_verifier.rs b/plonky2/src/plonk/recursive_verifier.rs index ecce34e1..487373e3 100644 --- a/plonky2/src/plonk/recursive_verifier.rs +++ b/plonky2/src/plonk/recursive_verifier.rs @@ -445,4 +445,46 @@ mod tests { fn init_logger() { let _ = env_logger::builder().format_timestamp(None).try_init(); } + + #[test] + fn test_cyclic_recursion() -> Result<()> { + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + // type FF = >::FE; + + let config = CircuitConfig::standard_recursion_config(); + let (proof, vd, cd) = dummy_proof::(&config, 1 << 13)?; + + let (proof, vd, cd) = + recursive_proof::(proof, vd, cd, &config, None, false, false)?; + let (_proof, _vd, cd) = + recursive_proof::(proof, vd, cd, &config, None, false, false)?; + + let config = CircuitConfig::standard_recursion_config(); + let mut pw = PartialWitness::new(); + let mut builder = CircuitBuilder::::new(config); + + let verifier_data = VerifierCircuitTarget { + constants_sigmas_cap: builder.add_virtual_cap(builder.config.fri_config.cap_height), + }; + for i in 0..1 << builder.config.fri_config.cap_height { + builder.register_public_inputs(&verifier_data.constants_sigmas_cap.0[i].elements); + } + let pt = builder.add_virtual_proof_with_pis(&cd); + builder.verify_proof(pt, &verifier_data, &cd); + + let inner_gates = cd.gates.iter().map(|g| g.0.id()).collect::>(); + for gate in &builder.gates { + assert!(inner_gates.contains(&gate.0.id()), "{}", gate.0.id()); + } + for _ in builder.num_gates()..(1 << 13) - 100 { + builder.add_gate(NoopGate, vec![]); + } + let data = builder.build::(); + dbg!(data.common.degree_bits); + let proof = data.prove(pw)?; + + data.verify(proof) + } } From 66a0e7725101d43b21ccabc7e7374ca950ae6f4b Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 13 Oct 2022 14:28:08 +0200 Subject: [PATCH 02/31] Working in test --- plonky2/src/plonk/circuit_data.rs | 2 +- plonky2/src/plonk/recursive_verifier.rs | 179 ++++++++++++++++++++++-- 2 files changed, 167 insertions(+), 14 deletions(-) diff --git a/plonky2/src/plonk/circuit_data.rs b/plonky2/src/plonk/circuit_data.rs index 4a37f665..1a73d7b6 100644 --- a/plonky2/src/plonk/circuit_data.rs +++ b/plonky2/src/plonk/circuit_data.rs @@ -276,7 +276,7 @@ pub struct ProverOnlyCircuitData< } /// Circuit data required by the verifier, but not the prover. -#[derive(Debug)] +#[derive(Debug, Eq, PartialEq)] pub struct VerifierOnlyCircuitData, const D: usize> { /// A commitment to each constant polynomial and each permutation polynomial. pub constants_sigmas_cap: MerkleCap, diff --git a/plonky2/src/plonk/recursive_verifier.rs b/plonky2/src/plonk/recursive_verifier.rs index 373ed69e..29d89c92 100644 --- a/plonky2/src/plonk/recursive_verifier.rs +++ b/plonky2/src/plonk/recursive_verifier.rs @@ -464,37 +464,190 @@ mod tests { // type FF = >::FE; let config = CircuitConfig::standard_recursion_config(); - let (proof, vd, cd) = dummy_proof::(&config, 1 << 13)?; + let (proof, vd, cd) = dummy_proof::(&config, 1 << 14)?; let (proof, vd, cd) = recursive_proof::(proof, vd, cd, &config, None, false, false)?; - let (_proof, _vd, cd) = - recursive_proof::(proof, vd, cd, &config, None, false, false)?; + let (_proof, _vd, mut cd) = + recursive_proof::(proof, vd, cd, &config, Some(14), false, false)?; + cd.num_public_inputs = 69; + // First proof let config = CircuitConfig::standard_recursion_config(); let mut pw = PartialWitness::new(); let mut builder = CircuitBuilder::::new(config); let verifier_data = VerifierCircuitTarget { constants_sigmas_cap: builder.add_virtual_cap(builder.config.fri_config.cap_height), + circuit_digest: builder.add_virtual_hash(), }; + builder.register_public_inputs(&verifier_data.circuit_digest.elements); for i in 0..1 << builder.config.fri_config.cap_height { builder.register_public_inputs(&verifier_data.constants_sigmas_cap.0[i].elements); } - let pt = builder.add_virtual_proof_with_pis(&cd); - builder.verify_proof(pt, &verifier_data, &cd); + let dummy_verifier_data = VerifierCircuitTarget { + constants_sigmas_cap: builder.add_virtual_cap(builder.config.fri_config.cap_height), + circuit_digest: builder.add_virtual_hash(), + }; + let condition = builder.add_virtual_bool_target(); + builder.register_public_input(condition.target); + pw.set_bool_target(condition, false); - let inner_gates = cd.gates.iter().map(|g| g.0.id()).collect::>(); - for gate in &builder.gates { - assert!(inner_gates.contains(&gate.0.id()), "{}", gate.0.id()); - } - for _ in builder.num_gates()..(1 << 13) - 100 { + let (dummy_proof, dummy_data) = + crate::plonk::conditional_recursive_verifier::dummy_proof(&cd)?; + let pt0 = builder.add_virtual_proof_with_pis(&cd); + let pt1 = builder.add_virtual_proof_with_pis(&cd); + + pw.set_proof_with_pis_target(&pt0, &dummy_proof); + pw.set_proof_with_pis_target(&pt1, &dummy_proof); + pw.set_hash_target( + dummy_verifier_data.circuit_digest, + dummy_data.verifier_only.circuit_digest, + ); + pw.set_cap_target( + &dummy_verifier_data.constants_sigmas_cap, + &dummy_data.verifier_only.constants_sigmas_cap, + ); + + builder.conditionally_verify_proof( + condition, + pt0, + &verifier_data, + pt1, + &dummy_verifier_data, + &cd, + ); + + while builder.num_gates() < 1 << 13 { builder.add_gate(NoopGate, vec![]); } - let data = builder.build::(); - dbg!(data.common.degree_bits); - let proof = data.prove(pw)?; + let data = builder.build::(); + dbg!(cd.degree_bits); + dbg!(data.common.degree_bits); + assert_eq!(&data.common, &cd); + pw.set_verifier_data_target(&verifier_data, &data.verifier_only); + let proof = data.prove(pw)?; + assert_eq!( + data.verifier_only.circuit_digest.elements[0], + proof.public_inputs[0] + ); + data.verify(proof.clone())?; + + // Second proof + let config = CircuitConfig::standard_recursion_config(); + let mut pw = PartialWitness::new(); + let mut builder = CircuitBuilder::::new(config); + + let verifier_data = VerifierCircuitTarget { + constants_sigmas_cap: builder.add_virtual_cap(builder.config.fri_config.cap_height), + circuit_digest: builder.add_virtual_hash(), + }; + builder.register_public_inputs(&verifier_data.circuit_digest.elements); + for i in 0..1 << builder.config.fri_config.cap_height { + builder.register_public_inputs(&verifier_data.constants_sigmas_cap.0[i].elements); + } + let dummy_verifier_data = VerifierCircuitTarget { + constants_sigmas_cap: builder.add_virtual_cap(builder.config.fri_config.cap_height), + circuit_digest: builder.add_virtual_hash(), + }; + let condition = builder.add_virtual_bool_target(); + builder.register_public_input(condition.target); + pw.set_bool_target(condition, true); + + let pt0 = builder.add_virtual_proof_with_pis(&data.common); + let pt1 = builder.add_virtual_proof_with_pis(&data.common); + + pw.set_proof_with_pis_target(&pt0, &proof); + pw.set_proof_with_pis_target(&pt1, &proof); + + builder.conditionally_verify_proof( + condition, + pt0, + &verifier_data, + pt1, + &dummy_verifier_data, + &data.common, + ); + + while builder.num_gates() < 1 << 13 { + builder.add_gate(NoopGate, vec![]); + } + + let data1 = builder.build::(); + assert_eq!(data.common, data1.common); + assert_eq!(data.verifier_only, data1.verifier_only); + dbg!(cd.degree_bits); + dbg!(data1.common.degree_bits); + pw.set_verifier_data_target(&verifier_data, &data.verifier_only); + pw.set_verifier_data_target(&dummy_verifier_data, &data.verifier_only); + let proof = data.prove(pw)?; + assert_eq!( + data.verifier_only.circuit_digest.elements[0], + proof.public_inputs[0] + ); + assert_eq!( + data1.verifier_only.circuit_digest.elements[0], + proof.public_inputs[0] + ); + data.verify(proof.clone())?; + + // Second proof + let config = CircuitConfig::standard_recursion_config(); + let mut pw = PartialWitness::new(); + let mut builder = CircuitBuilder::::new(config); + + let verifier_data = VerifierCircuitTarget { + constants_sigmas_cap: builder.add_virtual_cap(builder.config.fri_config.cap_height), + circuit_digest: builder.add_virtual_hash(), + }; + builder.register_public_inputs(&verifier_data.circuit_digest.elements); + for i in 0..1 << builder.config.fri_config.cap_height { + builder.register_public_inputs(&verifier_data.constants_sigmas_cap.0[i].elements); + } + let dummy_verifier_data = VerifierCircuitTarget { + constants_sigmas_cap: builder.add_virtual_cap(builder.config.fri_config.cap_height), + circuit_digest: builder.add_virtual_hash(), + }; + let condition = builder.add_virtual_bool_target(); + builder.register_public_input(condition.target); + pw.set_bool_target(condition, true); + + let pt0 = builder.add_virtual_proof_with_pis(&data.common); + let pt1 = builder.add_virtual_proof_with_pis(&data.common); + + pw.set_proof_with_pis_target(&pt0, &proof); + pw.set_proof_with_pis_target(&pt1, &proof); + + builder.conditionally_verify_proof( + condition, + pt0, + &verifier_data, + pt1, + &dummy_verifier_data, + &data.common, + ); + + while builder.num_gates() < 1 << 13 { + builder.add_gate(NoopGate, vec![]); + } + + let data2 = builder.build::(); + assert_eq!(data.common, data2.common); + assert_eq!(data.verifier_only, data2.verifier_only); + dbg!(cd.degree_bits); + dbg!(data1.common.degree_bits); + pw.set_verifier_data_target(&verifier_data, &data.verifier_only); + pw.set_verifier_data_target(&dummy_verifier_data, &data.verifier_only); + let proof = data.prove(pw)?; + assert_eq!( + data.verifier_only.circuit_digest.elements[0], + proof.public_inputs[0] + ); + assert_eq!( + data1.verifier_only.circuit_digest.elements[0], + proof.public_inputs[0] + ); data.verify(proof) } } From 29e0aef376ed13e6fc7cda0b3b44b6ab87c9c2e8 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 13 Oct 2022 14:39:08 +0200 Subject: [PATCH 03/31] New recursion folder --- plonky2/src/lib.rs | 1 + plonky2/src/plonk/mod.rs | 2 -- .../src/{plonk => recursion}/conditional_recursive_verifier.rs | 0 plonky2/src/recursion/mod.rs | 2 ++ plonky2/src/{plonk => recursion}/recursive_verifier.rs | 2 +- 5 files changed, 4 insertions(+), 3 deletions(-) rename plonky2/src/{plonk => recursion}/conditional_recursive_verifier.rs (100%) create mode 100644 plonky2/src/recursion/mod.rs rename plonky2/src/{plonk => recursion}/recursive_verifier.rs (99%) diff --git a/plonky2/src/lib.rs b/plonky2/src/lib.rs index 64acfe12..8a517a11 100644 --- a/plonky2/src/lib.rs +++ b/plonky2/src/lib.rs @@ -18,4 +18,5 @@ pub mod gates; pub mod hash; pub mod iop; pub mod plonk; +pub mod recursion; pub mod util; diff --git a/plonky2/src/plonk/mod.rs b/plonky2/src/plonk/mod.rs index 8cd7443f..604c1f79 100644 --- a/plonky2/src/plonk/mod.rs +++ b/plonky2/src/plonk/mod.rs @@ -1,6 +1,5 @@ pub mod circuit_builder; pub mod circuit_data; -pub mod conditional_recursive_verifier; pub mod config; pub(crate) mod copy_constraint; mod get_challenges; @@ -8,7 +7,6 @@ pub(crate) mod permutation_argument; pub mod plonk_common; pub mod proof; pub mod prover; -pub mod recursive_verifier; mod validate_shape; pub(crate) mod vanishing_poly; pub mod vars; diff --git a/plonky2/src/plonk/conditional_recursive_verifier.rs b/plonky2/src/recursion/conditional_recursive_verifier.rs similarity index 100% rename from plonky2/src/plonk/conditional_recursive_verifier.rs rename to plonky2/src/recursion/conditional_recursive_verifier.rs diff --git a/plonky2/src/recursion/mod.rs b/plonky2/src/recursion/mod.rs new file mode 100644 index 00000000..b83c4a85 --- /dev/null +++ b/plonky2/src/recursion/mod.rs @@ -0,0 +1,2 @@ +pub mod conditional_recursive_verifier; +pub mod recursive_verifier; diff --git a/plonky2/src/plonk/recursive_verifier.rs b/plonky2/src/recursion/recursive_verifier.rs similarity index 99% rename from plonky2/src/plonk/recursive_verifier.rs rename to plonky2/src/recursion/recursive_verifier.rs index 29d89c92..c35f21e2 100644 --- a/plonky2/src/plonk/recursive_verifier.rs +++ b/plonky2/src/recursion/recursive_verifier.rs @@ -494,7 +494,7 @@ mod tests { pw.set_bool_target(condition, false); let (dummy_proof, dummy_data) = - crate::plonk::conditional_recursive_verifier::dummy_proof(&cd)?; + crate::recursion::conditional_recursive_verifier::dummy_proof(&cd)?; let pt0 = builder.add_virtual_proof_with_pis(&cd); let pt1 = builder.add_virtual_proof_with_pis(&cd); From f194553345f460d9faf27f9c08ade481be21ea46 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 13 Oct 2022 18:13:57 +0200 Subject: [PATCH 04/31] Test not working --- plonky2/src/plonk/circuit_builder.rs | 4 + .../conditional_recursive_verifier.rs | 124 +++++----- plonky2/src/recursion/cyclic_recursion.rs | 227 ++++++++++++++++++ plonky2/src/recursion/mod.rs | 1 + plonky2/src/recursion/recursive_verifier.rs | 195 --------------- 5 files changed, 294 insertions(+), 257 deletions(-) create mode 100644 plonky2/src/recursion/cyclic_recursion.rs diff --git a/plonky2/src/plonk/circuit_builder.rs b/plonky2/src/plonk/circuit_builder.rs index 16d42685..d5a748e5 100644 --- a/plonky2/src/plonk/circuit_builder.rs +++ b/plonky2/src/plonk/circuit_builder.rs @@ -144,6 +144,10 @@ impl, const D: usize> CircuitBuilder { targets.iter().for_each(|&t| self.register_public_input(t)); } + pub fn num_public_inputs(&self) -> usize { + self.public_inputs.len() + } + /// Adds a new "virtual" target. This is not an actual wire in the witness, but just a target /// that help facilitate witness generation. In particular, a generator can assign a values to a /// virtual target, which can then be copied to other (virtual or concrete) targets. When we diff --git a/plonky2/src/recursion/conditional_recursive_verifier.rs b/plonky2/src/recursion/conditional_recursive_verifier.rs index 8ac0a4f2..8f53046c 100644 --- a/plonky2/src/recursion/conditional_recursive_verifier.rs +++ b/plonky2/src/recursion/conditional_recursive_verifier.rs @@ -66,9 +66,9 @@ impl, const D: usize> CircuitBuilder { pub fn conditionally_verify_proof>( &mut self, condition: BoolTarget, - proof_with_pis0: ProofWithPublicInputsTarget, + proof_with_pis0: &ProofWithPublicInputsTarget, inner_verifier_data0: &VerifierCircuitTarget, - proof_with_pis1: ProofWithPublicInputsTarget, + proof_with_pis1: &ProofWithPublicInputsTarget, inner_verifier_data1: &VerifierCircuitTarget, inner_common_data: &CommonCircuitData, ) where @@ -124,8 +124,8 @@ impl, const D: usize> CircuitBuilder { let selected_verifier_data = VerifierCircuitTarget { constants_sigmas_cap: self.select_cap( condition, - inner_verifier_data0.constants_sigmas_cap.clone(), - inner_verifier_data1.constants_sigmas_cap.clone(), + &inner_verifier_data0.constants_sigmas_cap, + &inner_verifier_data1.constants_sigmas_cap, ), circuit_digest: self.select_hash( condition, @@ -137,10 +137,10 @@ impl, const D: usize> CircuitBuilder { self.verify_proof(selected_proof, &selected_verifier_data, inner_common_data); } - fn select_vec(&mut self, b: BoolTarget, v0: Vec, v1: Vec) -> Vec { - v0.into_iter() + fn select_vec(&mut self, b: BoolTarget, v0: &[Target], v1: &[Target]) -> Vec { + v0.iter() .zip_eq(v1) - .map(|(t0, t1)| self.select(b, t0, t1)) + .map(|(t0, t1)| self.select(b, *t0, *t1)) .collect() } @@ -158,15 +158,15 @@ impl, const D: usize> CircuitBuilder { fn select_cap( &mut self, b: BoolTarget, - cap0: MerkleCapTarget, - cap1: MerkleCapTarget, + cap0: &MerkleCapTarget, + cap1: &MerkleCapTarget, ) -> MerkleCapTarget { assert_eq!(cap0.0.len(), cap1.0.len()); MerkleCapTarget( cap0.0 - .into_iter() - .zip_eq(cap1.0) - .map(|(h0, h1)| self.select_hash(b, h0, h1)) + .iter() + .zip_eq(&cap1.0) + .map(|(h0, h1)| self.select_hash(b, *h0, *h1)) .collect(), ) } @@ -174,10 +174,10 @@ impl, const D: usize> CircuitBuilder { fn select_vec_cap( &mut self, b: BoolTarget, - v0: Vec, - v1: Vec, + v0: &[MerkleCapTarget], + v1: &[MerkleCapTarget], ) -> Vec { - v0.into_iter() + v0.iter() .zip_eq(v1) .map(|(c0, c1)| self.select_cap(b, c0, c1)) .collect() @@ -186,53 +186,53 @@ impl, const D: usize> CircuitBuilder { fn select_opening_set( &mut self, b: BoolTarget, - os0: OpeningSetTarget, - os1: OpeningSetTarget, + os0: &OpeningSetTarget, + os1: &OpeningSetTarget, ) -> OpeningSetTarget { OpeningSetTarget { - constants: self.select_vec_ext(b, os0.constants, os1.constants), - plonk_sigmas: self.select_vec_ext(b, os0.plonk_sigmas, os1.plonk_sigmas), - wires: self.select_vec_ext(b, os0.wires, os1.wires), - plonk_zs: self.select_vec_ext(b, os0.plonk_zs, os1.plonk_zs), - plonk_zs_next: self.select_vec_ext(b, os0.plonk_zs_next, os1.plonk_zs_next), - partial_products: self.select_vec_ext(b, os0.partial_products, os1.partial_products), - quotient_polys: self.select_vec_ext(b, os0.quotient_polys, os1.quotient_polys), + constants: self.select_vec_ext(b, &os0.constants, &os1.constants), + plonk_sigmas: self.select_vec_ext(b, &os0.plonk_sigmas, &os1.plonk_sigmas), + wires: self.select_vec_ext(b, &os0.wires, &os1.wires), + plonk_zs: self.select_vec_ext(b, &os0.plonk_zs, &os1.plonk_zs), + plonk_zs_next: self.select_vec_ext(b, &os0.plonk_zs_next, &os1.plonk_zs_next), + partial_products: self.select_vec_ext(b, &os0.partial_products, &os1.partial_products), + quotient_polys: self.select_vec_ext(b, &os0.quotient_polys, &os1.quotient_polys), } } fn select_vec_ext( &mut self, b: BoolTarget, - v0: Vec>, - v1: Vec>, + v0: &[ExtensionTarget], + v1: &[ExtensionTarget], ) -> Vec> { - v0.into_iter() + v0.iter() .zip_eq(v1) - .map(|(e0, e1)| self.select_ext(b, e0, e1)) + .map(|(e0, e1)| self.select_ext(b, *e0, *e1)) .collect() } fn select_opening_proof( &mut self, b: BoolTarget, - proof0: FriProofTarget, - proof1: FriProofTarget, + proof0: &FriProofTarget, + proof1: &FriProofTarget, ) -> FriProofTarget { FriProofTarget { commit_phase_merkle_caps: self.select_vec_cap( b, - proof0.commit_phase_merkle_caps, - proof1.commit_phase_merkle_caps, + &proof0.commit_phase_merkle_caps, + &proof1.commit_phase_merkle_caps, ), query_round_proofs: self.select_vec_query_round( b, - proof0.query_round_proofs, - proof1.query_round_proofs, + &proof0.query_round_proofs, + &proof1.query_round_proofs, ), final_poly: PolynomialCoeffsExtTarget(self.select_vec_ext( b, - proof0.final_poly.0, - proof1.final_poly.0, + &proof0.final_poly.0, + &proof1.final_poly.0, )), pow_witness: self.select(b, proof0.pow_witness, proof1.pow_witness), } @@ -241,26 +241,26 @@ impl, const D: usize> CircuitBuilder { fn select_query_round( &mut self, b: BoolTarget, - qr0: FriQueryRoundTarget, - qr1: FriQueryRoundTarget, + qr0: &FriQueryRoundTarget, + qr1: &FriQueryRoundTarget, ) -> FriQueryRoundTarget { FriQueryRoundTarget { initial_trees_proof: self.select_initial_tree_proof( b, - qr0.initial_trees_proof, - qr1.initial_trees_proof, + &qr0.initial_trees_proof, + &qr1.initial_trees_proof, ), - steps: self.select_vec_query_step(b, qr0.steps, qr1.steps), + steps: self.select_vec_query_step(b, &qr0.steps, &qr1.steps), } } fn select_vec_query_round( &mut self, b: BoolTarget, - v0: Vec>, - v1: Vec>, + v0: &[FriQueryRoundTarget], + v1: &[FriQueryRoundTarget], ) -> Vec> { - v0.into_iter() + v0.iter() .zip_eq(v1) .map(|(qr0, qr1)| self.select_query_round(b, qr0, qr1)) .collect() @@ -269,14 +269,14 @@ impl, const D: usize> CircuitBuilder { fn select_initial_tree_proof( &mut self, b: BoolTarget, - proof0: FriInitialTreeProofTarget, - proof1: FriInitialTreeProofTarget, + proof0: &FriInitialTreeProofTarget, + proof1: &FriInitialTreeProofTarget, ) -> FriInitialTreeProofTarget { FriInitialTreeProofTarget { evals_proofs: proof0 .evals_proofs - .into_iter() - .zip_eq(proof1.evals_proofs) + .iter() + .zip_eq(&proof1.evals_proofs) .map(|((v0, p0), (v1, p1))| { ( self.select_vec(b, v0, v1), @@ -290,15 +290,15 @@ impl, const D: usize> CircuitBuilder { fn select_merkle_proof( &mut self, b: BoolTarget, - proof0: MerkleProofTarget, - proof1: MerkleProofTarget, + proof0: &MerkleProofTarget, + proof1: &MerkleProofTarget, ) -> MerkleProofTarget { MerkleProofTarget { siblings: proof0 .siblings - .into_iter() - .zip_eq(proof1.siblings) - .map(|(h0, h1)| self.select_hash(b, h0, h1)) + .iter() + .zip_eq(&proof1.siblings) + .map(|(h0, h1)| self.select_hash(b, *h0, *h1)) .collect(), } } @@ -306,22 +306,22 @@ impl, const D: usize> CircuitBuilder { fn select_query_step( &mut self, b: BoolTarget, - qs0: FriQueryStepTarget, - qs1: FriQueryStepTarget, + qs0: &FriQueryStepTarget, + qs1: &FriQueryStepTarget, ) -> FriQueryStepTarget { FriQueryStepTarget { - evals: self.select_vec_ext(b, qs0.evals, qs1.evals), - merkle_proof: self.select_merkle_proof(b, qs0.merkle_proof, qs1.merkle_proof), + evals: self.select_vec_ext(b, &qs0.evals, &qs1.evals), + merkle_proof: self.select_merkle_proof(b, &qs0.merkle_proof, &qs1.merkle_proof), } } fn select_vec_query_step( &mut self, b: BoolTarget, - v0: Vec>, - v1: Vec>, + v0: &[FriQueryStepTarget], + v1: &[FriQueryStepTarget], ) -> Vec> { - v0.into_iter() + v0.iter() .zip_eq(v1) .map(|(qs0, qs1)| self.select_query_step(b, qs0, qs1)) .collect() @@ -384,9 +384,9 @@ mod tests { let b = builder.constant_bool(F::rand().0 % 2 == 0); builder.conditionally_verify_proof( b, - pt, + &pt, &inner_data, - dummy_pt, + &dummy_pt, &dummy_inner_data, &data.common, ); diff --git a/plonky2/src/recursion/cyclic_recursion.rs b/plonky2/src/recursion/cyclic_recursion.rs new file mode 100644 index 00000000..d39bfcf7 --- /dev/null +++ b/plonky2/src/recursion/cyclic_recursion.rs @@ -0,0 +1,227 @@ +use anyhow::Result; +use plonky2_field::extension::Extendable; + +use crate::gates::noop::NoopGate; +use crate::hash::hash_types::RichField; +use crate::iop::target::BoolTarget; +use crate::iop::witness::{PartialWitness, Witness}; +use crate::plonk::circuit_builder::CircuitBuilder; +use crate::plonk::circuit_data::{ + CircuitData, CommonCircuitData, VerifierCircuitTarget, VerifierOnlyCircuitData, +}; +use crate::plonk::config::Hasher; +use crate::plonk::config::{AlgebraicHasher, GenericConfig}; +use crate::plonk::proof::{ProofWithPublicInputs, ProofWithPublicInputsTarget}; +use crate::recursion::conditional_recursive_verifier::dummy_proof; + +pub struct CyclicRecursionData< + 'a, + F: RichField + Extendable, + C: GenericConfig, + const D: usize, +> { + proof: &'a Option>, + verifier_data: &'a VerifierOnlyCircuitData, + common_data: &'a CommonCircuitData, +} + +pub struct CyclicRecursionTarget { + pub proof: ProofWithPublicInputsTarget, + pub verifier_data: VerifierCircuitTarget, + pub dummy_proof: ProofWithPublicInputsTarget, + pub dummy_verifier_data: VerifierCircuitTarget, + pub base_case: BoolTarget, +} + +impl, const D: usize> CircuitBuilder { + pub fn cyclic_recursion>( + mut self, + mut common_data: CommonCircuitData, + ) -> Result<(CircuitData, CyclicRecursionTarget)> + where + C::Hasher: AlgebraicHasher, + [(); C::Hasher::HASH_SIZE]:, + { + let verifier_data = VerifierCircuitTarget { + constants_sigmas_cap: self.add_virtual_cap(self.config.fri_config.cap_height), + circuit_digest: self.add_virtual_hash(), + }; + self.register_public_inputs(&verifier_data.circuit_digest.elements); + for i in 0..self.config.fri_config.num_cap_elements() { + self.register_public_inputs(&verifier_data.constants_sigmas_cap.0[i].elements); + } + let dummy_verifier_data = VerifierCircuitTarget { + constants_sigmas_cap: self.add_virtual_cap(self.config.fri_config.cap_height), + circuit_digest: self.add_virtual_hash(), + }; + let base_case = self.add_virtual_bool_target(); + self.register_public_input(base_case.target); + + common_data.num_public_inputs = self.num_public_inputs(); + common_data.degree_bits = common_data.degree_bits.max(13); + dbg!(common_data.degree_bits); + + let proof = self.add_virtual_proof_with_pis(&common_data); + let dummy_proof = self.add_virtual_proof_with_pis(&common_data); + + self.conditionally_verify_proof( + base_case, + &dummy_proof, + &dummy_verifier_data, + &proof, + &verifier_data, + &common_data, + ); + + while self.num_gates() < 1 << (common_data.degree_bits - 1) { + self.add_gate(NoopGate, vec![]); + } + + let data = self.build::(); + dbg!(&data.common.degree_bits, common_data.degree_bits); + assert_eq!(&data.common, &common_data); + Ok(( + data, + CyclicRecursionTarget { + proof, + verifier_data, + dummy_proof, + dummy_verifier_data, + base_case, + }, + )) + } +} + +/// Set the targets in a `ProofTarget` to their corresponding values in a `Proof`. +pub fn set_cyclic_recursion_data_target< + F: RichField + Extendable, + C: GenericConfig, + const D: usize, +>( + pw: &mut PartialWitness, + cyclic_recursion_data_target: &CyclicRecursionTarget, + cyclic_recursion_data: &CyclicRecursionData, +) -> Result<()> +where + F: RichField + Extendable, + C::Hasher: AlgebraicHasher, + [(); C::Hasher::HASH_SIZE]:, +{ + if let Some(proof) = cyclic_recursion_data.proof { + pw.set_bool_target(cyclic_recursion_data_target.base_case, false); + pw.set_proof_with_pis_target(&cyclic_recursion_data_target.proof, proof); + pw.set_verifier_data_target( + &cyclic_recursion_data_target.verifier_data, + cyclic_recursion_data.verifier_data, + ); + pw.set_proof_with_pis_target(&cyclic_recursion_data_target.dummy_proof, proof); + pw.set_verifier_data_target( + &cyclic_recursion_data_target.dummy_verifier_data, + cyclic_recursion_data.verifier_data, + ); + } else { + let (dummy_proof, dummy_data) = dummy_proof(cyclic_recursion_data.common_data)?; + pw.set_bool_target(cyclic_recursion_data_target.base_case, true); + pw.set_proof_with_pis_target(&cyclic_recursion_data_target.proof, &dummy_proof); + pw.set_verifier_data_target( + &cyclic_recursion_data_target.verifier_data, + &dummy_data.verifier_only, + ); + pw.set_proof_with_pis_target(&cyclic_recursion_data_target.dummy_proof, &dummy_proof); + pw.set_verifier_data_target( + &cyclic_recursion_data_target.dummy_verifier_data, + &dummy_data.verifier_only, + ); + } + + Ok(()) +} + +#[cfg(test)] +mod tests { + use anyhow::Result; + use plonky2_field::extension::Extendable; + + use crate::field::types::Field; + use crate::hash::hash_types::RichField; + use crate::hash::poseidon::PoseidonHash; + use crate::iop::witness::{PartialWitness, Witness}; + use crate::plonk::circuit_builder::CircuitBuilder; + use crate::plonk::circuit_data::{CircuitConfig, CommonCircuitData, VerifierCircuitTarget}; + use crate::plonk::config::{AlgebraicHasher, GenericConfig, Hasher, PoseidonGoldilocksConfig}; + use crate::recursion::cyclic_recursion::{ + set_cyclic_recursion_data_target, CyclicRecursionData, + }; + + fn common_data_for_recursion< + F: RichField + Extendable, + C: GenericConfig, + const D: usize, + >() -> CommonCircuitData + where + C::Hasher: AlgebraicHasher, + [(); C::Hasher::HASH_SIZE]:, + { + let config = CircuitConfig::standard_recursion_config(); + let mut builder = CircuitBuilder::::new(config); + let data = builder.build::(); + let config = CircuitConfig::standard_recursion_config(); + let mut pw = PartialWitness::::new(); + let mut builder = CircuitBuilder::::new(config); + let proof = builder.add_virtual_proof_with_pis(&data.common); + let verifier_data = VerifierCircuitTarget { + constants_sigmas_cap: builder.add_virtual_cap(data.common.config.fri_config.cap_height), + circuit_digest: builder.add_virtual_hash(), + }; + builder.verify_proof(proof, &verifier_data, &data.common); + let data = builder.build::(); + + let config = CircuitConfig::standard_recursion_config(); + let mut builder = CircuitBuilder::::new(config); + let data = builder.build::(); + let config = CircuitConfig::standard_recursion_config(); + let mut pw = PartialWitness::::new(); + let mut builder = CircuitBuilder::::new(config); + let proof = builder.add_virtual_proof_with_pis(&data.common); + let verifier_data = VerifierCircuitTarget { + constants_sigmas_cap: builder.add_virtual_cap(data.common.config.fri_config.cap_height), + circuit_digest: builder.add_virtual_hash(), + }; + builder.verify_proof(proof, &verifier_data, &data.common); + builder.build::().common + } + + #[test] + fn test_cyclic_recursion() -> Result<()> { + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + + let config = CircuitConfig::standard_recursion_config(); + let mut pw = PartialWitness::new(); + let mut builder = CircuitBuilder::::new(config); + + // Build realistic circuit + let t = builder.add_virtual_target(); + pw.set_target(t, F::rand()); + let t_inv = builder.inverse(t); + let h = builder.hash_n_to_hash_no_pad::(vec![t_inv]); + builder.register_public_inputs(&h.elements); + + let common_data = common_data_for_recursion::(); + dbg!(common_data.degree_bits); + + let (cyclic_circuit_data, cyclic_data_target) = builder.cyclic_recursion(common_data)?; + let cyclic_recursion_data = CyclicRecursionData { + proof: &None, + verifier_data: &cyclic_circuit_data.verifier_only, + common_data: &cyclic_circuit_data.common, + }; + set_cyclic_recursion_data_target(&mut pw, &cyclic_data_target, &cyclic_recursion_data)?; + let proof = cyclic_circuit_data.prove(pw)?; + cyclic_circuit_data.verify(proof); + + Ok(()) + } +} diff --git a/plonky2/src/recursion/mod.rs b/plonky2/src/recursion/mod.rs index b83c4a85..33e8212e 100644 --- a/plonky2/src/recursion/mod.rs +++ b/plonky2/src/recursion/mod.rs @@ -1,2 +1,3 @@ pub mod conditional_recursive_verifier; +pub mod cyclic_recursion; pub mod recursive_verifier; diff --git a/plonky2/src/recursion/recursive_verifier.rs b/plonky2/src/recursion/recursive_verifier.rs index c35f21e2..7d901236 100644 --- a/plonky2/src/recursion/recursive_verifier.rs +++ b/plonky2/src/recursion/recursive_verifier.rs @@ -455,199 +455,4 @@ mod tests { fn init_logger() { let _ = env_logger::builder().format_timestamp(None).try_init(); } - - #[test] - fn test_cyclic_recursion() -> Result<()> { - const D: usize = 2; - type C = PoseidonGoldilocksConfig; - type F = >::F; - // type FF = >::FE; - - let config = CircuitConfig::standard_recursion_config(); - let (proof, vd, cd) = dummy_proof::(&config, 1 << 14)?; - - let (proof, vd, cd) = - recursive_proof::(proof, vd, cd, &config, None, false, false)?; - let (_proof, _vd, mut cd) = - recursive_proof::(proof, vd, cd, &config, Some(14), false, false)?; - cd.num_public_inputs = 69; - - // First proof - let config = CircuitConfig::standard_recursion_config(); - let mut pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); - - let verifier_data = VerifierCircuitTarget { - constants_sigmas_cap: builder.add_virtual_cap(builder.config.fri_config.cap_height), - circuit_digest: builder.add_virtual_hash(), - }; - builder.register_public_inputs(&verifier_data.circuit_digest.elements); - for i in 0..1 << builder.config.fri_config.cap_height { - builder.register_public_inputs(&verifier_data.constants_sigmas_cap.0[i].elements); - } - let dummy_verifier_data = VerifierCircuitTarget { - constants_sigmas_cap: builder.add_virtual_cap(builder.config.fri_config.cap_height), - circuit_digest: builder.add_virtual_hash(), - }; - let condition = builder.add_virtual_bool_target(); - builder.register_public_input(condition.target); - pw.set_bool_target(condition, false); - - let (dummy_proof, dummy_data) = - crate::recursion::conditional_recursive_verifier::dummy_proof(&cd)?; - let pt0 = builder.add_virtual_proof_with_pis(&cd); - let pt1 = builder.add_virtual_proof_with_pis(&cd); - - pw.set_proof_with_pis_target(&pt0, &dummy_proof); - pw.set_proof_with_pis_target(&pt1, &dummy_proof); - pw.set_hash_target( - dummy_verifier_data.circuit_digest, - dummy_data.verifier_only.circuit_digest, - ); - pw.set_cap_target( - &dummy_verifier_data.constants_sigmas_cap, - &dummy_data.verifier_only.constants_sigmas_cap, - ); - - builder.conditionally_verify_proof( - condition, - pt0, - &verifier_data, - pt1, - &dummy_verifier_data, - &cd, - ); - - while builder.num_gates() < 1 << 13 { - builder.add_gate(NoopGate, vec![]); - } - - let data = builder.build::(); - dbg!(cd.degree_bits); - dbg!(data.common.degree_bits); - assert_eq!(&data.common, &cd); - pw.set_verifier_data_target(&verifier_data, &data.verifier_only); - let proof = data.prove(pw)?; - assert_eq!( - data.verifier_only.circuit_digest.elements[0], - proof.public_inputs[0] - ); - data.verify(proof.clone())?; - - // Second proof - let config = CircuitConfig::standard_recursion_config(); - let mut pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); - - let verifier_data = VerifierCircuitTarget { - constants_sigmas_cap: builder.add_virtual_cap(builder.config.fri_config.cap_height), - circuit_digest: builder.add_virtual_hash(), - }; - builder.register_public_inputs(&verifier_data.circuit_digest.elements); - for i in 0..1 << builder.config.fri_config.cap_height { - builder.register_public_inputs(&verifier_data.constants_sigmas_cap.0[i].elements); - } - let dummy_verifier_data = VerifierCircuitTarget { - constants_sigmas_cap: builder.add_virtual_cap(builder.config.fri_config.cap_height), - circuit_digest: builder.add_virtual_hash(), - }; - let condition = builder.add_virtual_bool_target(); - builder.register_public_input(condition.target); - pw.set_bool_target(condition, true); - - let pt0 = builder.add_virtual_proof_with_pis(&data.common); - let pt1 = builder.add_virtual_proof_with_pis(&data.common); - - pw.set_proof_with_pis_target(&pt0, &proof); - pw.set_proof_with_pis_target(&pt1, &proof); - - builder.conditionally_verify_proof( - condition, - pt0, - &verifier_data, - pt1, - &dummy_verifier_data, - &data.common, - ); - - while builder.num_gates() < 1 << 13 { - builder.add_gate(NoopGate, vec![]); - } - - let data1 = builder.build::(); - assert_eq!(data.common, data1.common); - assert_eq!(data.verifier_only, data1.verifier_only); - dbg!(cd.degree_bits); - dbg!(data1.common.degree_bits); - pw.set_verifier_data_target(&verifier_data, &data.verifier_only); - pw.set_verifier_data_target(&dummy_verifier_data, &data.verifier_only); - let proof = data.prove(pw)?; - assert_eq!( - data.verifier_only.circuit_digest.elements[0], - proof.public_inputs[0] - ); - assert_eq!( - data1.verifier_only.circuit_digest.elements[0], - proof.public_inputs[0] - ); - data.verify(proof.clone())?; - - // Second proof - let config = CircuitConfig::standard_recursion_config(); - let mut pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); - - let verifier_data = VerifierCircuitTarget { - constants_sigmas_cap: builder.add_virtual_cap(builder.config.fri_config.cap_height), - circuit_digest: builder.add_virtual_hash(), - }; - builder.register_public_inputs(&verifier_data.circuit_digest.elements); - for i in 0..1 << builder.config.fri_config.cap_height { - builder.register_public_inputs(&verifier_data.constants_sigmas_cap.0[i].elements); - } - let dummy_verifier_data = VerifierCircuitTarget { - constants_sigmas_cap: builder.add_virtual_cap(builder.config.fri_config.cap_height), - circuit_digest: builder.add_virtual_hash(), - }; - let condition = builder.add_virtual_bool_target(); - builder.register_public_input(condition.target); - pw.set_bool_target(condition, true); - - let pt0 = builder.add_virtual_proof_with_pis(&data.common); - let pt1 = builder.add_virtual_proof_with_pis(&data.common); - - pw.set_proof_with_pis_target(&pt0, &proof); - pw.set_proof_with_pis_target(&pt1, &proof); - - builder.conditionally_verify_proof( - condition, - pt0, - &verifier_data, - pt1, - &dummy_verifier_data, - &data.common, - ); - - while builder.num_gates() < 1 << 13 { - builder.add_gate(NoopGate, vec![]); - } - - let data2 = builder.build::(); - assert_eq!(data.common, data2.common); - assert_eq!(data.verifier_only, data2.verifier_only); - dbg!(cd.degree_bits); - dbg!(data1.common.degree_bits); - pw.set_verifier_data_target(&verifier_data, &data.verifier_only); - pw.set_verifier_data_target(&dummy_verifier_data, &data.verifier_only); - let proof = data.prove(pw)?; - assert_eq!( - data.verifier_only.circuit_digest.elements[0], - proof.public_inputs[0] - ); - assert_eq!( - data1.verifier_only.circuit_digest.elements[0], - proof.public_inputs[0] - ); - data.verify(proof) - } } From 861b66a34a9aa89c305881f623293f3427724cc1 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 14 Oct 2022 10:32:40 +0200 Subject: [PATCH 05/31] Test passes for base proof --- plonky2/src/recursion/cyclic_recursion.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/plonky2/src/recursion/cyclic_recursion.rs b/plonky2/src/recursion/cyclic_recursion.rs index d39bfcf7..0a3308e6 100644 --- a/plonky2/src/recursion/cyclic_recursion.rs +++ b/plonky2/src/recursion/cyclic_recursion.rs @@ -59,7 +59,7 @@ impl, const D: usize> CircuitBuilder { common_data.num_public_inputs = self.num_public_inputs(); common_data.degree_bits = common_data.degree_bits.max(13); - dbg!(common_data.degree_bits); + common_data.fri_params.degree_bits = common_data.fri_params.degree_bits.max(13); let proof = self.add_virtual_proof_with_pis(&common_data); let dummy_proof = self.add_virtual_proof_with_pis(&common_data); @@ -76,10 +76,13 @@ impl, const D: usize> CircuitBuilder { while self.num_gates() < 1 << (common_data.degree_bits - 1) { self.add_gate(NoopGate, vec![]); } + for g in &common_data.gates { + self.add_gate_to_gate_set(g.clone()); + } let data = self.build::(); - dbg!(&data.common.degree_bits, common_data.degree_bits); assert_eq!(&data.common, &common_data); + Ok(( data, CyclicRecursionTarget { @@ -179,7 +182,6 @@ mod tests { let config = CircuitConfig::standard_recursion_config(); let mut builder = CircuitBuilder::::new(config); - let data = builder.build::(); let config = CircuitConfig::standard_recursion_config(); let mut pw = PartialWitness::::new(); let mut builder = CircuitBuilder::::new(config); @@ -210,7 +212,6 @@ mod tests { builder.register_public_inputs(&h.elements); let common_data = common_data_for_recursion::(); - dbg!(common_data.degree_bits); let (cyclic_circuit_data, cyclic_data_target) = builder.cyclic_recursion(common_data)?; let cyclic_recursion_data = CyclicRecursionData { From fce7a4797ad400b0e86130afde2fa11850af537f Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 14 Oct 2022 14:59:59 +0200 Subject: [PATCH 06/31] Working --- ecdsa/src/gadgets/glv.rs | 4 +- ecdsa/src/gadgets/nonnative.rs | 4 +- plonky2/src/gadgets/arithmetic.rs | 2 +- plonky2/src/plonk/circuit_builder.rs | 3 +- plonky2/src/recursion/cyclic_recursion.rs | 195 ++++++++++++++++++++-- 5 files changed, 191 insertions(+), 17 deletions(-) diff --git a/ecdsa/src/gadgets/glv.rs b/ecdsa/src/gadgets/glv.rs index 4302023e..539b5de3 100644 --- a/ecdsa/src/gadgets/glv.rs +++ b/ecdsa/src/gadgets/glv.rs @@ -55,8 +55,8 @@ impl, const D: usize> CircuitBuilderGlv ) { let k1 = self.add_virtual_nonnative_target_sized::(4); let k2 = self.add_virtual_nonnative_target_sized::(4); - let k1_neg = self.add_virtual_bool_target(); - let k2_neg = self.add_virtual_bool_target(); + let k1_neg = self.add_virtual_bool_target_unsafe(); + let k2_neg = self.add_virtual_bool_target_unsafe(); self.add_simple_generator(GLVDecompositionGenerator:: { k: k.clone(), diff --git a/ecdsa/src/gadgets/nonnative.rs b/ecdsa/src/gadgets/nonnative.rs index c6ff4753..29520bed 100644 --- a/ecdsa/src/gadgets/nonnative.rs +++ b/ecdsa/src/gadgets/nonnative.rs @@ -183,7 +183,7 @@ impl, const D: usize> CircuitBuilderNonNative b: &NonNativeTarget, ) -> NonNativeTarget { let sum = self.add_virtual_nonnative_target::(); - let overflow = self.add_virtual_bool_target(); + let overflow = self.add_virtual_bool_target_unsafe(); self.add_simple_generator(NonNativeAdditionGenerator:: { a: a.clone(), @@ -282,7 +282,7 @@ impl, const D: usize> CircuitBuilderNonNative b: &NonNativeTarget, ) -> NonNativeTarget { let diff = self.add_virtual_nonnative_target::(); - let overflow = self.add_virtual_bool_target(); + let overflow = self.add_virtual_bool_target_unsafe(); self.add_simple_generator(NonNativeSubtractionGenerator:: { a: a.clone(), diff --git a/plonky2/src/gadgets/arithmetic.rs b/plonky2/src/gadgets/arithmetic.rs index f4722df4..33facd74 100644 --- a/plonky2/src/gadgets/arithmetic.rs +++ b/plonky2/src/gadgets/arithmetic.rs @@ -345,7 +345,7 @@ impl, const D: usize> CircuitBuilder { pub fn is_equal(&mut self, x: Target, y: Target) -> BoolTarget { let zero = self.zero(); - let equal = self.add_virtual_bool_target(); + let equal = self.add_virtual_bool_target_unsafe(); let not_equal = self.not(equal); let inv = self.add_virtual_target(); self.add_simple_generator(EqualityGenerator { x, y, equal, inv }); diff --git a/plonky2/src/plonk/circuit_builder.rs b/plonky2/src/plonk/circuit_builder.rs index d5a748e5..24e83d01 100644 --- a/plonky2/src/plonk/circuit_builder.rs +++ b/plonky2/src/plonk/circuit_builder.rs @@ -202,8 +202,7 @@ impl, const D: usize> CircuitBuilder { PolynomialCoeffsExtTarget(coeffs) } - // TODO: Unsafe - pub fn add_virtual_bool_target(&mut self) -> BoolTarget { + pub fn add_virtual_bool_target_unsafe(&mut self) -> BoolTarget { BoolTarget::new_unsafe(self.add_virtual_target()) } diff --git a/plonky2/src/recursion/cyclic_recursion.rs b/plonky2/src/recursion/cyclic_recursion.rs index 0a3308e6..abf7f7a2 100644 --- a/plonky2/src/recursion/cyclic_recursion.rs +++ b/plonky2/src/recursion/cyclic_recursion.rs @@ -1,9 +1,12 @@ -use anyhow::Result; +use anyhow::{ensure, Result}; +use itertools::Itertools; use plonky2_field::extension::Extendable; +use plonky2_field::types::Field; use crate::gates::noop::NoopGate; -use crate::hash::hash_types::RichField; -use crate::iop::target::BoolTarget; +use crate::hash::hash_types::{HashOut, HashOutTarget, MerkleCapTarget, RichField}; +use crate::hash::merkle_tree::MerkleCap; +use crate::iop::target::{BoolTarget, Target}; use crate::iop::witness::{PartialWitness, Witness}; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_data::{ @@ -33,6 +36,85 @@ pub struct CyclicRecursionTarget { pub base_case: BoolTarget, } +pub struct CyclicPublicInputs< + F: RichField + Extendable, + C: GenericConfig, + const D: usize, +> { + pub circuit_digest: HashOut, + pub constants_sigmas_cap: MerkleCap, + pub base_case: bool, +} + +impl, C: GenericConfig, const D: usize> + CyclicPublicInputs +{ + fn from_slice(slice: &[F], common_data: &CommonCircuitData) -> Result + where + C::Hasher: AlgebraicHasher, + { + // The structure of the public inputs is `[...,circuit_digest, constants_sigmas_cap, base_case]`. + let cap_len = common_data.config.fri_config.num_cap_elements(); + let len = slice.len(); + ensure!(len >= 4 + 4 * cap_len + 1, "Not enough public inputs"); + let base_case = slice[len - 1]; + ensure!( + base_case.is_one() || base_case.is_zero(), + "Base case flag {:?} is not binary", + base_case + ); + let constants_sigmas_cap = MerkleCap( + (0..cap_len) + .map(|i| HashOut { + elements: std::array::from_fn(|j| slice[len - 1 - 4 * (cap_len - i) + j]), + }) + .collect(), + ); + let circuit_digest = + HashOut::from_partial(&slice[len - 5 - 4 * cap_len..len - 1 - 4 * cap_len]); + + Ok(Self { + circuit_digest, + constants_sigmas_cap, + base_case: base_case.is_one(), + }) + } +} + +pub struct CyclicPublicInputsTarget { + pub circuit_digest: HashOutTarget, + pub constants_sigmas_cap: MerkleCapTarget, + pub base_case: Target, +} + +impl CyclicPublicInputsTarget { + fn from_slice, C: GenericConfig, const D: usize>( + slice: &[Target], + common_data: &CommonCircuitData, + ) -> Result { + let cap_len = common_data.config.fri_config.num_cap_elements(); + let len = slice.len(); + ensure!(len >= 4 + 4 * cap_len + 1, "Not enough public inputs"); + let base_case = slice[len - 1]; + let constants_sigmas_cap = MerkleCapTarget( + (0..cap_len) + .map(|i| HashOutTarget { + elements: std::array::from_fn(|j| slice[len - 1 - 4 * (cap_len - i) + j]), + }) + .collect(), + ); + let circuit_digest = HashOutTarget { + elements: std::array::from_fn(|i| slice[len - 5 - 4 * cap_len + i]), + }; + + Ok(Self { + circuit_digest, + constants_sigmas_cap, + base_case, + }) + } +} + impl, const D: usize> CircuitBuilder { pub fn cyclic_recursion>( mut self, @@ -46,24 +128,39 @@ impl, const D: usize> CircuitBuilder { constants_sigmas_cap: self.add_virtual_cap(self.config.fri_config.cap_height), circuit_digest: self.add_virtual_hash(), }; + // The verifier data are public inputs. self.register_public_inputs(&verifier_data.circuit_digest.elements); for i in 0..self.config.fri_config.num_cap_elements() { self.register_public_inputs(&verifier_data.constants_sigmas_cap.0[i].elements); } + let dummy_verifier_data = VerifierCircuitTarget { constants_sigmas_cap: self.add_virtual_cap(self.config.fri_config.cap_height), circuit_digest: self.add_virtual_hash(), }; - let base_case = self.add_virtual_bool_target(); + // Unsafe is ok since `base_case` is a public input and its booleaness should be checked in the verifier. + let base_case = self.add_virtual_bool_target_unsafe(); self.register_public_input(base_case.target); common_data.num_public_inputs = self.num_public_inputs(); + // The `conditionally_verify_proof` gadget below takes 2^12 gates, so `degree_bits` cannot be smaller than 13. common_data.degree_bits = common_data.degree_bits.max(13); common_data.fri_params.degree_bits = common_data.fri_params.degree_bits.max(13); let proof = self.add_virtual_proof_with_pis(&common_data); let dummy_proof = self.add_virtual_proof_with_pis(&common_data); + let pis = CyclicPublicInputsTarget::from_slice(&proof.public_inputs, &common_data)?; + self.connect_hashes(pis.circuit_digest, verifier_data.circuit_digest); + for (h0, h1) in pis + .constants_sigmas_cap + .0 + .iter() + .zip_eq(&verifier_data.constants_sigmas_cap.0) + { + self.connect_hashes(*h0, *h1); + } + self.conditionally_verify_proof( base_case, &dummy_proof, @@ -107,7 +204,6 @@ pub fn set_cyclic_recursion_data_target< cyclic_recursion_data: &CyclicRecursionData, ) -> Result<()> where - F: RichField + Extendable, C::Hasher: AlgebraicHasher, [(); C::Hasher::HASH_SIZE]:, { @@ -124,12 +220,29 @@ where cyclic_recursion_data.verifier_data, ); } else { + dbg!("hi"); let (dummy_proof, dummy_data) = dummy_proof(cyclic_recursion_data.common_data)?; pw.set_bool_target(cyclic_recursion_data_target.base_case, true); - pw.set_proof_with_pis_target(&cyclic_recursion_data_target.proof, &dummy_proof); + let mut dummy_proof_real_vd = dummy_proof.clone(); + let pis_len = dummy_proof_real_vd.public_inputs.len(); + let num_cap = cyclic_recursion_data + .common_data + .config + .fri_config + .num_cap_elements(); + let s = pis_len - 5 - 4 * num_cap; + dummy_proof_real_vd.public_inputs[s..s + 4] + .copy_from_slice(&cyclic_recursion_data.verifier_data.circuit_digest.elements); + for i in 0..num_cap { + dummy_proof_real_vd.public_inputs[s + 4 * (1 + i)..s + 4 * (2 + i)].copy_from_slice( + &cyclic_recursion_data.verifier_data.constants_sigmas_cap.0[i].elements, + ); + } + pw.set_proof_with_pis_target(&cyclic_recursion_data_target.proof, &dummy_proof_real_vd); + dbg!(cyclic_recursion_data.verifier_data.circuit_digest); pw.set_verifier_data_target( &cyclic_recursion_data_target.verifier_data, - &dummy_data.verifier_only, + cyclic_recursion_data.verifier_data, ); pw.set_proof_with_pis_target(&cyclic_recursion_data_target.dummy_proof, &dummy_proof); pw.set_verifier_data_target( @@ -141,6 +254,29 @@ where Ok(()) } +pub fn check_cyclic_proof_verifier_data< + F: RichField + Extendable, + C: GenericConfig, + const D: usize, +>( + proof: &ProofWithPublicInputs, + verifier_data: &VerifierOnlyCircuitData, + common_data: &CommonCircuitData, +) -> Result<()> +where + C::Hasher: AlgebraicHasher, +{ + let pis = CyclicPublicInputs::from_slice(&proof.public_inputs, common_data)?; + dbg!(pis.circuit_digest); + dbg!(verifier_data.circuit_digest); + if !pis.base_case { + ensure!(verifier_data.constants_sigmas_cap == pis.constants_sigmas_cap); + ensure!(verifier_data.circuit_digest == pis.circuit_digest); + } + + Ok(()) +} + #[cfg(test)] mod tests { use anyhow::Result; @@ -154,7 +290,7 @@ mod tests { use crate::plonk::circuit_data::{CircuitConfig, CommonCircuitData, VerifierCircuitTarget}; use crate::plonk::config::{AlgebraicHasher, GenericConfig, Hasher, PoseidonGoldilocksConfig}; use crate::recursion::cyclic_recursion::{ - set_cyclic_recursion_data_target, CyclicRecursionData, + check_cyclic_proof_verifier_data, set_cyclic_recursion_data_target, CyclicRecursionData, }; fn common_data_for_recursion< @@ -183,7 +319,7 @@ mod tests { let config = CircuitConfig::standard_recursion_config(); let mut builder = CircuitBuilder::::new(config); let config = CircuitConfig::standard_recursion_config(); - let mut pw = PartialWitness::::new(); + let pw = PartialWitness::::new(); let mut builder = CircuitBuilder::::new(config); let proof = builder.add_virtual_proof_with_pis(&data.common); let verifier_data = VerifierCircuitTarget { @@ -220,8 +356,47 @@ mod tests { common_data: &cyclic_circuit_data.common, }; set_cyclic_recursion_data_target(&mut pw, &cyclic_data_target, &cyclic_recursion_data)?; + dbg!("yo"); let proof = cyclic_circuit_data.prove(pw)?; - cyclic_circuit_data.verify(proof); + check_cyclic_proof_verifier_data( + &proof, + &cyclic_recursion_data.verifier_data, + cyclic_recursion_data.common_data, + )?; + cyclic_circuit_data.verify(proof.clone())?; + + let mut pw = PartialWitness::new(); + pw.set_target(t, F::rand()); + let cyclic_recursion_data = CyclicRecursionData { + proof: &Some(proof), + verifier_data: &cyclic_circuit_data.verifier_only, + common_data: &cyclic_circuit_data.common, + }; + set_cyclic_recursion_data_target(&mut pw, &cyclic_data_target, &cyclic_recursion_data)?; + dbg!("yo"); + let proof = cyclic_circuit_data.prove(pw)?; + check_cyclic_proof_verifier_data( + &proof, + &cyclic_recursion_data.verifier_data, + cyclic_recursion_data.common_data, + )?; + cyclic_circuit_data.verify(proof.clone())?; + + let mut pw = PartialWitness::new(); + pw.set_target(t, F::rand()); + let cyclic_recursion_data = CyclicRecursionData { + proof: &Some(proof), + verifier_data: &cyclic_circuit_data.verifier_only, + common_data: &cyclic_circuit_data.common, + }; + set_cyclic_recursion_data_target(&mut pw, &cyclic_data_target, &cyclic_recursion_data)?; + let proof = cyclic_circuit_data.prove(pw)?; + check_cyclic_proof_verifier_data( + &proof, + &cyclic_recursion_data.verifier_data, + cyclic_recursion_data.common_data, + )?; + cyclic_circuit_data.verify(proof.clone())?; Ok(()) } From 51cea8d98b82cd94b016edeb7fe57247f85c9a6f Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 14 Oct 2022 15:34:08 +0200 Subject: [PATCH 07/31] `base_case` is decreasing --- plonky2/src/recursion/cyclic_recursion.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/plonky2/src/recursion/cyclic_recursion.rs b/plonky2/src/recursion/cyclic_recursion.rs index abf7f7a2..cc08d4eb 100644 --- a/plonky2/src/recursion/cyclic_recursion.rs +++ b/plonky2/src/recursion/cyclic_recursion.rs @@ -84,7 +84,7 @@ impl, C: GenericConfig, const D: usize> pub struct CyclicPublicInputsTarget { pub circuit_digest: HashOutTarget, pub constants_sigmas_cap: MerkleCapTarget, - pub base_case: Target, + pub base_case: BoolTarget, } impl CyclicPublicInputsTarget { @@ -95,7 +95,7 @@ impl CyclicPublicInputsTarget { let cap_len = common_data.config.fri_config.num_cap_elements(); let len = slice.len(); ensure!(len >= 4 + 4 * cap_len + 1, "Not enough public inputs"); - let base_case = slice[len - 1]; + let base_case = BoolTarget::new_unsafe(slice[len - 1]); let constants_sigmas_cap = MerkleCapTarget( (0..cap_len) .map(|i| HashOutTarget { @@ -151,6 +151,12 @@ impl, const D: usize> CircuitBuilder { let dummy_proof = self.add_virtual_proof_with_pis(&common_data); let pis = CyclicPublicInputsTarget::from_slice(&proof.public_inputs, &common_data)?; + // Check that the previous base case flag was boolean. + self.assert_bool(pis.base_case); + // Check that we cannot go from a non-base case to a base case by checking `previous_base_case - base_case \in {0,1}`. + let decrease = BoolTarget::new_unsafe(self.sub(pis.base_case.target, base_case.target)); + self.assert_bool(decrease); + // Connect previous verifier data to current one. This guarantees that every proof in the cycle uses the same verifier data. self.connect_hashes(pis.circuit_digest, verifier_data.circuit_digest); for (h0, h1) in pis .constants_sigmas_cap @@ -220,11 +226,11 @@ where cyclic_recursion_data.verifier_data, ); } else { - dbg!("hi"); let (dummy_proof, dummy_data) = dummy_proof(cyclic_recursion_data.common_data)?; pw.set_bool_target(cyclic_recursion_data_target.base_case, true); let mut dummy_proof_real_vd = dummy_proof.clone(); let pis_len = dummy_proof_real_vd.public_inputs.len(); + dummy_proof_real_vd.public_inputs[pis_len - 1] = F::ONE; let num_cap = cyclic_recursion_data .common_data .config @@ -239,7 +245,6 @@ where ); } pw.set_proof_with_pis_target(&cyclic_recursion_data_target.proof, &dummy_proof_real_vd); - dbg!(cyclic_recursion_data.verifier_data.circuit_digest); pw.set_verifier_data_target( &cyclic_recursion_data_target.verifier_data, cyclic_recursion_data.verifier_data, @@ -267,8 +272,6 @@ where C::Hasher: AlgebraicHasher, { let pis = CyclicPublicInputs::from_slice(&proof.public_inputs, common_data)?; - dbg!(pis.circuit_digest); - dbg!(verifier_data.circuit_digest); if !pis.base_case { ensure!(verifier_data.constants_sigmas_cap == pis.constants_sigmas_cap); ensure!(verifier_data.circuit_digest == pis.circuit_digest); @@ -356,7 +359,6 @@ mod tests { common_data: &cyclic_circuit_data.common, }; set_cyclic_recursion_data_target(&mut pw, &cyclic_data_target, &cyclic_recursion_data)?; - dbg!("yo"); let proof = cyclic_circuit_data.prove(pw)?; check_cyclic_proof_verifier_data( &proof, @@ -373,7 +375,6 @@ mod tests { common_data: &cyclic_circuit_data.common, }; set_cyclic_recursion_data_target(&mut pw, &cyclic_data_target, &cyclic_recursion_data)?; - dbg!("yo"); let proof = cyclic_circuit_data.prove(pw)?; check_cyclic_proof_verifier_data( &proof, From 35b173ed347116064da36b27cb42d2f1474dea15 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 14 Oct 2022 16:26:05 +0200 Subject: [PATCH 08/31] Comments --- plonky2/src/recursion/cyclic_recursion.rs | 56 +++++++++++++---------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/plonky2/src/recursion/cyclic_recursion.rs b/plonky2/src/recursion/cyclic_recursion.rs index cc08d4eb..9e4dcb4e 100644 --- a/plonky2/src/recursion/cyclic_recursion.rs +++ b/plonky2/src/recursion/cyclic_recursion.rs @@ -1,7 +1,7 @@ +#![allow(clippy::int_plus_one)] // Makes more sense for some inequalities below. use anyhow::{ensure, Result}; use itertools::Itertools; use plonky2_field::extension::Extendable; -use plonky2_field::types::Field; use crate::gates::noop::NoopGate; use crate::hash::hash_types::{HashOut, HashOutTarget, MerkleCapTarget, RichField}; @@ -138,6 +138,8 @@ impl, const D: usize> CircuitBuilder { constants_sigmas_cap: self.add_virtual_cap(self.config.fri_config.cap_height), circuit_digest: self.add_virtual_hash(), }; + + // Flag set to true for the base case of the cycle where we verify a dummy proof to bootstrap the cycle. Set to false otherwise. // Unsafe is ok since `base_case` is a public input and its booleaness should be checked in the verifier. let base_case = self.add_virtual_bool_target_unsafe(); self.register_public_input(base_case.target); @@ -167,6 +169,7 @@ impl, const D: usize> CircuitBuilder { self.connect_hashes(*h0, *h1); } + // Verify the dummy proof if `base_case` is set to true, otherwise verify the "real" proof. self.conditionally_verify_proof( base_case, &dummy_proof, @@ -176,15 +179,17 @@ impl, const D: usize> CircuitBuilder { &common_data, ); + // Make sure we have enough gates to match `common_data`. while self.num_gates() < 1 << (common_data.degree_bits - 1) { self.add_gate(NoopGate, vec![]); } + // Make sure we have every gate to match `common_data`. for g in &common_data.gates { self.add_gate_to_gate_set(g.clone()); } let data = self.build::(); - assert_eq!(&data.common, &common_data); + ensure!(data.common == common_data, "Common data does not match."); Ok(( data, @@ -199,7 +204,7 @@ impl, const D: usize> CircuitBuilder { } } -/// Set the targets in a `ProofTarget` to their corresponding values in a `Proof`. +/// Set the targets in a `CyclicRecursionTarget` to their corresponding values in a `CyclicRecursionData`. pub fn set_cyclic_recursion_data_target< F: RichField + Extendable, C: GenericConfig, @@ -228,23 +233,27 @@ where } else { let (dummy_proof, dummy_data) = dummy_proof(cyclic_recursion_data.common_data)?; pw.set_bool_target(cyclic_recursion_data_target.base_case, true); - let mut dummy_proof_real_vd = dummy_proof.clone(); - let pis_len = dummy_proof_real_vd.public_inputs.len(); - dummy_proof_real_vd.public_inputs[pis_len - 1] = F::ONE; + let mut proof = dummy_proof.clone(); + let pis_len = proof.public_inputs.len(); + // A base case must be following another base case. + proof.public_inputs[pis_len - 1] = F::ONE; + // The circuit checks that the verifier data is the same throughout the cycle, so + // we set the verifier data to the "real" verifier data even though it's unused in the base case. let num_cap = cyclic_recursion_data .common_data .config .fri_config .num_cap_elements(); let s = pis_len - 5 - 4 * num_cap; - dummy_proof_real_vd.public_inputs[s..s + 4] + proof.public_inputs[s..s + 4] .copy_from_slice(&cyclic_recursion_data.verifier_data.circuit_digest.elements); for i in 0..num_cap { - dummy_proof_real_vd.public_inputs[s + 4 * (1 + i)..s + 4 * (2 + i)].copy_from_slice( + proof.public_inputs[s + 4 * (1 + i)..s + 4 * (2 + i)].copy_from_slice( &cyclic_recursion_data.verifier_data.constants_sigmas_cap.0[i].elements, ); } - pw.set_proof_with_pis_target(&cyclic_recursion_data_target.proof, &dummy_proof_real_vd); + + pw.set_proof_with_pis_target(&cyclic_recursion_data_target.proof, &proof); pw.set_verifier_data_target( &cyclic_recursion_data_target.verifier_data, cyclic_recursion_data.verifier_data, @@ -259,6 +268,9 @@ where Ok(()) } +/// Additional checks to be performed on a cyclic recursive proof in addition to verifying the proof. +/// Checks that the `base_case` flag is boolean and that the purported verifier data in the public inputs +/// match the real verifier data. pub fn check_cyclic_proof_verifier_data< F: RichField + Extendable, C: GenericConfig, @@ -296,6 +308,7 @@ mod tests { check_cyclic_proof_verifier_data, set_cyclic_recursion_data_target, CyclicRecursionData, }; + // Generates `CommonCircuitData` usable for recursion. fn common_data_for_recursion< F: RichField + Extendable, C: GenericConfig, @@ -306,10 +319,9 @@ mod tests { [(); C::Hasher::HASH_SIZE]:, { let config = CircuitConfig::standard_recursion_config(); - let mut builder = CircuitBuilder::::new(config); + let builder = CircuitBuilder::::new(config); let data = builder.build::(); let config = CircuitConfig::standard_recursion_config(); - let mut pw = PartialWitness::::new(); let mut builder = CircuitBuilder::::new(config); let proof = builder.add_virtual_proof_with_pis(&data.common); let verifier_data = VerifierCircuitTarget { @@ -321,9 +333,6 @@ mod tests { let config = CircuitConfig::standard_recursion_config(); let mut builder = CircuitBuilder::::new(config); - let config = CircuitConfig::standard_recursion_config(); - let pw = PartialWitness::::new(); - let mut builder = CircuitBuilder::::new(config); let proof = builder.add_virtual_proof_with_pis(&data.common); let verifier_data = VerifierCircuitTarget { constants_sigmas_cap: builder.add_virtual_cap(data.common.config.fri_config.cap_height), @@ -352,9 +361,10 @@ mod tests { let common_data = common_data_for_recursion::(); + // Add cyclic recursion gadget. let (cyclic_circuit_data, cyclic_data_target) = builder.cyclic_recursion(common_data)?; let cyclic_recursion_data = CyclicRecursionData { - proof: &None, + proof: &None, // Base case: We don't have a proof to put here yet. verifier_data: &cyclic_circuit_data.verifier_only, common_data: &cyclic_circuit_data.common, }; @@ -362,15 +372,16 @@ mod tests { let proof = cyclic_circuit_data.prove(pw)?; check_cyclic_proof_verifier_data( &proof, - &cyclic_recursion_data.verifier_data, + cyclic_recursion_data.verifier_data, cyclic_recursion_data.common_data, )?; cyclic_circuit_data.verify(proof.clone())?; + // 1st recursive layer. let mut pw = PartialWitness::new(); pw.set_target(t, F::rand()); let cyclic_recursion_data = CyclicRecursionData { - proof: &Some(proof), + proof: &Some(proof), // Input previous proof. verifier_data: &cyclic_circuit_data.verifier_only, common_data: &cyclic_circuit_data.common, }; @@ -378,15 +389,16 @@ mod tests { let proof = cyclic_circuit_data.prove(pw)?; check_cyclic_proof_verifier_data( &proof, - &cyclic_recursion_data.verifier_data, + cyclic_recursion_data.verifier_data, cyclic_recursion_data.common_data, )?; cyclic_circuit_data.verify(proof.clone())?; + // 2nd recursive layer. let mut pw = PartialWitness::new(); pw.set_target(t, F::rand()); let cyclic_recursion_data = CyclicRecursionData { - proof: &Some(proof), + proof: &Some(proof), // Input previous proof. verifier_data: &cyclic_circuit_data.verifier_only, common_data: &cyclic_circuit_data.common, }; @@ -394,11 +406,9 @@ mod tests { let proof = cyclic_circuit_data.prove(pw)?; check_cyclic_proof_verifier_data( &proof, - &cyclic_recursion_data.verifier_data, + cyclic_recursion_data.verifier_data, cyclic_recursion_data.common_data, )?; - cyclic_circuit_data.verify(proof.clone())?; - - Ok(()) + cyclic_circuit_data.verify(proof) } } From 366567935c6182ee4f3760ab6e384655567ac13e Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 17 Oct 2022 10:34:08 +0200 Subject: [PATCH 09/31] Fix conflict --- plonky2/src/recursion/conditional_recursive_verifier.rs | 1 - plonky2/src/recursion/cyclic_recursion.rs | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/plonky2/src/recursion/conditional_recursive_verifier.rs b/plonky2/src/recursion/conditional_recursive_verifier.rs index 2c406904..b4da993e 100644 --- a/plonky2/src/recursion/conditional_recursive_verifier.rs +++ b/plonky2/src/recursion/conditional_recursive_verifier.rs @@ -24,7 +24,6 @@ use crate::plonk::proof::{ use crate::with_context; /// Generate a proof having a given `CommonCircuitData`. -#[allow(unused)] // TODO: should be used soon. pub(crate) fn dummy_proof< F: RichField + Extendable, C: GenericConfig, diff --git a/plonky2/src/recursion/cyclic_recursion.rs b/plonky2/src/recursion/cyclic_recursion.rs index 9e4dcb4e..6260a584 100644 --- a/plonky2/src/recursion/cyclic_recursion.rs +++ b/plonky2/src/recursion/cyclic_recursion.rs @@ -146,7 +146,6 @@ impl, const D: usize> CircuitBuilder { common_data.num_public_inputs = self.num_public_inputs(); // The `conditionally_verify_proof` gadget below takes 2^12 gates, so `degree_bits` cannot be smaller than 13. - common_data.degree_bits = common_data.degree_bits.max(13); common_data.fri_params.degree_bits = common_data.fri_params.degree_bits.max(13); let proof = self.add_virtual_proof_with_pis(&common_data); @@ -180,7 +179,7 @@ impl, const D: usize> CircuitBuilder { ); // Make sure we have enough gates to match `common_data`. - while self.num_gates() < 1 << (common_data.degree_bits - 1) { + while self.num_gates() < (common_data.degree() / 2) { self.add_gate(NoopGate, vec![]); } // Make sure we have every gate to match `common_data`. @@ -261,7 +260,7 @@ where pw.set_proof_with_pis_target(&cyclic_recursion_data_target.dummy_proof, &dummy_proof); pw.set_verifier_data_target( &cyclic_recursion_data_target.dummy_verifier_data, - &dummy_data.verifier_only, + &dummy_data, ); } From 09cee22d1f47037be3d6c9ae4a7761cc2393546b Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 17 Oct 2022 14:56:16 +0200 Subject: [PATCH 10/31] Better test --- .../conditional_recursive_verifier.rs | 2 +- plonky2/src/recursion/cyclic_recursion.rs | 103 +++++++++++++++--- 2 files changed, 91 insertions(+), 14 deletions(-) diff --git a/plonky2/src/recursion/conditional_recursive_verifier.rs b/plonky2/src/recursion/conditional_recursive_verifier.rs index b4da993e..510bb438 100644 --- a/plonky2/src/recursion/conditional_recursive_verifier.rs +++ b/plonky2/src/recursion/conditional_recursive_verifier.rs @@ -182,7 +182,7 @@ impl, const D: usize> CircuitBuilder { .collect() } - fn select_hash( + pub(crate) fn select_hash( &mut self, b: BoolTarget, h0: HashOutTarget, diff --git a/plonky2/src/recursion/cyclic_recursion.rs b/plonky2/src/recursion/cyclic_recursion.rs index 6260a584..e968e5e7 100644 --- a/plonky2/src/recursion/cyclic_recursion.rs +++ b/plonky2/src/recursion/cyclic_recursion.rs @@ -118,12 +118,19 @@ impl CyclicPublicInputsTarget { impl, const D: usize> CircuitBuilder { pub fn cyclic_recursion>( mut self, + previous_virtual_public_inputs: &[Target], + previous_base_case: Target, mut common_data: CommonCircuitData, ) -> Result<(CircuitData, CyclicRecursionTarget)> where C::Hasher: AlgebraicHasher, [(); C::Hasher::HASH_SIZE]:, { + ensure!( + previous_virtual_public_inputs.len() == self.num_public_inputs(), + "Incorrect number of public inputs." + ); + let verifier_data = VerifierCircuitTarget { constants_sigmas_cap: self.add_virtual_cap(self.config.fri_config.cap_height), circuit_digest: self.add_virtual_hash(), @@ -168,6 +175,14 @@ impl, const D: usize> CircuitBuilder { self.connect_hashes(*h0, *h1); } + self.connect(previous_base_case, pis.base_case.target); + for (x, y) in previous_virtual_public_inputs + .iter() + .zip(&proof.public_inputs) + { + self.connect(*x, *y); + } + // Verify the dummy proof if `base_case` is set to true, otherwise verify the "real" proof. self.conditionally_verify_proof( base_case, @@ -212,6 +227,8 @@ pub fn set_cyclic_recursion_data_target< pw: &mut PartialWitness, cyclic_recursion_data_target: &CyclicRecursionTarget, cyclic_recursion_data: &CyclicRecursionData, + // Public inputs to set in the base case to seed some initial data. + public_inputs: &[F], ) -> Result<()> where C::Hasher: AlgebraicHasher, @@ -233,6 +250,7 @@ where let (dummy_proof, dummy_data) = dummy_proof(cyclic_recursion_data.common_data)?; pw.set_bool_target(cyclic_recursion_data_target.base_case, true); let mut proof = dummy_proof.clone(); + proof.public_inputs[0..public_inputs.len()].copy_from_slice(public_inputs); let pis_len = proof.public_inputs.len(); // A base case must be following another base case. proof.public_inputs[pis_len - 1] = F::ONE; @@ -293,13 +311,17 @@ where #[cfg(test)] mod tests { + use anyhow::Result; use plonky2_field::extension::Extendable; + use plonky2_field::types::PrimeField64; use crate::field::types::Field; use crate::hash::hash_types::RichField; - use crate::hash::poseidon::PoseidonHash; - use crate::iop::witness::{PartialWitness, Witness}; + use crate::hash::hashing::hash_n_to_hash_no_pad; + use crate::hash::poseidon::{PoseidonHash, PoseidonPermutation}; + use crate::iop::target::BoolTarget; + use crate::iop::witness::PartialWitness; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_data::{CircuitConfig, CommonCircuitData, VerifierCircuitTarget}; use crate::plonk::config::{AlgebraicHasher, GenericConfig, Hasher, PoseidonGoldilocksConfig}; @@ -351,23 +373,54 @@ mod tests { let mut pw = PartialWitness::new(); let mut builder = CircuitBuilder::::new(config); - // Build realistic circuit - let t = builder.add_virtual_target(); - pw.set_target(t, F::rand()); - let t_inv = builder.inverse(t); - let h = builder.hash_n_to_hash_no_pad::(vec![t_inv]); + // Circuit that computes a repeated hash. + let initial_hash = builder.add_virtual_hash(); + builder.register_public_inputs(&initial_hash.elements); + // Hash from the previous proof. + let old_hash = builder.add_virtual_hash(); + // Flag set to true if the last proof was a base case. + let old_base_case = builder.add_virtual_target(); + // The input hash is either the previous hash or the initial hash depending on whether + // the last proof was a base case. + let input_hash = builder.select_hash( + BoolTarget::new_unsafe(old_base_case), + initial_hash, + old_hash, + ); + let h = builder.hash_n_to_hash_no_pad::(input_hash.elements.to_vec()); builder.register_public_inputs(&h.elements); + // Previous counter. + let old_counter = builder.add_virtual_target(); + let one = builder.one(); + let old_not_base_case = builder.sub(one, old_base_case); + // New counter is the previous counter +1 if the previous proof wasn't a base case. + let new_counter = builder.add(old_counter, old_not_base_case); + builder.register_public_input(new_counter); + let old_pis = [ + initial_hash.elements.as_slice(), + old_hash.elements.as_slice(), + [old_counter].as_slice(), + ] + .concat(); let common_data = common_data_for_recursion::(); // Add cyclic recursion gadget. - let (cyclic_circuit_data, cyclic_data_target) = builder.cyclic_recursion(common_data)?; + let (cyclic_circuit_data, cyclic_data_target) = + builder.cyclic_recursion(&old_pis, old_base_case, common_data)?; + let cyclic_recursion_data = CyclicRecursionData { proof: &None, // Base case: We don't have a proof to put here yet. verifier_data: &cyclic_circuit_data.verifier_only, common_data: &cyclic_circuit_data.common, }; - set_cyclic_recursion_data_target(&mut pw, &cyclic_data_target, &cyclic_recursion_data)?; + let initial_hash = [F::ZERO, F::ONE, F::TWO, F::from_canonical_usize(3)]; + set_cyclic_recursion_data_target( + &mut pw, + &cyclic_data_target, + &cyclic_recursion_data, + &initial_hash, + )?; let proof = cyclic_circuit_data.prove(pw)?; check_cyclic_proof_verifier_data( &proof, @@ -378,13 +431,17 @@ mod tests { // 1st recursive layer. let mut pw = PartialWitness::new(); - pw.set_target(t, F::rand()); let cyclic_recursion_data = CyclicRecursionData { proof: &Some(proof), // Input previous proof. verifier_data: &cyclic_circuit_data.verifier_only, common_data: &cyclic_circuit_data.common, }; - set_cyclic_recursion_data_target(&mut pw, &cyclic_data_target, &cyclic_recursion_data)?; + set_cyclic_recursion_data_target( + &mut pw, + &cyclic_data_target, + &cyclic_recursion_data, + &[], + )?; let proof = cyclic_circuit_data.prove(pw)?; check_cyclic_proof_verifier_data( &proof, @@ -395,19 +452,39 @@ mod tests { // 2nd recursive layer. let mut pw = PartialWitness::new(); - pw.set_target(t, F::rand()); let cyclic_recursion_data = CyclicRecursionData { proof: &Some(proof), // Input previous proof. verifier_data: &cyclic_circuit_data.verifier_only, common_data: &cyclic_circuit_data.common, }; - set_cyclic_recursion_data_target(&mut pw, &cyclic_data_target, &cyclic_recursion_data)?; + set_cyclic_recursion_data_target( + &mut pw, + &cyclic_data_target, + &cyclic_recursion_data, + &[], + )?; let proof = cyclic_circuit_data.prove(pw)?; check_cyclic_proof_verifier_data( &proof, cyclic_recursion_data.verifier_data, cyclic_recursion_data.common_data, )?; + + // Verify that the proof correctly computes a repeated hash. + let initial_hash = &proof.public_inputs[..4]; + let hash = &proof.public_inputs[4..8]; + let counter = proof.public_inputs[8]; + let mut h: [F; 4] = initial_hash.try_into().unwrap(); + assert_eq!( + hash, + std::iter::repeat_with(|| { + h = hash_n_to_hash_no_pad::(&h).elements; + h + }) + .nth(counter.to_canonical_u64() as usize) + .unwrap() + ); + cyclic_circuit_data.verify(proof) } } From c3e9827b5e54ecbf9eb713a3001fdf7d3df001b7 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 17 Oct 2022 14:59:51 +0200 Subject: [PATCH 11/31] Minor --- plonky2/src/plonk/circuit_builder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plonky2/src/plonk/circuit_builder.rs b/plonky2/src/plonk/circuit_builder.rs index fffe22a8..82a72504 100644 --- a/plonky2/src/plonk/circuit_builder.rs +++ b/plonky2/src/plonk/circuit_builder.rs @@ -50,7 +50,7 @@ pub struct CircuitBuilder, const D: usize> { pub config: CircuitConfig, /// The types of gates used in this circuit. - pub(crate) gates: HashSet>, + gates: HashSet>, /// The concrete placement of each gate. pub(crate) gate_instances: Vec>, From 9639ff22dc11c814886609427eabeadece7e4523 Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Mon, 17 Oct 2022 11:31:08 -0700 Subject: [PATCH 12/31] MPT storage logic --- evm/src/cpu/kernel/aggregator.rs | 6 ++- evm/src/cpu/kernel/asm/mpt/accounts.asm | 53 +++++++++++++++++++ .../asm/mpt/hash/hash_trie_specific.asm | 2 +- evm/src/cpu/kernel/asm/mpt/read.asm | 18 +++---- .../kernel/asm/mpt/storage/storage_read.asm | 28 ++++++++++ .../kernel/asm/mpt/storage/storage_write.asm | 33 ++++++++++++ evm/src/cpu/kernel/asm/mpt/storage_read.asm | 2 - evm/src/cpu/kernel/asm/mpt/storage_write.asm | 2 - evm/src/cpu/kernel/asm/mpt/util.asm | 11 ++++ evm/src/cpu/kernel/asm/util/keccak.asm | 14 +++++ evm/src/generation/mpt.rs | 8 ++- 11 files changed, 156 insertions(+), 21 deletions(-) create mode 100644 evm/src/cpu/kernel/asm/mpt/accounts.asm create mode 100644 evm/src/cpu/kernel/asm/mpt/storage/storage_read.asm create mode 100644 evm/src/cpu/kernel/asm/mpt/storage/storage_write.asm delete mode 100644 evm/src/cpu/kernel/asm/mpt/storage_read.asm delete mode 100644 evm/src/cpu/kernel/asm/mpt/storage_write.asm create mode 100644 evm/src/cpu/kernel/asm/util/keccak.asm diff --git a/evm/src/cpu/kernel/aggregator.rs b/evm/src/cpu/kernel/aggregator.rs index e0a64314..8fe49739 100644 --- a/evm/src/cpu/kernel/aggregator.rs +++ b/evm/src/cpu/kernel/aggregator.rs @@ -39,6 +39,7 @@ pub(crate) fn combined_kernel() -> Kernel { include_str!("asm/memory/metadata.asm"), include_str!("asm/memory/packing.asm"), include_str!("asm/memory/txn_fields.asm"), + include_str!("asm/mpt/accounts.asm"), include_str!("asm/mpt/delete/delete.asm"), include_str!("asm/mpt/hash/hash.asm"), include_str!("asm/mpt/hash/hash_trie_specific.asm"), @@ -50,8 +51,8 @@ pub(crate) fn combined_kernel() -> Kernel { include_str!("asm/mpt/load/load.asm"), include_str!("asm/mpt/load/load_trie_specific.asm"), include_str!("asm/mpt/read.asm"), - include_str!("asm/mpt/storage_read.asm"), - include_str!("asm/mpt/storage_write.asm"), + include_str!("asm/mpt/storage/storage_read.asm"), + include_str!("asm/mpt/storage/storage_write.asm"), include_str!("asm/mpt/util.asm"), include_str!("asm/ripemd/box.asm"), include_str!("asm/ripemd/compression.asm"), @@ -77,6 +78,7 @@ pub(crate) fn combined_kernel() -> Kernel { include_str!("asm/transactions/type_2.asm"), include_str!("asm/util/assertions.asm"), include_str!("asm/util/basic_macros.asm"), + include_str!("asm/util/keccak.asm"), ]; let parsed_files = files.iter().map(|f| parse(f)).collect_vec(); diff --git a/evm/src/cpu/kernel/asm/mpt/accounts.asm b/evm/src/cpu/kernel/asm/mpt/accounts.asm new file mode 100644 index 00000000..0e49da98 --- /dev/null +++ b/evm/src/cpu/kernel/asm/mpt/accounts.asm @@ -0,0 +1,53 @@ +// Return a pointer to the current account's data in the state trie. +%macro current_account_data + ADDRESS %mpt_read_state_trie + // stack: account_ptr + // account_ptr should be non-null as long as the prover provided the proper + // Merkle data. But a bad prover may not have, and we don't want return a + // null pointer for security reasons. + DUP1 ISZERO %jumpi(panic) + // stack: account_ptr +%endmacro + +// Returns a pointer to the root of the storage trie associated with the current account. +%macro current_storage_trie + // stack: (empty) + %current_account_data + // stack: account_ptr + %add_const(2) + // stack: storage_root_ptr_ptr + %mload_trie_data + // stack: storage_root_ptr +%endmacro + +global make_default_account: + PANIC // TODO + +// Create a copy of the given account. The copy can then safely be mutated as +// needed, while leaving the original account data untouched. +// +// This writes the new account's data to MPT data, but does not register the new +// account in the state trie. +// +// Pre stack: old_account_ptr, retdest +// Post stack: new_account_ptr +global make_account_copy: + // stack: old_account_ptr, retdest + %get_trie_data_size // pointer to new account we're about to create + // stack: new_account_ptr, old_account_ptr, retdest + + DUP2 %mload_trie_data %append_to_trie_data + DUP2 %add_const(1) %mload_trie_data %append_to_trie_data + DUP2 %add_const(3) %mload_trie_data %append_to_trie_data + SWAP1 %add_const(4) %mload_trie_data %append_to_trie_data + + // stack: new_account_ptr, retdest + SWAP1 + JUMP + +// Convenience macro to call make_account_copy and return where we left off. +%macro make_account_copy + %stack (old_account_ptr) -> (old_account_ptr, %%after) + %jump(make_account_copy) +%%after: +%endmacro diff --git a/evm/src/cpu/kernel/asm/mpt/hash/hash_trie_specific.asm b/evm/src/cpu/kernel/asm/mpt/hash/hash_trie_specific.asm index 4f9b58b4..39253b9f 100644 --- a/evm/src/cpu/kernel/asm/mpt/hash/hash_trie_specific.asm +++ b/evm/src/cpu/kernel/asm/mpt/hash/hash_trie_specific.asm @@ -95,4 +95,4 @@ encode_receipt: PANIC // TODO encode_storage_value: - PANIC // TODO + PANIC // TODO: RLP encode as variable-len scalar? diff --git a/evm/src/cpu/kernel/asm/mpt/read.asm b/evm/src/cpu/kernel/asm/mpt/read.asm index d375bedc..08aa02c3 100644 --- a/evm/src/cpu/kernel/asm/mpt/read.asm +++ b/evm/src/cpu/kernel/asm/mpt/read.asm @@ -3,26 +3,26 @@ // state trie. Returns null if the address is not found. global mpt_read_state_trie: // stack: addr, retdest - // The key is the hash of the address. Since KECCAK_GENERAL takes input from - // memory, we will write addr bytes to SEGMENT_KERNEL_GENERAL[0..20] first. - %stack (addr) -> (0, @SEGMENT_KERNEL_GENERAL, 0, addr, 20, mpt_read_state_trie_after_mstore) - %jump(mstore_unpacking) -mpt_read_state_trie_after_mstore: - // stack: retdest - %stack () -> (0, @SEGMENT_KERNEL_GENERAL, 0, 20) // context, segment, offset, len - KECCAK_GENERAL + %addr_to_state_key // stack: key, retdest PUSH 64 // num_nibbles %mload_global_metadata(@GLOBAL_METADATA_STATE_TRIE_ROOT) // node_ptr // stack: node_ptr, num_nibbles, key, retdest %jump(mpt_read) +// Convenience macro to call mpt_read_state_trie and return where we left off. +%macro mpt_read_state_trie + %stack (addr) -> (addr, %%after) + %jump(mpt_read_state_trie) +%%after: +%endmacro + // Read a value from a MPT. // // Arguments: // - the virtual address of the trie to search in -// - the key, as a U256 // - the number of nibbles in the key (should start at 64) +// - the key, as a U256 // // This function returns a pointer to the value, or 0 if the key is not found. global mpt_read: diff --git a/evm/src/cpu/kernel/asm/mpt/storage/storage_read.asm b/evm/src/cpu/kernel/asm/mpt/storage/storage_read.asm new file mode 100644 index 00000000..d9f74714 --- /dev/null +++ b/evm/src/cpu/kernel/asm/mpt/storage/storage_read.asm @@ -0,0 +1,28 @@ +// Read a word from the current account's storage trie. +// +// Pre stack: slot, retdest +// Post stack: value + +global storage_read: + // stack: slot, retdest + %stack (slot) -> (slot, after_storage_read) + %slot_to_storage_key + // stack: storage_key, after_storage_read, retdest + PUSH 64 // storage_key has 64 nibbles + %current_storage_trie + // stack: storage_root_ptr, 64, storage_key, after_storage_read, retdest + %jump(mpt_read) + +after_storage_read: + // stack: value_ptr, retdest + DUP1 %jumpi(storage_key_exists) + + // Storage key not found; return default value of 0. + %stack (value_ptr, retdest) -> (retdest, 0) + JUMP + +storage_key_exists: + // stack: value_ptr, retdest + %mload_trie_data // TODO: If we end up not using value pointers in storage tries, remove this. + SWAP1 + JUMP diff --git a/evm/src/cpu/kernel/asm/mpt/storage/storage_write.asm b/evm/src/cpu/kernel/asm/mpt/storage/storage_write.asm new file mode 100644 index 00000000..6afe0a64 --- /dev/null +++ b/evm/src/cpu/kernel/asm/mpt/storage/storage_write.asm @@ -0,0 +1,33 @@ +// Write a word to the current account's storage trie. +// +// Pre stack: slot, value, retdest +// Post stack: (empty) + +global storage_write: + // stack: slot, value, retdest + // TODO: If value = 0, delete the key instead of inserting 0? + // TODO: Do we need to write value to MPT data and insert value_ptr? Currently some logic assumes all values are pointers, but could be relaxed so a value is any single word. + %stack (slot, value) -> (slot, value, after_storage_insert) + %slot_to_storage_key + // stack: storage_key, value, after_storage_write, retdest + PUSH 64 // storage_key has 64 nibbles + %current_storage_trie + // stack: storage_root_ptr, 64, storage_key, value, after_storage_insert, retdest + %jump(mpt_insert) + +after_storage_insert: + // stack: new_storage_root_ptr, retdest + %current_account_data + // stack: old_account_ptr, new_storage_root_ptr, retdest + %make_account_copy + // stack: new_account_ptr, new_storage_root_ptr, retdest + + // Update the copied account with our new storage root pointer. + %stack (new_account_ptr, new_storage_root_ptr) -> (new_account_ptr, new_storage_root_ptr, new_account_ptr) + %add_const(2) + // stack: new_account_storage_root_ptr_ptr, new_storage_root_ptr, new_account_ptr, retdest + %mstore_trie_data + // stack: new_account_ptr, retdest + + SWAP1 + JUMP diff --git a/evm/src/cpu/kernel/asm/mpt/storage_read.asm b/evm/src/cpu/kernel/asm/mpt/storage_read.asm deleted file mode 100644 index 04fea17a..00000000 --- a/evm/src/cpu/kernel/asm/mpt/storage_read.asm +++ /dev/null @@ -1,2 +0,0 @@ -global storage_read: - // TODO diff --git a/evm/src/cpu/kernel/asm/mpt/storage_write.asm b/evm/src/cpu/kernel/asm/mpt/storage_write.asm deleted file mode 100644 index 940fb548..00000000 --- a/evm/src/cpu/kernel/asm/mpt/storage_write.asm +++ /dev/null @@ -1,2 +0,0 @@ -global storage_write: - // TODO diff --git a/evm/src/cpu/kernel/asm/mpt/util.asm b/evm/src/cpu/kernel/asm/mpt/util.asm index 0faa72f4..0f7689e1 100644 --- a/evm/src/cpu/kernel/asm/mpt/util.asm +++ b/evm/src/cpu/kernel/asm/mpt/util.asm @@ -165,3 +165,14 @@ SWAP4 %div_const(4) SWAP4 // bits_2 -> len_2 (in nibbles) // stack: len_common, key_common, len_1, key_1, len_2, key_2 %endmacro + +// Computes state_key = Keccak256(addr). Clobbers @SEGMENT_KERNEL_GENERAL. +%macro addr_to_state_key + %keccak256_word(20) +%endmacro + +// Given a storage slot (a 256-bit integer), computes storage_key = Keccak256(slot). +// Clobbers @SEGMENT_KERNEL_GENERAL. +%macro slot_to_storage_key + %keccak256_word(32) +%endmacro diff --git a/evm/src/cpu/kernel/asm/util/keccak.asm b/evm/src/cpu/kernel/asm/util/keccak.asm new file mode 100644 index 00000000..5c05a2d4 --- /dev/null +++ b/evm/src/cpu/kernel/asm/util/keccak.asm @@ -0,0 +1,14 @@ +// Computes Keccak256(input_word). Clobbers @SEGMENT_KERNEL_GENERAL. +// +// Pre stack: input_word +// Post stack: hash +%macro keccak256_word(num_bytes) + // Since KECCAK_GENERAL takes its input from memory, we will first write + // input_word's bytes to @SEGMENT_KERNEL_GENERAL[0..$num_bytes]. + %stack (word) -> (0, @SEGMENT_KERNEL_GENERAL, 0, word, $num_bytes, %%after_mstore) + %jump(mstore_unpacking) +%%after_mstore: + // stack: (empty) + %stack () -> (0, @SEGMENT_KERNEL_GENERAL, 0, $num_bytes) // context, segment, offset, len + KECCAK_GENERAL +%endmacro diff --git a/evm/src/generation/mpt.rs b/evm/src/generation/mpt.rs index 8ceb195a..4107b978 100644 --- a/evm/src/generation/mpt.rs +++ b/evm/src/generation/mpt.rs @@ -68,11 +68,10 @@ pub(crate) fn mpt_prover_inputs( PartialTrie::Hash(h) => prover_inputs.push(U256::from_big_endian(h.as_bytes())), PartialTrie::Branch { children, value } => { if value.is_empty() { - // There's no value, so value_len = 0. - prover_inputs.push(U256::zero()); + prover_inputs.push(U256::zero()); // value_present = 0 } else { let parsed_value = parse_value(value); - prover_inputs.push(parsed_value.len().into()); + prover_inputs.push(U256::one()); // value_present = 1 prover_inputs.extend(parsed_value); } for child in children { @@ -107,8 +106,7 @@ pub(crate) fn mpt_prover_inputs_state_trie( PartialTrie::Hash(h) => prover_inputs.push(U256::from_big_endian(h.as_bytes())), PartialTrie::Branch { children, value } => { assert!(value.is_empty(), "State trie should not have branch values"); - // There's no value, so value_len = 0. - prover_inputs.push(U256::zero()); + prover_inputs.push(U256::zero()); // value_present = 0 for (i, child) in children.iter().enumerate() { let extended_key = key.merge(&Nibbles { From a2edff467025f6b7f1d993368d81b58b46212fb9 Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Mon, 17 Oct 2022 23:12:03 -0700 Subject: [PATCH 13/31] Small storage fixes --- .../asm/mpt/insert/insert_trie_specific.asm | 7 ++-- .../kernel/asm/mpt/storage/storage_read.asm | 6 ++- .../kernel/asm/mpt/storage/storage_write.asm | 25 ++++++++---- evm/src/cpu/kernel/interpreter.rs | 12 ++++-- evm/src/cpu/kernel/tests/mpt/insert.rs | 39 +++++++++++-------- evm/src/cpu/kernel/tests/mpt/mod.rs | 11 +++++- 6 files changed, 68 insertions(+), 32 deletions(-) diff --git a/evm/src/cpu/kernel/asm/mpt/insert/insert_trie_specific.asm b/evm/src/cpu/kernel/asm/mpt/insert/insert_trie_specific.asm index 4c03d96c..61630753 100644 --- a/evm/src/cpu/kernel/asm/mpt/insert/insert_trie_specific.asm +++ b/evm/src/cpu/kernel/asm/mpt/insert/insert_trie_specific.asm @@ -2,9 +2,10 @@ // Mutate the state trie, inserting the given key-value pair. global mpt_insert_state_trie: - // stack: num_nibbles, key, value_ptr, retdest - %stack (num_nibbles, key, value_ptr) - -> (num_nibbles, key, value_ptr, mpt_insert_state_trie_save) + // stack: key, value_ptr, retdest + %stack (key, value_ptr) + -> (key, value_ptr, mpt_insert_state_trie_save) + PUSH 64 // num_nibbles %mload_global_metadata(@GLOBAL_METADATA_STATE_TRIE_ROOT) // stack: state_root_ptr, num_nibbles, key, value_ptr, mpt_insert_state_trie_save, retdest %jump(mpt_insert) diff --git a/evm/src/cpu/kernel/asm/mpt/storage/storage_read.asm b/evm/src/cpu/kernel/asm/mpt/storage/storage_read.asm index d9f74714..d8801cda 100644 --- a/evm/src/cpu/kernel/asm/mpt/storage/storage_read.asm +++ b/evm/src/cpu/kernel/asm/mpt/storage/storage_read.asm @@ -17,12 +17,14 @@ after_storage_read: // stack: value_ptr, retdest DUP1 %jumpi(storage_key_exists) - // Storage key not found; return default value of 0. + // Storage key not found. Return default value_ptr = 0, + // which derefs to 0 since @SEGMENT_TRIE_DATA[0] = 0. %stack (value_ptr, retdest) -> (retdest, 0) JUMP storage_key_exists: // stack: value_ptr, retdest - %mload_trie_data // TODO: If we end up not using value pointers in storage tries, remove this. + %mload_trie_data + // stack: value, retdest SWAP1 JUMP diff --git a/evm/src/cpu/kernel/asm/mpt/storage/storage_write.asm b/evm/src/cpu/kernel/asm/mpt/storage/storage_write.asm index 6afe0a64..057e4bb5 100644 --- a/evm/src/cpu/kernel/asm/mpt/storage/storage_write.asm +++ b/evm/src/cpu/kernel/asm/mpt/storage/storage_write.asm @@ -4,15 +4,24 @@ // Post stack: (empty) global storage_write: + // TODO: If value = 0, delete the key instead of inserting 0. // stack: slot, value, retdest - // TODO: If value = 0, delete the key instead of inserting 0? - // TODO: Do we need to write value to MPT data and insert value_ptr? Currently some logic assumes all values are pointers, but could be relaxed so a value is any single word. - %stack (slot, value) -> (slot, value, after_storage_insert) + + // First we write the value to MPT data, and get a pointer to it. + %get_trie_data_size + // stack: value_ptr, slot, value, retdest + SWAP2 + // stack: value, slot, value_ptr, retdest + %append_to_trie_data + // stack: slot, value_ptr, retdest + + // Next, call mpt_insert on the current account's storage root. + %stack (slot, value_ptr) -> (slot, value_ptr, after_storage_insert) %slot_to_storage_key - // stack: storage_key, value, after_storage_write, retdest + // stack: storage_key, value_ptr, after_storage_write, retdest PUSH 64 // storage_key has 64 nibbles %current_storage_trie - // stack: storage_root_ptr, 64, storage_key, value, after_storage_insert, retdest + // stack: storage_root_ptr, 64, storage_key, value_ptr, after_storage_insert, retdest %jump(mpt_insert) after_storage_insert: @@ -29,5 +38,7 @@ after_storage_insert: %mstore_trie_data // stack: new_account_ptr, retdest - SWAP1 - JUMP + // Save this updated account to the state trie. + ADDRESS %addr_to_state_key + // stack: state_key, new_account_ptr, retdest + %jump(mpt_insert_state_trie) diff --git a/evm/src/cpu/kernel/interpreter.rs b/evm/src/cpu/kernel/interpreter.rs index bca6d095..a2c25bf6 100644 --- a/evm/src/cpu/kernel/interpreter.rs +++ b/evm/src/cpu/kernel/interpreter.rs @@ -328,6 +328,8 @@ impl<'a> Interpreter<'a> { if self.debug_offsets.contains(&self.offset) { println!("At {}, stack={:?}", self.offset_name(), self.stack()); + } else if let Some(label) = self.offset_label() { + println!("At {}", label); } Ok(()) @@ -335,12 +337,16 @@ impl<'a> Interpreter<'a> { /// Get a string representation of the current offset for debugging purposes. fn offset_name(&self) -> String { + self.offset_label() + .unwrap_or_else(|| self.offset.to_string()) + } + + fn offset_label(&self) -> Option { // TODO: Not sure we should use KERNEL? Interpreter is more general in other places. - let label = KERNEL + KERNEL .global_labels .iter() - .find_map(|(k, v)| (*v == self.offset).then(|| k.clone())); - label.unwrap_or_else(|| self.offset.to_string()) + .find_map(|(k, v)| (*v == self.offset).then(|| k.clone())) } fn run_stop(&mut self) { diff --git a/evm/src/cpu/kernel/tests/mpt/insert.rs b/evm/src/cpu/kernel/tests/mpt/insert.rs index 3a52948d..35ab6e80 100644 --- a/evm/src/cpu/kernel/tests/mpt/insert.rs +++ b/evm/src/cpu/kernel/tests/mpt/insert.rs @@ -6,18 +6,20 @@ use super::nibbles; use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::constants::global_metadata::GlobalMetadata; use crate::cpu::kernel::interpreter::Interpreter; -use crate::cpu::kernel::tests::mpt::{test_account_1_rlp, test_account_2}; +use crate::cpu::kernel::tests::mpt::{ + nibbles_64, nibbles_count, test_account_1_rlp, test_account_2, +}; use crate::generation::mpt::{all_mpt_prover_inputs_reversed, AccountRlp}; use crate::generation::TrieInputs; #[test] fn mpt_insert_empty() -> Result<()> { - test_state_trie(Default::default(), nibbles(0xABC), test_account_2()) + test_state_trie(Default::default(), nibbles_64(0xABC), test_account_2()) } #[test] fn mpt_insert_leaf_identical_keys() -> Result<()> { - let key = nibbles(0xABC); + let key = nibbles_64(0xABC); let state_trie = PartialTrie::Leaf { nibbles: key, value: test_account_1_rlp(), @@ -28,37 +30,39 @@ fn mpt_insert_leaf_identical_keys() -> Result<()> { #[test] fn mpt_insert_leaf_nonoverlapping_keys() -> Result<()> { let state_trie = PartialTrie::Leaf { - nibbles: nibbles(0xABC), + nibbles: nibbles_64(0xABC), value: test_account_1_rlp(), }; - test_state_trie(state_trie, nibbles(0x123), test_account_2()) + test_state_trie(state_trie, nibbles_64(0x123), test_account_2()) } #[test] fn mpt_insert_leaf_overlapping_keys() -> Result<()> { let state_trie = PartialTrie::Leaf { - nibbles: nibbles(0xABC), + nibbles: nibbles_64(0xABC), value: test_account_1_rlp(), }; - test_state_trie(state_trie, nibbles(0xADE), test_account_2()) + test_state_trie(state_trie, nibbles_64(0xADE), test_account_2()) } #[test] +#[ignore] // TODO: Not valid for state trie, all keys have same len. fn mpt_insert_leaf_insert_key_extends_leaf_key() -> Result<()> { let state_trie = PartialTrie::Leaf { nibbles: nibbles(0xABC), value: test_account_1_rlp(), }; - test_state_trie(state_trie, nibbles(0xABCDE), test_account_2()) + test_state_trie(state_trie, nibbles_64(0xABCDE), test_account_2()) } #[test] +#[ignore] // TODO: Not valid for state trie, all keys have same len. fn mpt_insert_leaf_leaf_key_extends_insert_key() -> Result<()> { let state_trie = PartialTrie::Leaf { nibbles: nibbles(0xABCDE), value: test_account_1_rlp(), }; - test_state_trie(state_trie, nibbles(0xABC), test_account_2()) + test_state_trie(state_trie, nibbles_64(0xABC), test_account_2()) } #[test] @@ -69,7 +73,7 @@ fn mpt_insert_branch_replacing_empty_child() -> Result<()> { value: vec![], }; - test_state_trie(state_trie, nibbles(0xABC), test_account_2()) + test_state_trie(state_trie, nibbles_64(0xABC), test_account_2()) } #[test] @@ -92,7 +96,7 @@ fn mpt_insert_extension_nonoverlapping_keys() -> Result<()> { } .into(), }; - test_state_trie(state_trie, nibbles(0x12345), test_account_2()) + test_state_trie(state_trie, nibbles_64(0x12345), test_account_2()) } #[test] @@ -115,29 +119,33 @@ fn mpt_insert_extension_insert_key_extends_node_key() -> Result<()> { } .into(), }; - test_state_trie(state_trie, nibbles(0xABCDEF), test_account_2()) + test_state_trie(state_trie, nibbles_64(0xABCDEF), test_account_2()) } #[test] fn mpt_insert_branch_to_leaf_same_key() -> Result<()> { let leaf = PartialTrie::Leaf { - nibbles: nibbles(0xBCD), + nibbles: nibbles_count(0xBCD, 63), value: test_account_1_rlp(), } .into(); + let mut children = std::array::from_fn(|_| PartialTrie::Empty.into()); - children[0xA] = leaf; + children[0] = leaf; let state_trie = PartialTrie::Branch { children, value: vec![], }; - test_state_trie(state_trie, nibbles(0xABCD), test_account_2()) + test_state_trie(state_trie, nibbles_64(0xABCD), test_account_2()) } /// Note: The account's storage_root is ignored, as we can't insert a new storage_root without the /// accompanying trie data. An empty trie's storage_root is used instead. fn test_state_trie(state_trie: PartialTrie, k: Nibbles, mut account: AccountRlp) -> Result<()> { + assert_eq!(k.count, 64); + + // Ignore any storage_root; see documentation note. account.storage_root = PartialTrie::Empty.calc_hash(); let trie_inputs = TrieInputs { @@ -177,7 +185,6 @@ fn test_state_trie(state_trie: PartialTrie, k: Nibbles, mut account: AccountRlp) interpreter.push(0xDEADBEEFu32.into()); interpreter.push(value_ptr.into()); // value_ptr interpreter.push(k.packed); // key - interpreter.push(k.count.into()); // num_nibbles interpreter.run()?; assert_eq!( diff --git a/evm/src/cpu/kernel/tests/mpt/mod.rs b/evm/src/cpu/kernel/tests/mpt/mod.rs index 2c7999df..4ac6396e 100644 --- a/evm/src/cpu/kernel/tests/mpt/mod.rs +++ b/evm/src/cpu/kernel/tests/mpt/mod.rs @@ -13,13 +13,22 @@ mod read; /// Note that this preserves all nibbles (eg. `0x123` is not interpreted as `0x0123`). pub(crate) fn nibbles>(v: T) -> Nibbles { let packed = v.into(); - Nibbles { count: Nibbles::get_num_nibbles_in_key(&packed), packed, } } +pub(crate) fn nibbles_64>(v: T) -> Nibbles { + let packed = v.into(); + Nibbles { count: 64, packed } +} + +pub(crate) fn nibbles_count>(v: T, count: usize) -> Nibbles { + let packed = v.into(); + Nibbles { count, packed } +} + pub(crate) fn test_account_1() -> AccountRlp { AccountRlp { nonce: U256::from(1111), From f55e07659c3c8a03dc74fc2ae318bb30c3c5972a Mon Sep 17 00:00:00 2001 From: Hamish Ivey-Law <426294+unzvfu@users.noreply.github.com> Date: Thu, 20 Oct 2022 04:46:01 +1100 Subject: [PATCH 14/31] Implement SUBMOD instruction (#789) * Implement SUBMOD instruction. * Implement recursive circuit version of SUBMOD. --- evm/src/arithmetic/arithmetic_stark.rs | 2 + evm/src/arithmetic/columns.rs | 9 +-- evm/src/arithmetic/modular.rs | 97 ++++++++++++++++---------- evm/src/arithmetic/utils.rs | 26 +++++++ 4 files changed, 95 insertions(+), 39 deletions(-) diff --git a/evm/src/arithmetic/arithmetic_stark.rs b/evm/src/arithmetic/arithmetic_stark.rs index fc168cee..3f9812b0 100644 --- a/evm/src/arithmetic/arithmetic_stark.rs +++ b/evm/src/arithmetic/arithmetic_stark.rs @@ -53,6 +53,8 @@ impl ArithmeticStark { compare::generate(local_values, columns::IS_GT); } else if local_values[columns::IS_ADDMOD].is_one() { modular::generate(local_values, columns::IS_ADDMOD); + } else if local_values[columns::IS_SUBMOD].is_one() { + modular::generate(local_values, columns::IS_SUBMOD); } else if local_values[columns::IS_MULMOD].is_one() { modular::generate(local_values, columns::IS_MULMOD); } else if local_values[columns::IS_MOD].is_one() { diff --git a/evm/src/arithmetic/columns.rs b/evm/src/arithmetic/columns.rs index ee73f223..0478e55e 100644 --- a/evm/src/arithmetic/columns.rs +++ b/evm/src/arithmetic/columns.rs @@ -26,7 +26,8 @@ pub const IS_SDIV: usize = IS_DIV + 1; pub const IS_MOD: usize = IS_SDIV + 1; pub const IS_SMOD: usize = IS_MOD + 1; pub const IS_ADDMOD: usize = IS_SMOD + 1; -pub const IS_MULMOD: usize = IS_ADDMOD + 1; +pub const IS_SUBMOD: usize = IS_ADDMOD + 1; +pub const IS_MULMOD: usize = IS_SUBMOD + 1; pub const IS_LT: usize = IS_MULMOD + 1; pub const IS_GT: usize = IS_LT + 1; pub const IS_SLT: usize = IS_GT + 1; @@ -37,9 +38,9 @@ pub const IS_SAR: usize = IS_SHR + 1; const START_SHARED_COLS: usize = IS_SAR + 1; -pub(crate) const ALL_OPERATIONS: [usize; 16] = [ - IS_ADD, IS_MUL, IS_SUB, IS_DIV, IS_SDIV, IS_MOD, IS_SMOD, IS_ADDMOD, IS_MULMOD, IS_LT, IS_GT, - IS_SLT, IS_SGT, IS_SHL, IS_SHR, IS_SAR, +pub(crate) const ALL_OPERATIONS: [usize; 17] = [ + IS_ADD, IS_MUL, IS_SUB, IS_DIV, IS_SDIV, IS_MOD, IS_SMOD, IS_ADDMOD, IS_SUBMOD, IS_MULMOD, + IS_LT, IS_GT, IS_SLT, IS_SGT, IS_SHL, IS_SHR, IS_SAR, ]; /// Within the Arithmetic Unit, there are shared columns which can be diff --git a/evm/src/arithmetic/modular.rs b/evm/src/arithmetic/modular.rs index 53051cda..df8f7e5a 100644 --- a/evm/src/arithmetic/modular.rs +++ b/evm/src/arithmetic/modular.rs @@ -83,7 +83,7 @@ //! - if modulus is 0, then the test output < modulus, checking that //! the output is reduced, will fail, because output is non-negative. -use num::{BigUint, Zero}; +use num::{bigint::Sign, BigInt, Zero}; use plonky2::field::extension::Extendable; use plonky2::field::packed::PackedField; use plonky2::field::types::Field; @@ -98,55 +98,65 @@ use crate::arithmetic::utils::*; use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer}; use crate::range_check_error; -/// Convert the base-2^16 representation of a number into a BigUint. +/// Convert the base-2^16 representation of a number into a BigInt. /// -/// Given `N` unsigned 16-bit values in `limbs`, return the BigUint +/// Given `N` signed (16 + ε)-bit values in `limbs`, return the BigInt /// /// \sum_{i=0}^{N-1} limbs[i] * β^i. /// -fn columns_to_biguint(limbs: &[i64; N]) -> BigUint { +/// This is basically "evaluate the given polynomial at β". Although +/// the input type is i64, the values must always be in (-2^16 - ε, +/// 2^16 + ε) because of the caller's range check on the inputs (the ε +/// allows us to convert calculated output, which can be bigger than +/// 2^16). +fn columns_to_bigint(limbs: &[i64; N]) -> BigInt { const BASE: i64 = 1i64 << LIMB_BITS; - // Although the input type is i64, the values must always be in - // [0, 2^16 + ε) because of the caller's range check on the inputs - // (the ε allows us to convert calculated output, which can be - // bigger than 2^16). - debug_assert!(limbs.iter().all(|&x| x >= 0)); - - let mut limbs_u32 = Vec::with_capacity(N / 2 + 1); + let mut pos_limbs_u32 = Vec::with_capacity(N / 2 + 1); + let mut neg_limbs_u32 = Vec::with_capacity(N / 2 + 1); let mut cy = 0i64; // cy is necessary to handle ε > 0 for i in 0..(N / 2) { let t = cy + limbs[2 * i] + BASE * limbs[2 * i + 1]; - limbs_u32.push(t as u32); - cy = t >> 32; + pos_limbs_u32.push(if t > 0 { t as u32 } else { 0u32 }); + neg_limbs_u32.push(if t < 0 { -t as u32 } else { 0u32 }); + cy = t / (1i64 << 32); } if N & 1 != 0 { // If N is odd we need to add the last limb on its own let t = cy + limbs[N - 1]; - limbs_u32.push(t as u32); - cy = t >> 32; + pos_limbs_u32.push(if t > 0 { t as u32 } else { 0u32 }); + neg_limbs_u32.push(if t < 0 { -t as u32 } else { 0u32 }); + cy = t / (1i64 << 32); } - limbs_u32.push(cy as u32); + pos_limbs_u32.push(if cy > 0 { cy as u32 } else { 0u32 }); + neg_limbs_u32.push(if cy < 0 { -cy as u32 } else { 0u32 }); - BigUint::from_slice(&limbs_u32) + let pos = BigInt::from_slice(Sign::Plus, &pos_limbs_u32); + let neg = BigInt::from_slice(Sign::Plus, &neg_limbs_u32); + pos - neg } -/// Convert a BigUint into a base-2^16 representation. +/// Convert a BigInt into a base-2^16 representation. /// -/// Given a BigUint `num`, return an array of `N` unsigned 16-bit +/// Given a BigInt `num`, return an array of `N` signed 16-bit /// values, say `limbs`, such that /// /// num = \sum_{i=0}^{N-1} limbs[i] * β^i. /// /// Note that `N` must be at least ceil(log2(num)/16) in order to be /// big enough to hold `num`. -fn biguint_to_columns(num: &BigUint) -> [i64; N] { +fn bigint_to_columns(num: &BigInt) -> [i64; N] { assert!(num.bits() <= 16 * N as u64); let mut output = [0i64; N]; for (i, limb) in num.iter_u32_digits().enumerate() { output[2 * i] = limb as u16 as i64; output[2 * i + 1] = (limb >> LIMB_BITS) as i64; } + if num.sign() == Sign::Minus { + for c in output.iter_mut() { + *c = -*c; + } + } output } @@ -164,12 +174,12 @@ fn generate_modular_op( let input1_limbs = read_value_i64_limbs(lv, MODULAR_INPUT_1); let mut modulus_limbs = read_value_i64_limbs(lv, MODULAR_MODULUS); - // The use of BigUints is just to avoid having to implement - // modular reduction. - let mut modulus = columns_to_biguint(&modulus_limbs); + // BigInts are just used to avoid having to implement modular + // reduction. + let mut modulus = columns_to_bigint(&modulus_limbs); // constr_poly is initialised to the calculated input, and is - // used as such for the BigUint reduction; later, other values are + // used as such for the BigInt reduction; later, other values are // added/subtracted, which is where its meaning as the "constraint // polynomial" comes in. let mut constr_poly = [0i64; 2 * N_LIMBS]; @@ -182,20 +192,25 @@ fn generate_modular_op( mod_is_zero = F::ONE; } - let input = columns_to_biguint(&constr_poly); + let input = columns_to_bigint(&constr_poly); // modulus != 0 here, because, if the given modulus was zero, then // we added 1 to it above. - let output = &input % &modulus; - let output_limbs = biguint_to_columns::(&output); - let quot = (&input - &output) / &modulus; // exact division - let quot_limbs = biguint_to_columns::<{ 2 * N_LIMBS }>("); + let mut output = &input % &modulus; + // output will be -ve (but > -modulus) if input was -ve, so we can + // add modulus to obtain a "canonical" +ve output. + if output.sign() == Sign::Minus { + output += &modulus; + } + let output_limbs = bigint_to_columns::(&output); + let quot = (&input - &output) / &modulus; // exact division; can be -ve + let quot_limbs = bigint_to_columns::<{ 2 * N_LIMBS }>("); // two_exp_256 == 2^256 - let mut two_exp_256 = BigUint::zero(); + let mut two_exp_256 = BigInt::zero(); two_exp_256.set_bit(256, true); // output < modulus here, so the proof requires (output - modulus) % 2^256: - let out_aux_red = biguint_to_columns::(&(two_exp_256 + output - modulus)); + let out_aux_red = bigint_to_columns::(&(two_exp_256 + output - modulus)); // constr_poly is the array of coefficients of the polynomial // @@ -215,7 +230,7 @@ fn generate_modular_op( lv[MODULAR_OUTPUT].copy_from_slice(&output_limbs.map(|c| F::from_canonical_i64(c))); lv[MODULAR_OUT_AUX_RED].copy_from_slice(&out_aux_red.map(|c| F::from_canonical_i64(c))); - lv[MODULAR_QUO_INPUT].copy_from_slice("_limbs.map(|c| F::from_canonical_i64(c))); + lv[MODULAR_QUO_INPUT].copy_from_slice("_limbs.map(|c| F::from_noncanonical_i64(c))); lv[MODULAR_AUX_INPUT].copy_from_slice(&aux_limbs.map(|c| F::from_noncanonical_i64(c))); lv[MODULAR_MOD_IS_ZERO] = mod_is_zero; } @@ -226,6 +241,7 @@ fn generate_modular_op( pub(crate) fn generate(lv: &mut [F; NUM_ARITH_COLUMNS], filter: usize) { match filter { columns::IS_ADDMOD => generate_modular_op(lv, pol_add), + columns::IS_SUBMOD => generate_modular_op(lv, pol_sub), columns::IS_MULMOD => generate_modular_op(lv, pol_mul_wide), columns::IS_MOD => generate_modular_op(lv, |a, _| pol_extend(a)), _ => panic!("generate modular operation called with unknown opcode"), @@ -310,7 +326,10 @@ pub(crate) fn eval_packed_generic( ) { // NB: The CTL code guarantees that filter is 0 or 1, i.e. that // only one of the operations below is "live". - let filter = lv[columns::IS_ADDMOD] + lv[columns::IS_MULMOD] + lv[columns::IS_MOD]; + let filter = lv[columns::IS_ADDMOD] + + lv[columns::IS_MULMOD] + + lv[columns::IS_MOD] + + lv[columns::IS_SUBMOD]; // constr_poly has 2*N_LIMBS limbs let constr_poly = modular_constr_poly(lv, yield_constr, filter); @@ -319,11 +338,13 @@ pub(crate) fn eval_packed_generic( let input1 = read_value(lv, MODULAR_INPUT_1); let add_input = pol_add(input0, input1); + let sub_input = pol_sub(input0, input1); let mul_input = pol_mul_wide(input0, input1); let mod_input = pol_extend(input0); for (input, &filter) in [ (&add_input, &lv[columns::IS_ADDMOD]), + (&sub_input, &lv[columns::IS_SUBMOD]), (&mul_input, &lv[columns::IS_MULMOD]), (&mod_input, &lv[columns::IS_MOD]), ] { @@ -406,6 +427,7 @@ pub(crate) fn eval_ext_circuit, const D: usize>( ) { let filter = builder.add_many_extension([ lv[columns::IS_ADDMOD], + lv[columns::IS_SUBMOD], lv[columns::IS_MULMOD], lv[columns::IS_MOD], ]); @@ -416,11 +438,13 @@ pub(crate) fn eval_ext_circuit, const D: usize>( let input1 = read_value(lv, MODULAR_INPUT_1); let add_input = pol_add_ext_circuit(builder, input0, input1); + let sub_input = pol_sub_ext_circuit(builder, input0, input1); let mul_input = pol_mul_wide_ext_circuit(builder, input0, input1); let mod_input = pol_extend_ext_circuit(builder, input0); for (input, &filter) in [ (&add_input, &lv[columns::IS_ADDMOD]), + (&sub_input, &lv[columns::IS_SUBMOD]), (&mul_input, &lv[columns::IS_MULMOD]), (&mod_input, &lv[columns::IS_MOD]), ] { @@ -458,6 +482,7 @@ mod tests { // if `IS_ADDMOD == 0`, then the constraints should be met even // if all values are garbage. lv[IS_ADDMOD] = F::ZERO; + lv[IS_SUBMOD] = F::ZERO; lv[IS_MULMOD] = F::ZERO; lv[IS_MOD] = F::ZERO; @@ -480,9 +505,10 @@ mod tests { let mut rng = ChaCha8Rng::seed_from_u64(0x6feb51b7ec230f25); let mut lv = [F::default(); NUM_ARITH_COLUMNS].map(|_| F::rand_from_rng(&mut rng)); - for op_filter in [IS_ADDMOD, IS_MOD, IS_MULMOD] { + for op_filter in [IS_ADDMOD, IS_SUBMOD, IS_MOD, IS_MULMOD] { // Reset operation columns, then select one lv[IS_ADDMOD] = F::ZERO; + lv[IS_SUBMOD] = F::ZERO; lv[IS_MULMOD] = F::ZERO; lv[IS_MOD] = F::ZERO; lv[op_filter] = F::ONE; @@ -529,9 +555,10 @@ mod tests { let mut rng = ChaCha8Rng::seed_from_u64(0x6feb51b7ec230f25); let mut lv = [F::default(); NUM_ARITH_COLUMNS].map(|_| F::rand_from_rng(&mut rng)); - for op_filter in [IS_ADDMOD, IS_MOD, IS_MULMOD] { + for op_filter in [IS_ADDMOD, IS_SUBMOD, IS_MOD, IS_MULMOD] { // Reset operation columns, then select one lv[IS_ADDMOD] = F::ZERO; + lv[IS_SUBMOD] = F::ZERO; lv[IS_MULMOD] = F::ZERO; lv[IS_MOD] = F::ZERO; lv[op_filter] = F::ONE; diff --git a/evm/src/arithmetic/utils.rs b/evm/src/arithmetic/utils.rs index 871a9646..74999ab4 100644 --- a/evm/src/arithmetic/utils.rs +++ b/evm/src/arithmetic/utils.rs @@ -118,6 +118,32 @@ pub(crate) fn pol_add_ext_circuit, const D: usize>( sum } +/// Return a(x) - b(x); returned array is bigger than necessary to +/// make the interface consistent with `pol_mul_wide`. +pub(crate) fn pol_sub(a: [T; N_LIMBS], b: [T; N_LIMBS]) -> [T; 2 * N_LIMBS - 1] +where + T: Sub + Copy + Default, +{ + let mut diff = pol_zero(); + for i in 0..N_LIMBS { + diff[i] = a[i] - b[i]; + } + diff +} + +pub(crate) fn pol_sub_ext_circuit, const D: usize>( + builder: &mut CircuitBuilder, + a: [ExtensionTarget; N_LIMBS], + b: [ExtensionTarget; N_LIMBS], +) -> [ExtensionTarget; 2 * N_LIMBS - 1] { + let zero = builder.zero_extension(); + let mut sum = [zero; 2 * N_LIMBS - 1]; + for i in 0..N_LIMBS { + sum[i] = builder.sub_extension(a[i], b[i]); + } + sum +} + /// a(x) -= b(x), but must have deg(a) >= deg(b). pub(crate) fn pol_sub_assign(a: &mut [T], b: &[T]) where From 61b6b161067c6407da7a3dd44101013318050d56 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 20 Oct 2022 14:06:48 +0200 Subject: [PATCH 15/31] Fix interpreter --- evm/src/cpu/kernel/interpreter.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/evm/src/cpu/kernel/interpreter.rs b/evm/src/cpu/kernel/interpreter.rs index a2c25bf6..0b274221 100644 --- a/evm/src/cpu/kernel/interpreter.rs +++ b/evm/src/cpu/kernel/interpreter.rs @@ -6,6 +6,7 @@ use anyhow::{anyhow, bail, ensure}; use ethereum_types::{U256, U512}; use keccak_hash::keccak; use plonky2::field::goldilocks_field::GoldilocksField; +use plonky2_util::ceil_div_usize; use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::assembler::Kernel; @@ -582,7 +583,7 @@ impl<'a> Interpreter<'a> { [Segment::MainMemory as usize] .content .len(); - self.push(U256::from(num_bytes)); + self.push(U256::from(ceil_div_usize(num_bytes, 32) * 32)); } fn run_jumpdest(&mut self) { From 71ed3c43ac1d738b158fc2802514c2992d2e01f3 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 20 Oct 2022 14:32:28 +0200 Subject: [PATCH 16/31] Fix fix interpreter --- .../cpu/kernel/constants/context_metadata.rs | 6 +++- evm/src/cpu/kernel/interpreter.rs | 28 ++++++++--------- evm/src/cpu/kernel/tests/mpt/read.rs | 3 +- evm/src/generation/memory.rs | 30 +++++++++++++++++-- 4 files changed, 48 insertions(+), 19 deletions(-) diff --git a/evm/src/cpu/kernel/constants/context_metadata.rs b/evm/src/cpu/kernel/constants/context_metadata.rs index a2c460fc..0b2dbee5 100644 --- a/evm/src/cpu/kernel/constants/context_metadata.rs +++ b/evm/src/cpu/kernel/constants/context_metadata.rs @@ -23,10 +23,12 @@ pub(crate) enum ContextMetadata { /// Pointer to the initial version of the state trie, at the creation of this context. Used when /// we need to revert a context. StateTrieCheckpointPointer = 9, + /// Size of active memory. + MSize = 10, } impl ContextMetadata { - pub(crate) const COUNT: usize = 10; + pub(crate) const COUNT: usize = 11; pub(crate) fn all() -> [Self; Self::COUNT] { [ @@ -40,6 +42,7 @@ impl ContextMetadata { Self::CallValue, Self::Static, Self::StateTrieCheckpointPointer, + Self::MSize, ] } @@ -56,6 +59,7 @@ impl ContextMetadata { ContextMetadata::CallValue => "CTX_METADATA_CALL_VALUE", ContextMetadata::Static => "CTX_METADATA_STATIC", ContextMetadata::StateTrieCheckpointPointer => "CTX_METADATA_STATE_TRIE_CHECKPOINT_PTR", + ContextMetadata::MSize => "CTX_METADATA_MSIZE", } } } diff --git a/evm/src/cpu/kernel/interpreter.rs b/evm/src/cpu/kernel/interpreter.rs index 0b274221..0e66a08b 100644 --- a/evm/src/cpu/kernel/interpreter.rs +++ b/evm/src/cpu/kernel/interpreter.rs @@ -49,7 +49,7 @@ impl InterpreterMemory { } impl InterpreterMemory { - fn mload_general(&self, context: usize, segment: Segment, offset: usize) -> U256 { + fn mload_general(&mut self, context: usize, segment: Segment, offset: usize) -> U256 { let value = self.context_memory[context].segments[segment as usize].get(offset); assert!( value.bits() <= segment.bit_range(), @@ -145,18 +145,19 @@ impl<'a> Interpreter<'a> { Ok(()) } - fn code(&self) -> &MemorySegmentState { - &self.memory.context_memory[self.context].segments[Segment::Code as usize] + fn code(&mut self) -> &mut MemorySegmentState { + &mut self.memory.context_memory[self.context].segments[Segment::Code as usize] } - fn code_slice(&self, n: usize) -> Vec { - self.code().content[self.offset..self.offset + n] + fn code_slice(&mut self, n: usize) -> Vec { + let offset = self.offset; + self.code().content[offset..offset + n] .iter() .map(|u256| u256.byte(0)) .collect::>() } - pub(crate) fn get_txn_field(&self, field: NormalizedTxnField) -> U256 { + pub(crate) fn get_txn_field(&mut self, field: NormalizedTxnField) -> U256 { self.memory.context_memory[0].segments[Segment::TxnFields as usize].get(field as usize) } @@ -169,7 +170,7 @@ impl<'a> Interpreter<'a> { &self.memory.context_memory[0].segments[Segment::TxnData as usize].content } - pub(crate) fn get_global_metadata_field(&self, field: GlobalMetadata) -> U256 { + pub(crate) fn get_global_metadata_field(&mut self, field: GlobalMetadata) -> U256 { self.memory.context_memory[0].segments[Segment::GlobalMetadata as usize].get(field as usize) } @@ -224,7 +225,8 @@ impl<'a> Interpreter<'a> { } fn run_opcode(&mut self) -> anyhow::Result<()> { - let opcode = self.code().get(self.offset).byte(0); + let offset = self.offset; + let opcode = self.code().get(offset).byte(0); self.incr(1); match opcode { 0x00 => self.run_stop(), // "STOP", @@ -579,11 +581,9 @@ impl<'a> Interpreter<'a> { } fn run_msize(&mut self) { - let num_bytes = self.memory.context_memory[self.context].segments - [Segment::MainMemory as usize] - .content - .len(); - self.push(U256::from(ceil_div_usize(num_bytes, 32) * 32)); + self.push(U256::from( + self.memory.context_memory[self.context].segments[Segment::MainMemory as usize].msize, + )) } fn run_jumpdest(&mut self) { @@ -709,7 +709,7 @@ mod tests { 0x53, ]; let pis = HashMap::new(); - let run = run(&code, 0, vec![], &pis)?; + let mut run = run(&code, 0, vec![], &pis)?; assert_eq!(run.stack(), &[0xff.into(), 0xff00.into()]); assert_eq!( run.memory.context_memory[0].segments[Segment::MainMemory as usize].get(0x27), diff --git a/evm/src/cpu/kernel/tests/mpt/read.rs b/evm/src/cpu/kernel/tests/mpt/read.rs index d8808e24..12728cd1 100644 --- a/evm/src/cpu/kernel/tests/mpt/read.rs +++ b/evm/src/cpu/kernel/tests/mpt/read.rs @@ -31,7 +31,8 @@ fn mpt_read() -> Result<()> { interpreter.push(0xdeadbeefu32.into()); interpreter.push(0xABCDEFu64.into()); interpreter.push(6.into()); - interpreter.push(interpreter.get_global_metadata_field(GlobalMetadata::StateTrieRoot)); + let state_trie_root = interpreter.get_global_metadata_field(GlobalMetadata::StateTrieRoot); + interpreter.push(state_trie_root); interpreter.run()?; assert_eq!(interpreter.stack().len(), 1); diff --git a/evm/src/generation/memory.rs b/evm/src/generation/memory.rs index 944b42a6..18ed2e16 100644 --- a/evm/src/generation/memory.rs +++ b/evm/src/generation/memory.rs @@ -1,4 +1,5 @@ use ethereum_types::U256; +use plonky2_util::ceil_div_usize; use crate::memory::memory_stark::MemoryOp; use crate::memory::segments::Segment; @@ -22,19 +23,34 @@ impl Default for MemoryState { } } -#[derive(Clone, Default, Debug)] +#[derive(Clone, Debug)] pub(crate) struct MemoryContextState { /// The content of each memory segment. pub segments: [MemorySegmentState; Segment::COUNT], } -#[derive(Clone, Default, Debug)] +impl Default for MemoryContextState { + fn default() -> Self { + Self { + segments: Segment::all().map(|segment| MemorySegmentState { + content: vec![], + segment, + msize: 0, + }), + } + } +} + +#[derive(Clone, Debug)] pub(crate) struct MemorySegmentState { pub content: Vec, + pub segment: Segment, + pub msize: usize, } impl MemorySegmentState { - pub(crate) fn get(&self, virtual_addr: usize) -> U256 { + pub(crate) fn get(&mut self, virtual_addr: usize) -> U256 { + self.update_msize(virtual_addr); self.content .get(virtual_addr) .copied() @@ -42,9 +58,17 @@ impl MemorySegmentState { } pub(crate) fn set(&mut self, virtual_addr: usize, value: U256) { + assert_eq!(value >> self.segment.bit_range(), U256::zero()); + self.update_msize(virtual_addr); if virtual_addr >= self.content.len() { self.content.resize(virtual_addr + 1, U256::zero()); } self.content[virtual_addr] = value; } + + fn update_msize(&mut self, virtual_addr: usize) { + let word_size = 256 / self.segment.bit_range(); + let new_msize = ceil_div_usize(virtual_addr + 1, word_size) * 32; + self.msize = self.msize.max(new_msize); + } } From 9982d79999cdbf577e5ba256dee3359164c81434 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 20 Oct 2022 19:23:01 +0200 Subject: [PATCH 17/31] Add msize --- evm/src/cpu/kernel/asm/memory/core.asm | 18 ++++++++++++ evm/src/cpu/kernel/asm/memory/metadata.asm | 20 +++++++++++++ .../cpu/kernel/constants/context_metadata.rs | 2 +- evm/src/cpu/kernel/interpreter.rs | 18 ++++++++++-- evm/src/generation/memory.rs | 29 ++----------------- 5 files changed, 57 insertions(+), 30 deletions(-) diff --git a/evm/src/cpu/kernel/asm/memory/core.asm b/evm/src/cpu/kernel/asm/memory/core.asm index 2b4d2b68..f6bb99b6 100644 --- a/evm/src/cpu/kernel/asm/memory/core.asm +++ b/evm/src/cpu/kernel/asm/memory/core.asm @@ -393,3 +393,21 @@ %mstore_kernel_general_2 // stack: (empty) %endmacro + +%macro mload_main + // stack: offset + DUP1 + // stack: offset, offset + %update_msize + // stack: offset + %mload_current(@SEGMENT_MAIN_MEMORY) +%endmacro + +%macro mstore_main + // stack: offset, value + DUP1 + // stack: offset, offset, value + %update_msize + // stack: offset, value + %mstore_current(@SEGMENT_MAIN_MEMORY) +%endmacro diff --git a/evm/src/cpu/kernel/asm/memory/metadata.asm b/evm/src/cpu/kernel/asm/memory/metadata.asm index 644699e0..f5cc523c 100644 --- a/evm/src/cpu/kernel/asm/memory/metadata.asm +++ b/evm/src/cpu/kernel/asm/memory/metadata.asm @@ -45,3 +45,23 @@ %macro callvalue %mload_context_metadata(@CTX_METADATA_CALL_VALUE) %endmacro + +%macro msize + %mload_context_metadata(@CTX_METADATA_MSIZE) +%endmacro + +%macro update_msize + // stack: offset + %add_const(32) + // stack: 32 + offset + %div_const(32) + // stack: (offset+32)/32 = ceil_div_usize(offset+1, 32) + %mul_const(32) + // stack: ceil_div_usize(offset+1, 32)*32 + %msize + // stack: current_msize, ceil_div_usize(offset+1, 32) * 32 + %max + // stack: new_msize + %mstore_context_metadata(@CTX_METADATA_MSIZE) +%endmacro + diff --git a/evm/src/cpu/kernel/constants/context_metadata.rs b/evm/src/cpu/kernel/constants/context_metadata.rs index 0b2dbee5..fab74373 100644 --- a/evm/src/cpu/kernel/constants/context_metadata.rs +++ b/evm/src/cpu/kernel/constants/context_metadata.rs @@ -23,7 +23,7 @@ pub(crate) enum ContextMetadata { /// Pointer to the initial version of the state trie, at the creation of this context. Used when /// we need to revert a context. StateTrieCheckpointPointer = 9, - /// Size of active memory. + /// Size of the active main memory. MSize = 10, } diff --git a/evm/src/cpu/kernel/interpreter.rs b/evm/src/cpu/kernel/interpreter.rs index 0e66a08b..4cc8c813 100644 --- a/evm/src/cpu/kernel/interpreter.rs +++ b/evm/src/cpu/kernel/interpreter.rs @@ -10,6 +10,7 @@ use plonky2_util::ceil_div_usize; use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::assembler::Kernel; +use crate::cpu::kernel::constants::context_metadata::ContextMetadata; use crate::cpu::kernel::constants::global_metadata::GlobalMetadata; use crate::cpu::kernel::constants::txn_fields::NormalizedTxnField; use crate::generation::memory::{MemoryContextState, MemorySegmentState}; @@ -46,9 +47,7 @@ impl InterpreterMemory { mem } -} -impl InterpreterMemory { fn mload_general(&mut self, context: usize, segment: Segment, offset: usize) -> U256 { let value = self.context_memory[context].segments[segment as usize].get(offset); assert!( @@ -67,6 +66,16 @@ impl InterpreterMemory { ); self.context_memory[context].segments[segment as usize].set(offset, value) } + + fn update_msize(&mut self, context: usize, offset: usize) { + let current_msize = self.context_memory[context].segments + [Segment::ContextMetadata as usize] + .get(ContextMetadata::MSize as usize); + let msize = ceil_div_usize(offset + 1, 32) * 32; + let new_msize = current_msize.max(msize.into()); + self.context_memory[context].segments[Segment::ContextMetadata as usize] + .set(ContextMetadata::MSize as usize, new_msize) + } } pub struct Interpreter<'a> { @@ -502,6 +511,8 @@ impl<'a> Interpreter<'a> { fn run_keccak_general(&mut self) { let context = self.pop().as_usize(); let segment = Segment::all()[self.pop().as_usize()]; + // Not strictly needed but here to avoid surprises with MSIZE. + assert_ne!(segment, Segment::MainMemory, "Call KECCAK256 instead."); let offset = self.pop().as_usize(); let size = self.pop().as_usize(); let bytes = (offset..offset + size) @@ -582,7 +593,8 @@ impl<'a> Interpreter<'a> { fn run_msize(&mut self) { self.push(U256::from( - self.memory.context_memory[self.context].segments[Segment::MainMemory as usize].msize, + self.memory.context_memory[self.context].segments[Segment::ContextMetadata as usize] + .get(ContextMetadata::MSize as usize), )) } diff --git a/evm/src/generation/memory.rs b/evm/src/generation/memory.rs index 18ed2e16..d5dd21ac 100644 --- a/evm/src/generation/memory.rs +++ b/evm/src/generation/memory.rs @@ -23,34 +23,19 @@ impl Default for MemoryState { } } -#[derive(Clone, Debug)] +#[derive(Clone, Default, Debug)] pub(crate) struct MemoryContextState { /// The content of each memory segment. pub segments: [MemorySegmentState; Segment::COUNT], } -impl Default for MemoryContextState { - fn default() -> Self { - Self { - segments: Segment::all().map(|segment| MemorySegmentState { - content: vec![], - segment, - msize: 0, - }), - } - } -} - -#[derive(Clone, Debug)] +#[derive(Clone, Default, Debug)] pub(crate) struct MemorySegmentState { pub content: Vec, - pub segment: Segment, - pub msize: usize, } impl MemorySegmentState { - pub(crate) fn get(&mut self, virtual_addr: usize) -> U256 { - self.update_msize(virtual_addr); + pub(crate) fn get(&self, virtual_addr: usize) -> U256 { self.content .get(virtual_addr) .copied() @@ -58,17 +43,9 @@ impl MemorySegmentState { } pub(crate) fn set(&mut self, virtual_addr: usize, value: U256) { - assert_eq!(value >> self.segment.bit_range(), U256::zero()); - self.update_msize(virtual_addr); if virtual_addr >= self.content.len() { self.content.resize(virtual_addr + 1, U256::zero()); } self.content[virtual_addr] = value; } - - fn update_msize(&mut self, virtual_addr: usize) { - let word_size = 256 / self.segment.bit_range(); - let new_msize = ceil_div_usize(virtual_addr + 1, word_size) * 32; - self.msize = self.msize.max(new_msize); - } } From fab3fe77c0e68e7b238c7e513432d5ddf66b03a2 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 20 Oct 2022 19:28:24 +0200 Subject: [PATCH 18/31] Minor --- evm/src/cpu/kernel/interpreter.rs | 33 +++++++++------------------- evm/src/cpu/kernel/tests/mpt/read.rs | 3 +-- evm/src/generation/memory.rs | 1 - 3 files changed, 11 insertions(+), 26 deletions(-) diff --git a/evm/src/cpu/kernel/interpreter.rs b/evm/src/cpu/kernel/interpreter.rs index 4cc8c813..7df55d44 100644 --- a/evm/src/cpu/kernel/interpreter.rs +++ b/evm/src/cpu/kernel/interpreter.rs @@ -6,7 +6,6 @@ use anyhow::{anyhow, bail, ensure}; use ethereum_types::{U256, U512}; use keccak_hash::keccak; use plonky2::field::goldilocks_field::GoldilocksField; -use plonky2_util::ceil_div_usize; use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::assembler::Kernel; @@ -66,16 +65,6 @@ impl InterpreterMemory { ); self.context_memory[context].segments[segment as usize].set(offset, value) } - - fn update_msize(&mut self, context: usize, offset: usize) { - let current_msize = self.context_memory[context].segments - [Segment::ContextMetadata as usize] - .get(ContextMetadata::MSize as usize); - let msize = ceil_div_usize(offset + 1, 32) * 32; - let new_msize = current_msize.max(msize.into()); - self.context_memory[context].segments[Segment::ContextMetadata as usize] - .set(ContextMetadata::MSize as usize, new_msize) - } } pub struct Interpreter<'a> { @@ -154,19 +143,18 @@ impl<'a> Interpreter<'a> { Ok(()) } - fn code(&mut self) -> &mut MemorySegmentState { - &mut self.memory.context_memory[self.context].segments[Segment::Code as usize] + fn code(&self) -> &MemorySegmentState { + &self.memory.context_memory[self.context].segments[Segment::Code as usize] } - fn code_slice(&mut self, n: usize) -> Vec { - let offset = self.offset; - self.code().content[offset..offset + n] + fn code_slice(&self, n: usize) -> Vec { + self.code().content[self.offset..self.offset + n] .iter() .map(|u256| u256.byte(0)) .collect::>() } - pub(crate) fn get_txn_field(&mut self, field: NormalizedTxnField) -> U256 { + pub(crate) fn get_txn_field(&self, field: NormalizedTxnField) -> U256 { self.memory.context_memory[0].segments[Segment::TxnFields as usize].get(field as usize) } @@ -179,7 +167,7 @@ impl<'a> Interpreter<'a> { &self.memory.context_memory[0].segments[Segment::TxnData as usize].content } - pub(crate) fn get_global_metadata_field(&mut self, field: GlobalMetadata) -> U256 { + pub(crate) fn get_global_metadata_field(&self, field: GlobalMetadata) -> U256 { self.memory.context_memory[0].segments[Segment::GlobalMetadata as usize].get(field as usize) } @@ -234,8 +222,7 @@ impl<'a> Interpreter<'a> { } fn run_opcode(&mut self) -> anyhow::Result<()> { - let offset = self.offset; - let opcode = self.code().get(offset).byte(0); + let opcode = self.code().get(self.offset).byte(0); self.incr(1); match opcode { 0x00 => self.run_stop(), // "STOP", @@ -592,10 +579,10 @@ impl<'a> Interpreter<'a> { } fn run_msize(&mut self) { - self.push(U256::from( + self.push( self.memory.context_memory[self.context].segments[Segment::ContextMetadata as usize] .get(ContextMetadata::MSize as usize), - )) + ) } fn run_jumpdest(&mut self) { @@ -721,7 +708,7 @@ mod tests { 0x53, ]; let pis = HashMap::new(); - let mut run = run(&code, 0, vec![], &pis)?; + let run = run(&code, 0, vec![], &pis)?; assert_eq!(run.stack(), &[0xff.into(), 0xff00.into()]); assert_eq!( run.memory.context_memory[0].segments[Segment::MainMemory as usize].get(0x27), diff --git a/evm/src/cpu/kernel/tests/mpt/read.rs b/evm/src/cpu/kernel/tests/mpt/read.rs index 12728cd1..d8808e24 100644 --- a/evm/src/cpu/kernel/tests/mpt/read.rs +++ b/evm/src/cpu/kernel/tests/mpt/read.rs @@ -31,8 +31,7 @@ fn mpt_read() -> Result<()> { interpreter.push(0xdeadbeefu32.into()); interpreter.push(0xABCDEFu64.into()); interpreter.push(6.into()); - let state_trie_root = interpreter.get_global_metadata_field(GlobalMetadata::StateTrieRoot); - interpreter.push(state_trie_root); + interpreter.push(interpreter.get_global_metadata_field(GlobalMetadata::StateTrieRoot)); interpreter.run()?; assert_eq!(interpreter.stack().len(), 1); diff --git a/evm/src/generation/memory.rs b/evm/src/generation/memory.rs index d5dd21ac..944b42a6 100644 --- a/evm/src/generation/memory.rs +++ b/evm/src/generation/memory.rs @@ -1,5 +1,4 @@ use ethereum_types::U256; -use plonky2_util::ceil_div_usize; use crate::memory::memory_stark::MemoryOp; use crate::memory::segments::Segment; From 0a800f8261c312d540fbabc37f316f4904c860d2 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 20 Oct 2022 19:29:35 +0200 Subject: [PATCH 19/31] Minor --- evm/src/cpu/kernel/asm/memory/metadata.asm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evm/src/cpu/kernel/asm/memory/metadata.asm b/evm/src/cpu/kernel/asm/memory/metadata.asm index f5cc523c..1a495682 100644 --- a/evm/src/cpu/kernel/asm/memory/metadata.asm +++ b/evm/src/cpu/kernel/asm/memory/metadata.asm @@ -57,7 +57,7 @@ %div_const(32) // stack: (offset+32)/32 = ceil_div_usize(offset+1, 32) %mul_const(32) - // stack: ceil_div_usize(offset+1, 32)*32 + // stack: ceil_div_usize(offset+1, 32) * 32 %msize // stack: current_msize, ceil_div_usize(offset+1, 32) * 32 %max From 77d5c625cd1b8e9614086a744d131c66913cf46f Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 20 Oct 2022 19:36:28 +0200 Subject: [PATCH 20/31] Minor --- evm/src/cpu/kernel/interpreter.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evm/src/cpu/kernel/interpreter.rs b/evm/src/cpu/kernel/interpreter.rs index 7df55d44..f6cae73e 100644 --- a/evm/src/cpu/kernel/interpreter.rs +++ b/evm/src/cpu/kernel/interpreter.rs @@ -47,7 +47,7 @@ impl InterpreterMemory { mem } - fn mload_general(&mut self, context: usize, segment: Segment, offset: usize) -> U256 { + fn mload_general(&self, context: usize, segment: Segment, offset: usize) -> U256 { let value = self.context_memory[context].segments[segment as usize].get(offset); assert!( value.bits() <= segment.bit_range(), From 4af2ede6e6e5b54ffa328f960b55469cfc95cb39 Mon Sep 17 00:00:00 2001 From: Hamish Ivey-Law <426294+unzvfu@users.noreply.github.com> Date: Fri, 21 Oct 2022 16:25:38 +1100 Subject: [PATCH 21/31] Implement DIV instruction (#790) * Implement DIV instruction. * cargo fmt, clippy, minor doc update. * Add implementation of circuit version. --- evm/src/arithmetic/arithmetic_stark.rs | 2 + evm/src/arithmetic/columns.rs | 7 ++ evm/src/arithmetic/modular.rs | 106 ++++++++++++++++++------- 3 files changed, 87 insertions(+), 28 deletions(-) diff --git a/evm/src/arithmetic/arithmetic_stark.rs b/evm/src/arithmetic/arithmetic_stark.rs index 3f9812b0..08813a3b 100644 --- a/evm/src/arithmetic/arithmetic_stark.rs +++ b/evm/src/arithmetic/arithmetic_stark.rs @@ -59,6 +59,8 @@ impl ArithmeticStark { modular::generate(local_values, columns::IS_MULMOD); } else if local_values[columns::IS_MOD].is_one() { modular::generate(local_values, columns::IS_MOD); + } else if local_values[columns::IS_DIV].is_one() { + modular::generate(local_values, columns::IS_DIV); } else { todo!("the requested operation has not yet been implemented"); } diff --git a/evm/src/arithmetic/columns.rs b/evm/src/arithmetic/columns.rs index 0478e55e..10bf72d9 100644 --- a/evm/src/arithmetic/columns.rs +++ b/evm/src/arithmetic/columns.rs @@ -85,4 +85,11 @@ pub(crate) const MODULAR_AUX_INPUT: Range = AUX_INPUT_1; pub(crate) const MODULAR_MOD_IS_ZERO: usize = AUX_INPUT_1.end - 1; pub(crate) const MODULAR_OUT_AUX_RED: Range = AUX_INPUT_2; +#[allow(unused)] // TODO: Will be used when hooking into the CPU +pub(crate) const DIV_NUMERATOR: Range = MODULAR_INPUT_0; +#[allow(unused)] // TODO: Will be used when hooking into the CPU +pub(crate) const DIV_DENOMINATOR: Range = MODULAR_MODULUS; +#[allow(unused)] // TODO: Will be used when hooking into the CPU +pub(crate) const DIV_OUTPUT: Range = MODULAR_QUO_INPUT.start..MODULAR_QUO_INPUT.start + 16; + pub const NUM_ARITH_COLUMNS: usize = START_SHARED_COLS + NUM_SHARED_COLS; diff --git a/evm/src/arithmetic/modular.rs b/evm/src/arithmetic/modular.rs index df8f7e5a..d0020166 100644 --- a/evm/src/arithmetic/modular.rs +++ b/evm/src/arithmetic/modular.rs @@ -1,4 +1,5 @@ -//! Support for the EVM modular instructions ADDMOD, MULMOD and MOD. +//! Support for the EVM modular instructions ADDMOD, MULMOD and MOD, +//! as well as DIV. //! //! This crate verifies an EVM modular instruction, which takes three //! 256-bit inputs A, B and M, and produces a 256-bit output C satisfying @@ -82,8 +83,11 @@ //! - if modulus is non-zero, correct output is obtained //! - if modulus is 0, then the test output < modulus, checking that //! the output is reduced, will fail, because output is non-negative. +//! +//! In the case of DIV, we do something similar, except that we "replace" +//! the modulus with "2^256" to force the quotient to be zero. -use num::{bigint::Sign, BigInt, Zero}; +use num::{bigint::Sign, BigInt, One, Zero}; use plonky2::field::extension::Extendable; use plonky2::field::packed::PackedField; use plonky2::field::types::Field; @@ -166,6 +170,7 @@ fn bigint_to_columns(num: &BigInt) -> [i64; N] { /// zero if they are not used. fn generate_modular_op( lv: &mut [F; NUM_ARITH_COLUMNS], + filter: usize, operation: fn([i64; N_LIMBS], [i64; N_LIMBS]) -> [i64; 2 * N_LIMBS - 1], ) { // Inputs are all range-checked in [0, 2^16), so the "as i64" @@ -185,17 +190,31 @@ fn generate_modular_op( let mut constr_poly = [0i64; 2 * N_LIMBS]; constr_poly[..2 * N_LIMBS - 1].copy_from_slice(&operation(input0_limbs, input1_limbs)); + // two_exp_256 == 2^256 + let two_exp_256 = { + let mut t = BigInt::zero(); + t.set_bit(256, true); + t + }; + let mut mod_is_zero = F::ZERO; if modulus.is_zero() { - modulus += 1u32; - modulus_limbs[0] += 1i64; + if filter == columns::IS_DIV { + // set modulus = 2^256 + modulus = two_exp_256.clone(); + // modulus_limbs don't play a role below + } else { + // set modulus = 1 + modulus = BigInt::one(); + modulus_limbs[0] = 1i64; + } mod_is_zero = F::ONE; } let input = columns_to_bigint(&constr_poly); // modulus != 0 here, because, if the given modulus was zero, then - // we added 1 to it above. + // it was set to 1 or 2^256 above let mut output = &input % &modulus; // output will be -ve (but > -modulus) if input was -ve, so we can // add modulus to obtain a "canonical" +ve output. @@ -206,9 +225,6 @@ fn generate_modular_op( let quot = (&input - &output) / &modulus; // exact division; can be -ve let quot_limbs = bigint_to_columns::<{ 2 * N_LIMBS }>("); - // two_exp_256 == 2^256 - let mut two_exp_256 = BigInt::zero(); - two_exp_256.set_bit(256, true); // output < modulus here, so the proof requires (output - modulus) % 2^256: let out_aux_red = bigint_to_columns::(&(two_exp_256 + output - modulus)); @@ -240,10 +256,10 @@ fn generate_modular_op( /// `filter` must be one of `columns::IS_{ADDMOD,MULMOD,MOD}`. pub(crate) fn generate(lv: &mut [F; NUM_ARITH_COLUMNS], filter: usize) { match filter { - columns::IS_ADDMOD => generate_modular_op(lv, pol_add), - columns::IS_SUBMOD => generate_modular_op(lv, pol_sub), - columns::IS_MULMOD => generate_modular_op(lv, pol_mul_wide), - columns::IS_MOD => generate_modular_op(lv, |a, _| pol_extend(a)), + columns::IS_ADDMOD => generate_modular_op(lv, filter, pol_add), + columns::IS_SUBMOD => generate_modular_op(lv, filter, pol_sub), + columns::IS_MULMOD => generate_modular_op(lv, filter, pol_mul_wide), + columns::IS_MOD | columns::IS_DIV => generate_modular_op(lv, filter, |a, _| pol_extend(a)), _ => panic!("generate modular operation called with unknown opcode"), } } @@ -256,7 +272,6 @@ pub(crate) fn generate(lv: &mut [F; NUM_ARITH_COLUMNS], filter: us /// c(x) + q(x) * m(x) + (x - β) * s(x) /// /// and check consistency when m = 0, and that c is reduced. -#[allow(clippy::needless_range_loop)] fn modular_constr_poly( lv: &[P; NUM_ARITH_COLUMNS], yield_constr: &mut ConstraintConsumer

, @@ -284,19 +299,33 @@ fn modular_constr_poly( // modulus = 0. modulus[0] += mod_is_zero; - let output = &lv[MODULAR_OUTPUT]; + let mut output = read_value::(lv, MODULAR_OUTPUT); + + // Needed to compensate for adding mod_is_zero to modulus above, + // since the call eval_packed_generic_lt() below subtracts modulus + // verify in the case of a DIV. + output[0] += mod_is_zero * lv[IS_DIV]; // Verify that the output is reduced, i.e. output < modulus. let out_aux_red = &lv[MODULAR_OUT_AUX_RED]; - let is_less_than = P::ONES; + // this sets is_less_than to 1 unless we get mod_is_zero when + // doing a DIV; in that case, we need is_less_than=0, since the + // function checks + // + // output - modulus == out_aux_red + is_less_than*2^256 + // + // and we were given output = out_aux_red + let is_less_than = P::ONES - mod_is_zero * lv[IS_DIV]; eval_packed_generic_lt( yield_constr, filter, - output, + &output, &modulus, out_aux_red, is_less_than, ); + // restore output[0] + output[0] -= mod_is_zero * lv[IS_DIV]; // prod = q(x) * m(x) let quot = read_value::<{ 2 * N_LIMBS }, _>(lv, MODULAR_QUO_INPUT); @@ -308,7 +337,7 @@ fn modular_constr_poly( // constr_poly = c(x) + q(x) * m(x) let mut constr_poly: [_; 2 * N_LIMBS] = prod[0..2 * N_LIMBS].try_into().unwrap(); - pol_add_assign(&mut constr_poly, output); + pol_add_assign(&mut constr_poly, &output); // constr_poly = c(x) + q(x) * m(x) + (x - β) * s(x) let mut aux = read_value::<{ 2 * N_LIMBS }, _>(lv, MODULAR_AUX_INPUT); @@ -329,7 +358,8 @@ pub(crate) fn eval_packed_generic( let filter = lv[columns::IS_ADDMOD] + lv[columns::IS_MULMOD] + lv[columns::IS_MOD] - + lv[columns::IS_SUBMOD]; + + lv[columns::IS_SUBMOD] + + lv[columns::IS_DIV]; // constr_poly has 2*N_LIMBS limbs let constr_poly = modular_constr_poly(lv, yield_constr, filter); @@ -346,7 +376,7 @@ pub(crate) fn eval_packed_generic( (&add_input, &lv[columns::IS_ADDMOD]), (&sub_input, &lv[columns::IS_SUBMOD]), (&mul_input, &lv[columns::IS_MULMOD]), - (&mod_input, &lv[columns::IS_MOD]), + (&mod_input, &(lv[columns::IS_MOD] + lv[columns::IS_DIV])), ] { // Need constr_poly_copy to be the first argument to // pol_sub_assign, since it is the longer of the two @@ -388,18 +418,25 @@ fn modular_constr_poly_ext_circuit, const D: usize> modulus[0] = builder.add_extension(modulus[0], mod_is_zero); - let output = &lv[MODULAR_OUTPUT]; + let mut output = read_value::(lv, MODULAR_OUTPUT); + output[0] = builder.mul_add_extension(mod_is_zero, lv[IS_DIV], output[0]); + let out_aux_red = &lv[MODULAR_OUT_AUX_RED]; - let is_less_than = builder.one_extension(); + let one = builder.one_extension(); + let is_less_than = + builder.arithmetic_extension(F::NEG_ONE, F::ONE, mod_is_zero, lv[IS_DIV], one); + eval_ext_circuit_lt( builder, yield_constr, filter, - output, + &output, &modulus, out_aux_red, is_less_than, ); + output[0] = + builder.arithmetic_extension(F::NEG_ONE, F::ONE, mod_is_zero, lv[IS_DIV], output[0]); let quot = read_value::<{ 2 * N_LIMBS }, _>(lv, MODULAR_QUO_INPUT); let prod = pol_mul_wide2_ext_circuit(builder, quot, modulus); @@ -409,7 +446,7 @@ fn modular_constr_poly_ext_circuit, const D: usize> } let mut constr_poly: [_; 2 * N_LIMBS] = prod[0..2 * N_LIMBS].try_into().unwrap(); - pol_add_assign_ext_circuit(builder, &mut constr_poly, output); + pol_add_assign_ext_circuit(builder, &mut constr_poly, &output); let mut aux = read_value::<{ 2 * N_LIMBS }, _>(lv, MODULAR_AUX_INPUT); aux[2 * N_LIMBS - 1] = builder.zero_extension(); @@ -430,6 +467,7 @@ pub(crate) fn eval_ext_circuit, const D: usize>( lv[columns::IS_SUBMOD], lv[columns::IS_MULMOD], lv[columns::IS_MOD], + lv[columns::IS_DIV], ]); let constr_poly = modular_constr_poly_ext_circuit(lv, builder, yield_constr, filter); @@ -442,11 +480,12 @@ pub(crate) fn eval_ext_circuit, const D: usize>( let mul_input = pol_mul_wide_ext_circuit(builder, input0, input1); let mod_input = pol_extend_ext_circuit(builder, input0); + let mod_div_filter = builder.add_extension(lv[columns::IS_MOD], lv[columns::IS_DIV]); for (input, &filter) in [ (&add_input, &lv[columns::IS_ADDMOD]), (&sub_input, &lv[columns::IS_SUBMOD]), (&mul_input, &lv[columns::IS_MULMOD]), - (&mod_input, &lv[columns::IS_MOD]), + (&mod_input, &mod_div_filter), ] { let mut constr_poly_copy = constr_poly; pol_sub_assign_ext_circuit(builder, &mut constr_poly_copy, input); @@ -485,6 +524,7 @@ mod tests { lv[IS_SUBMOD] = F::ZERO; lv[IS_MULMOD] = F::ZERO; lv[IS_MOD] = F::ZERO; + lv[IS_DIV] = F::ZERO; let mut constraint_consumer = ConstraintConsumer::new( vec![GoldilocksField(2), GoldilocksField(3), GoldilocksField(5)], @@ -505,12 +545,13 @@ mod tests { let mut rng = ChaCha8Rng::seed_from_u64(0x6feb51b7ec230f25); let mut lv = [F::default(); NUM_ARITH_COLUMNS].map(|_| F::rand_from_rng(&mut rng)); - for op_filter in [IS_ADDMOD, IS_SUBMOD, IS_MOD, IS_MULMOD] { + for op_filter in [IS_ADDMOD, IS_DIV, IS_SUBMOD, IS_MOD, IS_MULMOD] { // Reset operation columns, then select one lv[IS_ADDMOD] = F::ZERO; lv[IS_SUBMOD] = F::ZERO; lv[IS_MULMOD] = F::ZERO; lv[IS_MOD] = F::ZERO; + lv[IS_DIV] = F::ZERO; lv[op_filter] = F::ONE; for i in 0..N_RND_TESTS { @@ -555,12 +596,13 @@ mod tests { let mut rng = ChaCha8Rng::seed_from_u64(0x6feb51b7ec230f25); let mut lv = [F::default(); NUM_ARITH_COLUMNS].map(|_| F::rand_from_rng(&mut rng)); - for op_filter in [IS_ADDMOD, IS_SUBMOD, IS_MOD, IS_MULMOD] { + for op_filter in [IS_ADDMOD, IS_SUBMOD, IS_DIV, IS_MOD, IS_MULMOD] { // Reset operation columns, then select one lv[IS_ADDMOD] = F::ZERO; lv[IS_SUBMOD] = F::ZERO; lv[IS_MULMOD] = F::ZERO; lv[IS_MOD] = F::ZERO; + lv[IS_DIV] = F::ZERO; lv[op_filter] = F::ONE; for _i in 0..N_RND_TESTS { @@ -575,7 +617,11 @@ mod tests { generate(&mut lv, op_filter); // check that the correct output was generated - assert!(lv[MODULAR_OUTPUT].iter().all(|&c| c == F::ZERO)); + if op_filter == IS_DIV { + assert!(lv[DIV_OUTPUT].iter().all(|&c| c == F::ZERO)); + } else { + assert!(lv[MODULAR_OUTPUT].iter().all(|&c| c == F::ZERO)); + } let mut constraint_consumer = ConstraintConsumer::new( vec![GoldilocksField(2), GoldilocksField(3), GoldilocksField(5)], @@ -590,7 +636,11 @@ mod tests { .all(|&acc| acc == F::ZERO)); // Corrupt one output limb by setting it to a non-zero value - let random_oi = MODULAR_OUTPUT.start + rng.gen::() % N_LIMBS; + let random_oi = if op_filter == IS_DIV { + DIV_OUTPUT.start + rng.gen::() % N_LIMBS + } else { + MODULAR_OUTPUT.start + rng.gen::() % N_LIMBS + }; lv[random_oi] = F::from_canonical_u16(rng.gen_range(1..u16::MAX)); eval_packed_generic(&lv, &mut constraint_consumer); From f28ff42fe3aa1fe36b017b83c47f9a930265e875 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 24 Oct 2022 13:35:16 +0200 Subject: [PATCH 22/31] PR feedback --- plonky2/src/recursion/cyclic_recursion.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/plonky2/src/recursion/cyclic_recursion.rs b/plonky2/src/recursion/cyclic_recursion.rs index e968e5e7..8a70e28a 100644 --- a/plonky2/src/recursion/cyclic_recursion.rs +++ b/plonky2/src/recursion/cyclic_recursion.rs @@ -152,8 +152,6 @@ impl, const D: usize> CircuitBuilder { self.register_public_input(base_case.target); common_data.num_public_inputs = self.num_public_inputs(); - // The `conditionally_verify_proof` gadget below takes 2^12 gates, so `degree_bits` cannot be smaller than 13. - common_data.fri_params.degree_bits = common_data.fri_params.degree_bits.max(13); let proof = self.add_virtual_proof_with_pis(&common_data); let dummy_proof = self.add_virtual_proof_with_pis(&common_data); @@ -203,7 +201,12 @@ impl, const D: usize> CircuitBuilder { } let data = self.build::(); - ensure!(data.common == common_data, "Common data does not match."); + ensure!( + data.common == common_data, + "Common data does not match. Final circuit has common data {:?} instead of {:?}.", + data.common, + common_data + ); Ok(( data, @@ -317,6 +320,7 @@ mod tests { use plonky2_field::types::PrimeField64; use crate::field::types::Field; + use crate::gates::noop::NoopGate; use crate::hash::hash_types::RichField; use crate::hash::hashing::hash_n_to_hash_no_pad; use crate::hash::poseidon::{PoseidonHash, PoseidonPermutation}; @@ -360,6 +364,9 @@ mod tests { circuit_digest: builder.add_virtual_hash(), }; builder.verify_proof(proof, &verifier_data, &data.common); + while builder.num_gates() < 1 << 12 { + builder.add_gate(NoopGate, vec![]); + } builder.build::().common } From 0e58efdcc18478676f861b5c74e7db9ff07f83b1 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 25 Oct 2022 10:08:21 +0200 Subject: [PATCH 23/31] Remove Config from `CommonCircuitData` --- evm/src/recursive_verifier.rs | 4 +-- plonky2/examples/bench_recursion.rs | 8 ++--- plonky2/src/iop/generator.rs | 2 +- plonky2/src/plonk/circuit_data.rs | 20 ++++------- .../plonk/conditional_recursive_verifier.rs | 20 +++++------ plonky2/src/plonk/get_challenges.rs | 20 +++++------ plonky2/src/plonk/proof.rs | 12 +++---- plonky2/src/plonk/prover.rs | 10 +++--- plonky2/src/plonk/recursive_verifier.rs | 32 ++++++++--------- plonky2/src/plonk/validate_shape.rs | 4 +-- plonky2/src/plonk/vanishing_poly.rs | 19 +++++----- plonky2/src/plonk/verifier.rs | 6 ++-- plonky2/src/util/serialization.rs | 36 +++++++++---------- 13 files changed, 94 insertions(+), 99 deletions(-) diff --git a/evm/src/recursive_verifier.rs b/evm/src/recursive_verifier.rs index bc64bb57..445497f8 100644 --- a/evm/src/recursive_verifier.rs +++ b/evm/src/recursive_verifier.rs @@ -235,7 +235,7 @@ impl, C: GenericConfig, const D: usize> .zip(verifier_data_target) .enumerate() { - builder.verify_proof( + builder.verify_proof::( recursive_proof, &verifier_data_target, &verifier_data[i].common, @@ -579,7 +579,7 @@ where { let recursive_proofs = std::array::from_fn(|i| { let verifier_data = &verifier_data[i]; - builder.add_virtual_proof_with_pis(&verifier_data.common) + builder.add_virtual_proof_with_pis::(&verifier_data.common) }); let verifier_data = std::array::from_fn(|i| { let verifier_data = &verifier_data[i]; diff --git a/plonky2/examples/bench_recursion.rs b/plonky2/examples/bench_recursion.rs index f4379e7a..c9d24be7 100644 --- a/plonky2/examples/bench_recursion.rs +++ b/plonky2/examples/bench_recursion.rs @@ -32,7 +32,7 @@ use structopt::StructOpt; type ProofTuple = ( ProofWithPublicInputs, VerifierOnlyCircuitData, - CommonCircuitData, + CommonCircuitData, ); #[derive(Clone, StructOpt, Debug)] @@ -112,7 +112,7 @@ where let (inner_proof, inner_vd, inner_cd) = inner; let mut builder = CircuitBuilder::::new(config.clone()); let mut pw = PartialWitness::new(); - let pt = builder.add_virtual_proof_with_pis(inner_cd); + let pt = builder.add_virtual_proof_with_pis::(inner_cd); pw.set_proof_with_pis_target(&pt, inner_proof); let inner_data = VerifierCircuitTarget { @@ -121,7 +121,7 @@ where }; pw.set_verifier_data_target(&inner_data, inner_vd); - builder.verify_proof(pt, &inner_data, inner_cd); + builder.verify_proof::(pt, &inner_data, inner_cd); builder.print_gate_counts(0); if let Some(min_degree_bits) = min_degree_bits { @@ -150,7 +150,7 @@ where fn test_serialization, C: GenericConfig, const D: usize>( proof: &ProofWithPublicInputs, vd: &VerifierOnlyCircuitData, - cd: &CommonCircuitData, + cd: &CommonCircuitData, ) -> Result<()> where [(); C::Hasher::HASH_SIZE]:, diff --git a/plonky2/src/iop/generator.rs b/plonky2/src/iop/generator.rs index 3614b2e4..9948198e 100644 --- a/plonky2/src/iop/generator.rs +++ b/plonky2/src/iop/generator.rs @@ -22,7 +22,7 @@ pub(crate) fn generate_partial_witness< >( inputs: PartialWitness, prover_data: &'a ProverOnlyCircuitData, - common_data: &'a CommonCircuitData, + common_data: &'a CommonCircuitData, ) -> PartitionWitness<'a, F> { let config = &common_data.config; let generators = &prover_data.generators; diff --git a/plonky2/src/plonk/circuit_data.rs b/plonky2/src/plonk/circuit_data.rs index 5143e730..b3747159 100644 --- a/plonky2/src/plonk/circuit_data.rs +++ b/plonky2/src/plonk/circuit_data.rs @@ -106,7 +106,7 @@ impl CircuitConfig { pub struct CircuitData, C: GenericConfig, const D: usize> { pub prover_only: ProverOnlyCircuitData, pub verifier_only: VerifierOnlyCircuitData, - pub common: CommonCircuitData, + pub common: CommonCircuitData, } impl, C: GenericConfig, const D: usize> @@ -196,7 +196,7 @@ pub struct ProverCircuitData< const D: usize, > { pub prover_only: ProverOnlyCircuitData, - pub common: CommonCircuitData, + pub common: CommonCircuitData, } impl, C: GenericConfig, const D: usize> @@ -223,7 +223,7 @@ pub struct VerifierCircuitData< const D: usize, > { pub verifier_only: VerifierOnlyCircuitData, - pub common: CommonCircuitData, + pub common: CommonCircuitData, } impl, C: GenericConfig, const D: usize> @@ -287,17 +287,13 @@ pub struct VerifierOnlyCircuitData, const D: usize> { /// Circuit data required by both the prover and the verifier. #[derive(Debug, Eq, PartialEq)] -pub struct CommonCircuitData< - F: RichField + Extendable, - C: GenericConfig, - const D: usize, -> { +pub struct CommonCircuitData, const D: usize> { pub config: CircuitConfig, pub(crate) fri_params: FriParams, /// The types of gates used in this circuit, along with their prefixes. - pub(crate) gates: Vec>, + pub(crate) gates: Vec>, /// Information on the circuit's selector polynomials. pub(crate) selectors_info: SelectorsInfo, @@ -314,15 +310,13 @@ pub struct CommonCircuitData< pub(crate) num_public_inputs: usize, /// The `{k_i}` valued used in `S_ID_i` in Plonk's permutation argument. - pub(crate) k_is: Vec, + pub(crate) k_is: Vec, /// The number of partial products needed to compute the `Z` polynomials. pub(crate) num_partial_products: usize, } -impl, C: GenericConfig, const D: usize> - CommonCircuitData -{ +impl, const D: usize> CommonCircuitData { pub const fn degree_bits(&self) -> usize { self.fri_params.degree_bits } diff --git a/plonky2/src/plonk/conditional_recursive_verifier.rs b/plonky2/src/plonk/conditional_recursive_verifier.rs index 2c406904..4f54ec3f 100644 --- a/plonky2/src/plonk/conditional_recursive_verifier.rs +++ b/plonky2/src/plonk/conditional_recursive_verifier.rs @@ -30,7 +30,7 @@ pub(crate) fn dummy_proof< C: GenericConfig, const D: usize, >( - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) -> Result<( ProofWithPublicInputs, VerifierOnlyCircuitData, @@ -80,7 +80,7 @@ impl, const D: usize> CircuitBuilder { inner_verifier_data0: &VerifierCircuitTarget, proof_with_pis1: &ProofWithPublicInputsTarget, inner_verifier_data1: &VerifierCircuitTarget, - inner_common_data: &CommonCircuitData, + inner_common_data: &CommonCircuitData, ) where C::Hasher: AlgebraicHasher, { @@ -144,7 +144,7 @@ impl, const D: usize> CircuitBuilder { ), }; - self.verify_proof(selected_proof, &selected_verifier_data, inner_common_data); + self.verify_proof::(selected_proof, &selected_verifier_data, inner_common_data); } /// Conditionally verify a proof with a new generated dummy proof. @@ -153,18 +153,18 @@ impl, const D: usize> CircuitBuilder { condition: BoolTarget, proof_with_pis: &ProofWithPublicInputsTarget, inner_verifier_data: &VerifierCircuitTarget, - inner_common_data: &CommonCircuitData, + inner_common_data: &CommonCircuitData, ) -> (ProofWithPublicInputsTarget, VerifierCircuitTarget) where C::Hasher: AlgebraicHasher, { - let dummy_proof = self.add_virtual_proof_with_pis(inner_common_data); + let dummy_proof = self.add_virtual_proof_with_pis::(inner_common_data); let dummy_verifier_data = VerifierCircuitTarget { constants_sigmas_cap: self .add_virtual_cap(inner_common_data.config.fri_config.cap_height), circuit_digest: self.add_virtual_hash(), }; - self.conditionally_verify_proof( + self.conditionally_verify_proof::( condition, proof_with_pis, inner_verifier_data, @@ -406,10 +406,10 @@ mod tests { // Conditionally verify the two proofs. let mut builder = CircuitBuilder::::new(config); let mut pw = PartialWitness::new(); - let pt = builder.add_virtual_proof_with_pis(&data.common); + let pt = builder.add_virtual_proof_with_pis::(&data.common); pw.set_proof_with_pis_target(&pt, &proof); - let dummy_pt = builder.add_virtual_proof_with_pis(&data.common); - pw.set_proof_with_pis_target(&dummy_pt, &dummy_proof); + let dummy_pt = builder.add_virtual_proof_with_pis::(&data.common); + pw.set_proof_with_pis_target::(&dummy_pt, &dummy_proof); let inner_data = VerifierCircuitTarget { constants_sigmas_cap: builder.add_virtual_cap(data.common.config.fri_config.cap_height), circuit_digest: builder.add_virtual_hash(), @@ -421,7 +421,7 @@ mod tests { }; pw.set_verifier_data_target(&dummy_inner_data, &dummy_data); let b = builder.constant_bool(F::rand().0 % 2 == 0); - builder.conditionally_verify_proof( + builder.conditionally_verify_proof::( b, &pt, &inner_data, diff --git a/plonky2/src/plonk/get_challenges.rs b/plonky2/src/plonk/get_challenges.rs index f497380f..116529e7 100644 --- a/plonky2/src/plonk/get_challenges.rs +++ b/plonky2/src/plonk/get_challenges.rs @@ -30,7 +30,7 @@ fn get_challenges, C: GenericConfig, cons final_poly: &PolynomialCoeffs, pow_witness: F, circuit_digest: &<>::Hasher as Hasher>::Hash, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) -> anyhow::Result> { let config = &common_data.config; let num_challenges = config.num_challenges; @@ -74,7 +74,7 @@ impl, C: GenericConfig, const D: usize> pub(crate) fn fri_query_indices( &self, circuit_digest: &<>::Hasher as Hasher>::Hash, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) -> anyhow::Result> { Ok(self .get_challenges(self.get_public_inputs_hash(), circuit_digest, common_data)? @@ -87,7 +87,7 @@ impl, C: GenericConfig, const D: usize> &self, public_inputs_hash: <>::InnerHasher as Hasher>::Hash, circuit_digest: &<>::Hasher as Hasher>::Hash, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) -> anyhow::Result> { let Proof { wires_cap, @@ -103,7 +103,7 @@ impl, C: GenericConfig, const D: usize> }, } = &self.proof; - get_challenges( + get_challenges::( public_inputs_hash, wires_cap, plonk_zs_partial_products_cap, @@ -126,7 +126,7 @@ impl, C: GenericConfig, const D: usize> &self, public_inputs_hash: <>::InnerHasher as Hasher>::Hash, circuit_digest: &<>::Hasher as Hasher>::Hash, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) -> anyhow::Result> { let CompressedProof { wires_cap, @@ -142,7 +142,7 @@ impl, C: GenericConfig, const D: usize> }, } = &self.proof; - get_challenges( + get_challenges::( public_inputs_hash, wires_cap, plonk_zs_partial_products_cap, @@ -160,7 +160,7 @@ impl, C: GenericConfig, const D: usize> pub(crate) fn get_inferred_elements( &self, challenges: &ProofChallenges, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) -> FriInferredElements { let ProofChallenges { plonk_zeta, @@ -244,7 +244,7 @@ impl, const D: usize> CircuitBuilder { final_poly: &PolynomialCoeffsExtTarget, pow_witness: Target, inner_circuit_digest: HashOutTarget, - inner_common_data: &CommonCircuitData, + inner_common_data: &CommonCircuitData, ) -> ProofChallengesTarget where C::Hasher: AlgebraicHasher, @@ -292,7 +292,7 @@ impl ProofWithPublicInputsTarget { builder: &mut CircuitBuilder, public_inputs_hash: HashOutTarget, inner_circuit_digest: HashOutTarget, - inner_common_data: &CommonCircuitData, + inner_common_data: &CommonCircuitData, ) -> ProofChallengesTarget where C::Hasher: AlgebraicHasher, @@ -311,7 +311,7 @@ impl ProofWithPublicInputsTarget { }, } = &self.proof; - builder.get_challenges( + builder.get_challenges::( public_inputs_hash, wires_cap, plonk_zs_partial_products_cap, diff --git a/plonky2/src/plonk/proof.rs b/plonky2/src/plonk/proof.rs index 2ec26c75..1a7a26db 100644 --- a/plonky2/src/plonk/proof.rs +++ b/plonky2/src/plonk/proof.rs @@ -82,7 +82,7 @@ impl, C: GenericConfig, const D: usize> pub fn compress( self, circuit_digest: &<>::Hasher as Hasher>::Hash, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) -> anyhow::Result> { let indices = self.fri_query_indices(circuit_digest, common_data)?; let compressed_proof = self.proof.compress(&indices, &common_data.fri_params); @@ -106,7 +106,7 @@ impl, C: GenericConfig, const D: usize> pub fn from_bytes( bytes: Vec, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) -> anyhow::Result { let mut buffer = Buffer::new(bytes); let proof = buffer.read_proof_with_public_inputs(common_data)?; @@ -178,7 +178,7 @@ impl, C: GenericConfig, const D: usize> pub fn decompress( self, circuit_digest: &<>::Hasher as Hasher>::Hash, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) -> anyhow::Result> where [(); C::Hasher::HASH_SIZE]:, @@ -198,7 +198,7 @@ impl, C: GenericConfig, const D: usize> pub(crate) fn verify( self, verifier_data: &VerifierOnlyCircuitData, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) -> anyhow::Result<()> where [(); C::Hasher::HASH_SIZE]:, @@ -240,7 +240,7 @@ impl, C: GenericConfig, const D: usize> pub fn from_bytes( bytes: Vec, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) -> anyhow::Result { let mut buffer = Buffer::new(bytes); let proof = buffer.read_compressed_proof_with_public_inputs(common_data)?; @@ -303,7 +303,7 @@ impl, const D: usize> OpeningSet { wires_commitment: &PolynomialBatch, zs_partial_products_commitment: &PolynomialBatch, quotient_polys_commitment: &PolynomialBatch, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) -> Self { let eval_commitment = |z: F::Extension, c: &PolynomialBatch| { c.polynomials diff --git a/plonky2/src/plonk/prover.rs b/plonky2/src/plonk/prover.rs index 8476a2d9..621f20ef 100644 --- a/plonky2/src/plonk/prover.rs +++ b/plonky2/src/plonk/prover.rs @@ -28,7 +28,7 @@ use crate::util::transpose; pub fn prove, C: GenericConfig, const D: usize>( prover_data: &ProverOnlyCircuitData, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, inputs: PartialWitness, timing: &mut TimingTree, ) -> Result> @@ -233,7 +233,7 @@ fn all_wires_permutation_partial_products< betas: &[F], gammas: &[F], prover_data: &ProverOnlyCircuitData, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) -> Vec>> { (0..common_data.config.num_challenges) .map(|i| { @@ -260,7 +260,7 @@ fn wires_permutation_partial_products_and_zs< beta: F, gamma: F, prover_data: &ProverOnlyCircuitData, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) -> Vec> { let degree = common_data.quotient_degree_factor; let subgroup = &prover_data.subgroup; @@ -318,7 +318,7 @@ fn compute_quotient_polys< C: GenericConfig, const D: usize, >( - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, prover_data: &'a ProverOnlyCircuitData, public_inputs_hash: &<>::InnerHasher as Hasher>::Hash, wires_commitment: &'a PolynomialBatch, @@ -424,7 +424,7 @@ fn compute_quotient_polys< public_inputs_hash, ); - let mut quotient_values_batch = eval_vanishing_poly_base_batch( + let mut quotient_values_batch = eval_vanishing_poly_base_batch::( common_data, &indices_batch, &shifted_xs_batch, diff --git a/plonky2/src/plonk/recursive_verifier.rs b/plonky2/src/plonk/recursive_verifier.rs index bb9076be..8dbab974 100644 --- a/plonky2/src/plonk/recursive_verifier.rs +++ b/plonky2/src/plonk/recursive_verifier.rs @@ -19,7 +19,7 @@ impl, const D: usize> CircuitBuilder { &mut self, proof_with_pis: ProofWithPublicInputsTarget, inner_verifier_data: &VerifierCircuitTarget, - inner_common_data: &CommonCircuitData, + inner_common_data: &CommonCircuitData, ) where C::Hasher: AlgebraicHasher, { @@ -29,14 +29,14 @@ impl, const D: usize> CircuitBuilder { ); let public_inputs_hash = self.hash_n_to_hash_no_pad::(proof_with_pis.public_inputs.clone()); - let challenges = proof_with_pis.get_challenges( + let challenges = proof_with_pis.get_challenges::( self, public_inputs_hash, inner_verifier_data.circuit_digest, inner_common_data, ); - self.verify_proof_with_challenges( + self.verify_proof_with_challenges::( proof_with_pis.proof, public_inputs_hash, challenges, @@ -52,7 +52,7 @@ impl, const D: usize> CircuitBuilder { public_inputs_hash: HashOutTarget, challenges: ProofChallengesTarget, inner_verifier_data: &VerifierCircuitTarget, - inner_common_data: &CommonCircuitData, + inner_common_data: &CommonCircuitData, ) where C::Hasher: AlgebraicHasher, { @@ -75,7 +75,7 @@ impl, const D: usize> CircuitBuilder { let vanishing_polys_zeta = with_context!( self, "evaluate the vanishing polynomial at our challenge point, zeta.", - eval_vanishing_poly_circuit( + eval_vanishing_poly_circuit::( self, inner_common_data, challenges.plonk_zeta, @@ -129,9 +129,9 @@ impl, const D: usize> CircuitBuilder { pub fn add_virtual_proof_with_pis>( &mut self, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) -> ProofWithPublicInputsTarget { - let proof = self.add_virtual_proof(common_data); + let proof = self.add_virtual_proof::(common_data); let public_inputs = self.add_virtual_targets(common_data.num_public_inputs); ProofWithPublicInputsTarget { proof, @@ -141,7 +141,7 @@ impl, const D: usize> CircuitBuilder { fn add_virtual_proof>( &mut self, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) -> ProofTarget { let config = &common_data.config; let fri_params = &common_data.fri_params; @@ -159,14 +159,14 @@ impl, const D: usize> CircuitBuilder { wires_cap: self.add_virtual_cap(cap_height), plonk_zs_partial_products_cap: self.add_virtual_cap(cap_height), quotient_polys_cap: self.add_virtual_cap(cap_height), - openings: self.add_opening_set(common_data), + openings: self.add_opening_set::(common_data), opening_proof: self.add_virtual_fri_proof(num_leaves_per_oracle, fri_params), } } fn add_opening_set>( &mut self, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) -> OpeningSetTarget { let config = &common_data.config; let num_challenges = config.num_challenges; @@ -330,7 +330,7 @@ mod tests { ) -> Result<( ProofWithPublicInputs, VerifierOnlyCircuitData, - CommonCircuitData, + CommonCircuitData, )> where [(); C::Hasher::HASH_SIZE]:, @@ -356,7 +356,7 @@ mod tests { >( inner_proof: ProofWithPublicInputs, inner_vd: VerifierOnlyCircuitData, - inner_cd: CommonCircuitData, + inner_cd: CommonCircuitData, config: &CircuitConfig, min_degree_bits: Option, print_gate_counts: bool, @@ -364,7 +364,7 @@ mod tests { ) -> Result<( ProofWithPublicInputs, VerifierOnlyCircuitData, - CommonCircuitData, + CommonCircuitData, )> where InnerC::Hasher: AlgebraicHasher, @@ -372,7 +372,7 @@ mod tests { { let mut builder = CircuitBuilder::::new(config.clone()); let mut pw = PartialWitness::new(); - let pt = builder.add_virtual_proof_with_pis(&inner_cd); + let pt = builder.add_virtual_proof_with_pis::(&inner_cd); pw.set_proof_with_pis_target(&pt, &inner_proof); let inner_data = VerifierCircuitTarget { @@ -385,7 +385,7 @@ mod tests { ); pw.set_hash_target(inner_data.circuit_digest, inner_vd.circuit_digest); - builder.verify_proof(pt, &inner_data, &inner_cd); + builder.verify_proof::(pt, &inner_data, &inner_cd); if print_gate_counts { builder.print_gate_counts(0); @@ -422,7 +422,7 @@ mod tests { >( proof: &ProofWithPublicInputs, vd: &VerifierOnlyCircuitData, - cd: &CommonCircuitData, + cd: &CommonCircuitData, ) -> Result<()> where [(); C::Hasher::HASH_SIZE]:, diff --git a/plonky2/src/plonk/validate_shape.rs b/plonky2/src/plonk/validate_shape.rs index f7ec1b6e..1e6708cc 100644 --- a/plonky2/src/plonk/validate_shape.rs +++ b/plonky2/src/plonk/validate_shape.rs @@ -8,7 +8,7 @@ use crate::plonk::proof::{OpeningSet, Proof, ProofWithPublicInputs}; pub(crate) fn validate_proof_with_pis_shape( proof_with_pis: &ProofWithPublicInputs, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) -> anyhow::Result<()> where F: RichField + Extendable, @@ -32,7 +32,7 @@ where fn validate_proof_shape( proof: &Proof, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) -> anyhow::Result<()> where F: RichField + Extendable, diff --git a/plonky2/src/plonk/vanishing_poly.rs b/plonky2/src/plonk/vanishing_poly.rs index 303f698b..28d43f4f 100644 --- a/plonky2/src/plonk/vanishing_poly.rs +++ b/plonky2/src/plonk/vanishing_poly.rs @@ -25,7 +25,7 @@ pub(crate) fn eval_vanishing_poly< C: GenericConfig, const D: usize, >( - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, x: F::Extension, vars: EvaluationVars, local_zs: &[F::Extension], @@ -39,7 +39,7 @@ pub(crate) fn eval_vanishing_poly< let max_degree = common_data.quotient_degree_factor; let num_prods = common_data.num_partial_products; - let constraint_terms = evaluate_gate_constraints(common_data, vars); + let constraint_terms = evaluate_gate_constraints::(common_data, vars); // The L_0(x) (Z(x) - 1) vanishing terms. let mut vanishing_z_1_terms = Vec::new(); @@ -100,7 +100,7 @@ pub(crate) fn eval_vanishing_poly_base_batch< C: GenericConfig, const D: usize, >( - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, indices_batch: &[usize], xs_batch: &[F], vars_batch: EvaluationVarsBaseBatch, @@ -126,7 +126,8 @@ pub(crate) fn eval_vanishing_poly_base_batch< let num_gate_constraints = common_data.num_gate_constraints; - let constraint_terms_batch = evaluate_gate_constraints_base_batch(common_data, vars_batch); + let constraint_terms_batch = + evaluate_gate_constraints_base_batch::(common_data, vars_batch); debug_assert!(constraint_terms_batch.len() == n * num_gate_constraints); let num_challenges = common_data.config.num_challenges; @@ -210,7 +211,7 @@ pub fn evaluate_gate_constraints< C: GenericConfig, const D: usize, >( - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, vars: EvaluationVars, ) -> Vec { let mut constraints = vec![F::Extension::ZERO; common_data.num_gate_constraints]; @@ -244,7 +245,7 @@ pub fn evaluate_gate_constraints_base_batch< C: GenericConfig, const D: usize, >( - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, vars_batch: EvaluationVarsBaseBatch, ) -> Vec { let mut constraints_batch = vec![F::ZERO; common_data.num_gate_constraints * vars_batch.len()]; @@ -276,7 +277,7 @@ pub fn evaluate_gate_constraints_circuit< const D: usize, >( builder: &mut CircuitBuilder, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, vars: EvaluationTargets, ) -> Vec> { let mut all_gate_constraints = vec![builder.zero_extension(); common_data.num_gate_constraints]; @@ -311,7 +312,7 @@ pub(crate) fn eval_vanishing_poly_circuit< const D: usize, >( builder: &mut CircuitBuilder, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, x: ExtensionTarget, x_pow_deg: ExtensionTarget, vars: EvaluationTargets, @@ -329,7 +330,7 @@ pub(crate) fn eval_vanishing_poly_circuit< let constraint_terms = with_context!( builder, "evaluate gate constraints", - evaluate_gate_constraints_circuit(builder, common_data, vars,) + evaluate_gate_constraints_circuit::(builder, common_data, vars,) ); // The L_0(x) (Z(x) - 1) vanishing terms. diff --git a/plonky2/src/plonk/verifier.rs b/plonky2/src/plonk/verifier.rs index 37ddfffa..52681558 100644 --- a/plonky2/src/plonk/verifier.rs +++ b/plonky2/src/plonk/verifier.rs @@ -15,7 +15,7 @@ use crate::plonk::vars::EvaluationVars; pub(crate) fn verify, C: GenericConfig, const D: usize>( proof_with_pis: ProofWithPublicInputs, verifier_data: &VerifierOnlyCircuitData, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) -> Result<()> where [(); C::Hasher::HASH_SIZE]:, @@ -47,7 +47,7 @@ pub(crate) fn verify_with_challenges< public_inputs_hash: <>::InnerHasher as Hasher>::Hash, challenges: ProofChallenges, verifier_data: &VerifierOnlyCircuitData, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) -> Result<()> where [(); C::Hasher::HASH_SIZE]:, @@ -65,7 +65,7 @@ where let partial_products = &proof.openings.partial_products; // Evaluate the vanishing polynomial at our challenge point, zeta. - let vanishing_polys_zeta = eval_vanishing_poly( + let vanishing_polys_zeta = eval_vanishing_poly::( common_data, challenges.plonk_zeta, vars, diff --git a/plonky2/src/util/serialization.rs b/plonky2/src/util/serialization.rs index 978134b6..076e42f4 100644 --- a/plonky2/src/util/serialization.rs +++ b/plonky2/src/util/serialization.rs @@ -165,7 +165,7 @@ impl Buffer { const D: usize, >( &mut self, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) -> Result> { let config = &common_data.config; let constants = self.read_field_ext_vec::(common_data.num_constants)?; @@ -233,7 +233,7 @@ impl Buffer { const D: usize, >( &mut self, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) -> Result> { let config = &common_data.config; let salt = salt_size(common_data.fri_params.hiding); @@ -312,12 +312,12 @@ impl Buffer { const D: usize, >( &mut self, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) -> Result>> { let config = &common_data.config; let mut fqrs = Vec::with_capacity(config.fri_config.num_query_rounds); for _ in 0..config.fri_config.num_query_rounds { - let initial_trees_proof = self.read_fri_initial_proof(common_data)?; + let initial_trees_proof = self.read_fri_initial_proof::(common_data)?; let steps = common_data .fri_params .reduction_arity_bits @@ -345,13 +345,13 @@ impl Buffer { } fn read_fri_proof, C: GenericConfig, const D: usize>( &mut self, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) -> Result> { let config = &common_data.config; let commit_phase_merkle_caps = (0..common_data.fri_params.reduction_arity_bits.len()) .map(|_| self.read_merkle_cap(config.fri_config.cap_height)) .collect::>>()?; - let query_round_proofs = self.read_fri_query_rounds(common_data)?; + let query_round_proofs = self.read_fri_query_rounds::(common_data)?; let final_poly = PolynomialCoeffs::new( self.read_field_ext_vec::(common_data.fri_params.final_poly_len())?, ); @@ -376,14 +376,14 @@ impl Buffer { } pub fn read_proof, C: GenericConfig, const D: usize>( &mut self, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) -> Result> { let config = &common_data.config; let wires_cap = self.read_merkle_cap(config.fri_config.cap_height)?; let plonk_zs_partial_products_cap = self.read_merkle_cap(config.fri_config.cap_height)?; let quotient_polys_cap = self.read_merkle_cap(config.fri_config.cap_height)?; - let openings = self.read_opening_set(common_data)?; - let opening_proof = self.read_fri_proof(common_data)?; + let openings = self.read_opening_set::(common_data)?; + let opening_proof = self.read_fri_proof::(common_data)?; Ok(Proof { wires_cap, @@ -415,7 +415,7 @@ impl Buffer { const D: usize, >( &mut self, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) -> Result> { let proof = self.read_proof(common_data)?; let public_inputs = self.read_field_vec( @@ -460,7 +460,7 @@ impl Buffer { const D: usize, >( &mut self, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) -> Result> { let config = &common_data.config; let original_indices = (0..config.fri_config.num_query_rounds) @@ -471,7 +471,7 @@ impl Buffer { indices.dedup(); let mut pairs = Vec::new(); for &i in &indices { - pairs.push((i, self.read_fri_initial_proof(common_data)?)); + pairs.push((i, self.read_fri_initial_proof::(common_data)?)); } let initial_trees_proofs = HashMap::from_iter(pairs); @@ -521,13 +521,13 @@ impl Buffer { const D: usize, >( &mut self, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) -> Result> { let config = &common_data.config; let commit_phase_merkle_caps = (0..common_data.fri_params.reduction_arity_bits.len()) .map(|_| self.read_merkle_cap(config.fri_config.cap_height)) .collect::>>()?; - let query_round_proofs = self.read_compressed_fri_query_rounds(common_data)?; + let query_round_proofs = self.read_compressed_fri_query_rounds::(common_data)?; let final_poly = PolynomialCoeffs::new( self.read_field_ext_vec::(common_data.fri_params.final_poly_len())?, ); @@ -560,14 +560,14 @@ impl Buffer { const D: usize, >( &mut self, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) -> Result> { let config = &common_data.config; let wires_cap = self.read_merkle_cap(config.fri_config.cap_height)?; let plonk_zs_partial_products_cap = self.read_merkle_cap(config.fri_config.cap_height)?; let quotient_polys_cap = self.read_merkle_cap(config.fri_config.cap_height)?; - let openings = self.read_opening_set(common_data)?; - let opening_proof = self.read_compressed_fri_proof(common_data)?; + let openings = self.read_opening_set::(common_data)?; + let opening_proof = self.read_compressed_fri_proof::(common_data)?; Ok(CompressedProof { wires_cap, @@ -599,7 +599,7 @@ impl Buffer { const D: usize, >( &mut self, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) -> Result> { let proof = self.read_compressed_proof(common_data)?; let public_inputs = self.read_field_vec( From b97ec3bda1eff132b542f221aa911aba1aa4b3a2 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 25 Oct 2022 10:50:40 +0200 Subject: [PATCH 24/31] New clippy lint --- evm/src/bin/assemble.rs | 2 +- evm/src/cpu/kernel/assembler.rs | 32 +++++++++---------- evm/src/cpu/kernel/cost_estimator.rs | 2 +- evm/src/cpu/kernel/interpreter.rs | 2 +- evm/src/cpu/kernel/opcodes.rs | 2 +- .../cpu/kernel/stack/stack_manipulation.rs | 14 ++++---- evm/src/cpu/kernel/tests/curve_ops.rs | 4 +-- field/src/extension/algebra.rs | 2 +- insertion/src/insertion_gate.rs | 2 +- plonky2/benches/hashing.rs | 2 +- plonky2/examples/square_root.rs | 4 +-- plonky2/src/bin/generate_constants.rs | 2 +- plonky2/src/fri/recursive_verifier.rs | 4 +-- plonky2/src/gates/arithmetic_base.rs | 2 +- plonky2/src/gates/arithmetic_extension.rs | 2 +- plonky2/src/gates/base_sum.rs | 2 +- plonky2/src/gates/constant.rs | 2 +- plonky2/src/gates/exponentiation.rs | 2 +- .../src/gates/high_degree_interpolation.rs | 2 +- plonky2/src/gates/low_degree_interpolation.rs | 2 +- plonky2/src/gates/multiplication_extension.rs | 2 +- plonky2/src/gates/poseidon.rs | 2 +- plonky2/src/gates/poseidon_mds.rs | 2 +- plonky2/src/gates/random_access.rs | 2 +- plonky2/src/gates/reducing.rs | 2 +- plonky2/src/gates/reducing_extension.rs | 2 +- u32/src/gates/add_many_u32.rs | 2 +- u32/src/gates/arithmetic_u32.rs | 2 +- u32/src/gates/comparison.rs | 2 +- u32/src/gates/range_check_u32.rs | 2 +- u32/src/gates/subtraction_u32.rs | 2 +- util/src/lib.rs | 2 +- waksman/src/gates/assert_le.rs | 2 +- waksman/src/gates/switch.rs | 2 +- 34 files changed, 58 insertions(+), 58 deletions(-) diff --git a/evm/src/bin/assemble.rs b/evm/src/bin/assemble.rs index 68eeadf8..1cf3a67c 100644 --- a/evm/src/bin/assemble.rs +++ b/evm/src/bin/assemble.rs @@ -9,5 +9,5 @@ fn main() { args.next(); let file_contents: Vec<_> = args.map(|path| fs::read_to_string(path).unwrap()).collect(); let assembled = assemble_to_bytes(&file_contents[..]); - println!("{}", encode(&assembled)); + println!("{}", encode(assembled)); } diff --git a/evm/src/cpu/kernel/assembler.rs b/evm/src/cpu/kernel/assembler.rs index 09af71bf..aad2dd53 100644 --- a/evm/src/cpu/kernel/assembler.rs +++ b/evm/src/cpu/kernel/assembler.rs @@ -83,7 +83,7 @@ impl Macro { self.params .iter() .position(|p| p == param) - .unwrap_or_else(|| panic!("No such param: {} {:?}", param, &self.params)) + .unwrap_or_else(|| panic!("No such param: {param} {:?}", &self.params)) } } @@ -140,7 +140,7 @@ fn find_macros(files: &[File]) -> HashMap { items: items.clone(), }; let old = macros.insert(signature.clone(), macro_); - assert!(old.is_none(), "Duplicate macro signature: {:?}", signature); + assert!(old.is_none(), "Duplicate macro signature: {signature:?}"); } } } @@ -186,9 +186,9 @@ fn expand_macro_call( }; let macro_ = macros .get(&signature) - .unwrap_or_else(|| panic!("No such macro: {:?}", signature)); + .unwrap_or_else(|| panic!("No such macro: {signature:?}")); - let get_actual_label = |macro_label| format!("@{}.{}", macro_counter, macro_label); + let get_actual_label = |macro_label| format!("@{macro_counter}.{macro_label}"); let get_arg = |var| { let param_index = macro_.get_param_index(var); @@ -242,7 +242,7 @@ fn inline_constants(body: Vec, constants: &HashMap) -> Vec { - panic!("Item should have been expanded already: {:?}", item); + panic!("Item should have been expanded already: {item:?}"); } Item::GlobalLabelDeclaration(label) => { let old = global_labels.insert(label.clone(), *offset); - assert!(old.is_none(), "Duplicate global label: {}", label); + assert!(old.is_none(), "Duplicate global label: {label}"); } Item::LocalLabelDeclaration(label) => { let old = local_labels.insert(label.clone(), *offset); - assert!(old.is_none(), "Duplicate local label: {}", label); + assert!(old.is_none(), "Duplicate local label: {label}"); } Item::Push(target) => *offset += 1 + push_target_size(target) as usize, Item::ProverInput(prover_input_fn) => { @@ -319,7 +319,7 @@ fn assemble_file( | Item::Repeat(_, _) | Item::StackManipulation(_, _) | Item::MacroLabelDeclaration(_) => { - panic!("Item should have been expanded already: {:?}", item); + panic!("Item should have been expanded already: {item:?}"); } Item::GlobalLabelDeclaration(_) | Item::LocalLabelDeclaration(_) => { // Nothing to do; we processed labels in the prior phase. @@ -331,7 +331,7 @@ fn assemble_file( let offset = local_labels .get(&label) .or_else(|| global_labels.get(&label)) - .unwrap_or_else(|| panic!("No such label: {}", label)); + .unwrap_or_else(|| panic!("No such label: {label}")); // We want the BYTES_PER_OFFSET least significant bytes in BE order. // It's easiest to rev the first BYTES_PER_OFFSET bytes of the LE encoding. (0..BYTES_PER_OFFSET) @@ -339,9 +339,9 @@ fn assemble_file( .map(|i| offset.to_le_bytes()[i as usize]) .collect() } - PushTarget::MacroLabel(v) => panic!("Macro label not in a macro: {}", v), - PushTarget::MacroVar(v) => panic!("Variable not in a macro: {}", v), - PushTarget::Constant(c) => panic!("Constant wasn't inlined: {}", c), + PushTarget::MacroLabel(v) => panic!("Macro label not in a macro: {v}"), + PushTarget::MacroVar(v) => panic!("Variable not in a macro: {v}"), + PushTarget::Constant(c) => panic!("Constant wasn't inlined: {c}"), }; code.push(get_push_opcode(target_bytes.len() as u8)); code.extend(target_bytes); @@ -362,9 +362,9 @@ fn push_target_size(target: &PushTarget) -> u8 { match target { PushTarget::Literal(n) => u256_to_trimmed_be_bytes(n).len() as u8, PushTarget::Label(_) => BYTES_PER_OFFSET, - PushTarget::MacroLabel(v) => panic!("Macro label not in a macro: {}", v), - PushTarget::MacroVar(v) => panic!("Variable not in a macro: {}", v), - PushTarget::Constant(c) => panic!("Constant wasn't inlined: {}", c), + PushTarget::MacroLabel(v) => panic!("Macro label not in a macro: {v}"), + PushTarget::MacroVar(v) => panic!("Variable not in a macro: {v}"), + PushTarget::Constant(c) => panic!("Constant wasn't inlined: {c}"), } } diff --git a/evm/src/cpu/kernel/cost_estimator.rs b/evm/src/cpu/kernel/cost_estimator.rs index 3dfcf63a..ae837647 100644 --- a/evm/src/cpu/kernel/cost_estimator.rs +++ b/evm/src/cpu/kernel/cost_estimator.rs @@ -21,7 +21,7 @@ fn cost_estimate_item(item: &Item) -> u32 { Push(Label(_)) => cost_estimate_push(BYTES_PER_OFFSET as usize), ProverInput(_) => 1, StandardOp(op) => cost_estimate_standard_op(op.as_str()), - _ => panic!("Unexpected item: {:?}", item), + _ => panic!("Unexpected item: {item:?}"), } } diff --git a/evm/src/cpu/kernel/interpreter.rs b/evm/src/cpu/kernel/interpreter.rs index f6cae73e..8057792b 100644 --- a/evm/src/cpu/kernel/interpreter.rs +++ b/evm/src/cpu/kernel/interpreter.rs @@ -328,7 +328,7 @@ impl<'a> Interpreter<'a> { if self.debug_offsets.contains(&self.offset) { println!("At {}, stack={:?}", self.offset_name(), self.stack()); } else if let Some(label) = self.offset_label() { - println!("At {}", label); + println!("At {label}"); } Ok(()) diff --git a/evm/src/cpu/kernel/opcodes.rs b/evm/src/cpu/kernel/opcodes.rs index 20601267..31074ff6 100644 --- a/evm/src/cpu/kernel/opcodes.rs +++ b/evm/src/cpu/kernel/opcodes.rs @@ -134,6 +134,6 @@ pub(crate) fn get_opcode(mnemonic: &str) -> u8 { "REVERT" => 0xfd, "INVALID" => 0xfe, "SELFDESTRUCT" => 0xff, - _ => panic!("Unrecognized mnemonic {}", mnemonic), + _ => panic!("Unrecognized mnemonic {mnemonic}"), } } diff --git a/evm/src/cpu/kernel/stack/stack_manipulation.rs b/evm/src/cpu/kernel/stack/stack_manipulation.rs index 36e4b83a..73a24029 100644 --- a/evm/src/cpu/kernel/stack/stack_manipulation.rs +++ b/evm/src/cpu/kernel/stack/stack_manipulation.rs @@ -35,7 +35,7 @@ fn expand(names: Vec, replacements: Vec) -> stack_blocks.insert(name.clone(), n); (0..n) .map(|i| { - let literal_name = format!("@{}.{}", name, i); + let literal_name = format!("@{name}.{i}"); StackItem::NamedItem(literal_name) }) .collect_vec() @@ -52,7 +52,7 @@ fn expand(names: Vec, replacements: Vec) -> let n = *stack_blocks.get(&name).unwrap(); (0..n) .map(|i| { - let literal_name = format!("@{}.{}", name, i); + let literal_name = format!("@{name}.{i}"); StackItem::NamedItem(literal_name) }) .collect_vec() @@ -64,7 +64,7 @@ fn expand(names: Vec, replacements: Vec) -> StackReplacement::MacroLabel(_) | StackReplacement::MacroVar(_) | StackReplacement::Constant(_) => { - panic!("Should have been expanded already: {:?}", item) + panic!("Should have been expanded already: {item:?}") } }) .collect_vec(); @@ -157,7 +157,7 @@ fn shortest_path( } } - panic!("No path found from {:?} to {:?}", src, dst) + panic!("No path found from {src:?} to {dst:?}") } /// A node in the priority queue used by Dijkstra's algorithm. @@ -279,7 +279,7 @@ impl StackOp { PushTarget::MacroLabel(_) | PushTarget::MacroVar(_) | PushTarget::Constant(_) => { - panic!("Target should have been expanded already: {:?}", target) + panic!("Target should have been expanded already: {target:?}") } }; // This is just a rough estimate; we can update it after implementing PUSH. @@ -326,8 +326,8 @@ impl StackOp { match self { StackOp::Push(target) => Item::Push(target), Pop => Item::StandardOp("POP".into()), - StackOp::Dup(n) => Item::StandardOp(format!("DUP{}", n)), - StackOp::Swap(n) => Item::StandardOp(format!("SWAP{}", n)), + StackOp::Dup(n) => Item::StandardOp(format!("DUP{n}")), + StackOp::Swap(n) => Item::StandardOp(format!("SWAP{n}")), } } } diff --git a/evm/src/cpu/kernel/tests/curve_ops.rs b/evm/src/cpu/kernel/tests/curve_ops.rs index 0aaa94ea..9ba24185 100644 --- a/evm/src/cpu/kernel/tests/curve_ops.rs +++ b/evm/src/cpu/kernel/tests/curve_ops.rs @@ -150,7 +150,7 @@ mod bn { assert_eq!(stack, vec![U256::MAX, U256::MAX]); // Multiple calls - let ec_mul_hex = format!("0x{:x}", ec_mul); + let ec_mul_hex = format!("0x{ec_mul:x}"); let initial_stack = u256ify([ "0xdeadbeef", s, @@ -288,7 +288,7 @@ mod secp { assert_eq!(stack, u256ify([identity.1, identity.0])?); // Multiple calls - let ec_mul_hex = format!("0x{:x}", ec_mul); + let ec_mul_hex = format!("0x{ec_mul:x}"); let initial_stack = u256ify([ "0xdeadbeef", s, diff --git a/field/src/extension/algebra.rs b/field/src/extension/algebra.rs index 54bea694..5840ae81 100644 --- a/field/src/extension/algebra.rs +++ b/field/src/extension/algebra.rs @@ -45,7 +45,7 @@ impl, const D: usize> Display for ExtensionAlgebra { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "({})", self.0[0])?; for i in 1..D { - write!(f, " + ({})*b^{}", self.0[i], i)?; + write!(f, " + ({})*b^{i}", self.0[i])?; } Ok(()) } diff --git a/insertion/src/insertion_gate.rs b/insertion/src/insertion_gate.rs index ea8f4194..2757dd23 100644 --- a/insertion/src/insertion_gate.rs +++ b/insertion/src/insertion_gate.rs @@ -73,7 +73,7 @@ impl, const D: usize> InsertionGate { impl, const D: usize> Gate for InsertionGate { fn id(&self) -> String { - format!("{:?}", self, D) + format!("{self:?}") } fn eval_unfiltered(&self, vars: EvaluationVars) -> Vec { diff --git a/plonky2/benches/hashing.rs b/plonky2/benches/hashing.rs index 4632c4c4..673e0572 100644 --- a/plonky2/benches/hashing.rs +++ b/plonky2/benches/hashing.rs @@ -24,7 +24,7 @@ pub(crate) fn bench_keccak(c: &mut Criterion) { pub(crate) fn bench_poseidon(c: &mut Criterion) { c.bench_function( - &format!("poseidon<{}, {}>", type_name::(), SPONGE_WIDTH), + &format!("poseidon<{}, {SPONGE_WIDTH}>", type_name::()), |b| { b.iter_batched( || F::rand_arr::(), diff --git a/plonky2/examples/square_root.rs b/plonky2/examples/square_root.rs index 0bc89f47..7d4d2fee 100644 --- a/plonky2/examples/square_root.rs +++ b/plonky2/examples/square_root.rs @@ -31,7 +31,7 @@ impl, const D: usize> SimpleGenerator let x_squared = witness.get_target(self.x_squared); let x = x_squared.sqrt().unwrap(); - println!("Square root: {}", x); + println!("Square root: {x}"); out_buffer.set_target(self.x, x); } @@ -75,7 +75,7 @@ fn main() -> Result<()> { let proof = data.prove(pw.clone())?; let x_squared_actual = proof.public_inputs[0]; - println!("Field element (square): {}", x_squared_actual); + println!("Field element (square): {x_squared_actual}"); data.verify(proof) } diff --git a/plonky2/src/bin/generate_constants.rs b/plonky2/src/bin/generate_constants.rs index 258c6b78..c5f8fae2 100644 --- a/plonky2/src/bin/generate_constants.rs +++ b/plonky2/src/bin/generate_constants.rs @@ -21,7 +21,7 @@ pub(crate) fn main() { // Print the constants in the format we prefer in our code. for chunk in constants.chunks(4) { for (i, c) in chunk.iter().enumerate() { - print!("{:#018x},", c); + print!("{c:#018x},"); if i != chunk.len() - 1 { print!(" "); } diff --git a/plonky2/src/fri/recursive_verifier.rs b/plonky2/src/fri/recursive_verifier.rs index ac7e3a87..d14420c1 100644 --- a/plonky2/src/fri/recursive_verifier.rs +++ b/plonky2/src/fri/recursive_verifier.rs @@ -176,7 +176,7 @@ impl, const D: usize> CircuitBuilder { with_context!( self, level, - &format!("verify one (of {}) query rounds", num_queries), + &format!("verify one (of {num_queries}) query rounds"), self.fri_verifier_query_round::( instance, challenges, @@ -207,7 +207,7 @@ impl, const D: usize> CircuitBuilder { { with_context!( self, - &format!("verify {}'th initial Merkle proof", i), + &format!("verify {i}'th initial Merkle proof"), self.verify_merkle_proof_to_cap_with_cap_index::( evals.clone(), x_index_bits, diff --git a/plonky2/src/gates/arithmetic_base.rs b/plonky2/src/gates/arithmetic_base.rs index 207af2d0..03560faf 100644 --- a/plonky2/src/gates/arithmetic_base.rs +++ b/plonky2/src/gates/arithmetic_base.rs @@ -53,7 +53,7 @@ impl ArithmeticGate { impl, const D: usize> Gate for ArithmeticGate { fn id(&self) -> String { - format!("{:?}", self) + format!("{self:?}") } fn eval_unfiltered(&self, vars: EvaluationVars) -> Vec { diff --git a/plonky2/src/gates/arithmetic_extension.rs b/plonky2/src/gates/arithmetic_extension.rs index e4e07f83..26b7074b 100644 --- a/plonky2/src/gates/arithmetic_extension.rs +++ b/plonky2/src/gates/arithmetic_extension.rs @@ -51,7 +51,7 @@ impl ArithmeticExtensionGate { impl, const D: usize> Gate for ArithmeticExtensionGate { fn id(&self) -> String { - format!("{:?}", self) + format!("{self:?}") } fn eval_unfiltered(&self, vars: EvaluationVars) -> Vec { diff --git a/plonky2/src/gates/base_sum.rs b/plonky2/src/gates/base_sum.rs index 5be54eeb..1252c8e3 100644 --- a/plonky2/src/gates/base_sum.rs +++ b/plonky2/src/gates/base_sum.rs @@ -49,7 +49,7 @@ impl BaseSumGate { impl, const D: usize, const B: usize> Gate for BaseSumGate { fn id(&self) -> String { - format!("{:?} + Base: {}", self, B) + format!("{self:?} + Base: {B}") } fn eval_unfiltered(&self, vars: EvaluationVars) -> Vec { diff --git a/plonky2/src/gates/constant.rs b/plonky2/src/gates/constant.rs index 7d68b088..513caad9 100644 --- a/plonky2/src/gates/constant.rs +++ b/plonky2/src/gates/constant.rs @@ -33,7 +33,7 @@ impl ConstantGate { impl, const D: usize> Gate for ConstantGate { fn id(&self) -> String { - format!("{:?}", self) + format!("{self:?}") } fn eval_unfiltered(&self, vars: EvaluationVars) -> Vec { diff --git a/plonky2/src/gates/exponentiation.rs b/plonky2/src/gates/exponentiation.rs index aa977308..ca1ba395 100644 --- a/plonky2/src/gates/exponentiation.rs +++ b/plonky2/src/gates/exponentiation.rs @@ -70,7 +70,7 @@ impl, const D: usize> ExponentiationGate { impl, const D: usize> Gate for ExponentiationGate { fn id(&self) -> String { - format!("{:?}", self, D) + format!("{self:?}") } fn eval_unfiltered(&self, vars: EvaluationVars) -> Vec { diff --git a/plonky2/src/gates/high_degree_interpolation.rs b/plonky2/src/gates/high_degree_interpolation.rs index bcdf2276..0bc4ab65 100644 --- a/plonky2/src/gates/high_degree_interpolation.rs +++ b/plonky2/src/gates/high_degree_interpolation.rs @@ -87,7 +87,7 @@ impl, const D: usize> Gate for HighDegreeInterpolationGate { fn id(&self) -> String { - format!("{:?}", self, D) + format!("{self:?}") } fn eval_unfiltered(&self, vars: EvaluationVars) -> Vec { diff --git a/plonky2/src/gates/low_degree_interpolation.rs b/plonky2/src/gates/low_degree_interpolation.rs index 3edc4175..8fd2ed47 100644 --- a/plonky2/src/gates/low_degree_interpolation.rs +++ b/plonky2/src/gates/low_degree_interpolation.rs @@ -80,7 +80,7 @@ impl, const D: usize> LowDegreeInterpolationGate, const D: usize> Gate for LowDegreeInterpolationGate { fn id(&self) -> String { - format!("{:?}", self, D) + format!("{self:?}") } fn eval_unfiltered(&self, vars: EvaluationVars) -> Vec { diff --git a/plonky2/src/gates/multiplication_extension.rs b/plonky2/src/gates/multiplication_extension.rs index ab29bba7..8e6b44d7 100644 --- a/plonky2/src/gates/multiplication_extension.rs +++ b/plonky2/src/gates/multiplication_extension.rs @@ -48,7 +48,7 @@ impl MulExtensionGate { impl, const D: usize> Gate for MulExtensionGate { fn id(&self) -> String { - format!("{:?}", self) + format!("{self:?}") } fn eval_unfiltered(&self, vars: EvaluationVars) -> Vec { diff --git a/plonky2/src/gates/poseidon.rs b/plonky2/src/gates/poseidon.rs index 3ae8db83..26ec2594 100644 --- a/plonky2/src/gates/poseidon.rs +++ b/plonky2/src/gates/poseidon.rs @@ -98,7 +98,7 @@ impl, const D: usize> PoseidonGate { impl, const D: usize> Gate for PoseidonGate { fn id(&self) -> String { - format!("{:?}", self, SPONGE_WIDTH) + format!("{self:?}") } fn eval_unfiltered(&self, vars: EvaluationVars) -> Vec { diff --git a/plonky2/src/gates/poseidon_mds.rs b/plonky2/src/gates/poseidon_mds.rs index 2ccfa640..289246e1 100644 --- a/plonky2/src/gates/poseidon_mds.rs +++ b/plonky2/src/gates/poseidon_mds.rs @@ -117,7 +117,7 @@ impl + Poseidon, const D: usize> PoseidonMdsGate + Poseidon, const D: usize> Gate for PoseidonMdsGate { fn id(&self) -> String { - format!("{:?}", self, SPONGE_WIDTH) + format!("{self:?}") } fn eval_unfiltered(&self, vars: EvaluationVars) -> Vec { diff --git a/plonky2/src/gates/random_access.rs b/plonky2/src/gates/random_access.rs index fa365f16..3ea2f55e 100644 --- a/plonky2/src/gates/random_access.rs +++ b/plonky2/src/gates/random_access.rs @@ -115,7 +115,7 @@ impl, const D: usize> RandomAccessGate { impl, const D: usize> Gate for RandomAccessGate { fn id(&self) -> String { - format!("{:?}", self, D) + format!("{self:?}") } fn eval_unfiltered(&self, vars: EvaluationVars) -> Vec { diff --git a/plonky2/src/gates/reducing.rs b/plonky2/src/gates/reducing.rs index 31960b64..02f8ac2d 100644 --- a/plonky2/src/gates/reducing.rs +++ b/plonky2/src/gates/reducing.rs @@ -55,7 +55,7 @@ impl ReducingGate { impl, const D: usize> Gate for ReducingGate { fn id(&self) -> String { - format!("{:?}", self) + format!("{self:?}") } fn eval_unfiltered(&self, vars: EvaluationVars) -> Vec { diff --git a/plonky2/src/gates/reducing_extension.rs b/plonky2/src/gates/reducing_extension.rs index 2ae25059..8b04ec99 100644 --- a/plonky2/src/gates/reducing_extension.rs +++ b/plonky2/src/gates/reducing_extension.rs @@ -58,7 +58,7 @@ impl ReducingExtensionGate { impl, const D: usize> Gate for ReducingExtensionGate { fn id(&self) -> String { - format!("{:?}", self) + format!("{self:?}") } fn eval_unfiltered(&self, vars: EvaluationVars) -> Vec { diff --git a/u32/src/gates/add_many_u32.rs b/u32/src/gates/add_many_u32.rs index 622c3df3..f37075cd 100644 --- a/u32/src/gates/add_many_u32.rs +++ b/u32/src/gates/add_many_u32.rs @@ -84,7 +84,7 @@ impl, const D: usize> U32AddManyGate { impl, const D: usize> Gate for U32AddManyGate { fn id(&self) -> String { - format!("{:?}", self) + format!("{self:?}") } fn eval_unfiltered(&self, vars: EvaluationVars) -> Vec { diff --git a/u32/src/gates/arithmetic_u32.rs b/u32/src/gates/arithmetic_u32.rs index c05ed86c..47889954 100644 --- a/u32/src/gates/arithmetic_u32.rs +++ b/u32/src/gates/arithmetic_u32.rs @@ -86,7 +86,7 @@ impl, const D: usize> U32ArithmeticGate { impl, const D: usize> Gate for U32ArithmeticGate { fn id(&self) -> String { - format!("{:?}", self) + format!("{self:?}") } fn eval_unfiltered(&self, vars: EvaluationVars) -> Vec { diff --git a/u32/src/gates/comparison.rs b/u32/src/gates/comparison.rs index 6af34208..a2a0cfcf 100644 --- a/u32/src/gates/comparison.rs +++ b/u32/src/gates/comparison.rs @@ -91,7 +91,7 @@ impl, const D: usize> ComparisonGate { impl, const D: usize> Gate for ComparisonGate { fn id(&self) -> String { - format!("{:?}", self, D) + format!("{self:?}") } fn eval_unfiltered(&self, vars: EvaluationVars) -> Vec { diff --git a/u32/src/gates/range_check_u32.rs b/u32/src/gates/range_check_u32.rs index 615abb98..6e8f2cd5 100644 --- a/u32/src/gates/range_check_u32.rs +++ b/u32/src/gates/range_check_u32.rs @@ -48,7 +48,7 @@ impl, const D: usize> U32RangeCheckGate { impl, const D: usize> Gate for U32RangeCheckGate { fn id(&self) -> String { - format!("{:?}", self) + format!("{self:?}") } fn eval_unfiltered(&self, vars: EvaluationVars) -> Vec { diff --git a/u32/src/gates/subtraction_u32.rs b/u32/src/gates/subtraction_u32.rs index 3737de55..b08d900b 100644 --- a/u32/src/gates/subtraction_u32.rs +++ b/u32/src/gates/subtraction_u32.rs @@ -80,7 +80,7 @@ impl, const D: usize> U32SubtractionGate { impl, const D: usize> Gate for U32SubtractionGate { fn id(&self) -> String { - format!("{:?}", self) + format!("{self:?}") } fn eval_unfiltered(&self, vars: EvaluationVars) -> Vec { diff --git a/util/src/lib.rs b/util/src/lib.rs index bbc2af98..b22a4236 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -31,7 +31,7 @@ pub fn log2_ceil(n: usize) -> usize { /// Computes `log_2(n)`, panicking if `n` is not a power of two. pub fn log2_strict(n: usize) -> usize { let res = n.trailing_zeros(); - assert!(n.wrapping_shr(res) == 1, "Not a power of two: {}", n); + assert!(n.wrapping_shr(res) == 1, "Not a power of two: {n}"); // Tell the optimizer about the semantics of `log2_strict`. i.e. it can replace `n` with // `1 << res` and vice versa. assume(n == 1 << res); diff --git a/waksman/src/gates/assert_le.rs b/waksman/src/gates/assert_le.rs index c67a7125..27242370 100644 --- a/waksman/src/gates/assert_le.rs +++ b/waksman/src/gates/assert_le.rs @@ -84,7 +84,7 @@ impl, const D: usize> AssertLessThanGate { impl, const D: usize> Gate for AssertLessThanGate { fn id(&self) -> String { - format!("{:?}", self, D) + format!("{self:?}") } fn eval_unfiltered(&self, vars: EvaluationVars) -> Vec { diff --git a/waksman/src/gates/switch.rs b/waksman/src/gates/switch.rs index 2c2ca8c8..4509bf0a 100644 --- a/waksman/src/gates/switch.rs +++ b/waksman/src/gates/switch.rs @@ -74,7 +74,7 @@ impl, const D: usize> SwitchGate { impl, const D: usize> Gate for SwitchGate { fn id(&self) -> String { - format!("{:?}", self, D) + format!("{self:?}") } fn eval_unfiltered(&self, vars: EvaluationVars) -> Vec { From e8fd8bd1d8196afabf976aea0f123a109648ac0e Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 25 Oct 2022 22:51:24 +0200 Subject: [PATCH 25/31] Add type hints --- plonky2/src/recursion/cyclic_recursion.rs | 35 ++++++++++++----------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/plonky2/src/recursion/cyclic_recursion.rs b/plonky2/src/recursion/cyclic_recursion.rs index 8a70e28a..10fe9dd0 100644 --- a/plonky2/src/recursion/cyclic_recursion.rs +++ b/plonky2/src/recursion/cyclic_recursion.rs @@ -25,7 +25,7 @@ pub struct CyclicRecursionData< > { proof: &'a Option>, verifier_data: &'a VerifierOnlyCircuitData, - common_data: &'a CommonCircuitData, + common_data: &'a CommonCircuitData, } pub struct CyclicRecursionTarget { @@ -49,7 +49,7 @@ pub struct CyclicPublicInputs< impl, C: GenericConfig, const D: usize> CyclicPublicInputs { - fn from_slice(slice: &[F], common_data: &CommonCircuitData) -> Result + fn from_slice(slice: &[F], common_data: &CommonCircuitData) -> Result where C::Hasher: AlgebraicHasher, { @@ -90,7 +90,7 @@ pub struct CyclicPublicInputsTarget { impl CyclicPublicInputsTarget { fn from_slice, C: GenericConfig, const D: usize>( slice: &[Target], - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) -> Result { let cap_len = common_data.config.fri_config.num_cap_elements(); let len = slice.len(); @@ -120,7 +120,7 @@ impl, const D: usize> CircuitBuilder { mut self, previous_virtual_public_inputs: &[Target], previous_base_case: Target, - mut common_data: CommonCircuitData, + mut common_data: CommonCircuitData, ) -> Result<(CircuitData, CyclicRecursionTarget)> where C::Hasher: AlgebraicHasher, @@ -153,10 +153,11 @@ impl, const D: usize> CircuitBuilder { common_data.num_public_inputs = self.num_public_inputs(); - let proof = self.add_virtual_proof_with_pis(&common_data); - let dummy_proof = self.add_virtual_proof_with_pis(&common_data); + let proof = self.add_virtual_proof_with_pis::(&common_data); + let dummy_proof = self.add_virtual_proof_with_pis::(&common_data); - let pis = CyclicPublicInputsTarget::from_slice(&proof.public_inputs, &common_data)?; + let pis = + CyclicPublicInputsTarget::from_slice::(&proof.public_inputs, &common_data)?; // Check that the previous base case flag was boolean. self.assert_bool(pis.base_case); // Check that we cannot go from a non-base case to a base case by checking `previous_base_case - base_case \in {0,1}`. @@ -182,7 +183,7 @@ impl, const D: usize> CircuitBuilder { } // Verify the dummy proof if `base_case` is set to true, otherwise verify the "real" proof. - self.conditionally_verify_proof( + self.conditionally_verify_proof::( base_case, &dummy_proof, &dummy_verifier_data, @@ -250,7 +251,7 @@ where cyclic_recursion_data.verifier_data, ); } else { - let (dummy_proof, dummy_data) = dummy_proof(cyclic_recursion_data.common_data)?; + let (dummy_proof, dummy_data) = dummy_proof::(cyclic_recursion_data.common_data)?; pw.set_bool_target(cyclic_recursion_data_target.base_case, true); let mut proof = dummy_proof.clone(); proof.public_inputs[0..public_inputs.len()].copy_from_slice(public_inputs); @@ -298,12 +299,12 @@ pub fn check_cyclic_proof_verifier_data< >( proof: &ProofWithPublicInputs, verifier_data: &VerifierOnlyCircuitData, - common_data: &CommonCircuitData, + common_data: &CommonCircuitData, ) -> Result<()> where C::Hasher: AlgebraicHasher, { - let pis = CyclicPublicInputs::from_slice(&proof.public_inputs, common_data)?; + let pis = CyclicPublicInputs::::from_slice(&proof.public_inputs, common_data)?; if !pis.base_case { ensure!(verifier_data.constants_sigmas_cap == pis.constants_sigmas_cap); ensure!(verifier_data.circuit_digest == pis.circuit_digest); @@ -338,7 +339,7 @@ mod tests { F: RichField + Extendable, C: GenericConfig, const D: usize, - >() -> CommonCircuitData + >() -> CommonCircuitData where C::Hasher: AlgebraicHasher, [(); C::Hasher::HASH_SIZE]:, @@ -348,22 +349,22 @@ mod tests { let data = builder.build::(); let config = CircuitConfig::standard_recursion_config(); let mut builder = CircuitBuilder::::new(config); - let proof = builder.add_virtual_proof_with_pis(&data.common); + let proof = builder.add_virtual_proof_with_pis::(&data.common); let verifier_data = VerifierCircuitTarget { constants_sigmas_cap: builder.add_virtual_cap(data.common.config.fri_config.cap_height), circuit_digest: builder.add_virtual_hash(), }; - builder.verify_proof(proof, &verifier_data, &data.common); + builder.verify_proof::(proof, &verifier_data, &data.common); let data = builder.build::(); let config = CircuitConfig::standard_recursion_config(); let mut builder = CircuitBuilder::::new(config); - let proof = builder.add_virtual_proof_with_pis(&data.common); + let proof = builder.add_virtual_proof_with_pis::(&data.common); let verifier_data = VerifierCircuitTarget { constants_sigmas_cap: builder.add_virtual_cap(data.common.config.fri_config.cap_height), circuit_digest: builder.add_virtual_hash(), }; - builder.verify_proof(proof, &verifier_data, &data.common); + builder.verify_proof::(proof, &verifier_data, &data.common); while builder.num_gates() < 1 << 12 { builder.add_gate(NoopGate, vec![]); } @@ -414,7 +415,7 @@ mod tests { // Add cyclic recursion gadget. let (cyclic_circuit_data, cyclic_data_target) = - builder.cyclic_recursion(&old_pis, old_base_case, common_data)?; + builder.cyclic_recursion::(&old_pis, old_base_case, common_data)?; let cyclic_recursion_data = CyclicRecursionData { proof: &None, // Base case: We don't have a proof to put here yet. From 7afbddb0b6b082a3f99be449d7998019a107a577 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 25 Oct 2022 22:57:36 +0200 Subject: [PATCH 26/31] Add `goal_common_data` to `CircuitBuilder` --- plonky2/src/plonk/circuit_builder.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/plonky2/src/plonk/circuit_builder.rs b/plonky2/src/plonk/circuit_builder.rs index 82a72504..5327fc9b 100644 --- a/plonky2/src/plonk/circuit_builder.rs +++ b/plonky2/src/plonk/circuit_builder.rs @@ -83,6 +83,11 @@ pub struct CircuitBuilder, const D: usize> { /// List of constant generators used to fill the constant wires. constant_generators: Vec>, + + /// Optional common data. When it is `Some(goal_data)`, the `build` function panics if the resulting + /// common data doesn't equal `goal_data`. + /// This is used in cyclic recursion. + pub(crate) goal_common_data: Option>, } impl, const D: usize> CircuitBuilder { @@ -102,6 +107,7 @@ impl, const D: usize> CircuitBuilder { arithmetic_results: HashMap::new(), current_slots: HashMap::new(), constant_generators: Vec::new(), + goal_common_data: None, }; builder.check_config(); builder @@ -830,6 +836,9 @@ impl, const D: usize> CircuitBuilder { k_is, num_partial_products, }; + if let Some(goal_data) = self.goal_common_data { + assert_eq!(goal_data, common); + } let prover_only = ProverOnlyCircuitData { generators: self.generators, From 341e1ebeec714c79f3af2ec144d161eb5236f9ed Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Wed, 26 Oct 2022 10:58:38 +0200 Subject: [PATCH 27/31] Working --- plonky2/src/recursion/cyclic_recursion.rs | 116 ++++++++-------------- 1 file changed, 40 insertions(+), 76 deletions(-) diff --git a/plonky2/src/recursion/cyclic_recursion.rs b/plonky2/src/recursion/cyclic_recursion.rs index 10fe9dd0..2b3693e1 100644 --- a/plonky2/src/recursion/cyclic_recursion.rs +++ b/plonky2/src/recursion/cyclic_recursion.rs @@ -10,7 +10,7 @@ use crate::iop::target::{BoolTarget, Target}; use crate::iop::witness::{PartialWitness, Witness}; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_data::{ - CircuitData, CommonCircuitData, VerifierCircuitTarget, VerifierOnlyCircuitData, + CommonCircuitData, VerifierCircuitTarget, VerifierOnlyCircuitData, }; use crate::plonk::config::Hasher; use crate::plonk::config::{AlgebraicHasher, GenericConfig}; @@ -43,7 +43,6 @@ pub struct CyclicPublicInputs< > { pub circuit_digest: HashOut, pub constants_sigmas_cap: MerkleCap, - pub base_case: bool, } impl, C: GenericConfig, const D: usize> @@ -53,30 +52,23 @@ impl, C: GenericConfig, const D: usize> where C::Hasher: AlgebraicHasher, { - // The structure of the public inputs is `[...,circuit_digest, constants_sigmas_cap, base_case]`. + // The structure of the public inputs is `[..., circuit_digest, constants_sigmas_cap]`. let cap_len = common_data.config.fri_config.num_cap_elements(); let len = slice.len(); - ensure!(len >= 4 + 4 * cap_len + 1, "Not enough public inputs"); - let base_case = slice[len - 1]; - ensure!( - base_case.is_one() || base_case.is_zero(), - "Base case flag {:?} is not binary", - base_case - ); + ensure!(len >= 4 + 4 * cap_len, "Not enough public inputs"); let constants_sigmas_cap = MerkleCap( (0..cap_len) .map(|i| HashOut { - elements: std::array::from_fn(|j| slice[len - 1 - 4 * (cap_len - i) + j]), + elements: std::array::from_fn(|j| slice[len - 4 * (cap_len - i) + j]), }) .collect(), ); let circuit_digest = - HashOut::from_partial(&slice[len - 5 - 4 * cap_len..len - 1 - 4 * cap_len]); + HashOut::from_partial(&slice[len - 4 - 4 * cap_len..len - 4 * cap_len]); Ok(Self { circuit_digest, constants_sigmas_cap, - base_case: base_case.is_one(), }) } } @@ -84,7 +76,6 @@ impl, C: GenericConfig, const D: usize> pub struct CyclicPublicInputsTarget { pub circuit_digest: HashOutTarget, pub constants_sigmas_cap: MerkleCapTarget, - pub base_case: BoolTarget, } impl CyclicPublicInputsTarget { @@ -94,34 +85,31 @@ impl CyclicPublicInputsTarget { ) -> Result { let cap_len = common_data.config.fri_config.num_cap_elements(); let len = slice.len(); - ensure!(len >= 4 + 4 * cap_len + 1, "Not enough public inputs"); - let base_case = BoolTarget::new_unsafe(slice[len - 1]); + ensure!(len >= 4 + 4 * cap_len, "Not enough public inputs"); let constants_sigmas_cap = MerkleCapTarget( (0..cap_len) .map(|i| HashOutTarget { - elements: std::array::from_fn(|j| slice[len - 1 - 4 * (cap_len - i) + j]), + elements: std::array::from_fn(|j| slice[len - 4 * (cap_len - i) + j]), }) .collect(), ); let circuit_digest = HashOutTarget { - elements: std::array::from_fn(|i| slice[len - 5 - 4 * cap_len + i]), + elements: std::array::from_fn(|i| slice[len - 4 - 4 * cap_len + i]), }; Ok(Self { circuit_digest, constants_sigmas_cap, - base_case, }) } } impl, const D: usize> CircuitBuilder { pub fn cyclic_recursion>( - mut self, + &mut self, previous_virtual_public_inputs: &[Target], - previous_base_case: Target, - mut common_data: CommonCircuitData, - ) -> Result<(CircuitData, CyclicRecursionTarget)> + common_data: &mut CommonCircuitData, + ) -> Result> where C::Hasher: AlgebraicHasher, [(); C::Hasher::HASH_SIZE]:, @@ -147,22 +135,15 @@ impl, const D: usize> CircuitBuilder { }; // Flag set to true for the base case of the cycle where we verify a dummy proof to bootstrap the cycle. Set to false otherwise. - // Unsafe is ok since `base_case` is a public input and its booleaness should be checked in the verifier. - let base_case = self.add_virtual_bool_target_unsafe(); - self.register_public_input(base_case.target); + let base_case = self.add_virtual_bool_target_safe(); common_data.num_public_inputs = self.num_public_inputs(); - let proof = self.add_virtual_proof_with_pis::(&common_data); - let dummy_proof = self.add_virtual_proof_with_pis::(&common_data); + let proof = self.add_virtual_proof_with_pis::(common_data); + let dummy_proof = self.add_virtual_proof_with_pis::(common_data); let pis = - CyclicPublicInputsTarget::from_slice::(&proof.public_inputs, &common_data)?; - // Check that the previous base case flag was boolean. - self.assert_bool(pis.base_case); - // Check that we cannot go from a non-base case to a base case by checking `previous_base_case - base_case \in {0,1}`. - let decrease = BoolTarget::new_unsafe(self.sub(pis.base_case.target, base_case.target)); - self.assert_bool(decrease); + CyclicPublicInputsTarget::from_slice::(&proof.public_inputs, common_data)?; // Connect previous verifier data to current one. This guarantees that every proof in the cycle uses the same verifier data. self.connect_hashes(pis.circuit_digest, verifier_data.circuit_digest); for (h0, h1) in pis @@ -174,7 +155,6 @@ impl, const D: usize> CircuitBuilder { self.connect_hashes(*h0, *h1); } - self.connect(previous_base_case, pis.base_case.target); for (x, y) in previous_virtual_public_inputs .iter() .zip(&proof.public_inputs) @@ -189,7 +169,7 @@ impl, const D: usize> CircuitBuilder { &dummy_verifier_data, &proof, &verifier_data, - &common_data, + common_data, ); // Make sure we have enough gates to match `common_data`. @@ -201,24 +181,13 @@ impl, const D: usize> CircuitBuilder { self.add_gate_to_gate_set(g.clone()); } - let data = self.build::(); - ensure!( - data.common == common_data, - "Common data does not match. Final circuit has common data {:?} instead of {:?}.", - data.common, - common_data - ); - - Ok(( - data, - CyclicRecursionTarget { - proof, - verifier_data, - dummy_proof, - dummy_verifier_data, - base_case, - }, - )) + Ok(CyclicRecursionTarget { + proof, + verifier_data, + dummy_proof, + dummy_verifier_data, + base_case, + }) } } @@ -256,8 +225,6 @@ where let mut proof = dummy_proof.clone(); proof.public_inputs[0..public_inputs.len()].copy_from_slice(public_inputs); let pis_len = proof.public_inputs.len(); - // A base case must be following another base case. - proof.public_inputs[pis_len - 1] = F::ONE; // The circuit checks that the verifier data is the same throughout the cycle, so // we set the verifier data to the "real" verifier data even though it's unused in the base case. let num_cap = cyclic_recursion_data @@ -265,7 +232,7 @@ where .config .fri_config .num_cap_elements(); - let s = pis_len - 5 - 4 * num_cap; + let s = pis_len - 4 - 4 * num_cap; proof.public_inputs[s..s + 4] .copy_from_slice(&cyclic_recursion_data.verifier_data.circuit_digest.elements); for i in 0..num_cap { @@ -305,10 +272,8 @@ where C::Hasher: AlgebraicHasher, { let pis = CyclicPublicInputs::::from_slice(&proof.public_inputs, common_data)?; - if !pis.base_case { - ensure!(verifier_data.constants_sigmas_cap == pis.constants_sigmas_cap); - ensure!(verifier_data.circuit_digest == pis.circuit_digest); - } + ensure!(verifier_data.constants_sigmas_cap == pis.constants_sigmas_cap); + ensure!(verifier_data.circuit_digest == pis.circuit_digest); Ok(()) } @@ -325,7 +290,6 @@ mod tests { use crate::hash::hash_types::RichField; use crate::hash::hashing::hash_n_to_hash_no_pad; use crate::hash::poseidon::{PoseidonHash, PoseidonPermutation}; - use crate::iop::target::BoolTarget; use crate::iop::witness::PartialWitness; use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_data::{CircuitConfig, CommonCircuitData, VerifierCircuitTarget}; @@ -386,24 +350,15 @@ mod tests { builder.register_public_inputs(&initial_hash.elements); // Hash from the previous proof. let old_hash = builder.add_virtual_hash(); - // Flag set to true if the last proof was a base case. - let old_base_case = builder.add_virtual_target(); // The input hash is either the previous hash or the initial hash depending on whether // the last proof was a base case. - let input_hash = builder.select_hash( - BoolTarget::new_unsafe(old_base_case), - initial_hash, - old_hash, - ); + let input_hash = builder.add_virtual_hash(); let h = builder.hash_n_to_hash_no_pad::(input_hash.elements.to_vec()); builder.register_public_inputs(&h.elements); // Previous counter. let old_counter = builder.add_virtual_target(); let one = builder.one(); - let old_not_base_case = builder.sub(one, old_base_case); - // New counter is the previous counter +1 if the previous proof wasn't a base case. - let new_counter = builder.add(old_counter, old_not_base_case); - builder.register_public_input(new_counter); + let new_counter = builder.add_virtual_public_input(); let old_pis = [ initial_hash.elements.as_slice(), old_hash.elements.as_slice(), @@ -411,11 +366,19 @@ mod tests { ] .concat(); - let common_data = common_data_for_recursion::(); + let mut common_data = common_data_for_recursion::(); // Add cyclic recursion gadget. - let (cyclic_circuit_data, cyclic_data_target) = - builder.cyclic_recursion::(&old_pis, old_base_case, common_data)?; + let cyclic_data_target = builder.cyclic_recursion::(&old_pis, &mut common_data)?; + let input_hash_bis = + builder.select_hash(cyclic_data_target.base_case, initial_hash, old_hash); + builder.connect_hashes(input_hash, input_hash_bis); + let not_base_case = builder.sub(one, cyclic_data_target.base_case.target); + // New counter is the previous counter +1 if the previous proof wasn't a base case. + let new_counter_bis = builder.add(old_counter, not_base_case); + builder.connect(new_counter, new_counter_bis); + + let cyclic_circuit_data = builder.build::(); let cyclic_recursion_data = CyclicRecursionData { proof: &None, // Base case: We don't have a proof to put here yet. @@ -482,6 +445,7 @@ mod tests { let initial_hash = &proof.public_inputs[..4]; let hash = &proof.public_inputs[4..8]; let counter = proof.public_inputs[8]; + dbg!(counter); let mut h: [F; 4] = initial_hash.try_into().unwrap(); assert_eq!( hash, From 73e9e6119b232f43df96e756fbdca3ed4fe870cd Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Wed, 26 Oct 2022 11:02:45 +0200 Subject: [PATCH 28/31] `CyclicPublicInputs` is just `VerifierOnlyCircuitData` --- plonky2/src/recursion/cyclic_recursion.rs | 29 +++++------------------ 1 file changed, 6 insertions(+), 23 deletions(-) diff --git a/plonky2/src/recursion/cyclic_recursion.rs b/plonky2/src/recursion/cyclic_recursion.rs index 2b3693e1..0dd3b730 100644 --- a/plonky2/src/recursion/cyclic_recursion.rs +++ b/plonky2/src/recursion/cyclic_recursion.rs @@ -36,21 +36,10 @@ pub struct CyclicRecursionTarget { pub base_case: BoolTarget, } -pub struct CyclicPublicInputs< - F: RichField + Extendable, - C: GenericConfig, - const D: usize, -> { - pub circuit_digest: HashOut, - pub constants_sigmas_cap: MerkleCap, -} - -impl, C: GenericConfig, const D: usize> - CyclicPublicInputs -{ - fn from_slice(slice: &[F], common_data: &CommonCircuitData) -> Result +impl, const D: usize> VerifierOnlyCircuitData { + fn from_slice(slice: &[C::F], common_data: &CommonCircuitData) -> Result where - C::Hasher: AlgebraicHasher, + C::Hasher: AlgebraicHasher, { // The structure of the public inputs is `[..., circuit_digest, constants_sigmas_cap]`. let cap_len = common_data.config.fri_config.num_cap_elements(); @@ -73,12 +62,7 @@ impl, C: GenericConfig, const D: usize> } } -pub struct CyclicPublicInputsTarget { - pub circuit_digest: HashOutTarget, - pub constants_sigmas_cap: MerkleCapTarget, -} - -impl CyclicPublicInputsTarget { +impl VerifierCircuitTarget { fn from_slice, C: GenericConfig, const D: usize>( slice: &[Target], common_data: &CommonCircuitData, @@ -142,8 +126,7 @@ impl, const D: usize> CircuitBuilder { let proof = self.add_virtual_proof_with_pis::(common_data); let dummy_proof = self.add_virtual_proof_with_pis::(common_data); - let pis = - CyclicPublicInputsTarget::from_slice::(&proof.public_inputs, common_data)?; + let pis = VerifierCircuitTarget::from_slice::(&proof.public_inputs, common_data)?; // Connect previous verifier data to current one. This guarantees that every proof in the cycle uses the same verifier data. self.connect_hashes(pis.circuit_digest, verifier_data.circuit_digest); for (h0, h1) in pis @@ -271,7 +254,7 @@ pub fn check_cyclic_proof_verifier_data< where C::Hasher: AlgebraicHasher, { - let pis = CyclicPublicInputs::::from_slice(&proof.public_inputs, common_data)?; + let pis = VerifierOnlyCircuitData::::from_slice(&proof.public_inputs, common_data)?; ensure!(verifier_data.constants_sigmas_cap == pis.constants_sigmas_cap); ensure!(verifier_data.circuit_digest == pis.circuit_digest); From 8a60fe19eae81764e9152be287f213df514a0b18 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Wed, 26 Oct 2022 15:04:47 +0200 Subject: [PATCH 29/31] Cyclic recursion gadget doesn't move circuit builder --- plonky2/src/plonk/circuit_data.rs | 1 + plonky2/src/recursion/cyclic_recursion.rs | 41 ++++++++++++++--------- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/plonky2/src/plonk/circuit_data.rs b/plonky2/src/plonk/circuit_data.rs index 66dbf3f2..b5e411f1 100644 --- a/plonky2/src/plonk/circuit_data.rs +++ b/plonky2/src/plonk/circuit_data.rs @@ -488,6 +488,7 @@ impl, const D: usize> CommonCircuitData { /// is intentionally missing certain fields, such as `CircuitConfig`, because we support only a /// limited form of dynamic inner circuits. We can't practically make things like the wire count /// dynamic, at least not without setting a maximum wire count and paying for the worst case. +#[derive(Clone)] pub struct VerifierCircuitTarget { /// A commitment to each constant polynomial and each permutation polynomial. pub constants_sigmas_cap: MerkleCapTarget, diff --git a/plonky2/src/recursion/cyclic_recursion.rs b/plonky2/src/recursion/cyclic_recursion.rs index 0dd3b730..98661a92 100644 --- a/plonky2/src/recursion/cyclic_recursion.rs +++ b/plonky2/src/recursion/cyclic_recursion.rs @@ -89,20 +89,15 @@ impl VerifierCircuitTarget { } impl, const D: usize> CircuitBuilder { - pub fn cyclic_recursion>( + /// Add verifier data and register it as public inputs. + /// WARNING: Do not register any public input after calling this! + pub fn verifier_data_for_cyclic_recursion>( &mut self, - previous_virtual_public_inputs: &[Target], - common_data: &mut CommonCircuitData, - ) -> Result> + ) -> VerifierCircuitTarget where C::Hasher: AlgebraicHasher, [(); C::Hasher::HASH_SIZE]:, { - ensure!( - previous_virtual_public_inputs.len() == self.num_public_inputs(), - "Incorrect number of public inputs." - ); - let verifier_data = VerifierCircuitTarget { constants_sigmas_cap: self.add_virtual_cap(self.config.fri_config.cap_height), circuit_digest: self.add_virtual_hash(), @@ -113,6 +108,21 @@ impl, const D: usize> CircuitBuilder { self.register_public_inputs(&verifier_data.constants_sigmas_cap.0[i].elements); } + verifier_data + } + + /// Cyclic recursion gadget. + /// WARNING: Do not register any public input after calling this! + pub fn cyclic_recursion>( + &mut self, + previous_virtual_public_inputs: &[Target], + verifier_data: &VerifierCircuitTarget, // should be registered as public inputs already + common_data: &CommonCircuitData, + ) -> Result> + where + C::Hasher: AlgebraicHasher, + [(); C::Hasher::HASH_SIZE]:, + { let dummy_verifier_data = VerifierCircuitTarget { constants_sigmas_cap: self.add_virtual_cap(self.config.fri_config.cap_height), circuit_digest: self.add_virtual_hash(), @@ -121,8 +131,6 @@ impl, const D: usize> CircuitBuilder { // Flag set to true for the base case of the cycle where we verify a dummy proof to bootstrap the cycle. Set to false otherwise. let base_case = self.add_virtual_bool_target_safe(); - common_data.num_public_inputs = self.num_public_inputs(); - let proof = self.add_virtual_proof_with_pis::(common_data); let dummy_proof = self.add_virtual_proof_with_pis::(common_data); @@ -151,7 +159,7 @@ impl, const D: usize> CircuitBuilder { &dummy_proof, &dummy_verifier_data, &proof, - &verifier_data, + verifier_data, common_data, ); @@ -166,7 +174,7 @@ impl, const D: usize> CircuitBuilder { Ok(CyclicRecursionTarget { proof, - verifier_data, + verifier_data: verifier_data.clone(), dummy_proof, dummy_verifier_data, base_case, @@ -351,8 +359,12 @@ mod tests { let mut common_data = common_data_for_recursion::(); + let verifier_data = builder.verifier_data_for_cyclic_recursion::(); + common_data.num_public_inputs = builder.num_public_inputs(); + // Add cyclic recursion gadget. - let cyclic_data_target = builder.cyclic_recursion::(&old_pis, &mut common_data)?; + let cyclic_data_target = + builder.cyclic_recursion::(&old_pis, &verifier_data, &common_data)?; let input_hash_bis = builder.select_hash(cyclic_data_target.base_case, initial_hash, old_hash); builder.connect_hashes(input_hash, input_hash_bis); @@ -428,7 +440,6 @@ mod tests { let initial_hash = &proof.public_inputs[..4]; let hash = &proof.public_inputs[4..8]; let counter = proof.public_inputs[8]; - dbg!(counter); let mut h: [F; 4] = initial_hash.try_into().unwrap(); assert_eq!( hash, From 3026533a8a6600510dd9dee968ddbcd9e4673b31 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Wed, 26 Oct 2022 16:44:05 +0200 Subject: [PATCH 30/31] Fix `keccak256_word` --- evm/src/cpu/kernel/asm/util/keccak.asm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/evm/src/cpu/kernel/asm/util/keccak.asm b/evm/src/cpu/kernel/asm/util/keccak.asm index 5c05a2d4..92ba8d38 100644 --- a/evm/src/cpu/kernel/asm/util/keccak.asm +++ b/evm/src/cpu/kernel/asm/util/keccak.asm @@ -8,7 +8,7 @@ %stack (word) -> (0, @SEGMENT_KERNEL_GENERAL, 0, word, $num_bytes, %%after_mstore) %jump(mstore_unpacking) %%after_mstore: - // stack: (empty) - %stack () -> (0, @SEGMENT_KERNEL_GENERAL, 0, $num_bytes) // context, segment, offset, len + // stack: offset + %stack (offset) -> (0, @SEGMENT_KERNEL_GENERAL, 0, $num_bytes) // context, segment, offset, len KECCAK_GENERAL %endmacro From c47f767fc57e53aa8dc15004a2c0d8279fd6e800 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 27 Oct 2022 15:45:14 +0200 Subject: [PATCH 31/31] PR feedback --- plonky2/src/plonk/circuit_builder.rs | 22 ++++++++++- plonky2/src/recursion/cyclic_recursion.rs | 47 +++++++---------------- 2 files changed, 35 insertions(+), 34 deletions(-) diff --git a/plonky2/src/plonk/circuit_builder.rs b/plonky2/src/plonk/circuit_builder.rs index 5327fc9b..dfd23426 100644 --- a/plonky2/src/plonk/circuit_builder.rs +++ b/plonky2/src/plonk/circuit_builder.rs @@ -34,7 +34,7 @@ use crate::iop::target::{BoolTarget, Target}; use crate::iop::wire::Wire; use crate::plonk::circuit_data::{ CircuitConfig, CircuitData, CommonCircuitData, ProverCircuitData, ProverOnlyCircuitData, - VerifierCircuitData, VerifierOnlyCircuitData, + VerifierCircuitData, VerifierCircuitTarget, VerifierOnlyCircuitData, }; use crate::plonk::config::{GenericConfig, Hasher}; use crate::plonk::copy_constraint::CopyConstraint; @@ -88,6 +88,10 @@ pub struct CircuitBuilder, const D: usize> { /// common data doesn't equal `goal_data`. /// This is used in cyclic recursion. pub(crate) goal_common_data: Option>, + + /// Optional verifier data that is registered as public inputs. + /// This is used in cyclic recursion to hold the circuit's own verifier key. + pub(crate) verifier_data_public_input: Option, } impl, const D: usize> CircuitBuilder { @@ -108,6 +112,7 @@ impl, const D: usize> CircuitBuilder { current_slots: HashMap::new(), constant_generators: Vec::new(), goal_common_data: None, + verifier_data_public_input: None, }; builder.check_config(); builder @@ -224,6 +229,21 @@ impl, const D: usize> CircuitBuilder { self.register_public_input(t); t } + /// Add a virtual verifier data, register it as a public input and set it to `self.verifier_data_public_input`. + /// WARNING: Do not register any public input after calling this! TODO: relax this + pub(crate) fn add_verifier_data_public_input(&mut self) { + let verifier_data = VerifierCircuitTarget { + constants_sigmas_cap: self.add_virtual_cap(self.config.fri_config.cap_height), + circuit_digest: self.add_virtual_hash(), + }; + // The verifier data are public inputs. + self.register_public_inputs(&verifier_data.circuit_digest.elements); + for i in 0..self.config.fri_config.num_cap_elements() { + self.register_public_inputs(&verifier_data.constants_sigmas_cap.0[i].elements); + } + + self.verifier_data_public_input = Some(verifier_data); + } /// Adds a gate to the circuit, and returns its index. pub fn add_gate>(&mut self, gate_type: G, mut constants: Vec) -> usize { diff --git a/plonky2/src/recursion/cyclic_recursion.rs b/plonky2/src/recursion/cyclic_recursion.rs index 98661a92..f2ad7eb9 100644 --- a/plonky2/src/recursion/cyclic_recursion.rs +++ b/plonky2/src/recursion/cyclic_recursion.rs @@ -89,48 +89,31 @@ impl VerifierCircuitTarget { } impl, const D: usize> CircuitBuilder { - /// Add verifier data and register it as public inputs. - /// WARNING: Do not register any public input after calling this! - pub fn verifier_data_for_cyclic_recursion>( - &mut self, - ) -> VerifierCircuitTarget - where - C::Hasher: AlgebraicHasher, - [(); C::Hasher::HASH_SIZE]:, - { - let verifier_data = VerifierCircuitTarget { - constants_sigmas_cap: self.add_virtual_cap(self.config.fri_config.cap_height), - circuit_digest: self.add_virtual_hash(), - }; - // The verifier data are public inputs. - self.register_public_inputs(&verifier_data.circuit_digest.elements); - for i in 0..self.config.fri_config.num_cap_elements() { - self.register_public_inputs(&verifier_data.constants_sigmas_cap.0[i].elements); - } - - verifier_data - } - /// Cyclic recursion gadget. - /// WARNING: Do not register any public input after calling this! + /// WARNING: Do not register any public input after calling this! TODO: relax this pub fn cyclic_recursion>( &mut self, + // Flag set to true for the base case of the cycle where we verify a dummy proof to bootstrap the cycle. Set to false otherwise. + base_case: BoolTarget, previous_virtual_public_inputs: &[Target], - verifier_data: &VerifierCircuitTarget, // should be registered as public inputs already - common_data: &CommonCircuitData, + common_data: &mut CommonCircuitData, ) -> Result> where C::Hasher: AlgebraicHasher, [(); C::Hasher::HASH_SIZE]:, { + if self.verifier_data_public_input.is_none() { + self.add_verifier_data_public_input(); + } + let verifier_data = self.verifier_data_public_input.clone().unwrap(); + common_data.num_public_inputs = self.num_public_inputs(); + self.goal_common_data = Some(common_data.clone()); + let dummy_verifier_data = VerifierCircuitTarget { constants_sigmas_cap: self.add_virtual_cap(self.config.fri_config.cap_height), circuit_digest: self.add_virtual_hash(), }; - // Flag set to true for the base case of the cycle where we verify a dummy proof to bootstrap the cycle. Set to false otherwise. - let base_case = self.add_virtual_bool_target_safe(); - let proof = self.add_virtual_proof_with_pis::(common_data); let dummy_proof = self.add_virtual_proof_with_pis::(common_data); @@ -159,7 +142,7 @@ impl, const D: usize> CircuitBuilder { &dummy_proof, &dummy_verifier_data, &proof, - verifier_data, + &verifier_data, common_data, ); @@ -359,12 +342,10 @@ mod tests { let mut common_data = common_data_for_recursion::(); - let verifier_data = builder.verifier_data_for_cyclic_recursion::(); - common_data.num_public_inputs = builder.num_public_inputs(); - + let base_case = builder.add_virtual_bool_target_safe(); // Add cyclic recursion gadget. let cyclic_data_target = - builder.cyclic_recursion::(&old_pis, &verifier_data, &common_data)?; + builder.cyclic_recursion::(base_case, &old_pis, &mut common_data)?; let input_hash_bis = builder.select_hash(cyclic_data_target.base_case, initial_hash, old_hash); builder.connect_hashes(input_hash, input_hash_bis);