Browse Source

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>
main
Samuel Burnham 1 year ago
committed by GitHub
parent
commit
13964b6f16
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 93 additions and 37 deletions
  1. +2
    -2
      Cargo.toml
  2. +4
    -2
      src/circuit.rs
  3. +6
    -3
      src/commitments.rs
  4. +7
    -2
      src/lib.rs
  5. +2
    -1
      src/nifs.rs
  6. +3
    -2
      src/pasta.rs
  7. +6
    -3
      src/poseidon.rs
  8. +9
    -6
      src/r1cs.rs
  9. +3
    -1
      src/spartan_with_ipa_pc/ipa.rs
  10. +7
    -0
      src/spartan_with_ipa_pc/mod.rs
  11. +4
    -2
      src/spartan_with_ipa_pc/sumcheck.rs
  12. +33
    -10
      src/traits/mod.rs
  13. +7
    -3
      src/traits/snark.rs

+ 2
- 2
Cargo.toml

@ -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"

+ 4
- 2
src/circuit.rs

@ -28,8 +28,9 @@ use bellperson::{
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 @@ impl NovaAugmentedCircuitParams {
}
}
#[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,

+ 6
- 3
src/commitments.rs

@ -10,19 +10,22 @@ use core::{
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,
}

+ 7
- 2
src/lib.rs

@ -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 @@ where
}
/// 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 @@ where
}
/// 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>,

+ 2
- 1
src/nifs.rs

@ -10,10 +10,11 @@ use super::{
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>,

+ 3
- 2
src/pasta.rs

@ -15,6 +15,7 @@ use pasta_curves::{
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 @@ fn cpu_best_multiexp(coeffs: &[C::Scalar], bases: &[C]) -> C::Cu
//////////////////////////////////////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 @@ impl CompressedGroup for PallasCompressedElementWrapper {
//////////////////////////////////////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],
}

+ 6
- 3
src/poseidon.rs

@ -20,9 +20,10 @@ use neptune::{
},
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 @@ where
}
/// A Poseidon-based RO to use outside circuits
#[derive(Serialize, Deserialize)]
pub struct PoseidonRO<Base, Scalar>
where
Base: PrimeField + PrimeFieldBits,
@ -52,7 +54,7 @@ where
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 @@ where
}
/// 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 @@ where
impl<Scalar> ROCircuitTrait<Scalar> for PoseidonROCircuit<Scalar>
where
Scalar: PrimeField + PrimeFieldBits,
Scalar: PrimeField + PrimeFieldBits + Serialize + for<'de> Deserialize<'de>,
{
type Constants = PoseidonConstantsCircuit<Scalar>;

+ 9
- 6
src/r1cs.rs

@ -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 @@ pub struct 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>,

+ 3
- 1
src/spartan_with_ipa_pc/ipa.rs

@ -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 @@ impl InnerProductWitness {
}
/// 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 @@ impl NIFSForInnerProduct {
}
/// 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>>,

+ 7
- 0
src/spartan_with_ipa_pc/mod.rs

@ -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 @@ impl ProverKeyTrait for ProverKey {
}
/// 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 @@ impl VerifierKeyTrait for VerifierKey {
/// 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),

+ 4
- 2
src/spartan_with_ipa_pc/sumcheck.rs

@ -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 @@ pub struct UniPoly {
// 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>,

+ 33
- 10
src/traits/mod.rs

@ -10,6 +10,7 @@ use core::{
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 @@ pub trait Group:
+ 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 @@ pub trait Group:
}
/// 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 @@ pub trait ChallengeTrait {
/// 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 @@ pub trait ROTrait {
/// 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;

+ 7
- 3
src/traits/snark.rs

@ -5,6 +5,8 @@ use crate::{
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 @@ pub trait VerifierKeyTrait: Send + Sync {
}
/// 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 {

Loading…
Cancel
Save