mirror of https://github.com/zcash/halo2.git
195 lines
5.7 KiB
Rust
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(¶ms, &circuit, compress_selectors).expect("vk should not fail");
|
|
let pk = keygen_pk(¶ms, vk, &circuit).expect("pk should not fail");
|
|
|
|
let f = File::create("serialization-test.pk").unwrap();
|
|
let mut writer = BufWriter::new(f);
|
|
pk.write(&mut writer, SerdeFormat::RawBytes).unwrap();
|
|
writer.flush().unwrap();
|
|
|
|
let f = File::open("serialization-test.pk").unwrap();
|
|
let mut reader = BufReader::new(f);
|
|
#[allow(clippy::unit_arg)]
|
|
let pk = pk_read::<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<_>>,
|
|
_,
|
|
>(
|
|
¶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<Bn256>,
|
|
VerifierGWC<'_, Bn256>,
|
|
Challenge255<G1Affine>,
|
|
Blake2bRead<&[u8], G1Affine, Challenge255<G1Affine>>,
|
|
SingleStrategy<'_, Bn256>,
|
|
>(
|
|
¶ms,
|
|
pk.get_vk(),
|
|
strategy,
|
|
&[instances],
|
|
&mut transcript
|
|
)
|
|
.is_ok());
|
|
}
|