diff --git a/halo2_proofs/examples/simple-example.rs b/halo2_proofs/examples/simple-example.rs index 85b87537..2cc87a5a 100644 --- a/halo2_proofs/examples/simple-example.rs +++ b/halo2_proofs/examples/simple-example.rs @@ -6,6 +6,7 @@ use halo2_proofs::{ plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Fixed, Instance, Selector}, poly::Rotation, }; +use pasta_curves::EqAffine; // ANCHOR: instructions trait NumericInstructions: Chip { @@ -237,7 +238,7 @@ impl NumericInstructions for FieldChip { /// In this struct we store the private input variables. We use `Option` because /// they won't have any value during key generation. During proving, if any of these /// were `None` we would get an error. -#[derive(Default)] +#[derive(Copy, Clone)] struct MyCircuit { constant: F, a: Value, @@ -250,7 +251,11 @@ impl Circuit for MyCircuit { type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { - Self::default() + Self { + constant: self.constant, + a: Value::default(), + b: Value::default(), + } } fn configure(meta: &mut ConstraintSystem) -> Self::Config { @@ -308,7 +313,7 @@ fn main() { // ANCHOR: test-circuit // The number of rows in our circuit cannot exceed 2^k. Since our example // circuit is very small, we can pick a very small value here. - let k = 4; + const K: u32 = 4; // Prepare the private and public inputs to the circuit! let constant = Fp::from(7); @@ -328,12 +333,14 @@ fn main() { let mut public_inputs = vec![c]; // Given the correct public input, our circuit will verify. - let prover = MockProver::run(k, &circuit, vec![public_inputs.clone()]).unwrap(); + let prover = MockProver::run(K, &circuit, vec![public_inputs.clone()]).unwrap(); assert_eq!(prover.verify(), Ok(())); + assert!(circuit.test_prove_and_verify::(&[&public_inputs])); + // If we try some other public input, the proof will fail! public_inputs[0] += Fp::one(); - let prover = MockProver::run(k, &circuit, vec![public_inputs]).unwrap(); + let prover = MockProver::run(K, &circuit, vec![public_inputs]).unwrap(); assert!(prover.verify().is_err()); // ANCHOR_END: test-circuit } diff --git a/halo2_proofs/src/plonk/circuit.rs b/halo2_proofs/src/plonk/circuit.rs index a6494d87..e51f5b5c 100644 --- a/halo2_proofs/src/plonk/circuit.rs +++ b/halo2_proofs/src/plonk/circuit.rs @@ -11,6 +11,7 @@ use crate::{ circuit::{Layouter, Region, Value}, poly::Rotation, }; +use pasta_curves::arithmetic::CurveAffine; mod compress_selectors; @@ -482,6 +483,42 @@ pub trait Circuit { /// the caller will be different depending on the context, and they may or /// may not expect to have a witness present. fn synthesize(&self, config: Self::Config, layouter: impl Layouter) -> Result<(), Error>; + + /// Test proof creation and verification for this circuit. + fn test_prove_and_verify(self, instance: &[&[C::Scalar]]) -> bool + where + C: CurveAffine, + C::Scalar: ff::FromUniformBytes<64>, + Self: Sized, + { + use crate::{ + plonk::{create_proof, keygen_pk, keygen_vk, verify_proof, SingleVerifier}, + poly::commitment::Params, + transcript::{Blake2bRead, Blake2bWrite, Challenge255}, + }; + + let params = Params::::new(K); + + let vk = keygen_vk(¶ms, &self.without_witnesses()).expect("keygen_vk should not fail"); + let pk = + keygen_pk(¶ms, vk, &self.without_witnesses()).expect("keygen_pk should not fail"); + + let mut transcript = Blake2bWrite::<_, _, Challenge255>::init(vec![]); + create_proof( + ¶ms, + &pk, + &[self], + &[instance], + rand_core::OsRng, + &mut transcript, + ) + .expect("proof generation should not fail"); + let proof: Vec = transcript.finalize(); + + let strategy = SingleVerifier::new(¶ms); + let mut transcript = Blake2bRead::<_, _, Challenge255<_>>::init(&proof[..]); + verify_proof(¶ms, pk.get_vk(), strategy, &[instance], &mut transcript).is_ok() + } } /// Low-degree expression representing an identity that must hold over the committed columns.