Add serde proof serialization (#123) * Bump commit. * Bump commit. * (WIP) Add serde support * Minor fixes * Use neptune const generics * Use git patches * Impl serde for CompressedSNARK * Update dependencies, revert to typenum * Formatting * Update bellperson-nonnative patch * Cleanup * Remove bellperson-nonnative fork * Switch back to fil_pasta_curves * Update forked dependencies * Cleanup * Remove unnecessary patch * Update to lurk-pasta-msm --------- Co-authored-by: porcuquine <porcuquine@users.noreply.github.com>
@@ -21,7 +21,7 @@ rand_core = { version = "0.5", default-features = false }
rand_chacha = "0.3" itertools = "0.9.0" subtle = "2.4" -pasta_curves = { version = "0.4.0", features = ["repr-c"] } +pasta_curves = { version = "0.5.2", features = ["repr-c", "serde"], package = "fil_pasta_curves" } neptune = { version = "8.1.0", default-features = false } generic-array = "0.14.4" num-bigint = { version = "0.4", features = ["serde", "rand"] }@@ -34,7 +34,7 @@ bitvec = "1.0"
byteorder = "1.4.3" [target.'cfg(any(target_arch = "x86_64", target_arch = "aarch64"))'.dependencies] -pasta-msm = "0.1.3" +pasta-msm = { version = "0.1.0", package = "lurk-pasta-msm" } [dev-dependencies] criterion = "0.3.1"
@@ -28,8 +28,9 @@ },
Circuit, ConstraintSystem, SynthesisError, }; use ff::Field; +use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct NovaAugmentedCircuitParams { limb_width: usize, n_limbs: usize,@@ -46,7 +47,8 @@ }
} } -#[derive(Debug)] +#[derive(Debug, Serialize, Deserialize)] +#[serde(bound = "")] pub struct NovaAugmentedCircuitInputs<G: Group> { params: G::Scalar, // Hash(Shape of u2, Gens for u2). Needed for computing the challenge. i: G::Base,
@@ -10,19 +10,22 @@ };
use ff::Field; use merlin::Transcript; use rayon::prelude::*; +use serde::{Deserialize, Serialize}; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct CommitGens<G: Group> { gens: Vec<G::PreprocessedGroupElement>, _p: PhantomData<G>, } -#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(bound = "")] pub struct Commitment<G: Group> { pub(crate) comm: G, } -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(bound = "")] pub struct CompressedCommitment<C: CompressedGroup> { comm: C, }
@@ -35,12 +35,15 @@ use nifs::NIFS;
use r1cs::{ R1CSGens, R1CSInstance, R1CSShape, R1CSWitness, RelaxedR1CSInstance, RelaxedR1CSWitness, }; +use serde::{Deserialize, Serialize}; use traits::{ circuit::StepCircuit, snark::RelaxedR1CSSNARKTrait, AbsorbInROTrait, Group, ROConstants, ROConstantsCircuit, ROConstantsTrait, ROTrait, }; /// A type that holds public parameters of Nova +#[derive(Serialize, Deserialize)] +#[serde(bound = "")] pub struct PublicParams<G1, G2, C1, C2> where G1: Group<Base = <G2 as Group>::Scalar>,@@ -152,7 +155,8 @@ }
} /// A SNARK that proves the correct execution of an incremental computation -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(bound = "")] pub struct RecursiveSNARK<G1, G2, C1, C2> where G1: Group<Base = <G2 as Group>::Scalar>,@@ -497,7 +501,8 @@ }
} /// A SNARK that proves the knowledge of a valid `RecursiveSNARK` -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(bound = "")] pub struct CompressedSNARK<G1, G2, C1, C2, S1, S2> where G1: Group<Base = <G2 as Group>::Scalar>,
@@ -10,10 +10,11 @@ r1cs::{R1CSGens, R1CSInstance, R1CSShape, R1CSWitness, RelaxedR1CSInstance, RelaxedR1CSWitness},
traits::{AbsorbInROTrait, Group, ROTrait}, }; use core::marker::PhantomData; +use serde::{Deserialize, Serialize}; /// A SNARK that holds the proof of a step of an incremental computation #[allow(clippy::upper_case_acronyms)] -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct NIFS<G: Group> { pub(crate) comm_T: CompressedCommitment<G::CompressedGroupElement>, _p: PhantomData<G>,
@@ -15,6 +15,7 @@ group::{Curve, Group as AnotherGroup, GroupEncoding},
pallas, vesta, Ep, Eq, }; use rand_chacha::{rand_core::SeedableRng, ChaCha20Rng}; +use serde::{Deserialize, Serialize}; use sha3::Shake256; use std::io::Read;@@ -151,7 +152,7 @@
//////////////////////////////////////Pallas/////////////////////////////////////////////// /// A wrapper for compressed group elements that come from the pallas curve -#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)] pub struct PallasCompressedElementWrapper { repr: [u8; 32], }@@ -266,7 +267,7 @@
//////////////////////////////////////Vesta//////////////////////////////////////////////// /// A wrapper for compressed group elements that come from the vesta curve -#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)] pub struct VestaCompressedElementWrapper { repr: [u8; 32], }
@@ -20,9 +20,10 @@ vanilla::{Mode::Simplex, Sponge, SpongeTrait},
}, Strength, }; +use serde::{Deserialize, Serialize}; /// All Poseidon Constants that are used in Nova -#[derive(Clone)] +#[derive(Clone, Serialize, Deserialize)] pub struct PoseidonConstantsCircuit<Scalar: PrimeField>(PoseidonConstants<Scalar, U24>); impl<Scalar> ROConstantsTrait<Scalar> for PoseidonConstantsCircuit<Scalar>@@ -37,6 +38,7 @@ }
} /// A Poseidon-based RO to use outside circuits +#[derive(Serialize, Deserialize)] pub struct PoseidonRO<Base, Scalar> where Base: PrimeField + PrimeFieldBits,@@ -52,7 +54,7 @@ }
impl<Base, Scalar> ROTrait<Base, Scalar> for PoseidonRO<Base, Scalar> where - Base: PrimeField + PrimeFieldBits, + Base: PrimeField + PrimeFieldBits + Serialize + for<'de> Deserialize<'de>, Scalar: PrimeField + PrimeFieldBits, { type Constants = PoseidonConstantsCircuit<Base>;@@ -107,6 +109,7 @@ }
} /// A Poseidon-based RO gadget to use inside the verifier circuit. +#[derive(Serialize, Deserialize)] pub struct PoseidonROCircuit<Scalar> where Scalar: PrimeField + PrimeFieldBits,@@ -120,7 +123,7 @@ }
impl<Scalar> ROCircuitTrait<Scalar> for PoseidonROCircuit<Scalar> where - Scalar: PrimeField + PrimeFieldBits, + Scalar: PrimeField + PrimeFieldBits + Serialize + for<'de> Deserialize<'de>, { type Constants = PoseidonConstantsCircuit<Scalar>;
@@ -18,13 +18,14 @@ use serde::{Deserialize, Serialize};
use sha3::{Digest, Sha3_256}; /// Public parameters for a given R1CS -#[derive(Clone)] +#[derive(Clone, Serialize, Deserialize)] +#[serde(bound = "")] pub struct R1CSGens<G: Group> { pub(crate) gens: CommitGens<G>, } /// A type that holds the shape of the R1CS matrices -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct R1CSShape<G: Group> { pub(crate) num_cons: usize, pub(crate) num_vars: usize,@@ -36,27 +37,29 @@ digest: G::Scalar, // digest of the rest of R1CSShape
} /// A type that holds a witness for a given R1CS instance -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct R1CSWitness<G: Group> { W: Vec<G::Scalar>, } /// A type that holds an R1CS instance -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(bound = "")] pub struct R1CSInstance<G: Group> { pub(crate) comm_W: Commitment<G>, pub(crate) X: Vec<G::Scalar>, } /// A type that holds a witness for a given Relaxed R1CS instance -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct RelaxedR1CSWitness<G: Group> { pub(crate) W: Vec<G::Scalar>, pub(crate) E: Vec<G::Scalar>, } /// A type that holds a Relaxed R1CS instance -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(bound = "")] pub struct RelaxedR1CSInstance<G: Group> { pub(crate) comm_W: Commitment<G>, pub(crate) comm_E: Commitment<G>,
@@ -6,6 +6,7 @@ use core::{cmp::max, iter};
use ff::Field; use merlin::Transcript; use rayon::prelude::*; +use serde::{Deserialize, Serialize}; use std::marker::PhantomData; pub fn inner_product<T>(a: &[T], b: &[T]) -> T@@ -66,6 +67,7 @@ }
} /// A non-interactive folding scheme (NIFS) for inner product relations +#[derive(Serialize, Deserialize)] pub struct NIFSForInnerProduct<G: Group> { cross_term: G::Scalar, }@@ -181,7 +183,7 @@ }
} /// An inner product argument -#[derive(Debug)] +#[derive(Debug, Serialize, Deserialize)] pub struct InnerProductArgument<G: Group> { L_vec: Vec<CompressedCommitment<G::CompressedGroupElement>>, R_vec: Vec<CompressedCommitment<G::CompressedGroupElement>>,
@@ -20,9 +20,12 @@ use itertools::concat;
use merlin::Transcript; use polynomial::{EqPolynomial, MultilinearPolynomial, SparsePolynomial}; use rayon::prelude::*; +use serde::{Deserialize, Serialize}; use sumcheck::SumcheckProof; /// A type that represents the prover's key +#[derive(Serialize, Deserialize)] +#[serde(bound = "")] pub struct ProverKey<G: Group> { gens_r1cs: R1CSGens<G>, gens_ipa: CommitGens<G>,@@ -40,6 +43,8 @@ }
} /// A type that represents the verifier's key +#[derive(Serialize, Deserialize)] +#[serde(bound = "")] pub struct VerifierKey<G: Group> { gens_r1cs: R1CSGens<G>, gens_ipa: CommitGens<G>,@@ -59,6 +64,8 @@
/// A succinct proof of knowledge of a witness to a relaxed R1CS instance /// The proof is produced using Spartan's combination of the sum-check and /// the commitment to a vector viewed as a polynomial commitment +#[derive(Serialize, Deserialize)] +#[serde(bound = "")] pub struct RelaxedR1CSSNARK<G: Group> { sc_proof_outer: SumcheckProof<G>, claims_outer: (G::Scalar, G::Scalar, G::Scalar),
@@ -7,8 +7,10 @@ use core::marker::PhantomData;
use ff::Field; use merlin::Transcript; use rayon::prelude::*; +use serde::{Deserialize, Serialize}; -#[derive(Debug)] +#[derive(Debug, Serialize, Deserialize)] +#[serde(bound = "")] pub struct SumcheckProof<G: Group> { compressed_polys: Vec<CompressedUniPoly<G>>, }@@ -226,7 +228,7 @@ }
// ax^2 + bx + c stored as vec![a,c] // ax^3 + bx^2 + cx + d stored as vec![a,c,d] -#[derive(Debug)] +#[derive(Debug, Serialize, Deserialize)] pub struct CompressedUniPoly<G: Group> { coeffs_except_linear_term: Vec<G::Scalar>, _p: PhantomData<G>,
@@ -10,6 +10,7 @@ };
use ff::{PrimeField, PrimeFieldBits}; use merlin::Transcript; use num_bigint::BigInt; +use serde::{Deserialize, Serialize}; /// Represents an element of a group /// This is currently tailored for an elliptic curve group@@ -25,25 +26,35 @@ + ScalarMul<<Self as Group>::Scalar>
+ ScalarMulOwned<<Self as Group>::Scalar> + Send + Sync + + Serialize + + for<'de> Deserialize<'de> { /// A type representing an element of the base field of the group - type Base: PrimeField + PrimeFieldBits; + type Base: PrimeField + PrimeFieldBits + Serialize + for<'de> Deserialize<'de>; /// A type representing an element of the scalar field of the group - type Scalar: PrimeField + PrimeFieldBits + ChallengeTrait + Send + Sync; + type Scalar: PrimeField + + PrimeFieldBits + + ChallengeTrait + + Send + + Sync + + Serialize + + for<'de> Deserialize<'de>; /// A type representing the compressed version of the group element - type CompressedGroupElement: CompressedGroup<GroupElement = Self>; + type CompressedGroupElement: CompressedGroup<GroupElement = Self> + + Serialize + + for<'de> Deserialize<'de>; /// A type representing preprocessed group element - type PreprocessedGroupElement: Clone + Send + Sync; + type PreprocessedGroupElement: Clone + Send + Sync + Serialize + for<'de> Deserialize<'de>; /// A type that represents a hash function that consumes elements /// from the base field and squeezes out elements of the scalar field - type RO: ROTrait<Self::Base, Self::Scalar>; + type RO: ROTrait<Self::Base, Self::Scalar> + Serialize + for<'de> Deserialize<'de>; /// An alternate implementation of Self::RO in the circuit model - type ROCircuit: ROCircuitTrait<Self::Base>; + type ROCircuit: ROCircuitTrait<Self::Base> + Serialize + for<'de> Deserialize<'de>; /// A method to compute a multiexponentation fn vartime_multiscalar_mul(@@ -74,9 +85,11 @@ fn get_curve_params() -> (Self::Base, Self::Base, BigInt);
} /// Represents a compressed version of a group element -pub trait CompressedGroup: Clone + Copy + Debug + Eq + Sized + Send + Sync + 'static { +pub trait CompressedGroup: + Clone + Copy + Debug + Eq + Sized + Send + Sync + Serialize + for<'de> Deserialize<'de> + 'static +{ /// A type that holds the decompressed version of the compressed group element - type GroupElement: Group; + type GroupElement: Group + Serialize + for<'de> Deserialize<'de>; /// Decompresses the compressed group element fn decompress(&self) -> Option<Self::GroupElement>;@@ -106,7 +119,12 @@
/// A helper trait that defines the behavior of a hash function that we use as an RO pub trait ROTrait<Base, Scalar> { /// A type representing constants/parameters associated with the hash function - type Constants: ROConstantsTrait<Base> + Clone + Send + Sync; + type Constants: ROConstantsTrait<Base> + + Clone + + Send + + Sync + + Serialize + + for<'de> Deserialize<'de>; /// Initializes the hash function fn new(constants: Self::Constants, num_absorbs: usize) -> Self;@@ -121,7 +139,12 @@
/// A helper trait that defines the behavior of a hash function that we use as an RO in the circuit model pub trait ROCircuitTrait<Base: PrimeField> { /// A type representing constants/parameters associated with the hash function - type Constants: ROConstantsTrait<Base> + Clone + Send + Sync; + type Constants: ROConstantsTrait<Base> + + Clone + + Send + + Sync + + Serialize + + for<'de> Deserialize<'de>; /// Initializes the hash function fn new(constants: Self::Constants, num_absorbs: usize) -> Self;
@@ -5,6 +5,8 @@ r1cs::{R1CSGens, R1CSShape, RelaxedR1CSInstance, RelaxedR1CSWitness},
traits::Group, }; +use serde::{Deserialize, Serialize}; + /// A trait that defines the behavior of a zkSNARK's prover key pub trait ProverKeyTrait<G: Group>: Send + Sync { /// Produces a new prover's key@@ -18,12 +20,14 @@ fn new(gens: &R1CSGens<G>, S: &R1CSShape<G>) -> Self;
} /// A trait that defines the behavior of a zkSNARK -pub trait RelaxedR1CSSNARKTrait<G: Group>: Sized + Send + Sync { +pub trait RelaxedR1CSSNARKTrait<G: Group>: + Sized + Send + Sync + Serialize + for<'de> Deserialize<'de> +{ /// A type that represents the prover's key - type ProverKey: ProverKeyTrait<G>; + type ProverKey: ProverKeyTrait<G> + Serialize + for<'de> Deserialize<'de>; /// A type that represents the verifier's key - type VerifierKey: VerifierKeyTrait<G>; + type VerifierKey: VerifierKeyTrait<G> + Serialize + for<'de> Deserialize<'de>; /// Produces a prover key fn prover_key(gens: &R1CSGens<G>, S: &R1CSShape<G>) -> Self::ProverKey {