diff --git a/.clippy.toml b/.clippy.toml index 0538654263..6c89968bc2 100644 --- a/.clippy.toml +++ b/.clippy.toml @@ -1,4 +1,4 @@ -type-complexity-threshold = 999 +type-complexity-threshold = 1200 too-many-arguments-threshold = 20 disallowed-methods = [ # we use strict naming for pasta fields diff --git a/Cargo.toml b/Cargo.toml index 11f215fc15..2f689a8fee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -125,7 +125,7 @@ clap = "4.3.17" ff = "0.13" metrics = "0.22.0" neptune = { git = "https://github.com/lurk-lab/neptune", branch = "dev", features = ["abomonation"] } -nova = { git = "https://github.com/lurk-lab/arecibo", branch = "dev", package = "arecibo" } +nova = { git = "https://github.com/lurk-lab/arecibo", branch = "split-ck", package = "arecibo", features = ["abomonate"] } once_cell = "1.18.0" pairing = { version = "0.23" } pasta_curves = { git = "https://github.com/lurk-lab/pasta_curves", branch = "dev" } diff --git a/benches/fibonacci.rs b/benches/fibonacci.rs index d4d3b2b7c2..9cbd85c5b1 100644 --- a/benches/fibonacci.rs +++ b/benches/fibonacci.rs @@ -90,6 +90,7 @@ fn fibonacci_prove( true, Kind::NovaPublicParams, ); + let store = Store::default(); let pp = public_params(&instance).unwrap(); // Track the number of `Lurk frames / sec` @@ -103,8 +104,6 @@ fn fibonacci_prove( BenchmarkId::new(name, params), &prove_params, |b, prove_params| { - let store = Store::default(); - let ptr = fib_expr::(&store); let prover = NovaProver::new(prove_params.reduction_count, lang_rc.clone()); @@ -119,7 +118,7 @@ fn fibonacci_prove( let _ = black_box(result); }, BatchSize::LargeInput, - ) + ); }, ); } diff --git a/benches/sha256.rs b/benches/sha256.rs index 97603cbd9f..b8f6d55a0e 100644 --- a/benches/sha256.rs +++ b/benches/sha256.rs @@ -111,7 +111,7 @@ fn sha256_ivc_prove( let lurk_step = make_eval_step_from_config(&EvalConfig::new_ivc(&lang)); // use cached public params - let instance: Instance<'_, Fr, Sha256Coproc> = Instance::new( + let instance: Instance> = Instance::new( reduction_count, lang_rc.clone(), true, diff --git a/examples/sha256_ivc.rs b/examples/sha256_ivc.rs index 75e5f7557d..ce36b1822c 100644 --- a/examples/sha256_ivc.rs +++ b/examples/sha256_ivc.rs @@ -77,7 +77,7 @@ fn main() { let pp_start = Instant::now(); let instance = Instance::new(REDUCTION_COUNT, lang_rc, true, Kind::NovaPublicParams); - // see the documentation on `with_public_params` + // see the documentation on `public_params` let pp = public_params(&instance).unwrap(); let pp_end = pp_start.elapsed(); println!("Public parameters took {:?}", pp_end); diff --git a/src/cli/lurk_proof.rs b/src/cli/lurk_proof.rs index 3f61213ebe..1ccc37dea9 100644 --- a/src/cli/lurk_proof.rs +++ b/src/cli/lurk_proof.rs @@ -126,10 +126,7 @@ pub(crate) enum LurkProof< 'a, F: CurveCycleEquipped, C: Coprocessor + Serialize + DeserializeOwned, -> where - < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, - < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, -{ +> { Nova { proof: nova::Proof>, public_inputs: Vec, @@ -141,9 +138,6 @@ pub(crate) enum LurkProof< impl<'a, F: CurveCycleEquipped, C: Coprocessor + 'a + Serialize + DeserializeOwned> HasFieldModulus for LurkProof<'a, F, C> -where - < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, - < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, { fn field_modulus() -> String { F::MODULUS.to_owned() @@ -152,9 +146,6 @@ where impl<'a, F: CurveCycleEquipped + Serialize, C: Coprocessor + Serialize + DeserializeOwned> LurkProof<'a, F, C> -where - < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, - < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, { #[inline] pub(crate) fn persist(self, proof_key: &str) -> Result<()> { @@ -162,6 +153,17 @@ where } } +impl< + F: CurveCycleEquipped + DeserializeOwned, + C: Coprocessor + Serialize + DeserializeOwned + 'static, + > LurkProof<'static, F, C> +{ + #[inline] + pub(crate) fn is_cached(proof_key: &str) -> bool { + load::(&proof_path(proof_key)).is_ok() + } +} + impl< F: CurveCycleEquipped + DeserializeOwned, C: Coprocessor + Serialize + DeserializeOwned + 'static, @@ -180,11 +182,6 @@ where Ok(()) } - #[inline] - pub(crate) fn is_cached(proof_key: &str) -> bool { - load::(&proof_path(proof_key)).is_ok() - } - fn verify(&self) -> Result { match self { Self::Nova { diff --git a/src/cli/repl/meta_cmd.rs b/src/cli/repl/meta_cmd.rs index f025098b28..11e561ed9f 100644 --- a/src/cli/repl/meta_cmd.rs +++ b/src/cli/repl/meta_cmd.rs @@ -2,7 +2,6 @@ use ::nova::traits::Engine; use abomonation::Abomonation; use anyhow::{anyhow, bail, Context, Result}; use camino::{Utf8Path, Utf8PathBuf}; -use ff::PrimeField; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use std::{collections::HashMap, process}; @@ -49,8 +48,8 @@ impl< C: Coprocessor + Serialize + DeserializeOwned + 'static, > MetaCmd where - ::Repr: Abomonation, - <<::E2 as Engine>::Scalar as PrimeField>::Repr: Abomonation, + < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, + < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, { const LOAD: MetaCmd = MetaCmd { name: "load", diff --git a/src/cli/repl/mod.rs b/src/cli/repl/mod.rs index 8b6973883a..7d2a72e76c 100644 --- a/src/cli/repl/mod.rs +++ b/src/cli/repl/mod.rs @@ -3,7 +3,6 @@ mod meta_cmd; use abomonation::Abomonation; use anyhow::{anyhow, bail, Context, Result}; use camino::{Utf8Path, Utf8PathBuf}; -use ff::PrimeField; use nova::traits::Engine; use rustyline::{ error::ReadlineError, @@ -40,7 +39,7 @@ use crate::{ }, parser, proof::{ - nova::{CurveCycleEquipped, NovaProver}, + nova::{CurveCycleEquipped, NovaProver, E1, E2}, RecursiveSNARKTrait, }, public_parameters::{ @@ -167,8 +166,8 @@ impl< C: Coprocessor + Serialize + DeserializeOwned + 'static, > Repl where - ::Repr: Abomonation, - <<::E2 as Engine>::Scalar as PrimeField>::Repr: Abomonation, + < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, + < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, { pub(crate) fn new( store: Store, @@ -337,7 +336,6 @@ where let instance = Instance::new(self.rc, self.lang.clone(), true, Kind::NovaPublicParams); let pp = public_params(&instance)?; - let prover = NovaProver::<_, C>::new(self.rc, self.lang.clone()); info!("Proving"); diff --git a/src/lem/multiframe.rs b/src/lem/multiframe.rs index 11a57a2332..9fc1cfe5f9 100644 --- a/src/lem/multiframe.rs +++ b/src/lem/multiframe.rs @@ -1,10 +1,8 @@ -use abomonation::Abomonation; use anyhow::Result; use bellpepper::util_cs::witness_cs::WitnessCS; use bellpepper_core::{num::AllocatedNum, Circuit, ConstraintSystem, SynthesisError}; use elsa::sync::FrozenMap; -use ff::PrimeField; -use nova::{supernova::NonUniformCircuit, traits::Engine}; +use nova::supernova::NonUniformCircuit; use once_cell::sync::OnceCell; use rayon::prelude::*; use std::sync::Arc; @@ -904,8 +902,6 @@ impl<'a, F, C> NonUniformCircuit, E2, MultiFrame<'a, F, C>, C2> for where F: CurveCycleEquipped + LurkField, C: Coprocessor + 'a, - < as Engine>::Scalar as PrimeField>::Repr: Abomonation, - < as Engine>::Scalar as PrimeField>::Repr: Abomonation, { fn num_circuits(&self) -> usize { assert_eq!(self.pc, 0); diff --git a/src/proof/nova.rs b/src/proof/nova.rs index 03139a8651..1441b379b0 100644 --- a/src/proof/nova.rs +++ b/src/proof/nova.rs @@ -1,6 +1,4 @@ -use abomonation::Abomonation; use bellpepper_core::{num::AllocatedNum, ConstraintSystem}; -use ff::PrimeField; use halo2curves::bn256::Fr as Bn256Scalar; use nova::{ errors::NovaError, @@ -11,8 +9,9 @@ use nova::{ snark::RelaxedR1CSSNARKTrait, Engine, }, - CompressedSNARK, ProverKey, R1CSWithArity, RecursiveSNARK, VerifierKey, + AuxParams, CompressedSNARK, ProverKey, R1CSWithArity, RecursiveSNARK, VerifierKey, }; +use once_cell::sync::OnceCell; use pasta_curves::pallas; use serde::{Deserialize, Serialize}; use std::{ @@ -54,6 +53,11 @@ pub trait CurveCycleEquipped: LurkField { type E1: Engine::Scalar, Scalar = Self>; /// The group type for the second curve in the cycle. type E2: Engine::Scalar>; + + /// Label the the primary curve + const PRIMARY: &'static str; + /// Label the the secondary curve + const SECONDARY: &'static str; } impl CurveCycleEquipped for pallas::Scalar { @@ -62,6 +66,9 @@ impl CurveCycleEquipped for pallas::Scalar { type E1 = PallasEngine; type E2 = VestaEngine; + + const PRIMARY: &'static str = "pallas"; + const SECONDARY: &'static str = "vesta"; } // The impl CurveCycleEquipped for vesta::Scalar is academically possible, but voluntarily omitted to avoid confusion. @@ -71,6 +78,9 @@ impl CurveCycleEquipped for Bn256Scalar { type E1 = Bn256Engine; type E2 = GrumpkinEngine; + + const PRIMARY: &'static str = "bn256"; + const SECONDARY: &'static str = "grumpkin"; } // The impl CurveCycleEquipped for grumpkin::Scalar is academically possible, but voluntarily omitted to avoid confusion. @@ -103,6 +113,9 @@ pub type C2 = TrivialCircuit< as Engine>::Scalar>; /// Type alias for Nova Circuit Parameters with the curve cycle types defined above. pub type NovaCircuitShape = R1CSWithArity>; +/// Type alias for Nova Aux Parameters with the curve cycle types defined above. +pub type NovaAuxParams = AuxParams, E2>; + /// Type alias for Nova Public Parameters with the curve cycle types defined above. pub type NovaPublicParams = nova::PublicParams, E2, C1, C2>; @@ -112,50 +125,61 @@ pub type NovaPublicParams = nova::PublicParams, E2, C1, C2>; pub struct PublicParams> where F: CurveCycleEquipped, - // technical bounds that would disappear once associated_type_bounds stabilizes - < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, - < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, { - pp: NovaPublicParams, - pk: ProverKey, E2, SC, C2, SS1, SS2>, - vk: VerifierKey, E2, SC, C2, SS1, SS2>, + /// Public parameters for the Nova proving system. + pub pp: NovaPublicParams, + /// Prover and verifier key for final proof compression + #[serde(skip)] + pk_and_vk: OnceCell<( + ProverKey, E2, SC, C2, SS1, SS2>, + VerifierKey, E2, SC, C2, SS1, SS2>, + )>, } -impl> Abomonation for PublicParams -where - < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, - < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, +// this avoids dipping into the pk/vk +impl + std::fmt::Debug> std::fmt::Debug + for PublicParams { - unsafe fn entomb(&self, bytes: &mut W) -> std::io::Result<()> { - self.pp.entomb(bytes)?; - self.pk.entomb(bytes)?; - self.vk.entomb(bytes)?; - Ok(()) + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("PublicParams") + .field("pp", &self.pp) + .finish() } +} - unsafe fn exhume<'b>(&mut self, mut bytes: &'b mut [u8]) -> Option<&'b mut [u8]> { - let temp = bytes; - bytes = self.pp.exhume(temp)?; - let temp = bytes; - bytes = self.pk.exhume(temp)?; - let temp = bytes; - bytes = self.vk.exhume(temp)?; - Some(bytes) +impl> PublicParams { + /// provides a reference to a ProverKey suitable for producing a CompressedProof + pub fn pk(&self) -> &ProverKey, E2, SC, C2, SS1, SS2> { + let (pk, _vk) = self.pk_and_vk.get_or_init(|| { + CompressedSNARK::, E2, SC, C2, SS1, SS2>::setup(&self.pp).unwrap() + }); + pk } - fn extent(&self) -> usize { - self.pp.extent() + self.pk.extent() + self.vk.extent() + /// provides a reference to a VerifierKey suitable for verifying a CompressedProof + pub fn vk(&self) -> &VerifierKey, E2, SC, C2, SS1, SS2> { + let (_pk, vk) = self.pk_and_vk.get_or_init(|| { + CompressedSNARK::, E2, SC, C2, SS1, SS2>::setup(&self.pp).unwrap() + }); + vk + } +} + +impl> From> + for PublicParams +{ + fn from(pp: NovaPublicParams) -> PublicParams { + PublicParams { + pp, + pk_and_vk: OnceCell::new(), + } } } /// An enum representing the two types of proofs that can be generated and verified. #[derive(Serialize, Deserialize)] #[serde(bound = "")] -pub enum Proof> -where - < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, - < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, -{ +pub enum Proof> { /// A proof for the intermediate steps of a recursive computation along with /// the number of steps used for verification Recursive(Box, E2, C1, C2>>, usize), @@ -186,11 +210,7 @@ pub fn circuit_cache_key<'a, F: CurveCycleEquipped, C: Coprocessor + 'a>( pub fn public_params<'a, F: CurveCycleEquipped, C: Coprocessor + 'a>( reduction_count: usize, lang: Arc>, -) -> PublicParams> -where - < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, - < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, -{ +) -> PublicParams> { let (circuit_primary, circuit_secondary) = circuits(reduction_count, lang); let commitment_size_hint1 = as RelaxedR1CSSNARKTrait>>::ck_floor(); @@ -202,8 +222,10 @@ where &*commitment_size_hint1, &*commitment_size_hint2, ); - let (pk, vk) = CompressedSNARK::setup(&pp).unwrap(); - PublicParams { pp, pk, vk } + PublicParams { + pp, + pk_and_vk: OnceCell::new(), + } } /// Generates the circuits for the Nova proving system. @@ -220,9 +242,6 @@ pub fn circuits<'a, F: CurveCycleEquipped, C: Coprocessor + 'a>( impl<'a, F: CurveCycleEquipped, C: Coprocessor> RecursiveSNARKTrait> for Proof> -where - ::Repr: Abomonation, - <<::E2 as Engine>::Scalar as PrimeField>::Repr: Abomonation, { type PublicParams = PublicParams>; @@ -342,7 +361,7 @@ where Self::Recursive(recursive_snark, num_steps) => Ok(Self::Compressed( Box::new(CompressedSNARK::<_, _, _, _, SS1, SS2>::prove( &pp.pp, - &pp.pk, + pp.pk(), &recursive_snark, )?), num_steps, @@ -361,7 +380,7 @@ where p.verify(&pp.pp, *num_steps, z0_primary, &z0_secondary)? } Self::Compressed(p, num_steps) => { - p.verify(&pp.vk, *num_steps, z0_primary, &z0_secondary)? + p.verify(pp.vk(), *num_steps, z0_primary, &z0_secondary)? } }; @@ -379,11 +398,7 @@ pub struct NovaProver<'a, F: CurveCycleEquipped, C: Coprocessor> { _phantom: PhantomData<&'a ()>, } -impl<'a, F: CurveCycleEquipped, C: Coprocessor + 'a> NovaProver<'a, F, C> -where - < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, - < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, -{ +impl<'a, F: CurveCycleEquipped, C: Coprocessor + 'a> NovaProver<'a, F, C> { /// Create a new NovaProver with a reduction count and a `Lang` #[inline] pub fn new(reduction_count: usize, lang: Arc>) -> Self { @@ -417,9 +432,6 @@ where impl<'a, F: CurveCycleEquipped, C: Coprocessor + 'a> Prover<'a, F, C1LEM<'a, F, C>> for NovaProver<'a, F, C> -where - < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, - < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, { type PublicParams = PublicParams>; type RecursiveSnark = Proof>; diff --git a/src/proof/supernova.rs b/src/proof/supernova.rs index 74a7ef93db..9809be3fea 100644 --- a/src/proof/supernova.rs +++ b/src/proof/supernova.rs @@ -1,5 +1,3 @@ -use abomonation::Abomonation; -use ff::PrimeField; use nova::{ supernova::{ self, @@ -13,6 +11,7 @@ use nova::{ Engine, }, }; +use once_cell::sync::OnceCell; use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator}; use serde::{Deserialize, Serialize}; use std::{ @@ -47,26 +46,47 @@ pub type SuperNovaAuxParams = AuxParams, E2>; pub type SuperNovaPublicParams = supernova::PublicParams, E2, C1, C2>; /// A struct that contains public parameters for the SuperNova proving system. -pub struct PublicParams> -where - // technical bounds that would disappear once associated_type_bounds stabilizes - < as Engine>::Scalar as PrimeField>::Repr: Abomonation, - < as Engine>::Scalar as PrimeField>::Repr: Abomonation, -{ +pub struct PublicParams> { /// Public params for SuperNova. pub pp: SuperNovaPublicParams, - /// Prover key for SuperNova - pub pk: ProverKey, E2, SC, C2, SS1, SS2>, - /// Verifier key for SuperNova - pub vk: VerifierKey, E2, SC, C2, SS1, SS2>, + /// Prover key and Verifier key for SuperNova + // TODO: mark as #[serde(skip)] when serializing + pub pk_and_vk: OnceCell<( + ProverKey, E2, SC, C2, SS1, SS2>, + VerifierKey, E2, SC, C2, SS1, SS2>, + )>, } -impl> Index for PublicParams -where - // technical bounds that would disappear once associated_type_bounds stabilizes - < as Engine>::Scalar as PrimeField>::Repr: Abomonation, - < as Engine>::Scalar as PrimeField>::Repr: Abomonation, +impl> PublicParams { + /// provides a reference to a ProverKey suitable for producing a CompressedProof + pub fn pk(&self) -> &ProverKey, E2, SC, C2, SS1, SS2> { + let (pk, _vk) = self.pk_and_vk.get_or_init(|| { + CompressedSNARK::, E2, SC, C2, SS1, SS2>::setup(&self.pp).unwrap() + }); + pk + } + + /// provides a reference to a VerifierKey suitable for verifying a CompressedProof + pub fn vk(&self) -> &VerifierKey, E2, SC, C2, SS1, SS2> { + let (_pk, vk) = self.pk_and_vk.get_or_init(|| { + CompressedSNARK::, E2, SC, C2, SS1, SS2>::setup(&self.pp).unwrap() + }); + vk + } +} + +impl> From> + for PublicParams { + fn from(pp: SuperNovaPublicParams) -> PublicParams { + PublicParams { + pp, + pk_and_vk: OnceCell::new(), + } + } +} + +impl> Index for PublicParams { type Output = NovaCircuitShape; fn index(&self, index: usize) -> &Self::Output { @@ -74,12 +94,7 @@ where } } -impl> PublicParams -where - // technical bounds that would disappear once associated_type_bounds stabilizes - < as Engine>::Scalar as PrimeField>::Repr: Abomonation, - < as Engine>::Scalar as PrimeField>::Repr: Abomonation, -{ +impl> PublicParams { /// return the digest pub fn digest(&self) -> F { self.pp.digest() @@ -104,11 +119,7 @@ pub type SS2 = nova::spartan::snark::RelaxedR1CSSNARK, EE2>; pub fn public_params<'a, F: CurveCycleEquipped, C: Coprocessor + 'a>( rc: usize, lang: Arc>, -) -> PublicParams> -where - < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, - < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, -{ +) -> PublicParams> { let folding_config = Arc::new(FoldingConfig::new_nivc(lang, rc)); let non_uniform_circuit = C1LEM::<'a, F, C>::blank(folding_config, 0); @@ -121,18 +132,16 @@ where &*commitment_size_hint1, &*commitment_size_hint2, ); - let (pk, vk) = CompressedSNARK::setup(&pp).unwrap(); - PublicParams { pp, pk, vk } + PublicParams { + pp, + pk_and_vk: OnceCell::new(), + } } /// An enum representing the two types of proofs that can be generated and verified. #[derive(Serialize, Deserialize)] #[serde(bound = "")] -pub enum Proof> -where - < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, - < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, -{ +pub enum Proof> { /// A proof for the intermediate steps of a recursive computation Recursive(Box, E2>>), /// A proof for the final step of a recursive computation @@ -150,11 +159,7 @@ pub struct SuperNovaProver<'a, F: CurveCycleEquipped, C: Coprocessor + 'a> { _phantom: PhantomData<&'a ()>, } -impl<'a, F: CurveCycleEquipped, C: Coprocessor + 'a> SuperNovaProver<'a, F, C> -where - < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, - < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, -{ +impl<'a, F: CurveCycleEquipped, C: Coprocessor + 'a> SuperNovaProver<'a, F, C> { /// Create a new SuperNovaProver with a reduction count and a `Lang` #[inline] pub fn new(reduction_count: usize, lang: Arc>) -> Self { @@ -188,9 +193,6 @@ where impl<'a, F: CurveCycleEquipped, C: Coprocessor> RecursiveSNARKTrait> for Proof> -where - < as Engine>::Scalar as PrimeField>::Repr: Abomonation, - < as Engine>::Scalar as PrimeField>::Repr: Abomonation, { type PublicParams = PublicParams>; @@ -301,7 +303,7 @@ where Self::Recursive(recursive_snark) => { let snark = CompressedSNARK::<_, _, _, _, SS1, SS2>::prove( &pp.pp, - &pp.pk, + pp.pk(), recursive_snark, )?; Ok(Self::Compressed(Box::new(snark))) @@ -317,7 +319,7 @@ where let (zi_primary_verified, zi_secondary_verified) = match self { Self::Recursive(p) => p.verify(&pp.pp, z0_primary, &z0_secondary)?, - Self::Compressed(p) => p.verify(&pp.pp, &pp.vk, z0_primary, &z0_secondary)?, + Self::Compressed(p) => p.verify(&pp.pp, pp.vk(), z0_primary, &z0_secondary)?, }; Ok(zi_primary == zi_primary_verified && zi_secondary == &zi_secondary_verified) @@ -326,9 +328,6 @@ where impl<'a, F: CurveCycleEquipped, C: Coprocessor> Prover<'a, F, C1LEM<'a, F, C>> for SuperNovaProver<'a, F, C> -where - < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, - < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, { type PublicParams = PublicParams>; type RecursiveSnark = Proof>; @@ -419,11 +418,7 @@ pub fn circuit_cache_key<'a, F: CurveCycleEquipped, C: Coprocessor + 'a>( rc: usize, lang: Arc>, circuit_index: usize, -) -> F -where - < as Engine>::Scalar as PrimeField>::Repr: Abomonation, - < as Engine>::Scalar as PrimeField>::Repr: Abomonation, -{ +) -> F { let folding_config = Arc::new(FoldingConfig::new_nivc(lang, 2)); let circuit = C1LEM::<'a, F, C>::blank(folding_config, 0); let num_circuits = circuit.num_circuits(); @@ -436,11 +431,7 @@ where pub fn circuit_cache_keys<'a, F: CurveCycleEquipped, C: Coprocessor + 'a>( rc: usize, lang: &Arc>, -) -> CircuitDigests> -where - < as Engine>::Scalar as PrimeField>::Repr: Abomonation, - < as Engine>::Scalar as PrimeField>::Repr: Abomonation, -{ +) -> CircuitDigests> { let num_circuits = lang.coprocessor_count() + 1; let digests = (0..num_circuits) .map(|circuit_index| circuit_cache_key::(rc, lang.clone(), circuit_index)) diff --git a/src/proof/tests/mod.rs b/src/proof/tests/mod.rs index fdaa215085..649f8d3d10 100644 --- a/src/proof/tests/mod.rs +++ b/src/proof/tests/mod.rs @@ -1,10 +1,7 @@ mod nova_tests_lem; - -use abomonation::Abomonation; use bellpepper::util_cs::{metric_cs::MetricCS, witness_cs::WitnessCS, Comparable}; use bellpepper_core::{test_cs::TestConstraintSystem, Circuit, ConstraintSystem, Delta}; use expect_test::Expect; -use nova::traits::Engine; use std::sync::Arc; use crate::{ @@ -12,7 +9,7 @@ use crate::{ eval::lang::Lang, lem::{eval::EvalConfig, pointers::Ptr, store::Store}, proof::{ - nova::{public_params, CurveCycleEquipped, NovaProver, C1LEM, E1, E2}, + nova::{public_params, CurveCycleEquipped, NovaProver, C1LEM}, supernova::FoldingConfig, CEKState, EvaluationStore, FrameLike, Provable, Prover, RecursiveSNARKTrait, }, @@ -45,12 +42,7 @@ fn test_aux>( expected_emitted: Option<&[Ptr]>, expected_iterations: &Expect, lang: &Option>>, -) -// technical bounds that would disappear once associated_type_bounds stabilizes -where - < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, - < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, -{ +) { for chunk_size in REDUCTION_COUNTS_TO_TEST { nova_test_full_aux::( s, @@ -80,12 +72,7 @@ fn nova_test_full_aux>( check_nova: bool, limit: Option, lang: &Option>>, -) -// technical bounds that would disappear once associated_type_bounds stabilizes -where - < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, - < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, -{ +) { let expr = EvaluationStore::read(s, expr).unwrap(); let f = |l| { @@ -124,12 +111,7 @@ fn nova_test_full_aux2<'a, F: CurveCycleEquipped, C: Coprocessor + 'a>( check_nova: bool, limit: Option, lang: Arc>, -) -// technical bounds that would disappear once associated_type_bounds stabilizes -where - < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, - < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, -{ +) { let limit = limit.unwrap_or(10000); let e = s.initial_empty_env(); diff --git a/src/public_parameters/disk_cache.rs b/src/public_parameters/disk_cache.rs index c54cbc27a2..0f23913fa1 100644 --- a/src/public_parameters/disk_cache.rs +++ b/src/public_parameters/disk_cache.rs @@ -4,11 +4,10 @@ use std::marker::PhantomData; use abomonation::{encode, Abomonation}; use camino::{Utf8Path, Utf8PathBuf}; -use nova::traits::Engine; use crate::config::lurk_config; use crate::coprocessor::Coprocessor; -use crate::proof::nova::{CurveCycleEquipped, PublicParams, C1LEM, E1, E2}; +use crate::proof::nova::{CurveCycleEquipped, PublicParams, C1LEM}; use crate::public_parameters::error::Error; use super::instance::Instance; @@ -19,21 +18,16 @@ pub(crate) fn public_params_dir() -> &'static Utf8PathBuf { &lurk_config(None, None).public_params_dir } -pub(crate) struct DiskCache<'a, F, C> +pub(crate) struct DiskCache where F: CurveCycleEquipped, - C: Coprocessor + 'a, + C: Coprocessor, { dir: Utf8PathBuf, - _t: PhantomData<(&'a (), F, C)>, + _t: PhantomData<(F, C)>, } -impl<'a, F: CurveCycleEquipped, C: Coprocessor + 'a> DiskCache<'a, F, C> -where - // technical bounds that would disappear once associated_type_bounds stabilizes - < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, - < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, -{ +impl> DiskCache { pub(crate) fn new(disk_cache_path: &Utf8Path) -> Result { create_dir_all(disk_cache_path)?; @@ -43,9 +37,9 @@ where }) } - pub(crate) fn read( + pub(crate) fn read<'a>( &self, - instance: &Instance<'a, F, C>, + instance: &Instance, ) -> Result>, Error> { let file = instance.open(&self.dir)?; let reader = BufReader::new(file); @@ -55,7 +49,7 @@ where pub(crate) fn read_bytes( &self, - instance: &Instance<'a, F, C>, + instance: &Instance, byte_sink: &mut Vec, ) -> Result<(), Error> { let file = instance.open(&self.dir)?; @@ -66,18 +60,18 @@ where pub(crate) fn write( &self, - instance: &Instance<'a, F, C>, - data: &PublicParams>, + instance: &Instance, + data: &PublicParams>, ) -> Result<(), Error> { let file = instance.create(&self.dir)?; let writer = BufWriter::new(&file); - bincode::serialize_into(writer, &data) + bincode::serialize_into(writer, data) .map_err(|e| Error::Cache(format!("Public param cache serialization error: {}", e))) } pub(crate) fn write_abomonated( &self, - instance: &Instance<'a, F, C>, + instance: &Instance, data: &V, ) -> Result<(), Error> { let mut file = instance.create(&self.dir)?; diff --git a/src/public_parameters/instance.rs b/src/public_parameters/instance.rs index ad378467ab..8ec47a4d76 100644 --- a/src/public_parameters/instance.rs +++ b/src/public_parameters/instance.rs @@ -38,12 +38,10 @@ use std::{ fs::File, io::{self, BufReader, BufWriter}, - marker::PhantomData, sync::Arc, }; -use ::nova::{constants::NUM_HASH_BITS, traits::Engine}; -use abomonation::Abomonation; +use ::nova::constants::NUM_HASH_BITS; use camino::Utf8Path; use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; @@ -52,7 +50,7 @@ use crate::{ coprocessor::Coprocessor, eval::lang::Lang, proof::{ - nova::{self, CurveCycleEquipped, E1, E2}, + nova::{self, CurveCycleEquipped}, supernova::{self}, }, }; @@ -69,13 +67,12 @@ use crate::{ /// we derive the `num_circuits + 1` circuit param instances. This makes sure that we keep the SuperNova /// instances as modular as possible, and reuse as much overlapping circuit params as possible. #[derive(Debug)] -pub struct Instance<'a, F: CurveCycleEquipped, C: Coprocessor + 'a> { +pub struct Instance> { pub rc: usize, pub lang: Arc>, pub abomonated: bool, pub cache_key: F, pub kind: Kind, - pub _p: PhantomData<&'a ()>, } /// From [::nova], there are 3 "kinds" of public param objects that need to be cached. @@ -91,8 +88,11 @@ pub enum Kind { NovaPublicParams, /// Tag for [supernova::SuperNovaAuxParams] instances SuperNovaAuxParams, - /// Tag for [supernova::SuperNovaCircuitParams] instances + /// Tag for [nova::NovaCircuitShape] instances SuperNovaCircuitParams(usize), + + /// Tag for [CommitmentKey] instances + CommitmentKey, } /// What we put into the cache @@ -107,7 +107,7 @@ pub struct Metadata { impl Metadata { fn from_instance<'a, F: CurveCycleEquipped, C: Coprocessor + 'a>( - instance: &Instance<'a, F, C>, + instance: &Instance, ) -> Self { Metadata { rc: instance.rc, @@ -119,18 +119,15 @@ impl Metadata { } } -impl<'a, F: CurveCycleEquipped, C: Coprocessor> Instance<'a, F, C> -where - < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, - < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, -{ +impl> Instance { pub fn new(rc: usize, lang: Arc>, abomonated: bool, kind: Kind) -> Self { let cache_key = match kind { - Kind::NovaPublicParams => nova::circuit_cache_key::<'a, F, C>(rc, lang.clone()), + Kind::NovaPublicParams => nova::circuit_cache_key::(rc, lang.clone()), Kind::SuperNovaAuxParams => supernova::circuit_cache_keys::(rc, &lang).digest(), Kind::SuperNovaCircuitParams(circuit_index) => { - supernova::circuit_cache_key::<'a, F, C>(rc, lang.clone(), circuit_index) - } + supernova::circuit_cache_key::(rc, lang.clone(), circuit_index) + }, + Kind::CommitmentKey => panic!("use `Instance::new_cks` instead"), }; Instance { rc, @@ -138,10 +135,31 @@ where abomonated, cache_key, kind, - _p: PhantomData, } } + /// This is a hack for now. `rc` is the size of the key + pub fn new_cks(primary_len: usize, secondary_len: usize, abomonated: bool) -> (Self, Self) { + let primary_ck = compute_cache_key(F::PRIMARY); + let secondary_ck = compute_cache_key(F::SECONDARY); + let primary = Instance { + rc: primary_len, + lang: Arc::new(Lang::new()), + abomonated, + cache_key: primary_ck, + kind: Kind::CommitmentKey, + }; + let secondary = Instance { + rc: secondary_len, + lang: Arc::new(Lang::new()), + abomonated, + cache_key: secondary_ck, + kind: Kind::CommitmentKey, + }; + + (primary, secondary) + } + /// If this [Instance] is of [Kind::SuperNovaAuxParams], then generate the `num_circuits + 1` /// circuit param instances that are determined by the internal [Lang]. pub fn circuit_param_instances(&self) -> Vec { @@ -175,11 +193,7 @@ where } } -impl<'a, F: CurveCycleEquipped, C: Coprocessor> Instance<'a, F, C> -where - < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, - < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, -{ +impl> Instance { /// The key (or cache_key) of this [Instance] used to retrieve it from the file cache pub fn lang(&self) -> Arc> { self.lang.clone() @@ -233,7 +247,7 @@ where } /// Compute the cache key of any serializable object -fn compute_cache_key(o: &T) -> F { +fn compute_cache_key(o: &T) -> F { // obtain a vector of bytes representing public parameters let bytes = bincode::serialize(o).unwrap(); diff --git a/src/public_parameters/mem_cache.rs b/src/public_parameters/mem_cache.rs deleted file mode 100644 index 64d4899a3f..0000000000 --- a/src/public_parameters/mem_cache.rs +++ /dev/null @@ -1,132 +0,0 @@ -use std::{ - collections::{hash_map::Entry, HashMap}, - sync::{Arc, Mutex}, -}; - -use abomonation::{decode, Abomonation}; -use nova::traits::Engine; -use once_cell::sync::Lazy; -use tap::TapFallible; -use tracing::{info, warn}; - -use crate::proof::nova::C1LEM; -use crate::{ - coprocessor::Coprocessor, - proof::nova::{PublicParams, E1, E2}, -}; -use crate::{proof::nova::CurveCycleEquipped, public_parameters::error::Error}; - -use super::{ - disk_cache::{public_params_dir, DiskCache}, - instance::Instance, -}; - -type AnyMap = anymap::Map; -type PublicParamMap = HashMap<(usize, bool), Arc>>; - -/// This is a global registry for Coproc-specific parameters. -/// It is used to cache parameters for each Coproc, so that they are not -/// re-initialized on each call to `eval`. -/// The use of AnyMap is a workaround for the fact that we need static storage for generic parameters, -/// noting that this is not possible in Rust. -#[derive(Clone)] -pub(crate) struct PublicParamMemCache { - mem_cache: Arc>, -} - -pub(crate) static PUBLIC_PARAM_MEM_CACHE: Lazy = - Lazy::new(|| PublicParamMemCache { - mem_cache: Arc::new(Mutex::new(AnyMap::new())), - }); - -impl PublicParamMemCache { - fn get_from_disk_cache_or_update_with< - 'a, - F: CurveCycleEquipped, - C: Coprocessor + 'static, - Fn: FnOnce(&Instance<'static, F, C>) -> Arc>>, - >( - &'static self, - instance: &Instance<'static, F, C>, - default: Fn, - ) -> Result>>, Error> - where - < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, - < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, - { - // subdirectory search - let disk_cache = DiskCache::new(public_params_dir()).unwrap(); - - // read the file if it exists, otherwise initialize - if instance.abomonated { - let mut bytes = vec![]; - match disk_cache.read_bytes(instance, &mut bytes) { - Ok(()) => { - info!("loading abomonated {}", instance.key()); - let (pp, rest) = - unsafe { decode::>>(&mut bytes).unwrap() }; - assert!(rest.is_empty()); - Ok(Arc::new(pp.clone())) // this clone is VERY expensive - } - Err(Error::IO(e)) => { - warn!("{e}"); - info!("Generating fresh public parameters"); - let pp = default(instance); - // maybe just directly write - disk_cache - .write_abomonated(instance, &*pp) - .tap_ok(|_| { - info!("writing public params to disk-cache: {}", instance.key()) - }) - .map_err(|e| Error::Cache(format!("Disk write error: {e}")))?; - Ok(pp) - } - _ => unreachable!(), - } - } else { - // read the file if it exists, otherwise initialize - if let Ok(pp) = disk_cache.read(instance) { - info!("loading abomonated {}", instance.key()); - Ok(Arc::new(pp)) - } else { - let pp = default(instance); - disk_cache - .write(instance, &*pp) - .tap_ok(|_| info!("writing public params to disk-cache: {}", instance.key())) - .map_err(|e| Error::Cache(format!("Disk write error: {e}")))?; - Ok(pp) - } - } - } - - /// Check if params for this Coproc are in registry, if so, return them. - /// Otherwise, initialize with the passed in function. - pub(crate) fn get_from_mem_cache_or_update_with< - F: CurveCycleEquipped, - C: Coprocessor + 'static, - Fn: FnOnce(&Instance<'static, F, C>) -> Arc>>, - >( - &'static self, - instance: &Instance<'static, F, C>, - default: Fn, - ) -> Result>>, Error> - where - < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, - < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, - { - // re-grab the lock - let mut mem_cache = self.mem_cache.lock().unwrap(); - // retrieve the per-Coproc public param table - let entry = mem_cache.entry::>>(); - // deduce the map and populate it if needed - let param_entry = entry.or_default(); - match param_entry.entry((instance.rc, instance.abomonated)) { - Entry::Occupied(o) => Ok(o.into_mut()), - Entry::Vacant(v) => { - let val = self.get_from_disk_cache_or_update_with(instance, default)?; - Ok(v.insert(val)) - } - } - .cloned() // this clone is VERY expensive - } -} diff --git a/src/public_parameters/mod.rs b/src/public_parameters/mod.rs index 754be68ed4..2d000443aa 100644 --- a/src/public_parameters/mod.rs +++ b/src/public_parameters/mod.rs @@ -1,79 +1,149 @@ -use ::nova::{supernova::snark::CompressedSNARK, traits::Engine}; +use ::nova::traits::Engine; +use ::nova::{CommitmentKey, CommitmentKeyParams}; use abomonation::{decode, Abomonation}; -use std::sync::Arc; +use once_cell::sync::OnceCell; use crate::coprocessor::Coprocessor; -use crate::proof::nova::{self, NovaCircuitShape, PublicParams, C1LEM}; +use crate::proof::nova::{self, NovaCircuitShape, NovaAuxParams, NovaPublicParams, C1LEM}; use crate::proof::nova::{CurveCycleEquipped, E1, E2}; pub mod disk_cache; mod error; pub mod instance; -mod mem_cache; use crate::proof::supernova::{self, SuperNovaAuxParams, SuperNovaPublicParams}; -use crate::public_parameters::disk_cache::public_params_dir; +use crate::public_parameters::disk_cache::{public_params_dir, DiskCache}; use crate::public_parameters::error::Error; +use crate::public_parameters::instance::Instance; -use self::disk_cache::DiskCache; -use self::instance::Instance; +pub fn nova_aux_params<'a, F: CurveCycleEquipped, C: Coprocessor + 'a>( + instance: &Instance, +) -> Result, Error> +where + < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, + < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, +{ + let disk_cache = DiskCache::::new(public_params_dir()).unwrap(); -pub fn public_params<'a, F: CurveCycleEquipped, C: Coprocessor + 'static>( - instance: &Instance<'static, F, C>, -) -> Result>>, Error> + let mut bytes = vec![]; + disk_cache.read_bytes(instance, &mut bytes).and_then(|()| { + if let Some((aux_params, remaining)) = + unsafe { decode::>(&mut bytes) } + { + assert!(remaining.is_empty()); + Ok(aux_params.clone()) + } else { + Err(Error::Cache("failed to decode bytes".into())) + } + }) +} + +/// Attempts to extract abomonated public parameters. +pub fn public_params<'a, F: CurveCycleEquipped, C: Coprocessor + 'a>( + instance_primary: &Instance, +) -> Result>, Error> where < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, { - let f = |instance: &Instance<'static, F, C>| { - Arc::new(nova::public_params(instance.rc, instance.lang())) + let default = |instance: &Instance| { + nova::public_params::<'a, F, C>(instance.rc, instance.lang()) + }; + let disk_cache = DiskCache::::new(public_params_dir()).unwrap(); + + let maybe_circuit_params_vec = instance_primary + .circuit_param_instances() + .iter() + .map(|instance| circuit_params::(instance)) + .collect::>, _>>(); + + let maybe_aux_params = nova_aux_params::(instance_primary); + + let pp = if let (Ok(mut circuit_params_vec), Ok(aux_params)) = + (maybe_circuit_params_vec, maybe_aux_params) + { + let (primary, secondary) = Instance::::new_cks( + aux_params.ck_primary_len, + aux_params.ck_secondary_len, + instance_primary.abomonated, + ); + let ck_params = commitment_key_params(&primary, &secondary)?; + let pp = NovaPublicParams::>::from_parts( + circuit_params_vec.remove(0), // there should only be one element + ck_params, + aux_params, + ); + + nova::PublicParams::from(pp) + } else { + let pp = default(instance_primary); + + let (circuit_shape, ck_params, aux_params) = pp.pp.into_parts(); + + disk_cache.write_abomonated(instance_primary, &aux_params)?; + + let (primary, secondary) = Instance::new_cks( + aux_params.ck_primary_len, + aux_params.ck_secondary_len, + instance_primary.abomonated, + ); + disk_cache.write_abomonated(&primary, &ck_params.primary)?; + disk_cache.write_abomonated(&secondary, &ck_params.secondary)?; + + let instance = instance_primary.reindex(0); + disk_cache.write_abomonated(&instance, &circuit_shape)?; + + let pp = NovaPublicParams::>::from_parts( + circuit_shape, + ck_params, + aux_params, + ); + + nova::PublicParams::from(pp) }; - mem_cache::PUBLIC_PARAM_MEM_CACHE.get_from_mem_cache_or_update_with(instance, f) + + Ok(pp) } -/// Attempts to extract abomonated public parameters. -/// To avoid all copying overhead, we zerocopy all of the data within the file; -/// this leads to extremely high performance, but restricts the lifetime of the data -/// to the lifetime of the file. Thus, we cannot pass a reference out and must -/// rely on a closure to capture the data and continue the computation in `bind`. -pub fn with_public_params<'a, F, C, M, Fn, T>( - instance: &Instance<'a, F, C>, - bind: Fn, -) -> Result +pub fn commitment_key_params<'a, F: CurveCycleEquipped, C: Coprocessor + 'a>( + primary: &Instance, + secondary: &Instance, +) -> Result, E2>, Error> where - F: CurveCycleEquipped, - C: Coprocessor + 'a, - Fn: FnOnce(&PublicParams>) -> T, < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, { - let default = |instance: &Instance<'a, F, C>| nova::public_params(instance.rc, instance.lang()); let disk_cache = DiskCache::::new(public_params_dir()).unwrap(); let mut bytes = vec![]; - let pp = disk_cache.read_bytes(instance, &mut bytes).and_then(|()| { - if let Some((pp, remaining)) = unsafe { decode(&mut bytes) } { + let ck_primary = disk_cache.read_bytes(primary, &mut bytes).and_then(|()| { + if let Some((pp, remaining)) = unsafe { decode::>>(&mut bytes) } { assert!(remaining.is_empty()); - eprintln!("Using disk-cached public params for {}", instance.key()); - Ok(pp) + eprintln!("Using disk-cached commitment key for {}", primary.key()); + Ok(pp.clone()) } else { Err(Error::Cache("failed to decode bytes".into())) } - }); - - match pp { - Ok(pp) => Ok(bind(pp)), - Err(e) => { - eprintln!("{e}"); - let pp = default(instance); - disk_cache.write_abomonated(instance, &pp)?; - Ok(bind(&pp)) - } - } + })?; + let ck_secondary = disk_cache + .read_bytes(secondary, &mut bytes) + .and_then(|()| { + if let Some((pp, remaining)) = unsafe { decode::>>(&mut bytes) } { + assert!(remaining.is_empty()); + eprintln!("Using disk-cached commitment key for {}", secondary.key()); + Ok(pp.clone()) + } else { + Err(Error::Cache("failed to decode bytes".into())) + } + })?; + Ok(CommitmentKeyParams { + primary: ck_primary, + secondary: ck_secondary, + }) } -pub fn supernova_circuit_params<'a, F: CurveCycleEquipped, C: Coprocessor + 'a>( - instance: &Instance<'a, F, C>, +pub fn circuit_params<'a, F: CurveCycleEquipped, C: Coprocessor + 'a>( + instance: &Instance, ) -> Result, Error> where < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, @@ -85,7 +155,7 @@ where disk_cache.read_bytes(instance, &mut bytes).and_then(|()| { if let Some((pp, remaining)) = unsafe { decode::>(&mut bytes) } { assert!(remaining.is_empty()); - eprintln!("Using disk-cached public params for {}", instance.key()); + eprintln!("Using disk-cached circuit params for {}", instance.key()); Ok(pp.clone()) } else { Err(Error::Cache("failed to decode bytes".into())) @@ -94,7 +164,7 @@ where } pub fn supernova_aux_params<'a, F: CurveCycleEquipped, C: Coprocessor + 'a>( - instance: &Instance<'a, F, C>, + instance: &Instance, ) -> Result, Error> where < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, @@ -117,13 +187,13 @@ where /// Attempts to extract abomonated public parameters. pub fn supernova_public_params<'a, F: CurveCycleEquipped, C: Coprocessor + 'a>( - instance_primary: &Instance<'a, F, C>, + instance_primary: &Instance, ) -> Result>, Error> where < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, { - let default = |instance: &Instance<'a, F, C>| { + let default = |instance: &Instance| { supernova::public_params::<'a, F, C>(instance.rc, instance.lang()) }; let disk_cache = DiskCache::::new(public_params_dir()).unwrap(); @@ -131,7 +201,7 @@ where let maybe_circuit_params_vec = instance_primary .circuit_param_instances() .iter() - .map(|instance| supernova_circuit_params::(instance)) + .map(|instance| circuit_params::(instance)) .collect::>, _>>(); let maybe_aux_params = supernova_aux_params::(instance_primary); @@ -139,23 +209,37 @@ where let pp = if let (Ok(circuit_params_vec), Ok(aux_params)) = (maybe_circuit_params_vec, maybe_aux_params) { - println!("generating public params"); - + let (primary, secondary) = Instance::::new_cks( + aux_params.ck_primary_len, + aux_params.ck_secondary_len, + instance_primary.abomonated, + ); + let ck_params = commitment_key_params(&primary, &secondary)?; let pp = SuperNovaPublicParams::>::from_parts_unchecked( circuit_params_vec, + ck_params, aux_params, ); - let (pk, vk) = CompressedSNARK::setup(&pp).unwrap(); - supernova::PublicParams { pp, pk, vk } + supernova::PublicParams { + pp, + pk_and_vk: OnceCell::new(), + } } else { - println!("generating running claim params"); let pp = default(instance_primary); - let (circuit_params_vec, aux_params) = pp.pp.into_parts(); + let (circuit_params_vec, ck_params, aux_params) = pp.pp.into_parts(); disk_cache.write_abomonated(instance_primary, &aux_params)?; + let (primary, secondary) = Instance::::new_cks( + aux_params.ck_primary_len, + aux_params.ck_secondary_len, + instance_primary.abomonated, + ); + disk_cache.write_abomonated(&primary, &ck_params.primary)?; + disk_cache.write_abomonated(&secondary, &ck_params.secondary)?; + for (circuit_index, circuit_params) in circuit_params_vec.iter().enumerate() { let instance = instance_primary.reindex(circuit_index); disk_cache.write_abomonated(&instance, circuit_params)?; @@ -163,11 +247,14 @@ where let pp = SuperNovaPublicParams::>::from_parts_unchecked( circuit_params_vec, + ck_params, aux_params, ); - let (pk, vk) = CompressedSNARK::setup(&pp).unwrap(); - supernova::PublicParams { pp, pk, vk } + supernova::PublicParams { + pp, + pk_and_vk: OnceCell::new(), + } }; Ok(pp) @@ -178,6 +265,7 @@ mod tests { use super::{instance::Kind, *}; use crate::eval::lang::{Coproc, Lang}; use halo2curves::bn256::Fr as S1; + use std::sync::Arc; use tempfile::Builder; #[test]