Skip to content
This repository was archived by the owner on Dec 9, 2021. It is now read-only.

Commit dc95de4

Browse files
dlubarovwborgeaud
andauthored
Prevent Serde from adding redundant bounds on F (#83)
* Prevent Serde from adding redundant bounds on `F` Since `Field` is already a subtrait of `Serialize` and `DeserializeOwned`, we don't need serde to add its own bounds like `where F: Serialize`. The redundant bounds would normally be harmless, but they cause an error due to a compiler bug: rust-lang/rust#41617 * Added FFT+MSM precomputations to the VK serialization + Move to serde_cbor. * Remove unused import. * Use struct destructuring Co-authored-by: wborgeaud <[email protected]>
1 parent fb13331 commit dc95de4

File tree

6 files changed

+99
-66
lines changed

6 files changed

+99
-66
lines changed

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ blake3 = "0.3.3"
2525
anyhow = "1.0.31"
2626
once_cell = "1.4.0"
2727
serde = { version = "1.0", features = ["derive"] }
28-
bincode = "1.3.1"
2928
log = "0.4"
3029
pretty_env_logger = "0.4"
30+
serde_cbor = "0.11.1"
3131

3232
[dev-dependencies]
3333
criterion = "0.3.3"

src/fft.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use rayon::prelude::*;
22

33
use crate::util::{log2_ceil, log2_strict};
44
use crate::Field;
5+
use serde::{Serialize, Deserialize};
56

67
/// Permutes `arr` such that each index is mapped to its reverse in binary.
78
fn reverse_index_bits<T: Copy>(arr: Vec<T>) -> Vec<T> {
@@ -24,7 +25,8 @@ fn reverse_bits(n: usize, num_bits: usize) -> usize {
2425
result
2526
}
2627

27-
#[derive(Debug, Clone, Eq, PartialEq)]
28+
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
29+
#[serde(bound = "")]
2830
pub struct FftPrecomputation<F: Field> {
2931
/// For each layer index i, stores the cyclic subgroup corresponding to the evaluation domain of
3032
/// layer i. The indices within these subgroup vectors are bit-reversed.

src/plonk.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ impl<C: HaloCurve> Circuit<C> {
283283
);
284284

285285
// Get a list of all opened values, to append to the transcript.
286-
let all_opening_sets: Vec<OpeningSet<C>> =
286+
let all_opening_sets: Vec<OpeningSet<C::ScalarField>> =
287287
vec![o_local.clone(), o_right.clone(), o_below.clone()];
288288
let all_opened_values_sf: Vec<C::ScalarField> = all_opening_sets
289289
.iter()
@@ -463,7 +463,7 @@ impl<C: HaloCurve> Circuit<C> {
463463
old_proofs: &[OldProof<C>],
464464
pi_quotient_poly: &Polynomial<C::ScalarField>,
465465
zeta: C::ScalarField,
466-
) -> OpeningSet<C> {
466+
) -> OpeningSet<C::ScalarField> {
467467
let powers_of_zeta = powers(zeta, self.degree());
468468

469469
OpeningSet {

src/plonk_proof.rs

+20-16
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,11 @@ pub struct Proof<C: HaloCurve> {
3030
pub c_pis_quotient: AffinePoint<C>,
3131

3232
/// The opening of each polynomial at `zeta`.
33-
pub o_local: OpeningSet<C>,
33+
pub o_local: OpeningSet<C::ScalarField>,
3434
/// The opening of each polynomial at `g * zeta`.
35-
pub o_right: OpeningSet<C>,
35+
pub o_right: OpeningSet<C::ScalarField>,
3636
/// The opening of each polynomial at `g^65 * zeta`.
37-
pub o_below: OpeningSet<C>,
37+
pub o_below: OpeningSet<C::ScalarField>,
3838

3939
/// L in the Halo reduction.
4040
pub halo_l: Vec<AffinePoint<C>>,
@@ -47,7 +47,7 @@ pub struct Proof<C: HaloCurve> {
4747
}
4848

4949
impl<C: HaloCurve> Proof<C> {
50-
pub fn all_opening_sets(&self) -> Vec<OpeningSet<C>> {
50+
pub fn all_opening_sets(&self) -> Vec<OpeningSet<C::ScalarField>> {
5151
vec![
5252
self.o_local.clone(),
5353
self.o_right.clone(),
@@ -275,25 +275,29 @@ impl<C: HaloCurve, InnerC: HaloCurve<BaseField = C::ScalarField>> ProofTarget<C,
275275

276276
/// The opening of each Plonk polynomial at a particular point.
277277
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
278-
pub struct OpeningSet<C: Curve> {
278+
// Since `Field` is already a subtrait of `Serialize` and `DeserializeOwned`, we don't need serde to
279+
// add its own bounds `where F: Serialize`. The redundant bounds would normally be harmless, but
280+
// they cause an error due to a compiler bug: https://github.com/rust-lang/rust/issues/41617
281+
#[serde(bound = "")]
282+
pub struct OpeningSet<F: Field> {
279283
/// The purported opening of each constant polynomial.
280-
pub o_constants: Vec<C::ScalarField>,
284+
pub o_constants: Vec<F>,
281285
/// The purported opening of each S_sigma polynomial in the context of Plonk's permutation argument.
282-
pub o_plonk_sigmas: Vec<C::ScalarField>,
286+
pub o_plonk_sigmas: Vec<F>,
283287
/// The purported opening of each wire polynomial.
284-
pub o_wires: Vec<C::ScalarField>,
288+
pub o_wires: Vec<F>,
285289
/// The purported opening of `Z`.
286-
pub o_plonk_z: C::ScalarField,
290+
pub o_plonk_z: F,
287291
/// The purported opening of `t`.
288-
pub o_plonk_t: Vec<C::ScalarField>,
292+
pub o_plonk_t: Vec<F>,
289293
/// The purported opening of some old proofs `halo_g` polynomials.
290-
pub o_old_proofs: Vec<C::ScalarField>,
294+
pub o_old_proofs: Vec<F>,
291295
/// The purported opening of the public input quotient polynomial.
292-
pub o_pi_quotient: C::ScalarField,
296+
pub o_pi_quotient: F,
293297
}
294298

295-
impl<C: Curve> OpeningSet<C> {
296-
pub fn to_vec(&self) -> Vec<C::ScalarField> {
299+
impl<F: Field> OpeningSet<F> {
300+
pub fn to_vec(&self) -> Vec<F> {
297301
[
298302
self.o_constants.as_slice(),
299303
self.o_plonk_sigmas.as_slice(),
@@ -337,10 +341,10 @@ impl<C: Curve> OpeningSetTarget<C> {
337341
.concat()
338342
}
339343

340-
pub fn populate_witness<D: Curve>(
344+
pub fn populate_witness<F: Field>(
341345
&self,
342346
witness: &mut PartialWitness<C::ScalarField>,
343-
values: &OpeningSet<D>,
347+
values: &OpeningSet<F>,
344348
) -> Result<()> {
345349
// TODO: We temporarily assume that each opened value fits in both fields.
346350
witness.set_targets(

src/serialization.rs

+57-43
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ impl<C: Curve> FromBytes for AffinePoint<C> {
7373

7474
impl<C: Curve> Serialize for AffinePoint<C> {
7575
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
76-
where
77-
S: Serializer,
76+
where
77+
S: Serializer,
7878
{
7979
let mut buf = vec![];
8080
self.write(&mut buf)
@@ -85,8 +85,8 @@ impl<C: Curve> Serialize for AffinePoint<C> {
8585

8686
impl<'de, C: Curve> Deserialize<'de> for AffinePoint<C> {
8787
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
88-
where
89-
D: Deserializer<'de>,
88+
where
89+
D: Deserializer<'de>,
9090
{
9191
struct AffinePointVisitor<C: Curve> {
9292
phantom: std::marker::PhantomData<C>,
@@ -169,8 +169,8 @@ mod test {
169169
assert_eq!(x, y);
170170

171171
// Serde (de)serialization
172-
let ser = bincode::serialize(&x)?;
173-
let y = bincode::deserialize(&ser)?;
172+
let ser = serde_cbor::to_vec(&x)?;
173+
let y = serde_cbor::from_slice(&ser)?;
174174
assert_eq!(x, y);
175175

176176
Ok(())
@@ -201,11 +201,11 @@ mod test {
201201
assert_eq!(zero, q);
202202

203203
// Serde (de)serialization
204-
let ser = bincode::serialize(&p)?;
205-
let q = bincode::deserialize(&ser)?;
204+
let ser = serde_cbor::to_vec(&p)?;
205+
let q = serde_cbor::from_slice(&ser)?;
206206
assert_eq!(p, q);
207-
let ser = bincode::serialize(&zero)?;
208-
let q = bincode::deserialize(&ser)?;
207+
let ser = serde_cbor::to_vec(&zero)?;
208+
let q = serde_cbor::from_slice(&ser)?;
209209
assert_eq!(zero, q);
210210

211211
Ok(())
@@ -234,8 +234,7 @@ mod test {
234234
);
235235

236236
// Generate a proof and verification key for the factorial circuit.
237-
fn get_circuit_vk<C: HaloCurve, InnerC: HaloCurve<BaseField = C::ScalarField>>(
238-
) -> (Proof<C>, VerificationKey<C>) {
237+
fn get_circuit_vk<C: HaloCurve, InnerC: HaloCurve<BaseField=C::ScalarField>>() -> (Proof<C>, VerificationKey<C>) {
239238
let mut builder = CircuitBuilder::<C>::new(128);
240239
let n = 10;
241240
let factorial_usize = (1..=n).product();
@@ -261,37 +260,52 @@ mod test {
261260
(proof, vk)
262261
}
263262

264-
#[test]
265-
fn test_proof_vk_serialization_tweedledee() {
266-
let (proof, vk) = get_circuit_vk::<Tweedledee, Tweedledum>();
267-
let ser_proof = bincode::serialize(&proof).unwrap();
268-
let ser_vk = bincode::serialize(&vk).unwrap();
269-
270-
let der_proof = bincode::deserialize(&ser_proof).unwrap();
271-
let der_vk: VerificationKey<Tweedledee> = bincode::deserialize(&ser_vk).unwrap();
272-
273-
assert_eq!(proof, der_proof);
274-
assert_eq!(vk.c_constants, der_vk.c_constants);
275-
assert_eq!(vk.c_s_sigmas, der_vk.c_s_sigmas);
276-
assert_eq!(vk.degree, der_vk.degree);
277-
assert_eq!(vk.num_public_inputs, der_vk.num_public_inputs);
278-
assert_eq!(vk.security_bits, der_vk.security_bits);
279-
}
280263

281-
#[test]
282-
fn test_proof_vk_serialization_tweedledum() {
283-
let (proof, vk) = get_circuit_vk::<Tweedledum, Tweedledee>();
284-
let ser_proof = bincode::serialize(&proof).unwrap();
285-
let ser_vk = bincode::serialize(&vk).unwrap();
286-
287-
let der_proof = bincode::deserialize(&ser_proof).unwrap();
288-
let der_vk: VerificationKey<Tweedledum> = bincode::deserialize(&ser_vk).unwrap();
289-
290-
assert_eq!(proof, der_proof);
291-
assert_eq!(vk.c_constants, der_vk.c_constants);
292-
assert_eq!(vk.c_s_sigmas, der_vk.c_s_sigmas);
293-
assert_eq!(vk.degree, der_vk.degree);
294-
assert_eq!(vk.num_public_inputs, der_vk.num_public_inputs);
295-
assert_eq!(vk.security_bits, der_vk.security_bits);
264+
macro_rules! test_proof_vk_serialization {
265+
($curve:ty, $inner_curve:ty, $test_name:ident) => {
266+
#[test]
267+
fn $test_name() -> Result<()> {
268+
let (proof, vk) = get_circuit_vk::<$curve, $inner_curve>();
269+
let ser_proof = serde_cbor::to_vec(&proof)?;
270+
let ser_vk = serde_cbor::to_vec(&vk)?;
271+
let vk_no_fft = VerificationKey {
272+
fft_precomputation: None,
273+
..vk.clone()
274+
};
275+
let vk_no_msm = VerificationKey {
276+
pedersen_g_msm_precomputation: None,
277+
..vk.clone()
278+
};
279+
let vk_none = VerificationKey {
280+
fft_precomputation: None,
281+
pedersen_g_msm_precomputation: None,
282+
..vk.clone()
283+
};
284+
let ser_vk_no_fft = serde_cbor::to_vec(&vk_no_fft)?;
285+
let ser_vk_no_msm = serde_cbor::to_vec(&vk_no_msm)?;
286+
let ser_vk_none = serde_cbor::to_vec(&vk_none)?;
287+
println!("Vk size: {} bytes", ser_vk.len());
288+
println!("Vk size without fft precomputation: {} bytes", ser_vk_no_fft.len());
289+
println!("Vk size without msm precomputation: {} bytes", ser_vk_no_msm.len());
290+
println!("Vk size without any precomputation: {} bytes", ser_vk_none.len());
291+
292+
let der_proof = serde_cbor::from_slice(&ser_proof)?;
293+
let der_vk: VerificationKey<$curve> = serde_cbor::from_slice(&ser_vk)?;
294+
let der_vk_no_fft: VerificationKey<$curve> = serde_cbor::from_slice(&ser_vk_no_fft)?;
295+
let der_vk_no_msm: VerificationKey<$curve> = serde_cbor::from_slice(&ser_vk_no_msm)?;
296+
let der_vk_none: VerificationKey<$curve> = serde_cbor::from_slice(&ser_vk_none)?;
297+
298+
assert_eq!(proof, der_proof);
299+
assert_eq!(vk, der_vk);
300+
assert_eq!(vk_no_fft, der_vk_no_fft);
301+
assert_eq!(vk_no_msm, der_vk_no_msm);
302+
assert_eq!(vk_none, der_vk_none);
303+
304+
Ok(())
305+
}
306+
};
296307
}
308+
309+
test_proof_vk_serialization!(Tweedledee, Tweedledum, test_proof_vk_serialization_tweedledee);
310+
test_proof_vk_serialization!(Tweedledum, Tweedledee, test_proof_vk_serialization_tweedledum);
297311
}

src/verifier.rs

+16-3
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,16 @@ use crate::{blake_hash_usize_to_curve, fft_precompute, msm_execute_parallel, msm
1212

1313
pub const SECURITY_BITS: usize = 128;
1414

15-
#[derive(Debug, Clone, Serialize, Deserialize)]
15+
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
1616
pub struct VerificationKey<C: HaloCurve> {
1717
pub c_constants: Vec<AffinePoint<C>>,
1818
pub c_s_sigmas: Vec<AffinePoint<C>>,
1919
pub degree: usize,
2020
pub num_public_inputs: usize,
2121
pub security_bits: usize,
22-
#[serde(skip)]
22+
#[serde(default, skip_serializing_if = "Option::is_none")]
2323
pub pedersen_g_msm_precomputation: Option<MsmPrecomputation<C>>,
24-
#[serde(skip)]
24+
#[serde(default, skip_serializing_if = "Option::is_none")]
2525
pub fft_precomputation: Option<FftPrecomputation<C::ScalarField>>,
2626
}
2727

@@ -31,6 +31,19 @@ impl<C: HaloCurve> From<Circuit<C>> for VerificationKey<C> {
3131
}
3232
}
3333

34+
impl<C: HaloCurve> VerificationKey<C> {
35+
pub fn clear_msm_precomputation(&mut self) {
36+
self.pedersen_g_msm_precomputation = None;
37+
}
38+
pub fn clear_fft_precomputation(&mut self) {
39+
self.fft_precomputation = None;
40+
}
41+
pub fn clear_all(&mut self) {
42+
self.clear_fft_precomputation();
43+
self.clear_msm_precomputation();
44+
}
45+
}
46+
3447
/// Verifies a proof `proof` and some old proofs G points for a given verification key.
3548
/// If `verify_g` is `true`, the function completely verifies the proof, including the
3649
/// linear time check of the G point.

0 commit comments

Comments
 (0)