halo2/halo2_proofs/examples/serialization.rs

195 lines
5.7 KiB
Rust

use std::{
fs::File,
io::{BufReader, BufWriter, Write},
};
use ff::Field;
use halo2_proofs::{
circuit::{Layouter, SimpleFloorPlanner, Value},
plonk::{
create_proof, keygen_pk, keygen_vk_custom, pk_read, verify_proof, Advice, Circuit, Column,
ConstraintSystem, ErrorFront, Fixed, Instance,
},
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<Advice>,
b: Column<Advice>,
c: Column<Advice>,
q_a: Column<Fixed>,
q_b: Column<Fixed>,
q_c: Column<Fixed>,
q_ab: Column<Fixed>,
constant: Column<Fixed>,
#[allow(dead_code)]
instance: Column<Instance>,
}
impl StandardPlonkConfig {
fn configure(meta: &mut ConstraintSystem<Fr>) -> 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<Fr> 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<Fr>) -> Self::Config {
StandardPlonkConfig::configure(meta)
}
fn synthesize(
&self,
config: Self::Config,
mut layouter: impl Layouter<Fr>,
) -> Result<(), ErrorFront> {
layouter.assign_region(
|| "",
|mut region| {
region.assign_advice(|| "", config.a, 0, || Value::known(self.0))?;
region.assign_fixed(|| "", config.q_a, 0, || Value::known(-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, || Value::known(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::<Bn256>::setup(k, OsRng);
let compress_selectors = true;
let vk = keygen_vk_custom(&params, &circuit, compress_selectors).expect("vk should not fail");
let pk = keygen_pk(&params, vk, &circuit).expect("pk should not fail");
let f = File::create("serialization-test.pk").unwrap();
let mut writer = BufWriter::new(f);
pk.write(&mut writer, SerdeFormat::RawBytes).unwrap();
writer.flush().unwrap();
let f = File::open("serialization-test.pk").unwrap();
let mut reader = BufReader::new(f);
#[allow(clippy::unit_arg)]
let pk = pk_read::<G1Affine, _, StandardPlonk>(
&mut reader,
SerdeFormat::RawBytes,
compress_selectors,
#[cfg(feature = "circuit-params")]
circuit.params(),
)
.unwrap();
std::fs::remove_file("serialization-test.pk").unwrap();
let instances: &[&[Fr]] = &[&[circuit.0]];
let mut transcript = Blake2bWrite::<_, _, Challenge255<_>>::init(vec![]);
create_proof::<
KZGCommitmentScheme<Bn256>,
ProverGWC<'_, Bn256>,
Challenge255<G1Affine>,
_,
Blake2bWrite<Vec<u8>, G1Affine, Challenge255<_>>,
_,
>(
&params,
&pk,
&[circuit],
&[instances],
OsRng,
&mut transcript,
)
.expect("prover should not fail");
let proof = transcript.finalize();
let strategy = SingleStrategy::new(&params);
let mut transcript = Blake2bRead::<_, _, Challenge255<_>>::init(&proof[..]);
assert!(verify_proof::<
KZGCommitmentScheme<Bn256>,
VerifierGWC<'_, Bn256>,
Challenge255<G1Affine>,
Blake2bRead<&[u8], G1Affine, Challenge255<G1Affine>>,
SingleStrategy<'_, Bn256>,
>(
&params,
pk.get_vk(),
strategy,
&[instances],
&mut transcript
)
.is_ok());
}