diff --git a/Cargo.toml b/Cargo.toml index 2ee9c744b..9fa0cbc99 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ generic-array = "1.0.0" num-bigint = { version = "0.4", features = ["serde", "rand"] } num-traits = "0.2" num-integer = "0.1" -serde = { version = "1.0", features = ["derive"] } +serde = { version = "1.0", features = ["derive", "rc"] } bincode = "1.3" bitvec = "1.0" byteorder = "1.4.3" diff --git a/benches/pcs.rs b/benches/pcs.rs index f8cf4b2e6..764b306de 100644 --- a/benches/pcs.rs +++ b/benches/pcs.rs @@ -14,6 +14,7 @@ use halo2curves::bn256::Bn256; use rand::rngs::StdRng; use rand_core::{CryptoRng, RngCore, SeedableRng}; use std::any::type_name; +use std::sync::Arc; use std::time::Duration; // To run these benchmarks, first download `criterion` with `cargo install cargo-criterion`. @@ -44,7 +45,7 @@ struct BenchAssests> { poly: MultilinearPolynomial<::Scalar>, point: Vec<::Scalar>, eval: ::Scalar, - ck: <::CE as CommitmentEngineTrait>::CommitmentKey, + ck: Arc<<::CE as CommitmentEngineTrait>::CommitmentKey>, commitment: <::CE as CommitmentEngineTrait>::Commitment, prover_key: >::ProverKey, verifier_key: >::VerifierKey, @@ -78,10 +79,11 @@ impl> BenchAssests { // Mock commitment key. let ck = E::CE::setup(b"test", 1 << num_vars); + let ck = Arc::new(ck); // Commits to the provided vector using the provided generators. let commitment = E::CE::commit(&ck, poly.evaluations()); - let (prover_key, verifier_key) = EE::setup(&ck); + let (prover_key, verifier_key) = EE::setup(ck.clone()); // Generate proof so that we can bench verification. let proof = EE::prove( diff --git a/examples/minroot.rs b/examples/minroot.rs index eba82fe8f..1ded8795d 100644 --- a/examples/minroot.rs +++ b/examples/minroot.rs @@ -1,6 +1,8 @@ //! Demonstrates how to use Nova to produce a recursive proof of the correct execution of //! iterations of the `MinRoot` function, thereby realizing a Nova-based verifiable delay function (VDF). //! We execute a configurable number of iterations of the `MinRoot` function per step of Nova's recursion. +#[cfg(feature = "abomonate")] +use arecibo::FlatPublicParams; use arecibo::{ provider::{Bn256EngineKZG, GrumpkinEngine}, traits::{ @@ -232,14 +234,16 @@ fn main() { ); println!("PublicParams::setup, took {:?} ", start.elapsed()); #[cfg(feature = "abomonate")] - { + let pp = { use abomonation::encode; let mut file = std::fs::File::create(utils::FILEPATH).unwrap(); + let flat_params = FlatPublicParams::try_from(pp).expect("error encoding pps!"); unsafe { - encode(&pp, &mut file).unwrap(); + encode(&flat_params, &mut file).unwrap(); } println!("Encoded!"); - } + PublicParams::from(flat_params) + }; println!( "Number of constraints per step (primary circuit): {}", @@ -270,7 +274,7 @@ fn main() { reader.read_to_end(&mut bytes).unwrap(); if let Some((result, remaining)) = unsafe { decode::< - PublicParams< + FlatPublicParams< E1, E2, MinRootCircuit<::GE>, @@ -278,8 +282,10 @@ fn main() { >, >(&mut bytes) } { - assert!(*result == pp, "decoded parameters not equal to original!"); + let result_pp = PublicParams::from(result.clone()); + assert!(result_pp == pp, "decoded parameters not equal to original!"); assert!(remaining.is_empty()); + println!("Decoded!"); } else { println!("Decoding failure!"); } @@ -352,8 +358,8 @@ fn main() { type E2 = GrumpkinEngine; type EE1 = arecibo::provider::hyperkzg::EvaluationEngine; type EE2 = arecibo::provider::ipa_pc::EvaluationEngine; - type S1 = arecibo::spartan::snark::RelaxedR1CSSNARK; // non-preprocessing SNARK - type S2 = arecibo::spartan::snark::RelaxedR1CSSNARK; // non-preprocessing SNARK + type S1 = arecibo::spartan::ppsnark::RelaxedR1CSSNARK; // non-preprocessing SNARK + type S2 = arecibo::spartan::ppsnark::RelaxedR1CSSNARK; // non-preprocessing SNARK let res = CompressedSNARK::<_, _, _, _, S1, S2>::prove(&pp, &pk, &recursive_snark); println!( diff --git a/src/lib.rs b/src/lib.rs index a0b367261..5d8aced27 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,6 +28,7 @@ pub mod traits; pub mod supernova; use once_cell::sync::OnceCell; +use traits::commitment::Len; use crate::digest::{DigestComputer, SimpleDigestible}; use crate::{ @@ -52,6 +53,7 @@ use r1cs::{ CommitmentKeyHint, R1CSInstance, R1CSShape, R1CSWitness, RelaxedR1CSInstance, RelaxedR1CSWitness, }; use serde::{Deserialize, Serialize}; +use std::sync::Arc; use traits::{ circuit::StepCircuit, commitment::{CommitmentEngineTrait, CommitmentTrait}, @@ -86,18 +88,56 @@ impl R1CSWithArity { } } -/// A type that holds public parameters of Nova -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Abomonation)] +/// A helper struct for holding [`CommitmentKey`]s +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(bound = "")] -#[abomonation_bounds( +pub struct CommitmentKeyParams where E1: Engine::Scalar>, E2: Engine::Scalar>, - C1: StepCircuit, - C2: StepCircuit, - ::Repr: Abomonation, - ::Repr: Abomonation, +{ + /// Primary key + pub primary: CommitmentKey, + /// Secondary key + pub secondary: CommitmentKey, +} + +/// Auxiliary [PublicParams] information about constants of the primary and +/// secondary circuit. This is used as a helper struct when reconstructing +/// [PublicParams] downstream in lurk. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Abomonation)] +#[serde(bound = "")] +#[abomonation_bounds(where + E1: Engine::Scalar>, + E2: Engine::Scalar>, + <::Scalar as ff::PrimeField>::Repr: Abomonation, + <::Scalar as ff::PrimeField>::Repr: Abomonation, )] +pub struct AuxParams +where + E1: Engine::Scalar>, + E2: Engine::Scalar>, +{ + /// Hint for how long `ck_primary` should be + pub ck_primary_len: usize, + ro_consts_primary: ROConstants, + ro_consts_circuit_primary: ROConstantsCircuit, + augmented_circuit_params_primary: NovaAugmentedCircuitParams, + + /// Hint for how long `ck_secondary` should be + pub ck_secondary_len: usize, + ro_consts_secondary: ROConstants, + ro_consts_circuit_secondary: ROConstantsCircuit, + circuit_shape_secondary: R1CSWithArity, + augmented_circuit_params_secondary: NovaAugmentedCircuitParams, + + #[abomonate_with(::Repr)] + digest: E1::Scalar, +} + +/// A type that holds public parameters of Nova +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(bound = "")] pub struct PublicParams where E1: Engine::Scalar>, @@ -105,19 +145,16 @@ where C1: StepCircuit, C2: StepCircuit, { - F_arity_primary: usize, - F_arity_secondary: usize, ro_consts_primary: ROConstants, ro_consts_circuit_primary: ROConstantsCircuit, - ck_primary: CommitmentKey, + ck_primary: Arc>, circuit_shape_primary: R1CSWithArity, ro_consts_secondary: ROConstants, ro_consts_circuit_secondary: ROConstantsCircuit, - ck_secondary: CommitmentKey, + ck_secondary: Arc>, circuit_shape_secondary: R1CSWithArity, augmented_circuit_params_primary: NovaAugmentedCircuitParams, augmented_circuit_params_secondary: NovaAugmentedCircuitParams, - #[abomonation_skip] #[serde(skip, default = "OnceCell::new")] digest: OnceCell, _p: PhantomData<(C1, C2)>, @@ -213,6 +250,7 @@ where let mut cs: ShapeCS = ShapeCS::new(); let _ = circuit_primary.synthesize(&mut cs); let (r1cs_shape_primary, ck_primary) = cs.r1cs_shape_and_key(ck_hint1); + let ck_primary = Arc::new(ck_primary); let circuit_shape_primary = R1CSWithArity::new(r1cs_shape_primary, F_arity_primary); // Initialize ck for the secondary @@ -225,11 +263,10 @@ where let mut cs: ShapeCS = ShapeCS::new(); let _ = circuit_secondary.synthesize(&mut cs); let (r1cs_shape_secondary, ck_secondary) = cs.r1cs_shape_and_key(ck_hint2); + let ck_secondary = Arc::new(ck_secondary); let circuit_shape_secondary = R1CSWithArity::new(r1cs_shape_secondary, F_arity_secondary); Self { - F_arity_primary, - F_arity_secondary, ro_consts_primary, ro_consts_circuit_primary, ck_primary, @@ -269,6 +306,84 @@ where self.circuit_shape_secondary.r1cs_shape.num_vars, ) } + + /// Breaks down an instance of [PublicParams] into the circuit params and auxiliary params. + pub fn into_parts( + self, + ) -> ( + R1CSWithArity, + CommitmentKeyParams, + AuxParams, + ) { + let digest = self.digest(); + + let Self { + ro_consts_primary, + ro_consts_circuit_primary, + ck_primary, + circuit_shape_primary, + ro_consts_secondary, + ro_consts_circuit_secondary, + ck_secondary, + circuit_shape_secondary, + augmented_circuit_params_primary, + augmented_circuit_params_secondary, + digest: _digest, + _p, + } = self; + + let ck_primary_len = ck_primary.length(); + let ck_secondary_len = ck_secondary.length(); + let ck_params = CommitmentKeyParams { + primary: Arc::try_unwrap(ck_primary).unwrap_or_else(|arc| (*arc).clone()), + secondary: Arc::try_unwrap(ck_secondary).unwrap_or_else(|arc| (*arc).clone()), + }; + + let aux_params = AuxParams { + ck_primary_len, + ro_consts_primary, + ro_consts_circuit_primary, + augmented_circuit_params_primary, + ck_secondary_len, + ro_consts_secondary, + ro_consts_circuit_secondary, + circuit_shape_secondary, + augmented_circuit_params_secondary, + digest, + }; + + (circuit_shape_primary, ck_params, aux_params) + } + + /// Create a [PublicParams] from a raw [R1CSWithArity] and auxiliary params. + pub fn from_parts( + circuit_shape: R1CSWithArity, + ck_params: CommitmentKeyParams, + aux_params: AuxParams, + ) -> Self { + assert_eq!(ck_params.primary.length(), aux_params.ck_primary_len, "incorrect primary key length"); + assert_eq!(ck_params.secondary.length(), aux_params.ck_secondary_len, "incorrect secondary key length"); + let pp = Self { + ro_consts_primary: aux_params.ro_consts_primary, + ro_consts_circuit_primary: aux_params.ro_consts_circuit_primary, + ck_primary: Arc::new(ck_params.primary), + circuit_shape_primary: circuit_shape, + augmented_circuit_params_primary: aux_params.augmented_circuit_params_primary, + ro_consts_secondary: aux_params.ro_consts_secondary, + ro_consts_circuit_secondary: aux_params.ro_consts_circuit_secondary, + ck_secondary: Arc::new(ck_params.secondary), + circuit_shape_secondary: aux_params.circuit_shape_secondary, + augmented_circuit_params_secondary: aux_params.augmented_circuit_params_secondary, + digest: OnceCell::new(), + _p: PhantomData, + }; + assert_eq!( + aux_params.digest, + pp.digest(), + "param data is invalid; aux_params contained the incorrect digest" + ); + pp + } } /// A resource buffer for [`RecursiveSNARK`] for storing scratch values that are computed by `prove_step`, @@ -331,7 +446,9 @@ where z0_primary: &[E1::Scalar], z0_secondary: &[E2::Scalar], ) -> Result { - if z0_primary.len() != pp.F_arity_primary || z0_secondary.len() != pp.F_arity_secondary { + if z0_primary.len() != pp.circuit_shape_primary.F_arity + || z0_secondary.len() != pp.circuit_shape_secondary.F_arity + { return Err(NovaError::InvalidInitialInputLength); } @@ -386,7 +503,7 @@ where let l_u_primary = u_primary; let r_W_primary = RelaxedR1CSWitness::from_r1cs_witness(r1cs_primary, l_w_primary); let r_U_primary = RelaxedR1CSInstance::from_r1cs_instance( - &pp.ck_primary, + &*pp.ck_primary, &pp.circuit_shape_primary.r1cs_shape, l_u_primary, ); @@ -398,7 +515,8 @@ where let r_U_secondary = RelaxedR1CSInstance::::default(&pp.ck_secondary, r1cs_secondary); assert!( - !(zi_primary.len() != pp.F_arity_primary || zi_secondary.len() != pp.F_arity_secondary), + !(zi_primary.len() != pp.circuit_shape_primary.F_arity + || zi_secondary.len() != pp.circuit_shape_secondary.F_arity), "Invalid step length" ); @@ -469,7 +587,7 @@ where // fold the secondary circuit's instance let nifs_secondary = NIFS::prove_mut( - &pp.ck_secondary, + &*pp.ck_secondary, &pp.ro_consts_secondary, &scalar_as_base::(pp.digest()), &pp.circuit_shape_secondary.r1cs_shape, @@ -510,7 +628,7 @@ where // fold the primary circuit's instance let nifs_primary = NIFS::prove_mut( - &pp.ck_primary, + &*pp.ck_primary, &pp.ro_consts_primary, &pp.digest(), &pp.circuit_shape_primary.r1cs_shape, @@ -601,7 +719,7 @@ where let (hash_primary, hash_secondary) = { let mut hasher = ::RO::new( pp.ro_consts_secondary.clone(), - NUM_FE_WITHOUT_IO_FOR_CRHF + 2 * pp.F_arity_primary, + NUM_FE_WITHOUT_IO_FOR_CRHF + 2 * pp.circuit_shape_primary.F_arity, ); hasher.absorb(pp.digest()); hasher.absorb(E1::Scalar::from(num_steps as u64)); @@ -615,7 +733,7 @@ where let mut hasher2 = ::RO::new( pp.ro_consts_primary.clone(), - NUM_FE_WITHOUT_IO_FOR_CRHF + 2 * pp.F_arity_secondary, + NUM_FE_WITHOUT_IO_FOR_CRHF + 2 * pp.circuit_shape_secondary.F_arity, ); hasher2.absorb(scalar_as_base::(pp.digest())); hasher2.absorb(E2::Scalar::from(num_steps as u64)); @@ -688,9 +806,7 @@ where } /// A type that holds the prover key for `CompressedSNARK` -#[derive(Clone, Debug, Serialize, Deserialize, Abomonation)] -#[serde(bound = "")] -#[abomonation_omit_bounds] +#[derive(Clone, Debug)] pub struct ProverKey where E1: Engine::Scalar>, @@ -706,18 +822,8 @@ where } /// A type that holds the verifier key for `CompressedSNARK` -#[derive(Debug, Clone, Serialize, Deserialize, Abomonation)] +#[derive(Debug, Clone, Serialize)] #[serde(bound = "")] -#[abomonation_bounds( - where - E1: Engine::Scalar>, - E2: Engine::Scalar>, - C1: StepCircuit, - C2: StepCircuit, - S1: RelaxedR1CSSNARKTrait, - S2: RelaxedR1CSSNARKTrait, - ::Repr: Abomonation, - )] pub struct VerifierKey where E1: Engine::Scalar>, @@ -731,7 +837,6 @@ where F_arity_secondary: usize, ro_consts_primary: ROConstants, ro_consts_secondary: ROConstants, - #[abomonate_with(::Repr)] pp_digest: E1::Scalar, vk_primary: S1::VerifierKey, vk_secondary: S2::VerifierKey, @@ -783,9 +888,12 @@ where ), NovaError, > { - let (pk_primary, vk_primary) = S1::setup(&pp.ck_primary, &pp.circuit_shape_primary.r1cs_shape)?; - let (pk_secondary, vk_secondary) = - S2::setup(&pp.ck_secondary, &pp.circuit_shape_secondary.r1cs_shape)?; + let (pk_primary, vk_primary) = + S1::setup(pp.ck_primary.clone(), &pp.circuit_shape_primary.r1cs_shape)?; + let (pk_secondary, vk_secondary) = S2::setup( + pp.ck_secondary.clone(), + &pp.circuit_shape_secondary.r1cs_shape, + )?; let pk = ProverKey { pk_primary, @@ -794,8 +902,8 @@ where }; let vk = VerifierKey { - F_arity_primary: pp.F_arity_primary, - F_arity_secondary: pp.F_arity_secondary, + F_arity_primary: pp.circuit_shape_primary.F_arity, + F_arity_secondary: pp.circuit_shape_secondary.F_arity, ro_consts_primary: pp.ro_consts_primary.clone(), ro_consts_secondary: pp.ro_consts_secondary.clone(), pp_digest: pp.digest(), @@ -815,7 +923,7 @@ where ) -> Result { // fold the secondary circuit's instance with its running instance let (nifs_secondary, (f_U_secondary, f_W_secondary)) = NIFS::prove( - &pp.ck_secondary, + &*pp.ck_secondary, &pp.ro_consts_secondary, &scalar_as_base::(pp.digest()), &pp.circuit_shape_secondary.r1cs_shape, @@ -980,7 +1088,8 @@ pub fn circuit_digest< cs.r1cs_shape().digest() } -type CommitmentKey = <::CE as CommitmentEngineTrait>::CommitmentKey; +/// must fix later +pub type CommitmentKey = <::CE as CommitmentEngineTrait>::CommitmentKey; type Commitment = <::CE as CommitmentEngineTrait>::Commitment; type CompressedCommitment = <<::CE as CommitmentEngineTrait>::Commitment as CommitmentTrait>::CompressedCommitment; type CE = ::CE; diff --git a/src/provider/hyperkzg.rs b/src/provider/hyperkzg.rs index 5dbb5a6e2..df91ff02b 100644 --- a/src/provider/hyperkzg.rs +++ b/src/provider/hyperkzg.rs @@ -10,7 +10,7 @@ use crate::{ errors::NovaError, provider::{ kzg_commitment::KZGCommitmentEngine, - non_hiding_kzg::{KZGProverKey, KZGVerifierKey, UniversalKZGParam}, + non_hiding_kzg::{trim, KZGProverKey, KZGVerifierKey, UniversalKZGParam}, pedersen::Commitment, traits::DlogGroup, util::iterators::DoubleEndedIteratorExt as _, @@ -31,6 +31,7 @@ use pairing::{Engine, MillerLoopResult, MultiMillerLoop}; use rayon::prelude::*; use ref_cast::RefCast as _; use serde::{de::DeserializeOwned, Deserialize, Serialize}; +use std::sync::Arc; /// Provides an implementation of a polynomial evaluation argument #[derive(Clone, Debug, Serialize, Deserialize)] @@ -121,8 +122,9 @@ where type ProverKey = KZGProverKey; type VerifierKey = KZGVerifierKey; - fn setup(ck: &UniversalKZGParam) -> (Self::ProverKey, Self::VerifierKey) { - ck.trim(ck.length() - 1) + fn setup(ck: Arc>) -> (Self::ProverKey, Self::VerifierKey) { + let len = ck.length() - 1; + trim(ck, len) } fn prove( @@ -428,7 +430,9 @@ mod tests { let n = 4; let ck: CommitmentKey = as CommitmentEngineTrait>::setup(b"test", n); - let (pk, _vk): (KZGProverKey, KZGVerifierKey) = EvaluationEngine::::setup(&ck); + let ck = Arc::new(ck); + let (pk, _vk): (KZGProverKey, KZGVerifierKey) = + EvaluationEngine::::setup(ck.clone()); // poly is in eval. representation; evaluated at [(0,0), (0,1), (1,0), (1,1)] let poly = vec![Fr::from(1), Fr::from(2), Fr::from(2), Fr::from(4)]; @@ -464,7 +468,9 @@ mod tests { fn test_inner(n: usize, poly: &[Fr], point: &[Fr], eval: Fr) -> Result<(), NovaError> { let ck: CommitmentKey = as CommitmentEngineTrait>::setup(b"test", n); - let (pk, vk): (KZGProverKey, KZGVerifierKey) = EvaluationEngine::::setup(&ck); + let ck = Arc::new(ck); + let (pk, vk): (KZGProverKey, KZGVerifierKey) = + EvaluationEngine::::setup(ck.clone()); // make a commitment let C = KZGCommitmentEngine::commit(&ck, poly); @@ -522,7 +528,9 @@ mod tests { let ck: CommitmentKey = as CommitmentEngineTrait>::setup(b"test", n); - let (pk, vk): (KZGProverKey, KZGVerifierKey) = EvaluationEngine::::setup(&ck); + let ck = Arc::new(ck); + let (pk, vk): (KZGProverKey, KZGVerifierKey) = + EvaluationEngine::::setup(ck.clone()); // make a commitment let C = KZGCommitmentEngine::commit(&ck, &poly); diff --git a/src/provider/ipa_pc.rs b/src/provider/ipa_pc.rs index 740f075b1..34f866984 100644 --- a/src/provider/ipa_pc.rs +++ b/src/provider/ipa_pc.rs @@ -1,5 +1,6 @@ //! This module implements `EvaluationEngine` using an IPA-based polynomial commitment scheme use crate::{ + digest::SimpleDigestible, errors::{NovaError, PCSError}, provider::{pedersen::CommitmentKeyExtTrait, traits::DlogGroup}, spartan::polys::eq::EqPolynomial, @@ -10,30 +11,29 @@ use crate::{ }, Commitment, CommitmentKey, CompressedCommitment, CE, }; -use abomonation_derive::Abomonation; use core::iter; use ff::Field; use rayon::prelude::*; use serde::{Deserialize, Serialize}; use std::marker::PhantomData; +use std::sync::Arc; /// Provides an implementation of the prover key -#[derive(Clone, Debug, Serialize, Deserialize, Abomonation)] -#[serde(bound = "")] -#[abomonation_omit_bounds] +#[derive(Clone, Debug)] pub struct ProverKey { ck_s: CommitmentKey, } /// Provides an implementation of the verifier key -#[derive(Clone, Debug, Serialize, Deserialize, Abomonation)] +#[derive(Clone, Debug, Serialize)] #[serde(bound = "")] -#[abomonation_omit_bounds] pub struct VerifierKey { - ck_v: CommitmentKey, + ck_v: Arc>, ck_s: CommitmentKey, } +impl SimpleDigestible for VerifierKey {} + /// Provides an implementation of a polynomial evaluation engine using IPA #[derive(Clone, Debug, Serialize, Deserialize)] pub struct EvaluationEngine { @@ -51,7 +51,7 @@ where type EvaluationArgument = InnerProductArgument; fn setup( - ck: &<::CE as CommitmentEngineTrait>::CommitmentKey, + ck: Arc<<::CE as CommitmentEngineTrait>::CommitmentKey>, ) -> (Self::ProverKey, Self::VerifierKey) { let ck_c = E::CE::setup(b"ipa", 1); diff --git a/src/provider/non_hiding_kzg.rs b/src/provider/non_hiding_kzg.rs index 45eba951a..c496bd530 100644 --- a/src/provider/non_hiding_kzg.rs +++ b/src/provider/non_hiding_kzg.rs @@ -1,5 +1,5 @@ //! Non-hiding variant of KZG10 scheme for univariate polynomials. -use crate::zip_with_for_each; +use crate::{digest::SimpleDigestible, zip_with_for_each}; use abomonation_derive::Abomonation; use ff::{Field, PrimeField, PrimeFieldBits}; use group::{prime::PrimeCurveAffine, Curve, Group as _}; @@ -8,7 +8,7 @@ use pairing::{Engine, MillerLoopResult, MultiMillerLoop}; use rand_core::{CryptoRng, RngCore}; use rayon::iter::{IntoParallelIterator, ParallelIterator}; use serde::{Deserialize, Serialize}; -use std::{borrow::Borrow, marker::PhantomData, ops::Mul}; +use std::{borrow::Borrow, marker::PhantomData, ops::Mul, sync::Arc}; use crate::{ errors::{NovaError, PCSError}, @@ -49,87 +49,86 @@ impl Len for UniversalKZGParam { } /// `UnivariateProverKey` is used to generate a proof -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Abomonation)] -#[abomonation_omit_bounds] -#[serde(bound( - serialize = "E::G1Affine: Serialize", - deserialize = "E::G1Affine: Deserialize<'de>" -))] +#[derive(Clone, Debug, Eq, PartialEq)] pub struct KZGProverKey { - /// generators - #[abomonate_with(Vec<[u64; 8]>)] // this is a hack; we just assume the size of the element. - pub powers_of_g: Vec, + /// generators from the universal parameters + uv_params: Arc>, + /// offset at which we start reading into the SRS + offset: usize, + /// maximum supported size + supported_size: usize, +} + +impl KZGProverKey { + pub(in crate::provider) fn new( + uv_params: Arc>, + offset: usize, + supported_size: usize, + ) -> Self { + assert!( + uv_params.max_degree() >= offset + supported_size, + "not enough bases (req: {} from offset {}) in the UVKZGParams (length: {})", + supported_size, + offset, + uv_params.max_degree() + ); + Self { + uv_params, + offset, + supported_size, + } + } + + pub fn powers_of_g(&self) -> &[E::G1Affine] { + &self.uv_params.powers_of_g[self.offset..self.offset + self.supported_size] + } } /// `UVKZGVerifierKey` is used to check evaluation proofs for a given /// commitment. -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Abomonation)] -#[abomonation_omit_bounds] -#[serde(bound( - serialize = "E::G1Affine: Serialize, E::G2Affine: Serialize", - deserialize = "E::G1Affine: Deserialize<'de>, E::G2Affine: Deserialize<'de>" -))] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +#[serde(bound(serialize = "E::G1Affine: Serialize, E::G2Affine: Serialize",))] pub struct KZGVerifierKey { /// The generator of G1. - #[abomonate_with([u64; 8])] // this is a hack; we just assume the size of the element. pub g: E::G1Affine, /// The generator of G2. - #[abomonate_with([u64; 16])] // this is a hack; we just assume the size of the element. pub h: E::G2Affine, /// β times the above generator of G2. - #[abomonate_with([u64; 16])] // this is a hack; we just assume the size of the element. pub beta_h: E::G2Affine, } +impl SimpleDigestible for KZGVerifierKey +where + E::G1Affine: Serialize, + E::G2Affine: Serialize, +{ +} + impl UniversalKZGParam { /// Returns the maximum supported degree pub fn max_degree(&self) -> usize { self.powers_of_g.len() } +} - /// Returns the prover parameters - /// - /// # Panics - /// if `supported_size` is greater than `self.max_degree()` - pub fn extract_prover_key(&self, supported_size: usize) -> KZGProverKey { - let powers_of_g = self.powers_of_g[..=supported_size].to_vec(); - KZGProverKey { powers_of_g } - } - - /// Returns the verifier parameters - /// - /// # Panics - /// If self.prover_params is empty. - pub fn extract_verifier_key(&self, supported_size: usize) -> KZGVerifierKey { - assert!( - self.powers_of_g.len() >= supported_size, - "supported_size is greater than self.max_degree()" - ); - KZGVerifierKey { - g: self.powers_of_g[0], - h: self.powers_of_h[0], - beta_h: self.powers_of_h[1], - } - } - - /// Trim the universal parameters to specialize the public parameters - /// for univariate polynomials to the given `supported_size`, and - /// returns prover key and verifier key. `supported_size` should - /// be in range `1..params.len()` - /// - /// # Panics - /// If `supported_size` is greater than `self.max_degree()`, or `self.max_degree()` is zero. - pub fn trim(&self, supported_size: usize) -> (KZGProverKey, KZGVerifierKey) { - let powers_of_g = self.powers_of_g[..=supported_size].to_vec(); - - let pk = KZGProverKey { powers_of_g }; - let vk = KZGVerifierKey { - g: self.powers_of_g[0], - h: self.powers_of_h[0], - beta_h: self.powers_of_h[1], - }; - (pk, vk) - } +/// Trim the universal parameters to specialize the public parameters +/// for univariate polynomials to the given `supported_size`, and +/// returns prover key and verifier key. `supported_size` should +/// be in range `1..params.len()` +/// +/// # Panics +/// If `supported_size` is greater than `self.max_degree()`, or `self.max_degree()` is zero. +pub fn trim( + ukzg: Arc>, + supported_size: usize, +) -> (KZGProverKey, KZGVerifierKey) { + assert!(ukzg.max_degree() > 0, "max_degree is zero"); + let g = ukzg.powers_of_g[0]; + let h = ukzg.powers_of_h[0]; + let beta_h = ukzg.powers_of_h[1]; + let pk = KZGProverKey::new(ukzg, 0, supported_size + 1); + let vk = KZGVerifierKey { g, h, beta_h }; + (pk, vk) } impl UniversalKZGParam @@ -246,12 +245,12 @@ where ) -> Result, NovaError> { let prover_param = prover_param.borrow(); - if poly.degree() > prover_param.powers_of_g.len() { + if poly.degree() > prover_param.powers_of_g().len() { return Err(NovaError::PCSError(PCSError::LengthError)); } let scalars = poly.coeffs.as_slice(); - let bases = prover_param.powers_of_g.as_slice(); + let bases = prover_param.powers_of_g(); // We can avoid some scalar multiplications if 'scalars' contains a lot of leading zeroes using // offset, that points where non-zero scalars start. @@ -271,12 +270,12 @@ where ) -> Result, NovaError> { let prover_param = prover_param.borrow(); - if poly.degree() > prover_param.powers_of_g.len() { + if poly.degree() > prover_param.powers_of_g().len() { return Err(NovaError::PCSError(PCSError::LengthError)); } let C = ::vartime_multiscalar_mul( poly.coeffs.as_slice(), - &prover_param.powers_of_g.as_slice()[..poly.coeffs.len()], + &prover_param.powers_of_g()[..poly.coeffs.len()], ); Ok(UVKZGCommitment(C.to_affine())) } @@ -312,7 +311,7 @@ where .ok_or(NovaError::PCSError(PCSError::ZMError))?; let proof = ::vartime_multiscalar_mul( witness_polynomial.coeffs.as_slice(), - &prover_param.powers_of_g.as_slice()[..witness_polynomial.coeffs.len()], + &prover_param.powers_of_g()[..witness_polynomial.coeffs.len()], ); let evaluation = UVKZGEvaluation(polynomial.evaluate(point)); @@ -456,8 +455,10 @@ mod tests { let mut rng = &mut thread_rng(); let degree = rng.gen_range(2..20); - let pp = UniversalKZGParam::::gen_srs_for_testing(&mut rng, degree); - let (ck, vk) = pp.trim(degree); + let pp = Arc::new(UniversalKZGParam::::gen_srs_for_testing( + &mut rng, degree, + )); + let (ck, vk) = trim(pp, degree); let p = random(degree, rng); let comm = UVKZGPCS::::commit(&ck, &p)?; let point = E::Fr::random(rng); @@ -488,8 +489,10 @@ mod tests { let degree = rng.gen_range(2..20); - let pp = UniversalKZGParam::::gen_srs_for_testing(&mut rng, degree); - let (ck, vk) = pp.trim(degree); + let pp = Arc::new(UniversalKZGParam::::gen_srs_for_testing( + &mut rng, degree, + )); + let (ck, vk) = trim(pp, degree); let mut comms = Vec::new(); let mut values = Vec::new(); diff --git a/src/provider/non_hiding_zeromorph.rs b/src/provider/non_hiding_zeromorph.rs index 3d6295161..a311ec13d 100644 --- a/src/provider/non_hiding_zeromorph.rs +++ b/src/provider/non_hiding_zeromorph.rs @@ -3,6 +3,7 @@ //! use crate::{ + digest::SimpleDigestible, errors::{NovaError, PCSError}, provider::{ non_hiding_kzg::{ @@ -18,7 +19,6 @@ use crate::{ }, Commitment, }; -use abomonation_derive::Abomonation; use ff::{BatchInvert, Field, PrimeField, PrimeFieldBits}; use group::{Curve, Group as _}; use itertools::Itertools as _; @@ -29,17 +29,13 @@ use rayon::{ }; use ref_cast::RefCast; use serde::{Deserialize, Serialize}; +use std::sync::Arc; use std::{borrow::Borrow, iter, marker::PhantomData}; use crate::provider::kzg_commitment::KZGCommitmentEngine; /// `ZMProverKey` is used to generate a proof -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Abomonation)] -#[abomonation_omit_bounds] -#[serde(bound( - serialize = "E::G1Affine: Serialize", - deserialize = "E::G1Affine: Deserialize<'de>" -))] +#[derive(Clone, Debug, Eq, PartialEq)] pub struct ZMProverKey { commit_pp: KZGProverKey, open_pp: KZGProverKey, @@ -47,41 +43,38 @@ pub struct ZMProverKey { /// `ZMVerifierKey` is used to check evaluation proofs for a given /// commitment. -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Abomonation)] -#[abomonation_omit_bounds] -#[serde(bound( - serialize = "E::G1Affine: Serialize, E::G2Affine: Serialize", - deserialize = "E::G1Affine: Deserialize<'de>, E::G2Affine: Deserialize<'de>" -))] +#[derive(Clone, Debug, Eq, PartialEq, Serialize)] +#[serde(bound(serialize = "E::G1Affine: Serialize, E::G2Affine: Serialize",))] pub struct ZMVerifierKey { vp: KZGVerifierKey, - #[abomonate_with([u64; 16])] // this is a hack; we just assume the size of the element. s_offset_h: E::G2Affine, } +impl SimpleDigestible for ZMVerifierKey +where + E::G1Affine: Serialize, + E::G2Affine: Serialize, +{ +} + /// Trim the universal parameters to specialize the public parameters /// for multilinear polynomials to the given `max_degree`, and /// returns prover key and verifier key. `supported_size` should /// be in range `1..params.len()` /// /// # Panics -/// If `supported_size` is greater than `self.max_degree()`, or `self.max_degree()` is zero. +/// If `params.max_degree() < 2 * max_degree + 1` // // TODO: important, we need a better way to handle that the commitment key should be 2^max_degree sized, // see the runtime error in commit() below -fn trim( - params: &UniversalKZGParam, +fn trim_zeromorph( + params: Arc>, max_degree: usize, ) -> (ZMProverKey, ZMVerifierKey) { - let (commit_pp, vp) = params.trim(max_degree); - let offset = params.powers_of_g.len() - max_degree; - let open_pp = { - let offset_powers_of_g1 = params.powers_of_g[offset..].to_vec(); - KZGProverKey { - powers_of_g: offset_powers_of_g1, - } - }; + let (commit_pp, vp) = crate::provider::non_hiding_kzg::trim(params.clone(), max_degree); + let offset = params.max_degree() - max_degree; let s_offset_h = params.powers_of_h[offset]; + let open_pp = KZGProverKey::new(params, offset, max_degree); ( ZMProverKey { commit_pp, open_pp }, @@ -160,7 +153,7 @@ where poly: &MultilinearPolynomial, ) -> Result, NovaError> { let pp = pp.borrow(); - if pp.commit_pp.powers_of_g.len() < poly.Z.len() { + if pp.commit_pp.powers_of_g().len() < poly.Z.len() { return Err(PCSError::LengthError.into()); } UVKZGPCS::commit(&pp.commit_pp, UVKZGPoly::ref_cast(&poly.Z)).map(|c| c.into()) @@ -179,7 +172,7 @@ where transcript.dom_sep(Self::protocol_name()); let pp = pp.borrow(); - if pp.commit_pp.powers_of_g.len() < poly.Z.len() { + if pp.commit_pp.powers_of_g().len() < poly.Z.len() { return Err(NovaError::PCSError(PCSError::LengthError)); } @@ -475,8 +468,9 @@ where type EvaluationArgument = ZMProof; - fn setup(ck: &UniversalKZGParam) -> (Self::ProverKey, Self::VerifierKey) { - trim(ck, ck.length() - 1) + fn setup(ck: Arc>) -> (Self::ProverKey, Self::VerifierKey) { + let len = ck.length() - 1; + trim_zeromorph(ck, len) } fn prove( @@ -515,9 +509,6 @@ where #[cfg(test)] mod test { - use std::borrow::Borrow; - use std::iter; - use ff::{Field, PrimeField, PrimeFieldBits}; use group::Curve; use halo2curves::bn256::Bn256; @@ -527,16 +518,22 @@ mod test { use rand::thread_rng; use rand_chacha::ChaCha20Rng; use rand_core::SeedableRng; + use std::borrow::Borrow; + use std::iter; + use std::sync::Arc; use super::quotients; + use super::trim_zeromorph; use crate::{ errors::PCSError, provider::{ keccak::Keccak256Transcript, - non_hiding_kzg::{KZGProverKey, UVKZGCommitment, UVKZGPoly, UniversalKZGParam, UVKZGPCS}, + non_hiding_kzg::{ + trim, KZGProverKey, UVKZGCommitment, UVKZGPoly, UniversalKZGParam, UVKZGPCS, + }, non_hiding_zeromorph::{ - batched_lifted_degree_quotient, eval_and_quotient_scalars, trim, ZMEvaluation, ZMPCS, + batched_lifted_degree_quotient, eval_and_quotient_scalars, ZMEvaluation, ZMPCS, }, traits::DlogGroup, util::test_utils::prove_verify_from_num_vars, @@ -556,14 +553,17 @@ mod test { let max_vars = 16; let mut rng = thread_rng(); let max_poly_size = 1 << (max_vars + 1); - let universal_setup = UniversalKZGParam::::gen_srs_for_testing(&mut rng, max_poly_size); + let universal_setup = Arc::new(UniversalKZGParam::::gen_srs_for_testing( + &mut rng, + max_poly_size, + )); for num_vars in 3..max_vars { // Setup let (pp, vk) = { let poly_size = 1 << (num_vars + 1); - trim(&universal_setup, poly_size) + trim_zeromorph(universal_setup.clone(), poly_size) }; // Commit and open @@ -830,12 +830,12 @@ mod test { { let prover_param = prover_param.borrow(); - if poly.degree() > prover_param.powers_of_g.len() { + if poly.degree() > prover_param.powers_of_g().len() { return Err(NovaError::PCSError(PCSError::LengthError)); } // We use following filter to optimise MSM for cases where scalars contain a lot of zeroes - let initial_bases = &prover_param.powers_of_g.as_slice()[..poly.coeffs.len()].to_vec(); + let initial_bases = &prover_param.powers_of_g()[..poly.coeffs.len()].to_vec(); let mut scalars = vec![]; let mut bases = vec![]; for (index, scalar) in poly.coeffs.iter().enumerate() { @@ -875,8 +875,10 @@ mod test { let (q_hat, offset) = batched_lifted_degree_quotient(E::Fr::random(&mut rng), "ients_polys); - let pp = UniversalKZGParam::::gen_srs_for_testing(&mut rng, degree); - let (ck, _vk) = pp.trim(degree); + let pp = Arc::new(UniversalKZGParam::::gen_srs_for_testing( + &mut rng, degree, + )); + let (ck, _vk) = trim(pp, degree); let commitment_expected = UVKZGPCS::commit(&ck, &q_hat)?; let commitment_actual_1 = commit_filtered(&ck, &q_hat)?; diff --git a/src/provider/util/mod.rs b/src/provider/util/mod.rs index 1b630c5b3..e74d28908 100644 --- a/src/provider/util/mod.rs +++ b/src/provider/util/mod.rs @@ -50,6 +50,7 @@ pub mod test_utils { use ff::Field; use rand::rngs::StdRng; use rand_core::{CryptoRng, RngCore}; + use std::sync::Arc; /// Returns a random polynomial, a point and calculate its evaluation. fn random_poly_with_eval( @@ -88,14 +89,15 @@ pub mod test_utils { // Mock commitment key. let ck = E::CE::setup(b"test", 1 << num_vars); + let ck = Arc::new(ck); // Commits to the provided vector using the provided generators. let commitment = E::CE::commit(&ck, poly.evaluations()); - prove_verify_with::(&ck, &commitment, &poly, &point, &eval, true) + prove_verify_with::(ck, &commitment, &poly, &point, &eval, true) } fn prove_verify_with>( - ck: &<::CE as CommitmentEngineTrait>::CommitmentKey, + ck: Arc<<::CE as CommitmentEngineTrait>::CommitmentKey>, commitment: &<::CE as CommitmentEngineTrait>::Commitment, poly: &MultilinearPolynomial<::Scalar>, point: &[::Scalar], @@ -106,12 +108,13 @@ pub mod test_utils { use std::ops::Add; // Generate Prover and verifier key for given commitment key. + let ock = ck.clone(); let (prover_key, verifier_key) = EE::setup(ck); // Generate proof. let mut prover_transcript = E::TE::new(b"TestEval"); let proof = EE::prove( - ck, + &*ock, &prover_key, &mut prover_transcript, commitment, diff --git a/src/spartan/batched.rs b/src/spartan/batched.rs index abd076d26..7657567fc 100644 --- a/src/spartan/batched.rs +++ b/src/spartan/batched.rs @@ -6,11 +6,10 @@ use ff::Field; use serde::{Deserialize, Serialize}; -use abomonation::Abomonation; -use abomonation_derive::Abomonation; use itertools::Itertools; use once_cell::sync::OnceCell; use rayon::prelude::*; +use std::sync::Arc; use super::{ compute_eval_table_sparse, @@ -59,23 +58,18 @@ pub struct BatchedRelaxedR1CSSNARK> { } /// A type that represents the prover's key -#[derive(Debug, Clone, Serialize, Deserialize, Abomonation)] -#[serde(bound = "")] -#[abomonation_bounds(where ::Repr: Abomonation)] +#[derive(Debug, Clone)] pub struct ProverKey> { pk_ee: EE::ProverKey, - #[abomonate_with(::Repr)] vk_digest: E::Scalar, // digest of the verifier's key } /// A type that represents the verifier's key -#[derive(Debug, Clone, Serialize, Deserialize, Abomonation)] +#[derive(Debug, Clone, Serialize)] #[serde(bound = "")] -#[abomonation_bounds(where ::Repr: Abomonation)] pub struct VerifierKey> { vk_ee: EE::VerifierKey, S: Vec>, - #[abomonation_skip] #[serde(skip, default = "OnceCell::new")] digest: OnceCell, } @@ -108,15 +102,13 @@ impl> DigestHelperTrait for VerifierK impl> BatchedRelaxedR1CSSNARKTrait for BatchedRelaxedR1CSSNARK -where - ::Repr: Abomonation, { type ProverKey = ProverKey; type VerifierKey = VerifierKey; fn setup( - ck: &CommitmentKey, + ck: Arc>, S: Vec<&R1CSShape>, ) -> Result<(Self::ProverKey, Self::VerifierKey), NovaError> { let (pk_ee, vk_ee) = EE::setup(ck); diff --git a/src/spartan/batched_ppsnark.rs b/src/spartan/batched_ppsnark.rs index 7abcc2174..e0a8ecdda 100644 --- a/src/spartan/batched_ppsnark.rs +++ b/src/spartan/batched_ppsnark.rs @@ -34,35 +34,29 @@ use crate::{ }, zip_with, zip_with_for_each, Commitment, CommitmentKey, CompressedCommitment, }; -use abomonation::Abomonation; -use abomonation_derive::Abomonation; -use ff::{Field, PrimeField}; +use ff::Field; use itertools::{chain, Itertools as _}; use once_cell::sync::*; use rayon::prelude::*; use serde::{Deserialize, Serialize}; +use std::sync::Arc; /// A type that represents the prover's key -#[derive(Debug, Clone, Serialize, Deserialize, Abomonation)] -#[serde(bound = "")] -#[abomonation_bounds(where < E::Scalar as PrimeField >::Repr: Abomonation)] +#[derive(Debug, Clone)] pub struct ProverKey> { pk_ee: EE::ProverKey, S_repr: Vec>, S_comm: Vec>, - #[abomonate_with(::Repr)] vk_digest: E::Scalar, // digest of verifier's key } /// A type that represents the verifier's key -#[derive(Debug, Clone, Serialize, Deserialize, Abomonation)] +#[derive(Debug, Clone, Serialize)] #[serde(bound = "")] -#[abomonation_bounds(where < E::Scalar as PrimeField >::Repr: Abomonation)] pub struct VerifierKey> { vk_ee: EE::VerifierKey, S_comm: Vec>, num_vars: Vec, - #[abomonation_skip] #[serde(skip, default = "OnceCell::new")] digest: OnceCell, } @@ -80,6 +74,7 @@ impl> VerifierKey { } } } + impl> SimpleDigestible for VerifierKey {} impl> DigestHelperTrait for VerifierKey { @@ -130,8 +125,6 @@ pub struct BatchedRelaxedR1CSSNARK> { impl> BatchedRelaxedR1CSSNARKTrait for BatchedRelaxedR1CSSNARK -where - ::Repr: Abomonation, { type ProverKey = ProverKey; type VerifierKey = VerifierKey; @@ -147,7 +140,7 @@ where } fn setup( - ck: &CommitmentKey, + ck: Arc>, S: Vec<&R1CSShape>, ) -> Result<(Self::ProverKey, Self::VerifierKey), NovaError> { for s in S.iter() { @@ -157,13 +150,13 @@ where return Err(NovaError::InternalError); } } - let (pk_ee, vk_ee) = EE::setup(ck); + let (pk_ee, vk_ee) = EE::setup(ck.clone()); let S = S.iter().map(|s| s.pad()).collect::>(); let S_repr = S.iter().map(R1CSShapeSparkRepr::new).collect::>(); let S_comm = S_repr .iter() - .map(|s_repr| s_repr.commit(ck)) + .map(|s_repr| s_repr.commit(&*ck)) .collect::>(); let num_vars = S.iter().map(|s| s.num_vars).collect::>(); let vk = VerifierKey::new(num_vars, S_comm.clone(), vk_ee); @@ -1092,10 +1085,7 @@ where } } -impl> BatchedRelaxedR1CSSNARK -where - ::Repr: Abomonation, -{ +impl> BatchedRelaxedR1CSSNARK { /// Runs the batched Sumcheck protocol for the claims of multiple instance of possibly different sizes. /// /// # Details diff --git a/src/spartan/ppsnark.rs b/src/spartan/ppsnark.rs index 88cb239a7..66b118fed 100644 --- a/src/spartan/ppsnark.rs +++ b/src/spartan/ppsnark.rs @@ -34,14 +34,13 @@ use crate::{ }, zip_with, Commitment, CommitmentKey, CompressedCommitment, }; -use abomonation::Abomonation; -use abomonation_derive::Abomonation; use core::cmp::max; -use ff::{Field, PrimeField}; +use ff::Field; use itertools::Itertools as _; use once_cell::sync::OnceCell; use rayon::prelude::*; use serde::{Deserialize, Serialize}; +use std::sync::Arc; use super::polys::masked_eq::MaskedEqPolynomial; @@ -52,35 +51,26 @@ fn padded(v: &[E::Scalar], n: usize, e: &E::Scalar) -> Vec } /// A type that holds `R1CSShape` in a form amenable to memory checking -#[derive(Debug, Clone, Serialize, Deserialize, Abomonation)] +#[derive(Debug, Clone, Serialize, Deserialize)] #[serde(bound = "")] -#[abomonation_bounds(where ::Repr: Abomonation)] pub struct R1CSShapeSparkRepr { pub(in crate::spartan) N: usize, // size of the vectors // dense representation - #[abomonate_with(Vec<::Repr>)] pub(in crate::spartan) row: Vec, - #[abomonate_with(Vec<::Repr>)] pub(in crate::spartan) col: Vec, - #[abomonate_with(Vec<::Repr>)] pub(in crate::spartan) val_A: Vec, - #[abomonate_with(Vec<::Repr>)] pub(in crate::spartan) val_B: Vec, - #[abomonate_with(Vec<::Repr>)] pub(in crate::spartan) val_C: Vec, // timestamp polynomials - #[abomonate_with(Vec<::Repr>)] pub(in crate::spartan) ts_row: Vec, - #[abomonate_with(Vec<::Repr>)] pub(in crate::spartan) ts_col: Vec, } /// A type that holds a commitment to a sparse polynomial -#[derive(Debug, Clone, Serialize, Deserialize, Abomonation)] +#[derive(Debug, Clone, Serialize, Deserialize)] #[serde(bound = "")] -#[abomonation_bounds(where ::Repr: Abomonation)] pub struct R1CSShapeSparkCommitment { pub(in crate::spartan) N: usize, // size of each vector @@ -255,32 +245,30 @@ impl R1CSShapeSparkRepr { } /// A type that represents the prover's key -#[derive(Debug, Clone, Serialize, Deserialize, Abomonation)] -#[serde(bound = "")] -#[abomonation_bounds(where ::Repr: Abomonation)] +#[derive(Debug, Clone)] pub struct ProverKey> { pk_ee: EE::ProverKey, S_repr: R1CSShapeSparkRepr, S_comm: R1CSShapeSparkCommitment, - #[abomonate_with(::Repr)] vk_digest: E::Scalar, // digest of verifier's key } /// A type that represents the verifier's key -#[derive(Debug, Clone, Serialize, Deserialize, Abomonation)] -#[serde(bound = "")] -#[abomonation_bounds(where ::Repr: Abomonation)] +#[derive(Debug, Clone, Serialize)] +#[serde(bound = "EE::VerifierKey: Serialize")] pub struct VerifierKey> { num_cons: usize, num_vars: usize, vk_ee: EE::VerifierKey, S_comm: R1CSShapeSparkCommitment, - #[abomonation_skip] #[serde(skip, default = "OnceCell::new")] digest: OnceCell, } -impl> SimpleDigestible for VerifierKey {} +impl> SimpleDigestible for VerifierKey where + EE::VerifierKey: Serialize +{ +} /// 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 @@ -337,10 +325,7 @@ pub struct RelaxedR1CSSNARK> { eval_arg: EE::EvaluationArgument, } -impl> RelaxedR1CSSNARK -where - ::Repr: Abomonation, -{ +impl> RelaxedR1CSSNARK { fn prove_helper( mem: &mut T1, outer: &mut T2, @@ -479,10 +464,7 @@ impl> DigestHelperTrait for VerifierK } } -impl> RelaxedR1CSSNARKTrait for RelaxedR1CSSNARK -where - ::Repr: Abomonation, -{ +impl> RelaxedR1CSSNARKTrait for RelaxedR1CSSNARK { type ProverKey = ProverKey; type VerifierKey = VerifierKey; @@ -494,20 +476,20 @@ where } fn setup( - ck: &CommitmentKey, + ck: Arc>, S: &R1CSShape, ) -> Result<(Self::ProverKey, Self::VerifierKey), NovaError> { // check the provided commitment key meets minimal requirements if ck.length() < Self::ck_floor()(S) { return Err(NovaError::InvalidCommitmentKeyLength); } - let (pk_ee, vk_ee) = EE::setup(ck); + let (pk_ee, vk_ee) = EE::setup(ck.clone()); // pad the R1CS matrices let S = S.pad(); let S_repr = R1CSShapeSparkRepr::new(&S); - let S_comm = S_repr.commit(ck); + let S_comm = S_repr.commit(&*ck); let vk = VerifierKey::new(S.num_cons, S.num_vars, S_comm.clone(), vk_ee); diff --git a/src/spartan/snark.rs b/src/spartan/snark.rs index 7d9bb8dd1..8396f7350 100644 --- a/src/spartan/snark.rs +++ b/src/spartan/snark.rs @@ -23,33 +23,26 @@ use crate::{ CommitmentKey, }; -use abomonation::Abomonation; -use abomonation_derive::Abomonation; use ff::Field; use itertools::Itertools as _; use once_cell::sync::OnceCell; - use rayon::prelude::*; use serde::{Deserialize, Serialize}; +use std::sync::Arc; /// A type that represents the prover's key -#[derive(Debug, Clone, Serialize, Deserialize, Abomonation)] -#[serde(bound = "")] -#[abomonation_bounds(where ::Repr: Abomonation)] +#[derive(Debug, Clone)] pub struct ProverKey> { pk_ee: EE::ProverKey, - #[abomonate_with(::Repr)] vk_digest: E::Scalar, // digest of the verifier's key } /// A type that represents the verifier's key -#[derive(Debug, Clone, Serialize, Deserialize, Abomonation)] +#[derive(Debug, Clone, Serialize)] #[serde(bound = "")] -#[abomonation_bounds(where ::Repr: Abomonation)] pub struct VerifierKey> { vk_ee: EE::VerifierKey, S: R1CSShape, - #[abomonation_skip] #[serde(skip, default = "OnceCell::new")] digest: OnceCell, } @@ -96,15 +89,12 @@ pub struct RelaxedR1CSSNARK> { eval_arg: EE::EvaluationArgument, } -impl> RelaxedR1CSSNARKTrait for RelaxedR1CSSNARK -where - ::Repr: Abomonation, -{ +impl> RelaxedR1CSSNARKTrait for RelaxedR1CSSNARK { type ProverKey = ProverKey; type VerifierKey = VerifierKey; fn setup( - ck: &CommitmentKey, + ck: Arc>, S: &R1CSShape, ) -> Result<(Self::ProverKey, Self::VerifierKey), NovaError> { let (pk_ee, vk_ee) = EE::setup(ck); diff --git a/src/supernova/mod.rs b/src/supernova/mod.rs index 66dff3a86..540788808 100644 --- a/src/supernova/mod.rs +++ b/src/supernova/mod.rs @@ -14,20 +14,21 @@ use crate::{ }, scalar_as_base, traits::{ - commitment::{CommitmentEngineTrait, CommitmentTrait}, + commitment::{CommitmentEngineTrait, CommitmentTrait, Len}, AbsorbInROTrait, Engine, ROConstants, ROConstantsCircuit, ROTrait, }, - Commitment, CommitmentKey, R1CSWithArity, + Commitment, CommitmentKey, CommitmentKeyParams, R1CSWithArity, }; use abomonation::Abomonation; use abomonation_derive::Abomonation; use bellpepper_core::SynthesisError; -use ff::{Field, PrimeField}; +use ff::Field; use itertools::Itertools as _; use once_cell::sync::OnceCell; use rayon::prelude::*; use serde::{Deserialize, Serialize}; +use std::sync::Arc; use tracing::debug; use crate::bellpepper::{ @@ -89,12 +90,12 @@ where ro_consts_primary: ROConstants, ro_consts_circuit_primary: ROConstantsCircuit, - ck_primary: CommitmentKey, // This is shared between all circuit params + ck_primary: Arc>, // This is shared between all circuit params augmented_circuit_params_primary: SuperNovaAugmentedCircuitParams, ro_consts_secondary: ROConstants, ro_consts_circuit_secondary: ROConstantsCircuit, - ck_secondary: CommitmentKey, + ck_secondary: Arc>, circuit_shape_secondary: R1CSWithArity, augmented_circuit_params_secondary: SuperNovaAugmentedCircuitParams, @@ -104,35 +105,36 @@ where _p: PhantomData<(C1, C2)>, } -/// Auxiliary [PublicParams] information about the commitment keys and +/// Auxiliary [PublicParams] information about constants of the primary /// secondary circuit. This is used as a helper struct when reconstructing /// [PublicParams] downstream in lurk. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Abomonation)] #[serde(bound = "")] -#[abomonation_bounds( -where +#[abomonation_bounds(where E1: Engine::Scalar>, E2: Engine::Scalar>, - ::Repr: Abomonation, - ::Repr: Abomonation, + <::Scalar as ff::PrimeField>::Repr: Abomonation, + <::Scalar as ff::PrimeField>::Repr: Abomonation, )] pub struct AuxParams where E1: Engine::Scalar>, E2: Engine::Scalar>, { + /// Hint for how long `ck_primary` should be + pub ck_primary_len: usize, ro_consts_primary: ROConstants, ro_consts_circuit_primary: ROConstantsCircuit, - ck_primary: CommitmentKey, // This is shared between all circuit params augmented_circuit_params_primary: SuperNovaAugmentedCircuitParams, + /// Hint for how long `ck_secondary` should be + pub ck_secondary_len: usize, ro_consts_secondary: ROConstants, ro_consts_circuit_secondary: ROConstantsCircuit, - ck_secondary: CommitmentKey, circuit_shape_secondary: R1CSWithArity, augmented_circuit_params_secondary: SuperNovaAugmentedCircuitParams, - #[abomonate_with(::Repr)] + #[abomonate_with(::Repr)] digest: E1::Scalar, } @@ -221,6 +223,7 @@ where .collect::>(); let ck_primary = Self::compute_primary_ck(&circuit_shapes, ck_hint1); + let ck_primary = Arc::new(ck_primary); let augmented_circuit_params_secondary = SuperNovaAugmentedCircuitParams::new(BN_LIMB_WIDTH, BN_N_LIMBS, false); @@ -241,6 +244,7 @@ where .synthesize(&mut cs) .expect("circuit synthesis failed"); let (r1cs_shape_secondary, ck_secondary) = cs.r1cs_shape_and_key(ck_hint2); + let ck_secondary = Arc::new(ck_secondary); let circuit_shape_secondary = R1CSWithArity::new(r1cs_shape_secondary, F_arity_secondary); let pp = Self { @@ -265,7 +269,13 @@ where } /// Breaks down an instance of [PublicParams] into the circuit params and auxiliary params. - pub fn into_parts(self) -> (Vec>, AuxParams) { + pub fn into_parts( + self, + ) -> ( + Vec>, + CommitmentKeyParams, + AuxParams, + ) { let digest = self.digest(); let Self { @@ -283,33 +293,46 @@ where _p, } = self; + let ck_primary_len = ck_primary.length(); + let ck_secondary_len = ck_secondary.length(); + let ck_params = CommitmentKeyParams { + primary: Arc::try_unwrap(ck_primary).unwrap_or_else(|arc| (*arc).clone()), + secondary: Arc::try_unwrap(ck_secondary).unwrap_or_else(|arc| (*arc).clone()), + }; + let aux_params = AuxParams { + ck_primary_len, ro_consts_primary, ro_consts_circuit_primary, - ck_primary, augmented_circuit_params_primary, + ck_secondary_len, ro_consts_secondary, ro_consts_circuit_secondary, - ck_secondary, circuit_shape_secondary, augmented_circuit_params_secondary, digest, }; - (circuit_shapes, aux_params) + (circuit_shapes, ck_params, aux_params) } /// Create a [PublicParams] from a vector of raw [R1CSWithArity] and auxiliary params. - pub fn from_parts(circuit_shapes: Vec>, aux_params: AuxParams) -> Self { + pub fn from_parts( + circuit_shapes: Vec>, + ck_params: CommitmentKeyParams, + aux_params: AuxParams, + ) -> Self { + assert_eq!(ck_params.primary.length(), aux_params.ck_primary_len, "incorrect primary key length"); + assert_eq!(ck_params.secondary.length(), aux_params.ck_secondary_len, "incorrect secondary key length"); let pp = Self { circuit_shapes, ro_consts_primary: aux_params.ro_consts_primary, ro_consts_circuit_primary: aux_params.ro_consts_circuit_primary, - ck_primary: aux_params.ck_primary, + ck_primary: Arc::new(ck_params.primary), augmented_circuit_params_primary: aux_params.augmented_circuit_params_primary, ro_consts_secondary: aux_params.ro_consts_secondary, ro_consts_circuit_secondary: aux_params.ro_consts_circuit_secondary, - ck_secondary: aux_params.ck_secondary, + ck_secondary: Arc::new(ck_params.secondary), circuit_shape_secondary: aux_params.circuit_shape_secondary, augmented_circuit_params_secondary: aux_params.augmented_circuit_params_secondary, digest: OnceCell::new(), @@ -327,17 +350,18 @@ where /// We don't check that the `aux_params.digest` is a valid digest for the created params. pub fn from_parts_unchecked( circuit_shapes: Vec>, + ck_params: CommitmentKeyParams, aux_params: AuxParams, ) -> Self { Self { circuit_shapes, ro_consts_primary: aux_params.ro_consts_primary, ro_consts_circuit_primary: aux_params.ro_consts_circuit_primary, - ck_primary: aux_params.ck_primary, + ck_primary: Arc::new(ck_params.primary), augmented_circuit_params_primary: aux_params.augmented_circuit_params_primary, ro_consts_secondary: aux_params.ro_consts_secondary, ro_consts_circuit_secondary: aux_params.ro_consts_circuit_secondary, - ck_secondary: aux_params.ck_secondary, + ck_secondary: Arc::new(ck_params.secondary), circuit_shape_secondary: aux_params.circuit_shape_secondary, augmented_circuit_params_secondary: aux_params.augmented_circuit_params_secondary, digest: aux_params.digest.into(), @@ -572,7 +596,7 @@ where RelaxedR1CSWitness::from_r1cs_witness(&pp[circuit_index].r1cs_shape, l_w_primary); let r_U_primary = RelaxedR1CSInstance::from_r1cs_instance( - &pp.ck_primary, + &*pp.ck_primary, &pp[circuit_index].r1cs_shape, l_u_primary, ); @@ -583,7 +607,7 @@ where // Initialize relaxed instance/witness pair for the secondary circuit proofs let r_W_secondary: RelaxedR1CSWitness = RelaxedR1CSWitness::::default(r1cs_secondary); - let r_U_secondary = RelaxedR1CSInstance::default(&pp.ck_secondary, r1cs_secondary); + let r_U_secondary = RelaxedR1CSInstance::default(&*pp.ck_secondary, r1cs_secondary); // Outputs of the two circuits and next program counter thus far. let zi_primary = zi_primary @@ -688,7 +712,7 @@ where // fold the secondary circuit's instance let nifs_secondary = NIFS::prove_mut( - &pp.ck_secondary, + &*pp.ck_secondary, &pp.ro_consts_secondary, &scalar_as_base::(self.pp_digest), &pp.circuit_shape_secondary.r1cs_shape, @@ -749,7 +773,7 @@ where (r_U_primary, r_W_primary) } else { self.r_U_primary[circuit_index] = Some(RelaxedR1CSInstance::default( - &pp.ck_primary, + &*pp.ck_primary, &pp[circuit_index].r1cs_shape, )); self.r_W_primary[circuit_index] = @@ -761,7 +785,7 @@ where }; let nifs_primary = NIFS::prove_mut( - &pp.ck_primary, + &*pp.ck_primary, &pp.ro_consts_primary, &self.pp_digest, &pp[circuit_index].r1cs_shape, @@ -974,7 +998,7 @@ where self.r_U_primary.iter().enumerate().for_each(|(i, U)| { U.as_ref() .unwrap_or(&RelaxedR1CSInstance::default( - &pp.ck_primary, + &*pp.ck_primary, &pp[i].r1cs_shape, )) .absorb_in_ro(&mut hasher); diff --git a/src/supernova/snark.rs b/src/supernova/snark.rs index 8a99bbbb4..8ec5b38aa 100644 --- a/src/supernova/snark.rs +++ b/src/supernova/snark.rs @@ -12,25 +12,12 @@ use crate::{ }; use crate::{errors::NovaError, scalar_as_base, RelaxedR1CSInstance, NIFS}; -use abomonation::Abomonation; -use abomonation_derive::Abomonation; use ff::PrimeField; use serde::{Deserialize, Serialize}; use std::marker::PhantomData; /// A type that holds the prover key for `CompressedSNARK` -#[derive(Debug, Clone, Serialize, Deserialize, Abomonation)] -#[serde(bound = "")] -#[abomonation_bounds( - where - E1: Engine::Scalar>, - E2: Engine::Scalar>, - C1: StepCircuit, - C2: StepCircuit, - S1: BatchedRelaxedR1CSSNARKTrait, - S2: RelaxedR1CSSNARKTrait, - ::Repr: Abomonation, - )] +#[derive(Debug, Clone)] pub struct ProverKey where E1: Engine::Scalar>, @@ -46,18 +33,7 @@ where } /// A type that holds the verifier key for `CompressedSNARK` -#[derive(Debug, Clone, Serialize, Deserialize, Abomonation)] -#[serde(bound = "")] -#[abomonation_bounds( - where - E1: Engine::Scalar>, - E2: Engine::Scalar>, - C1: StepCircuit, - C2: StepCircuit, - S1: BatchedRelaxedR1CSSNARKTrait, - S2: RelaxedR1CSSNARKTrait, - ::Repr: Abomonation, - )] +#[derive(Debug, Clone)] pub struct VerifierKey where E1: Engine::Scalar>, @@ -119,10 +95,12 @@ where ), SuperNovaError, > { - let (pk_primary, vk_primary) = S1::setup(&pp.ck_primary, pp.primary_r1cs_shapes())?; + let (pk_primary, vk_primary) = S1::setup(pp.ck_primary.clone(), pp.primary_r1cs_shapes())?; - let (pk_secondary, vk_secondary) = - S2::setup(&pp.ck_secondary, &pp.circuit_shape_secondary.r1cs_shape)?; + let (pk_secondary, vk_secondary) = S2::setup( + pp.ck_secondary.clone(), + &pp.circuit_shape_secondary.r1cs_shape, + )?; let prover_key = ProverKey { pk_primary, @@ -146,7 +124,7 @@ where ) -> Result { // fold the secondary circuit's instance let res_secondary = NIFS::prove( - &pp.ck_secondary, + &*pp.ck_secondary, &pp.ro_consts_secondary, &scalar_as_base::(pp.digest()), &pp.circuit_shape_secondary.r1cs_shape, @@ -167,7 +145,7 @@ where .map(|(idx, r_U)| { r_U .clone() - .unwrap_or_else(|| RelaxedR1CSInstance::default(&pp.ck_primary, &pp[idx].r1cs_shape)) + .unwrap_or_else(|| RelaxedR1CSInstance::default(&*pp.ck_primary, &pp[idx].r1cs_shape)) }) .collect::>(); diff --git a/src/supernova/test.rs b/src/supernova/test.rs index 569dc2646..6660b06f9 100644 --- a/src/supernova/test.rs +++ b/src/supernova/test.rs @@ -11,6 +11,7 @@ use crate::supernova::circuit::{ }; use crate::traits::snark::default_ck_hint; use crate::{bellpepper::test_shape_cs::TestShapeCS, gadgets::utils::alloc_one}; +use abomonation::Abomonation; use bellpepper_core::num::AllocatedNum; use bellpepper_core::{ConstraintSystem, SynthesisError}; use core::marker::PhantomData; diff --git a/src/traits/evaluation.rs b/src/traits/evaluation.rs index 726aa3931..8da8f2079 100644 --- a/src/traits/evaluation.rs +++ b/src/traits/evaluation.rs @@ -1,27 +1,36 @@ //! This module defines a collection of traits that define the behavior of a polynomial evaluation engine //! A vector of size N is treated as a multilinear polynomial in \log{N} variables, //! and a commitment provided by the commitment engine is treated as a multilinear polynomial commitment +use std::sync::Arc; + use crate::{ errors::NovaError, traits::{commitment::CommitmentEngineTrait, Engine}, }; -use abomonation::Abomonation; use serde::{Deserialize, Serialize}; /// A trait that ties different pieces of the commitment evaluation together pub trait EvaluationEngineTrait: Clone + Send + Sync { /// A type that holds the prover key - type ProverKey: Clone + Send + Sync + Serialize + for<'de> Deserialize<'de> + Abomonation; + type ProverKey: Clone + Send + Sync; /// A type that holds the verifier key - type VerifierKey: Clone + Send + Sync + Serialize + for<'de> Deserialize<'de> + Abomonation; + type VerifierKey: Clone + + Send + + Sync + // required for easy Digest computation purposes, could be relaxed to + // [`crate::digest::Digestible`] + + Serialize; /// A type that holds the evaluation argument type EvaluationArgument: Clone + Send + Sync + Serialize + for<'de> Deserialize<'de>; /// A method to perform any additional setup needed to produce proofs of evaluations + /// + /// **Note:** This method should be cheap and should not copy most of the + /// commitment key. Look at CommitmentEngineTrait::setup for generating SRS data. fn setup( - ck: &<::CE as CommitmentEngineTrait>::CommitmentKey, + ck: Arc<<::CE as CommitmentEngineTrait>::CommitmentKey>, ) -> (Self::ProverKey, Self::VerifierKey); /// A method to prove the evaluation of a multilinear polynomial diff --git a/src/traits/snark.rs b/src/traits/snark.rs index 9b8be9226..161c46f0e 100644 --- a/src/traits/snark.rs +++ b/src/traits/snark.rs @@ -6,8 +6,8 @@ use crate::{ CommitmentKey, }; -use abomonation::Abomonation; use serde::{Deserialize, Serialize}; +use std::sync::Arc; /// Public parameter creation takes a size hint. This size hint carries the particular requirements of /// the final compressing SNARK the user expected to use with these public parameters, and the below @@ -23,15 +23,10 @@ pub trait RelaxedR1CSSNARKTrait: Send + Sync + Serialize + for<'de> Deserialize<'de> { /// A type that represents the prover's key - type ProverKey: Send + Sync + Serialize + for<'de> Deserialize<'de> + Abomonation; + type ProverKey: Send + Sync; /// A type that represents the verifier's key - type VerifierKey: Send - + Sync - + Serialize - + for<'de> Deserialize<'de> - + DigestHelperTrait - + Abomonation; + type VerifierKey: Send + Sync + Serialize; /// This associated function (not a method) provides a hint that offers /// a minimum sizing cue for the commitment key used by this SNARK @@ -44,7 +39,7 @@ pub trait RelaxedR1CSSNARKTrait: /// Produces the keys for the prover and the verifier fn setup( - ck: &CommitmentKey, + ck: Arc>, S: &R1CSShape, ) -> Result<(Self::ProverKey, Self::VerifierKey), NovaError>; @@ -66,15 +61,10 @@ pub trait BatchedRelaxedR1CSSNARKTrait: Send + Sync + Serialize + for<'de> Deserialize<'de> { /// A type that represents the prover's key - type ProverKey: Send + Sync + Serialize + for<'de> Deserialize<'de> + Abomonation; + type ProverKey: Send + Sync; /// A type that represents the verifier's key - type VerifierKey: Send - + Sync - + Serialize - + for<'de> Deserialize<'de> - + DigestHelperTrait - + Abomonation; + type VerifierKey: Send + Sync + DigestHelperTrait; /// This associated function (not a method) provides a hint that offers /// a minimum sizing cue for the commitment key used by this SNARK @@ -85,8 +75,11 @@ pub trait BatchedRelaxedR1CSSNARKTrait: } /// Produces the keys for the prover and the verifier + /// + /// **Note:** This method should be cheap and should not copy most of the + /// commitment key. Look at CommitmentEngineTrait::setup for generating SRS data. fn setup( - ck: &CommitmentKey, + ck: Arc>, S: Vec<&R1CSShape>, ) -> Result<(Self::ProverKey, Self::VerifierKey), NovaError>;