use std::{ fs::File, io::{BufReader, BufWriter, Write}, }; use ff::Field; use halo2_axiom as halo2_proofs; use halo2_proofs::{ circuit::{Layouter, SimpleFloorPlanner, Value}, plonk::{ create_proof, keygen_pk, keygen_vk, verify_proof, Advice, Circuit, Column, ConstraintSystem, Error, Fixed, Instance, ProvingKey, }, poly::{ kzg::{ commitment::{KZGCommitmentScheme, ParamsKZG}, multiopen::{ProverGWC, VerifierGWC}, strategy::SingleStrategy, }, Rotation, }, transcript::{ Blake2bRead, Blake2bWrite, Challenge255, TranscriptReadBuffer, TranscriptWriterBuffer, }, SerdeFormat, }; use halo2curves::bn256::{Bn256, Fr, G1Affine}; use rand_core::OsRng; #[derive(Clone, Copy)] struct StandardPlonkConfig { a: Column, b: Column, c: Column, q_a: Column, q_b: Column, q_c: Column, q_ab: Column, constant: Column, #[allow(dead_code)] instance: Column, } impl StandardPlonkConfig { fn configure(meta: &mut ConstraintSystem) -> Self { let [a, b, c] = [(); 3].map(|_| meta.advice_column()); let [q_a, q_b, q_c, q_ab, constant] = [(); 5].map(|_| meta.fixed_column()); let instance = meta.instance_column(); [a, b, c].map(|column| meta.enable_equality(column)); meta.create_gate( "q_a·a + q_b·b + q_c·c + q_ab·a·b + constant + instance = 0", |meta| { let [a, b, c] = [a, b, c].map(|column| meta.query_advice(column, Rotation::cur())); let [q_a, q_b, q_c, q_ab, constant] = [q_a, q_b, q_c, q_ab, constant] .map(|column| meta.query_fixed(column, Rotation::cur())); let instance = meta.query_instance(instance, Rotation::cur()); Some( q_a * a.clone() + q_b * b.clone() + q_c * c + q_ab * a * b + constant + instance, ) }, ); StandardPlonkConfig { a, b, c, q_a, q_b, q_c, q_ab, constant, instance, } } } #[derive(Clone, Default)] struct StandardPlonk(Fr); impl Circuit for StandardPlonk { type Config = StandardPlonkConfig; type FloorPlanner = SimpleFloorPlanner; #[cfg(feature = "circuit-params")] type Params = (); fn without_witnesses(&self) -> Self { Self::default() } fn configure(meta: &mut ConstraintSystem) -> Self::Config { StandardPlonkConfig::configure(meta) } fn synthesize( &self, config: Self::Config, mut layouter: impl Layouter, ) -> Result<(), Error> { layouter.assign_region( || "", |mut region| { region.assign_advice(config.a, 0, Value::known(self.0)); region.assign_fixed(config.q_a, 0, -Fr::one()); region.assign_advice(config.a, 1, Value::known(-Fr::from(5u64))); for (idx, column) in (1..).zip([ config.q_a, config.q_b, config.q_c, config.q_ab, config.constant, ]) { region.assign_fixed(column, 1, Fr::from(idx as u64)); } let a = region.assign_advice(config.a, 2, Value::known(Fr::one())); a.copy_advice(&mut region, config.b, 3); a.copy_advice(&mut region, config.c, 4); Ok(()) }, ) } } fn main() { let k = 4; let circuit = StandardPlonk(Fr::random(OsRng)); let params = ParamsKZG::::setup(k, OsRng); let vk = keygen_vk(¶ms, &circuit).expect("vk should not fail"); let pk = keygen_pk(¶ms, vk, &circuit).expect("pk should not fail"); let format = SerdeFormat::RawBytes; let f = File::create("serialization-test.pk").unwrap(); let mut writer = BufWriter::new(f); pk.write(&mut writer, format).unwrap(); writer.flush().unwrap(); let f = File::open("serialization-test.pk").unwrap(); let mut reader = BufReader::new(f); let pk = { circuit.params(); ProvingKey::::read::<_, StandardPlonk>(&mut reader, format, ()) } .unwrap(); std::fs::remove_file("serialization-test.pk").unwrap(); let instances: &[&[Fr]] = &[&[circuit.0]]; let mut transcript = Blake2bWrite::<_, _, Challenge255<_>>::init(vec![]); create_proof::< KZGCommitmentScheme, ProverGWC<'_, Bn256>, Challenge255, _, Blake2bWrite, G1Affine, Challenge255<_>>, _, >( ¶ms, &pk, &[circuit], &[instances], OsRng, &mut transcript, ) .expect("prover should not fail"); let proof = transcript.finalize(); let strategy = SingleStrategy::new(¶ms); let mut transcript = Blake2bRead::<_, _, Challenge255<_>>::init(&proof[..]); assert!(verify_proof::< KZGCommitmentScheme, VerifierGWC<'_, Bn256>, Challenge255, Blake2bRead<&[u8], G1Affine, Challenge255>, SingleStrategy<'_, Bn256>, >( ¶ms, pk.get_vk(), strategy, &[instances], &mut transcript ) .is_ok()); }