forked from zcash/halo2
-
Notifications
You must be signed in to change notification settings - Fork 131
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add verifying key and proving key serialization (#103)
* VerifyingKey Serialization: merge Nalin's PR zcash#661 that allows for vkey serialization/deserialization and fixes the previous selector optimization issue * feat: add serialization & deserialization of pkey and vkey using serde derive * fix: add `num_fixed_commitments` to vkey serialization so correct number of fixed columns, post selector compression, are read * fix: serialize/deserialize pkey directly to/from file * Update: implement suggestions for PR * add `plonk::Error::Serde` to pass through serialization errors * update: remove serialization from evaluation as we now recalculate directly * fix: clippy warnings * feat: implement `ProvingKey` serialization without using external crates `serde` or `bincode` * examples: add `serialization` example to test `ProvingKey` read and write on "simple-example" * feat: added `to/from_bytes` for `ProvingKey` and `VerifyingKey` * add `pack`/`unpack` helper functions between `&[bool]` and `u8` * made serialization example use smaller example of standard plonk for less code bloat Co-authored-by: Nalin Bhardwaj <[email protected]>
- Loading branch information
1 parent
5fc8ce8
commit 246ce4e
Showing
6 changed files
with
500 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,182 @@ | ||
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, 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, | ||
}, | ||
}; | ||
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; | ||
|
||
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<(), Error> { | ||
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 vk = keygen_vk(¶ms, &circuit).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).unwrap(); | ||
writer.flush().unwrap(); | ||
|
||
let f = File::open("serialization-test.pk").unwrap(); | ||
let mut reader = BufReader::new(f); | ||
let pk = ProvingKey::<G1Affine>::read::<_, StandardPlonk>(&mut reader, ¶ms).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()); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.