From 9e8c203004f4b72dbc70c6791d02f77106de0ac7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Garillot?= Date: Tue, 30 Jan 2024 16:01:17 -0500 Subject: [PATCH 1/6] refactor: Refactor public parameters handling and caching This adapts to upstream https://github.com/lurk-lab/arecibo/pull/285, which removes the need for separate `ProverKey` and `VerifierKey` instances (the former containing `CommitmentKey` copies) in Public Parameters. - Implemented structural changes in `nova.rs` for improvements in key handling for the prover and verifier keys, which generated as `OnceCell`, - Revamped `disk_cache.rs` with added `Arc` imports, elimination of lifetime parameter `'a` from `DiskCache`, modifications of `read` and `write` functions, and updates in the serialization and deserialization steps. - Altered `public_params` and `supernova_public_params` functions in `mod.rs` to deal more capably with errors and modified various methods and tests to align with the changes in `disk_cache.rs`. - Removed complete `mem_cache.rs` file, which was unsafe, and unused. - Moved initialization of `store` to an earlier point in `fibonacci_prove` function and made minor formatting changes in `fibonacci.rs`. --- Cargo.toml | 2 +- benches/fibonacci.rs | 5 +- benches/sha256.rs | 2 +- examples/sha256_ivc.rs | 2 +- src/cli/repl/mod.rs | 1 - src/proof/nova.rs | 76 ++++++++++------ src/public_parameters/disk_cache.rs | 25 +++--- src/public_parameters/mem_cache.rs | 132 ---------------------------- src/public_parameters/mod.rs | 122 +++++++++++++------------ 9 files changed, 133 insertions(+), 234 deletions(-) delete mode 100644 src/public_parameters/mem_cache.rs diff --git a/Cargo.toml b/Cargo.toml index 11f215fc15..25e59c8215 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 = "killing_params", 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/repl/mod.rs b/src/cli/repl/mod.rs index 8b6973883a..086f816eb0 100644 --- a/src/cli/repl/mod.rs +++ b/src/cli/repl/mod.rs @@ -337,7 +337,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/proof/nova.rs b/src/proof/nova.rs index 03139a8651..246aa987e4 100644 --- a/src/proof/nova.rs +++ b/src/proof/nova.rs @@ -13,6 +13,7 @@ use nova::{ }, CompressedSNARK, ProverKey, R1CSWithArity, RecursiveSNARK, VerifierKey, }; +use once_cell::sync::OnceCell; use pasta_curves::pallas; use serde::{Deserialize, Serialize}; use std::{ @@ -112,39 +113,54 @@ 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() + } +} + +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 } - 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) + /// 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 } +} - fn extent(&self) -> usize { - self.pp.extent() + self.pk.extent() + self.vk.extent() +impl> From> + for PublicParams +{ + fn from(pp: NovaPublicParams) -> PublicParams { + PublicParams { + pp, + pk_and_vk: OnceCell::new(), + } } } @@ -202,8 +218,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. @@ -342,7 +360,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 +379,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)? } }; diff --git a/src/public_parameters/disk_cache.rs b/src/public_parameters/disk_cache.rs index c54cbc27a2..a63eabdb54 100644 --- a/src/public_parameters/disk_cache.rs +++ b/src/public_parameters/disk_cache.rs @@ -1,6 +1,7 @@ use std::fs::create_dir_all; use std::io::{BufReader, BufWriter, Read}; use std::marker::PhantomData; +use std::sync::Arc; use abomonation::{encode, Abomonation}; use camino::{Utf8Path, Utf8PathBuf}; @@ -19,16 +20,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> +impl> DiskCache where // technical bounds that would disappear once associated_type_bounds stabilizes < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, @@ -43,10 +44,10 @@ where }) } - pub(crate) fn read( + pub(crate) fn read<'a>( &self, - instance: &Instance<'a, F, C>, - ) -> Result>, Error> { + instance: &Instance, + ) -> Result>>, Error> { let file = instance.open(&self.dir)?; let reader = BufReader::new(file); bincode::deserialize_from(reader) @@ -55,7 +56,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 +67,18 @@ where pub(crate) fn write( &self, - instance: &Instance<'a, F, C>, - data: &PublicParams>, + instance: &Instance, + data: &Arc>>, ) -> 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/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..e37f8bbbe1 100644 --- a/src/public_parameters/mod.rs +++ b/src/public_parameters/mod.rs @@ -1,15 +1,15 @@ -use ::nova::{supernova::snark::CompressedSNARK, traits::Engine}; +use ::nova::{ + supernova::snark::CompressedSNARK, supernova::FlatAuxParams, traits::Engine, FlatPublicParams, +}; use abomonation::{decode, Abomonation}; -use std::sync::Arc; use crate::coprocessor::Coprocessor; -use crate::proof::nova::{self, NovaCircuitShape, PublicParams, C1LEM}; -use crate::proof::nova::{CurveCycleEquipped, E1, E2}; +use crate::proof::nova::{self, NovaCircuitShape, NovaPublicParams, PublicParams, C1LEM}; +use crate::proof::nova::{CurveCycleEquipped, C2, 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; @@ -17,63 +17,74 @@ use crate::public_parameters::error::Error; use self::disk_cache::DiskCache; use self::instance::Instance; +use std::sync::Arc; +use tap::TapFallible; +use tracing::{info, warn}; pub fn public_params<'a, F: CurveCycleEquipped, C: Coprocessor + 'static>( - instance: &Instance<'static, F, C>, + instance: &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())) - }; - mem_cache::PUBLIC_PARAM_MEM_CACHE.get_from_mem_cache_or_update_with(instance, f) -} - -/// 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 -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) } { - assert!(remaining.is_empty()); - eprintln!("Using disk-cached public params for {}", instance.key()); + let default = + |instance: &Instance| Arc::new(nova::public_params(instance.rc, instance.lang())); + + // 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::, E2, C1LEM<'a, F, C>, C2>>(&mut bytes) + .unwrap() + }; + assert!(rest.is_empty()); + let pp = + PublicParams::from(NovaPublicParams::>::from(pp.clone())); // this clone is VERY expensive + Ok(Arc::new(pp)) + } + Err(Error::IO(e)) => { + warn!("{e}"); + info!("Generating fresh public parameters"); + let pp = default(instance); + let pp = Arc::try_unwrap(pp).unwrap().pp; + let fp = FlatPublicParams::try_from(pp).unwrap(); + // maybe just directly write + disk_cache + .write_abomonated(instance, &fp) + .tap_ok(|_| info!("writing public params to disk-cache: {}", instance.key())) + .map_err(|e| Error::Cache(format!("Disk write error: {e}")))?; + Ok(Arc::new(PublicParams::from(NovaPublicParams::< + F, + C1LEM<'a, F, C>, + >::from(fp)))) + } + _ => unreachable!(), + } + } else { + // read the file if it exists, otherwise initialize + if let Ok(pp) = disk_cache.read(instance) { + info!("loading abomonated {}", instance.key()); Ok(pp) } 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)) + 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) } } } pub fn supernova_circuit_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, @@ -94,7 +105,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, @@ -104,11 +115,11 @@ where let mut bytes = vec![]; disk_cache.read_bytes(instance, &mut bytes).and_then(|()| { - if let Some((aux_params, remaining)) = - unsafe { decode::>(&mut bytes) } + if let Some((flat_aux_params, remaining)) = + unsafe { decode::, E2>>(&mut bytes) } { assert!(remaining.is_empty()); - Ok(aux_params.clone()) + Ok(SuperNovaAuxParams::::from(flat_aux_params.clone())) } else { Err(Error::Cache("failed to decode bytes".into())) } @@ -117,13 +128,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(); @@ -154,7 +165,9 @@ where let (circuit_params_vec, aux_params) = pp.pp.into_parts(); - disk_cache.write_abomonated(instance_primary, &aux_params)?; + let flat_aux_params = FlatAuxParams::, E2>::try_from(aux_params).unwrap(); + disk_cache.write_abomonated(instance_primary, &flat_aux_params)?; + let aux_params = SuperNovaAuxParams::::from(flat_aux_params); for (circuit_index, circuit_params) in circuit_params_vec.iter().enumerate() { let instance = instance_primary.reindex(circuit_index); @@ -178,6 +191,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] From f4f30ee6b0578169a7f9c106abc72fe718b1fd45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Garillot?= Date: Tue, 30 Jan 2024 16:11:12 -0500 Subject: [PATCH 2/6] refactor: Refactor code to remove lifetime on Instance + Abomonation dependency - Removed `Abomonation` trait and `PrimeField` imports from `multiframe.rs`, also simplified the `NonUniformCircuit` access in the same file. - Removed `Abomonation` trait bounds from the `circuit_cache_key` functions in `supernova.rs`. - Refactored `Instance<>` struct in `instance.rs`, removing the usage of `Abomonation` and `PhantomData`, and eliminated need for lifetime declaration `'a`. - Enhanced `open()` method in `instance.rs` to include metadata comparison to prevent instance mismatches. --- src/lem/multiframe.rs | 6 +----- src/proof/supernova.rs | 6 ------ src/public_parameters/instance.rs | 26 ++++++++------------------ 3 files changed, 9 insertions(+), 29 deletions(-) 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/supernova.rs b/src/proof/supernova.rs index 74a7ef93db..abf1def553 100644 --- a/src/proof/supernova.rs +++ b/src/proof/supernova.rs @@ -420,9 +420,6 @@ pub fn circuit_cache_key<'a, F: CurveCycleEquipped, C: Coprocessor + 'a>( lang: Arc>, circuit_index: usize, ) -> F -where - < as Engine>::Scalar as PrimeField>::Repr: Abomonation, - < as Engine>::Scalar as PrimeField>::Repr: Abomonation, { let folding_config = Arc::new(FoldingConfig::new_nivc(lang, 2)); let circuit = C1LEM::<'a, F, C>::blank(folding_config, 0); @@ -437,9 +434,6 @@ 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, { let num_circuits = lang.coprocessor_count() + 1; let digests = (0..num_circuits) diff --git a/src/public_parameters/instance.rs b/src/public_parameters/instance.rs index ad378467ab..492db09f1d 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. @@ -107,7 +104,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,17 +116,14 @@ 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) } }; Instance { @@ -138,7 +132,6 @@ where abomonated, cache_key, kind, - _p: PhantomData, } } @@ -175,10 +168,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> { From e7da82a79d9681bf80d8e9c1807844f40010862f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Garillot?= Date: Tue, 30 Jan 2024 16:41:46 -0500 Subject: [PATCH 3/6] refactor: Adapt SuperNova parameters and remove superfluous Abomonation bounds - Improved `supernova.rs` by using `OnceCell` to store `ProverKey` and `VerifierKey` and updating related methods, - removed uneeded Abomonation bounds in a few places. --- src/cli/lurk_proof.rs | 27 ++++---- src/cli/repl/meta_cmd.rs | 5 +- src/cli/repl/mod.rs | 7 +- src/proof/nova.rs | 26 +------ src/proof/supernova.rs | 101 ++++++++++++++-------------- src/proof/tests/mod.rs | 26 ++----- src/public_parameters/disk_cache.rs | 10 +-- src/public_parameters/instance.rs | 6 +- src/public_parameters/mod.rs | 29 ++++---- 9 files changed, 92 insertions(+), 145 deletions(-) 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 086f816eb0..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, diff --git a/src/proof/nova.rs b/src/proof/nova.rs index 246aa987e4..6b61ab019d 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, @@ -167,11 +165,7 @@ impl> From> /// 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), @@ -202,11 +196,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(); @@ -238,9 +228,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>; @@ -397,11 +384,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 { @@ -435,9 +418,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 abf1def553..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,8 +418,7 @@ pub fn circuit_cache_key<'a, F: CurveCycleEquipped, C: Coprocessor + 'a>( rc: usize, lang: Arc>, circuit_index: usize, -) -> F -{ +) -> 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(); @@ -433,8 +431,7 @@ pub fn circuit_cache_key<'a, F: CurveCycleEquipped, C: Coprocessor + 'a>( pub fn circuit_cache_keys<'a, F: CurveCycleEquipped, C: Coprocessor + 'a>( rc: usize, lang: &Arc>, -) -> CircuitDigests> -{ +) -> 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 a63eabdb54..e95c51977d 100644 --- a/src/public_parameters/disk_cache.rs +++ b/src/public_parameters/disk_cache.rs @@ -5,11 +5,10 @@ use std::sync::Arc; 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; @@ -29,12 +28,7 @@ where _t: PhantomData<(F, C)>, } -impl> DiskCache -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)?; diff --git a/src/public_parameters/instance.rs b/src/public_parameters/instance.rs index 492db09f1d..b09edf6298 100644 --- a/src/public_parameters/instance.rs +++ b/src/public_parameters/instance.rs @@ -116,8 +116,7 @@ impl Metadata { } } -impl> Instance -{ +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::(rc, lang.clone()), @@ -168,8 +167,7 @@ impl> Instance } } -impl> Instance -{ +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() diff --git a/src/public_parameters/mod.rs b/src/public_parameters/mod.rs index e37f8bbbe1..3e761c8b77 100644 --- a/src/public_parameters/mod.rs +++ b/src/public_parameters/mod.rs @@ -1,7 +1,9 @@ -use ::nova::{ - supernova::snark::CompressedSNARK, supernova::FlatAuxParams, traits::Engine, FlatPublicParams, -}; +use ::nova::{supernova::FlatAuxParams, traits::Engine, FlatPublicParams}; use abomonation::{decode, Abomonation}; +use once_cell::sync::OnceCell; +use std::sync::Arc; +use tap::TapFallible; +use tracing::{info, warn}; use crate::coprocessor::Coprocessor; use crate::proof::nova::{self, NovaCircuitShape, NovaPublicParams, PublicParams, C1LEM}; @@ -12,14 +14,9 @@ mod error; pub mod instance; 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 self::disk_cache::DiskCache; -use self::instance::Instance; -use std::sync::Arc; -use tap::TapFallible; -use tracing::{info, warn}; +use crate::public_parameters::instance::Instance; pub fn public_params<'a, F: CurveCycleEquipped, C: Coprocessor + 'static>( instance: &Instance, @@ -156,9 +153,11 @@ where circuit_params_vec, 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); @@ -178,9 +177,11 @@ where circuit_params_vec, aux_params, ); - let (pk, vk) = CompressedSNARK::setup(&pp).unwrap(); - supernova::PublicParams { pp, pk, vk } + supernova::PublicParams { + pp, + pk_and_vk: OnceCell::new(), + } }; Ok(pp) From 34abc4d469a191e6cb8966b1b8e6c1d19cf34094 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Garillot?= Date: Tue, 30 Jan 2024 17:05:30 -0500 Subject: [PATCH 4/6] chore: slience clippy --- .clippy.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From b48c847a300e24a012f1b78f9487773d8122e6a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Garillot?= Date: Tue, 30 Jan 2024 17:39:17 -0500 Subject: [PATCH 5/6] refactor: Refactor PublicParams cache to remove obsolete std::sync::Arc usage - reduced complexity by removing `std::sync::Arc` in `src/public_parameters/disk_cache.rs`. - Modified `read` and `write` functions in `DiskCache` to work directly with `PublicParams`. --- src/public_parameters/disk_cache.rs | 5 ++--- src/public_parameters/mod.rs | 18 +++++++----------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/src/public_parameters/disk_cache.rs b/src/public_parameters/disk_cache.rs index e95c51977d..0f23913fa1 100644 --- a/src/public_parameters/disk_cache.rs +++ b/src/public_parameters/disk_cache.rs @@ -1,7 +1,6 @@ use std::fs::create_dir_all; use std::io::{BufReader, BufWriter, Read}; use std::marker::PhantomData; -use std::sync::Arc; use abomonation::{encode, Abomonation}; use camino::{Utf8Path, Utf8PathBuf}; @@ -41,7 +40,7 @@ impl> DiskCache { pub(crate) fn read<'a>( &self, instance: &Instance, - ) -> Result>>, Error> { + ) -> Result>, Error> { let file = instance.open(&self.dir)?; let reader = BufReader::new(file); bincode::deserialize_from(reader) @@ -62,7 +61,7 @@ impl> DiskCache { pub(crate) fn write( &self, instance: &Instance, - data: &Arc>>, + data: &PublicParams>, ) -> Result<(), Error> { let file = instance.create(&self.dir)?; let writer = BufWriter::new(&file); diff --git a/src/public_parameters/mod.rs b/src/public_parameters/mod.rs index 3e761c8b77..1afdbc9c38 100644 --- a/src/public_parameters/mod.rs +++ b/src/public_parameters/mod.rs @@ -1,7 +1,6 @@ use ::nova::{supernova::FlatAuxParams, traits::Engine, FlatPublicParams}; use abomonation::{decode, Abomonation}; use once_cell::sync::OnceCell; -use std::sync::Arc; use tap::TapFallible; use tracing::{info, warn}; @@ -20,13 +19,12 @@ use crate::public_parameters::instance::Instance; pub fn public_params<'a, F: CurveCycleEquipped, C: Coprocessor + 'static>( instance: &Instance, -) -> Result>>, Error> +) -> Result>, Error> where < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, { - let default = - |instance: &Instance| Arc::new(nova::public_params(instance.rc, instance.lang())); + let default = |instance: &Instance| nova::public_params(instance.rc, instance.lang()); // subdirectory search let disk_cache = DiskCache::new(public_params_dir()).unwrap(); @@ -44,23 +42,21 @@ where assert!(rest.is_empty()); let pp = PublicParams::from(NovaPublicParams::>::from(pp.clone())); // this clone is VERY expensive - Ok(Arc::new(pp)) + Ok(pp) } Err(Error::IO(e)) => { warn!("{e}"); info!("Generating fresh public parameters"); let pp = default(instance); - let pp = Arc::try_unwrap(pp).unwrap().pp; - let fp = FlatPublicParams::try_from(pp).unwrap(); + let fp = FlatPublicParams::try_from(pp.pp).unwrap(); // maybe just directly write disk_cache .write_abomonated(instance, &fp) .tap_ok(|_| info!("writing public params to disk-cache: {}", instance.key())) .map_err(|e| Error::Cache(format!("Disk write error: {e}")))?; - Ok(Arc::new(PublicParams::from(NovaPublicParams::< - F, - C1LEM<'a, F, C>, - >::from(fp)))) + Ok(PublicParams::from( + NovaPublicParams::>::from(fp), + )) } _ => unreachable!(), } From 82680d619fa1e5d6945d543344d584ebe94f37e9 Mon Sep 17 00:00:00 2001 From: Hanting Zhang Date: Wed, 31 Jan 2024 19:55:06 +0000 Subject: [PATCH 6/6] reorganize public param module --- Cargo.toml | 2 +- src/proof/nova.rs | 16 ++- src/public_parameters/instance.rs | 32 ++++- src/public_parameters/mod.rs | 209 ++++++++++++++++++++---------- 4 files changed, 188 insertions(+), 71 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 25e59c8215..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 = "killing_params", package = "arecibo", features = ["abomonate"] } +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/src/proof/nova.rs b/src/proof/nova.rs index 6b61ab019d..1441b379b0 100644 --- a/src/proof/nova.rs +++ b/src/proof/nova.rs @@ -9,7 +9,7 @@ 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; @@ -53,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 { @@ -61,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. @@ -70,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. @@ -102,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>; diff --git a/src/public_parameters/instance.rs b/src/public_parameters/instance.rs index b09edf6298..8ec47a4d76 100644 --- a/src/public_parameters/instance.rs +++ b/src/public_parameters/instance.rs @@ -88,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 @@ -123,7 +126,8 @@ impl> Instance { Kind::SuperNovaAuxParams => supernova::circuit_cache_keys::(rc, &lang).digest(), Kind::SuperNovaCircuitParams(circuit_index) => { supernova::circuit_cache_key::(rc, lang.clone(), circuit_index) - } + }, + Kind::CommitmentKey => panic!("use `Instance::new_cks` instead"), }; Instance { rc, @@ -134,6 +138,28 @@ impl> Instance { } } + /// 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 { @@ -221,7 +247,7 @@ impl> Instance { } /// 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/mod.rs b/src/public_parameters/mod.rs index 1afdbc9c38..2d000443aa 100644 --- a/src/public_parameters/mod.rs +++ b/src/public_parameters/mod.rs @@ -1,12 +1,11 @@ -use ::nova::{supernova::FlatAuxParams, traits::Engine, FlatPublicParams}; +use ::nova::traits::Engine; +use ::nova::{CommitmentKey, CommitmentKeyParams}; use abomonation::{decode, Abomonation}; use once_cell::sync::OnceCell; -use tap::TapFallible; -use tracing::{info, warn}; use crate::coprocessor::Coprocessor; -use crate::proof::nova::{self, NovaCircuitShape, NovaPublicParams, PublicParams, C1LEM}; -use crate::proof::nova::{CurveCycleEquipped, C2, E1, E2}; +use crate::proof::nova::{self, NovaCircuitShape, NovaAuxParams, NovaPublicParams, C1LEM}; +use crate::proof::nova::{CurveCycleEquipped, E1, E2}; pub mod disk_cache; mod error; @@ -17,66 +16,133 @@ use crate::public_parameters::disk_cache::{public_params_dir, DiskCache}; use crate::public_parameters::error::Error; use crate::public_parameters::instance::Instance; -pub fn public_params<'a, F: CurveCycleEquipped, C: Coprocessor + 'static>( +pub fn nova_aux_params<'a, F: CurveCycleEquipped, C: Coprocessor + 'a>( instance: &Instance, -) -> Result>, Error> +) -> Result, Error> where < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, < as Engine>::Scalar as ff::PrimeField>::Repr: Abomonation, { - let default = |instance: &Instance| nova::public_params(instance.rc, instance.lang()); - - // 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::, E2, C1LEM<'a, F, C>, C2>>(&mut bytes) - .unwrap() - }; - assert!(rest.is_empty()); - let pp = - PublicParams::from(NovaPublicParams::>::from(pp.clone())); // this clone is VERY expensive - Ok(pp) - } - Err(Error::IO(e)) => { - warn!("{e}"); - info!("Generating fresh public parameters"); - let pp = default(instance); - let fp = FlatPublicParams::try_from(pp.pp).unwrap(); - // maybe just directly write - disk_cache - .write_abomonated(instance, &fp) - .tap_ok(|_| info!("writing public params to disk-cache: {}", instance.key())) - .map_err(|e| Error::Cache(format!("Disk write error: {e}")))?; - Ok(PublicParams::from( - NovaPublicParams::>::from(fp), - )) - } - _ => unreachable!(), + let disk_cache = DiskCache::::new(public_params_dir()).unwrap(); + + 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 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 { - // read the file if it exists, otherwise initialize - if let Ok(pp) = disk_cache.read(instance) { - info!("loading abomonated {}", instance.key()); - Ok(pp) + 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) + }; + + Ok(pp) +} + +pub fn commitment_key_params<'a, F: CurveCycleEquipped, C: Coprocessor + 'a>( + primary: &Instance, + secondary: &Instance, +) -> Result, E2>, 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(); + + let mut bytes = vec![]; + 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 commitment key for {}", primary.key()); + Ok(pp.clone()) } 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) + Err(Error::Cache("failed to decode bytes".into())) } - } + })?; + 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>( +pub fn circuit_params<'a, F: CurveCycleEquipped, C: Coprocessor + 'a>( instance: &Instance, ) -> Result, Error> where @@ -89,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())) @@ -108,11 +174,11 @@ where let mut bytes = vec![]; disk_cache.read_bytes(instance, &mut bytes).and_then(|()| { - if let Some((flat_aux_params, remaining)) = - unsafe { decode::, E2>>(&mut bytes) } + if let Some((aux_params, remaining)) = + unsafe { decode::>(&mut bytes) } { assert!(remaining.is_empty()); - Ok(SuperNovaAuxParams::::from(flat_aux_params.clone())) + Ok(aux_params.clone()) } else { Err(Error::Cache("failed to decode bytes".into())) } @@ -135,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); @@ -143,10 +209,15 @@ 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, ); @@ -155,14 +226,19 @@ where 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(); - let flat_aux_params = FlatAuxParams::, E2>::try_from(aux_params).unwrap(); - disk_cache.write_abomonated(instance_primary, &flat_aux_params)?; - let aux_params = SuperNovaAuxParams::::from(flat_aux_params); + 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); @@ -171,6 +247,7 @@ where let pp = SuperNovaPublicParams::>::from_parts_unchecked( circuit_params_vec, + ck_params, aux_params, );