diff --git a/Cargo.lock b/Cargo.lock index 518e06e6c1..7756b1bc61 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -232,7 +232,7 @@ dependencies = [ "blstrs", "byteorder", "crossbeam-channel", - "digest 0.10.7", + "digest", "ec-gpu", "ec-gpu-gen", "ff", @@ -330,34 +330,13 @@ dependencies = [ "constant_time_eq 0.2.6", ] -[[package]] -name = "block-buffer" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" -dependencies = [ - "block-padding", - "byte-tools", - "byteorder", - "generic-array 0.12.4", -] - [[package]] name = "block-buffer" version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array 0.14.7", -] - -[[package]] -name = "block-padding" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" -dependencies = [ - "byte-tools", + "generic-array", ] [[package]] @@ -413,12 +392,6 @@ version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" -[[package]] -name = "byte-tools" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" - [[package]] name = "bytecount" version = "0.6.3" @@ -787,7 +760,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array 0.14.7", + "generic-array", "typenum", ] @@ -837,22 +810,13 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" -[[package]] -name = "digest" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" -dependencies = [ - "generic-array 0.12.4", -] - [[package]] name = "digest" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer 0.10.4", + "block-buffer", "crypto-common", ] @@ -967,7 +931,7 @@ checksum = "16d9a9ea4c04632c16bc5c71a2fcc63d308481f7fc67eb1a1ce6315c44a426ae" dependencies = [ "execute-command-macro", "execute-command-tokens", - "generic-array 0.14.7", + "generic-array", ] [[package]] @@ -1153,15 +1117,6 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" -[[package]] -name = "generic-array" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" -dependencies = [ - "typenum", -] - [[package]] name = "generic-array" version = "0.14.7" @@ -1421,6 +1376,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.8" @@ -1531,7 +1495,7 @@ dependencies = [ "criterion", "dashmap", "ff", - "generic-array 0.14.7", + "generic-array", "getrandom", "hex", "home", @@ -1677,7 +1641,7 @@ dependencies = [ "ec-gpu", "ec-gpu-gen", "ff", - "generic-array 0.14.7", + "generic-array", "itertools 0.8.2", "log", "pasta_curves", @@ -1726,21 +1690,21 @@ checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" [[package]] name = "nova-snark" -version = "0.22.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90acdc02f86ed9f5f902b6eaf921774a608b953fc320bf4bba29598e51f67833" +checksum = "9e12911ac9672ad436acfc992f09e26a5960513bbe81d1572005cadd8c1be8f4" dependencies = [ "bellperson", "bincode", "bitvec", "byteorder", - "digest 0.8.1", + "digest", "ff", "flate2", - "generic-array 0.14.7", + "generic-array", "getrandom", "halo2curves", - "itertools 0.9.0", + "itertools 0.11.0", "neptune", "num-bigint 0.4.3", "num-integer", @@ -1841,12 +1805,6 @@ version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" -[[package]] -name = "opaque-debug" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" - [[package]] name = "opencl-sys" version = "0.2.4" @@ -2585,20 +2543,17 @@ checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.7", + "digest", ] [[package]] name = "sha3" -version = "0.8.2" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd26bc0e7a2e3a7c959bc494caf58b72ee0c71d67704e9520f736ca7e4853ecf" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" dependencies = [ - "block-buffer 0.7.3", - "byte-tools", - "digest 0.8.1", + "digest", "keccak", - "opaque-debug", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 3a7f739626..dda37a06f4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -109,7 +109,7 @@ ff = "0.13" log = "0.4.19" metrics = "0.21.1" neptune = { version = "10.0.0" } -nova = { package = "nova-snark", version = "0.22", default-features = false } +nova = { version = "0.23", default-features = false, package = "nova-snark" } once_cell = "1.18.0" pairing = { version = "0.23" } pasta_curves = { version = "0.5.1" } diff --git a/examples/sha256.rs b/examples/sha256.rs index 849082eced..5c8fa6df36 100644 --- a/examples/sha256.rs +++ b/examples/sha256.rs @@ -189,7 +189,7 @@ fn main() { println!("Setting up public parameters..."); let pp_start = Instant::now(); - let pp = public_params::>(REDUCTION_COUNT, lang_rc.clone()).unwrap(); + let pp = public_params::<_, Sha256Coproc>(REDUCTION_COUNT, lang_rc.clone()).unwrap(); let pp_end = pp_start.elapsed(); println!("Public parameters took {:?}", pp_end); diff --git a/fcomm/src/bin/fcomm.rs b/fcomm/src/bin/fcomm.rs index d217e5315a..02b69163a3 100644 --- a/fcomm/src/bin/fcomm.rs +++ b/fcomm/src/bin/fcomm.rs @@ -1,4 +1,5 @@ use log::info; +use lurk::proof::nova::CurveCycleEquipped; use std::convert::TryFrom; use std::env; use std::fs::read_to_string; @@ -492,7 +493,7 @@ fn opening_request, F: LurkField + Serialize + DeserializeOwned>( } // Get proof from supplied path or else from stdin. -fn proof<'a, P: AsRef, F: LurkField>( +fn proof<'a, P: AsRef, F: CurveCycleEquipped>( proof_path: Option

, ) -> Result, error::Error> where diff --git a/fcomm/src/lib.rs b/fcomm/src/lib.rs index da4aefac9d..81a4cb3164 100644 --- a/fcomm/src/lib.rs +++ b/fcomm/src/lib.rs @@ -9,7 +9,6 @@ use proptest_derive::Arbitrary; use ff::PrimeField; use hex::FromHex; -use lurk::error::ReductionError; #[cfg(not(target_arch = "wasm32"))] use lurk::field::FWrap; use lurk::{ @@ -38,6 +37,7 @@ use lurk_macros::serde_test; #[cfg(not(target_arch = "wasm32"))] use lurk::z_data; +use lurk::{error::ReductionError, proof::nova::CurveCycleEquipped}; use once_cell::sync::OnceCell; use pasta_curves::pallas; use rand::rngs::OsRng; @@ -269,9 +269,9 @@ pub struct VerificationResult { } #[derive(Serialize, Deserialize)] -pub struct Proof<'a, F: LurkField> { +pub struct Proof<'a, F: CurveCycleEquipped> { pub claim: Claim, - pub proof: nova::Proof<'a, Coproc>, + pub proof: nova::Proof<'a, F, Coproc>, pub num_steps: usize, pub reduction_count: ReductionCount, } @@ -632,7 +632,7 @@ impl<'a> Opening { chain: bool, only_use_cached_proofs: bool, nova_prover: &'a NovaProver>, - pp: &'a PublicParams<'_, Coproc>, + pp: &'a PublicParams<'_, S1, Coproc>, lang: Arc>>, ) -> Result, Error> { let claim = Self::apply(s, input, function, limit, chain, &lang)?; @@ -653,7 +653,7 @@ impl<'a> Opening { limit: usize, only_use_cached_proofs: bool, nova_prover: &'a NovaProver>, - pp: &'a PublicParams<'_, Coproc>, + pp: &'a PublicParams<'_, S1, Coproc>, lang: Arc>>, ) -> Result, Error> { let input = request.input.expr.ptr(s, limit, &lang); @@ -787,7 +787,7 @@ impl<'a> Proof<'a, S1> { limit: usize, only_use_cached_proofs: bool, nova_prover: &'a NovaProver>, - pp: &'a PublicParams<'_, Coproc>, + pp: &'a PublicParams<'_, S1, Coproc>, lang: Arc>>, ) -> Result { let env = supplied_env.unwrap_or_else(|| empty_sym_env(s)); @@ -825,7 +825,7 @@ impl<'a> Proof<'a, S1> { limit: usize, only_use_cached_proofs: bool, nova_prover: &'a NovaProver>, - pp: &'a PublicParams<'_, Coproc>, + pp: &'a PublicParams<'_, S1, Coproc>, lang: &Arc>>, ) -> Result { let reduction_count = nova_prover.reduction_count(); @@ -911,7 +911,7 @@ impl<'a> Proof<'a, S1> { pub fn verify( &self, - pp: &PublicParams<'_, Coproc>, + pp: &PublicParams<'_, S1, Coproc>, lang: &Lang>, ) -> Result { let (public_inputs, public_outputs) = self.io_vecs(lang)?; diff --git a/src/cli/lurk_proof.rs b/src/cli/lurk_proof.rs index d9c5fab6a4..b81ab5d849 100644 --- a/src/cli/lurk_proof.rs +++ b/src/cli/lurk_proof.rs @@ -4,7 +4,7 @@ use lurk::{ coprocessor::Coprocessor, eval::lang::{Coproc, Lang}, field::LurkField, - proof::nova, + proof::nova::{self, CurveCycleEquipped}, z_ptr::{ZContPtr, ZExprPtr}, z_store::ZStore, }; @@ -35,16 +35,14 @@ impl HasFieldModulus for LurkProofMeta { } } -type Pallas = pasta_curves::pallas::Scalar; // TODO: generalize this - /// Minimal data structure containing just enough for proof verification #[derive(Serialize, Deserialize)] -pub enum LurkProof<'a, F: LurkField> +pub enum LurkProof<'a, F: CurveCycleEquipped> where - Coproc: Coprocessor, + Coproc: Coprocessor, { Nova { - proof: nova::Proof<'a, Coproc>, + proof: nova::Proof<'a, F, Coproc>, public_inputs: Vec, public_outputs: Vec, num_steps: usize, @@ -53,9 +51,9 @@ where }, } -impl<'a, F: LurkField> HasFieldModulus for LurkProof<'a, F> +impl<'a, F: CurveCycleEquipped> HasFieldModulus for LurkProof<'a, F> where - Coproc: Coprocessor, + Coproc: Coprocessor, { fn field_modulus() -> String { F::MODULUS.to_owned() @@ -71,11 +69,12 @@ mod non_wasm { use anyhow::Result; use lurk::{ coprocessor::Coprocessor, eval::lang::Coproc, field::LurkField, - public_parameters::public_params, + proof::nova::CurveCycleEquipped, public_parameters::public_params, }; use serde::Serialize; - use super::{LurkProof, LurkProofMeta, Pallas}; + use super::{LurkProof, LurkProofMeta}; + use pasta_curves::pallas::Scalar; impl LurkProofMeta { #[inline] @@ -84,9 +83,9 @@ mod non_wasm { } } - impl<'a, F: LurkField + Serialize> LurkProof<'a, F> + impl<'a, F: CurveCycleEquipped + Serialize> LurkProof<'a, F> where - Coproc: Coprocessor, + Coproc: Coprocessor, { #[inline] pub fn persist(self, proof_key: &str) -> Result<()> { @@ -94,7 +93,7 @@ mod non_wasm { } } - impl<'a> LurkProof<'a, Pallas> { + impl<'a> LurkProof<'a, Scalar> { fn verify(self) -> Result { match self { Self::Nova { @@ -113,7 +112,7 @@ mod non_wasm { } pub fn verify_proof(proof_key: &str) -> Result<()> { - let lurk_proof: LurkProof<'_, Pallas> = load(proof_path(proof_key))?; + let lurk_proof: LurkProof<'_, Scalar> = load(proof_path(proof_key))?; if lurk_proof.verify()? { println!("✓ Proof \"{proof_key}\" verified"); } else { diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 0fbda97f30..504c7a533b 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -306,6 +306,8 @@ impl ReplCli { // LanguageField::BLS12_381 => repl!(limit, rc, blstrs::Scalar, backend), LanguageField::Vesta => todo!(), LanguageField::BLS12_381 => todo!(), + LanguageField::BN256 => todo!(), + LanguageField::Grumpkin => todo!(), } } } @@ -349,6 +351,8 @@ impl LoadCli { // LanguageField::BLS12_381 => load!(limit, rc, blstrs::Scalar, backend), LanguageField::Vesta => todo!(), LanguageField::BLS12_381 => todo!(), + LanguageField::BN256 => todo!(), + LanguageField::Grumpkin => todo!(), } } } diff --git a/src/field.rs b/src/field.rs index 73b1a700b2..4ef83d6622 100644 --- a/src/field.rs +++ b/src/field.rs @@ -5,6 +5,7 @@ //! as an extension of the ff::PrimeField trait, with conveniance methods //! relating this field to the expresions of the language. use ff::{PrimeField, PrimeFieldBits}; +use nova::provider::bn256_grumpkin::bn256; use serde::{Deserialize, Serialize}; use std::convert::TryFrom; use std::hash::Hash; @@ -40,6 +41,10 @@ pub enum LanguageField { Vesta, /// The BLS12-381 scalar field, BLS12_381, + /// The BN256 scalar field, + BN256, + /// THe Grumpkin scalar field, + Grumpkin, } impl std::fmt::Display for LanguageField { @@ -48,6 +53,8 @@ impl std::fmt::Display for LanguageField { Self::Pallas => write!(f, "Pallas"), Self::Vesta => write!(f, "Vesta"), Self::BLS12_381 => write!(f, "BLS12-381"), + Self::BN256 => write!(f, "BN256"), + Self::Grumpkin => write!(f, "Grumpkin"), } } } @@ -247,6 +254,12 @@ impl LurkField for pasta_curves::vesta::Scalar { const FIELD: LanguageField = LanguageField::Vesta; } +impl LurkField for bn256::Scalar { + const FIELD: LanguageField = LanguageField::BN256; +} + +// The impl LurkField for grumpkin::Scalar is technically possible, but voluntarily omitted to avoid confusion. + // For working around the orphan trait impl rule /// Wrapper struct around a field element that implements additional traits #[derive(Clone, Debug, PartialEq, Eq)] diff --git a/src/proof/nova.rs b/src/proof/nova.rs index 52d7da9483..291d87b91f 100644 --- a/src/proof/nova.rs +++ b/src/proof/nova.rs @@ -3,11 +3,14 @@ use std::marker::PhantomData; use bellperson::{gadgets::num::AllocatedNum, ConstraintSystem, SynthesisError}; - +use ff::Field; use nova::{ errors::NovaError, + provider::bn256_grumpkin::{bn256, grumpkin}, + provider::pedersen::CommitmentKeyExtTrait, traits::{ circuit::{StepCircuit, TrivialTestCircuit}, + commitment::CommitmentEngineTrait, Group, }, CompressedSNARK, ProverKey, RecursiveSNARK, VerifierKey, @@ -31,57 +34,114 @@ use crate::proof::{Prover, PublicParameters}; use crate::ptr::Ptr; use crate::store::Store; -/// Type alias for G1 group elements using the Pallas curve. -pub type G1 = pallas::Point; -/// Type alias for G2 group elements using the Vesta curve. -pub type G2 = vesta::Point; +/// This trait defines most of the requirements for programming generically over the supported Nova curve cycles +/// (currently Pallas/Vesta and BN254/Grumpkin). It being pegged on the `LurkField` trait encodes that we do +/// not expect more than one such cycle to be supported at a time for a given field. +pub trait CurveCycleEquipped: LurkField { + /// ## Why the next 4 types? + /// + /// The next 4 types are purely technical, and aim at laying out type bounds in a way that rust can find them. + /// They should eventually be replaceable by a bound on projections, once bounds on associated types progress. + /// They are technically equivalent to bounds of + /// >::CommitmentKey: CommitmentKeyExtTrait::CE>, + /// >::CommitmentKey: CommitmentKeyExtTrait::CE>, + /// but where clauses can't be *found* by the compiler at the point where Self::G1, Self::G2 are used + + /// ## OK, but why do we need bounds at all in the first place? + /// + /// As to *why* those see https://github.com/microsoft/Nova/pull/200 + /// and the bound `CommitmentKey: CommitmentKeyExtTrait` on [`nova::provider::ipa_pc::EvaluationEngine`] + /// Essentially, Nova relies on a commitment scheme that is additively homomorphic, but encodes the practicalities of this + /// (properties are unwieldy to encode) in the form of this CommitmentKeyExtTrait. + + /// The type of the commitment key used for points of the first curve in the cycle. + type CK1: CommitmentKeyExtTrait::CE>; + /// The type of the commitment key used for points of the second curve in the cycle. + type CK2: CommitmentKeyExtTrait::CE>; + /// The commitment engine type for the first curve in the cycle. + type CE1: CommitmentEngineTrait; + /// The commitment engine type for the second curve in the cycle. + type CE2: CommitmentEngineTrait; + + /// The group type for the first curve in the cycle. + type G1: Group::Scalar, Scalar = Self, CE = Self::CE1>; + /// The group type for the second curve in the cycle. + type G2: Group::Scalar, CE = Self::CE2>; +} + +impl CurveCycleEquipped for pallas::Scalar { + type CK1 = nova::provider::pedersen::CommitmentKey; + type CK2 = nova::provider::pedersen::CommitmentKey; + type CE1 = nova::provider::pedersen::CommitmentEngine; + type CE2 = nova::provider::pedersen::CommitmentEngine; + + type G1 = pallas::Point; + type G2 = vesta::Point; +} +// The impl CurveCycleEquipped for vesta::Scalar is academically possible, but voluntarily omitted to avoid confusion. -/// Type alias for scalar field elements on the Pallas curve. -pub type S1 = pallas::Scalar; -/// Type alias for scalar field elements on the Vesta curve. -pub type S2 = vesta::Scalar; +impl CurveCycleEquipped for bn256::Scalar { + type CK1 = nova::provider::pedersen::CommitmentKey; + type CK2 = nova::provider::pedersen::CommitmentKey; + type CE1 = nova::provider::pedersen::CommitmentEngine; + type CE2 = nova::provider::pedersen::CommitmentEngine; + + type G1 = bn256::Point; + type G2 = grumpkin::Point; +} +// The impl CurveCycleEquipped for grumpkin::Scalar is academically possible, but voluntarily omitted to avoid confusion. + +/// Convenience alias for the primary group type pegged to a LurkField through a CurveCycleEquipped type. +pub type G1 = ::G1; +/// Convenience alias for the secondary group type pegged to a LurkField through a CurveCycleEquipped type. +pub type G2 = ::G2; /// Type alias for the Evaluation Engine using G1 group elements. -pub type EE1 = nova::provider::ipa_pc::EvaluationEngine; +pub type EE1 = nova::provider::ipa_pc::EvaluationEngine>; /// Type alias for the Evaluation Engine using G2 group elements. -pub type EE2 = nova::provider::ipa_pc::EvaluationEngine; +pub type EE2 = nova::provider::ipa_pc::EvaluationEngine>; /// Type alias for the Relaxed R1CS Spartan SNARK using G1 group elements, EE1. -pub type SS1 = nova::spartan::RelaxedR1CSSNARK; +pub type SS1 = nova::spartan::snark::RelaxedR1CSSNARK, EE1>; /// Type alias for the Relaxed R1CS Spartan SNARK using G2 group elements, EE2. -pub type SS2 = nova::spartan::RelaxedR1CSSNARK; +pub type SS2 = nova::spartan::snark::RelaxedR1CSSNARK, EE2>; /// Type alias for a MultiFrame with S1 field elements. -pub type C1<'a, C> = MultiFrame<'a, S1, IO, Witness, C>; +/// This uses the <::G1 as Group>::Scalar type for the G1 scalar field elements +/// to reflect it this should not be used outside the Nova context +pub type C1<'a, F, C> = MultiFrame<'a, as Group>::Scalar, IO, Witness, C>; /// Type alias for a Trivial Test Circuit with G2 scalar field elements. -pub type C2 = TrivialTestCircuit<::Scalar>; +pub type C2 = TrivialTestCircuit< as Group>::Scalar>; /// Type alias for Nova Public Parameters with the curve cycle types defined above. -pub type NovaPublicParams<'a, C> = nova::PublicParams, C2>; +pub type NovaPublicParams<'a, F, C> = nova::PublicParams, G2, C1<'a, F, C>, C2>; /// A struct that contains public parameters for the Nova proving system. #[derive(Serialize, Deserialize)] #[serde(bound = "")] -pub struct PublicParams<'a, C: Coprocessor> { - pp: NovaPublicParams<'a, C>, - pk: ProverKey, C2, SS1, SS2>, - vk: VerifierKey, C2, SS1, SS2>, +pub struct PublicParams<'a, F: CurveCycleEquipped, C: Coprocessor> +where + F: CurveCycleEquipped, +{ + pp: NovaPublicParams<'a, F, C>, + pk: ProverKey, G2, C1<'a, F, C>, C2, SS1, SS2>, + vk: VerifierKey, G2, C1<'a, F, C>, C2, SS1, SS2>, } /// An enum representing the two types of proofs that can be generated and verified. #[derive(Serialize, Deserialize)] -pub enum Proof<'a, C: Coprocessor> { +pub enum Proof<'a, F: CurveCycleEquipped, C: Coprocessor> { /// A proof for the intermediate steps of a recursive computation - Recursive(Box, C2>>), + Recursive(Box, G2, C1<'a, F, C>, C2>>), /// A proof for the final step of a recursive computation - Compressed(Box, C2, SS1, SS2>>), + Compressed(Box, G2, C1<'a, F, C>, C2, SS1, SS2>>), } /// Generates the public parameters for the Nova proving system. -pub fn public_params<'a, C: Coprocessor>( +pub fn public_params<'a, F: CurveCycleEquipped, C: Coprocessor>( num_iters_per_step: usize, - lang: Arc>, -) -> PublicParams<'a, C> { + lang: Arc>, +) -> PublicParams<'a, F, C> { let (circuit_primary, circuit_secondary) = C1::circuits(num_iters_per_step, lang); let pp = nova::PublicParams::setup(circuit_primary, circuit_secondary); @@ -89,8 +149,8 @@ pub fn public_params<'a, C: Coprocessor>( PublicParams { pp, pk, vk } } -impl<'a, C: Coprocessor> MultiFrame<'a, S1, IO, Witness, C> { - fn circuits(count: usize, lang: Arc>) -> (C1<'a, C>, C2) { +impl<'a, F: CurveCycleEquipped, C: Coprocessor> C1<'a, F, C> { + fn circuits(count: usize, lang: Arc>) -> (C1<'a, F, C>, C2) { ( MultiFrame::blank(count, lang), TrivialTestCircuit::default(), @@ -100,19 +160,19 @@ impl<'a, C: Coprocessor> MultiFrame<'a, S1, IO, Witness, C> { /// A struct for the Nova prover that operates on field elements of type `F`. #[derive(Debug)] -pub struct NovaProver> { +pub struct NovaProver> { // `reduction_count` specifies the number of small-step reductions are performed in each recursive step. reduction_count: usize, lang: Lang, _p: PhantomData<(F, C)>, } -impl<'a, C: Coprocessor> PublicParameters for PublicParams<'a, C> {} +impl<'a, F: CurveCycleEquipped, C: Coprocessor> PublicParameters for PublicParams<'a, F, C> {} -impl<'a, C: Coprocessor + 'a> Prover<'a, '_, S1, C> for NovaProver { - type PublicParams = PublicParams<'a, C>; - fn new(reduction_count: usize, lang: Lang) -> Self { - NovaProver:: { +impl<'a, F: CurveCycleEquipped, C: Coprocessor + 'a> Prover<'a, '_, F, C> for NovaProver { + type PublicParams = PublicParams<'a, F, C>; + fn new(reduction_count: usize, lang: Lang) -> Self { + NovaProver:: { reduction_count, lang, _p: Default::default(), @@ -122,21 +182,21 @@ impl<'a, C: Coprocessor + 'a> Prover<'a, '_, S1, C> for NovaProver { self.reduction_count } - fn lang(&self) -> &Lang { + fn lang(&self) -> &Lang { &self.lang } } -impl> NovaProver { +impl> NovaProver { /// Evaluates and generates the frames of the computation given the expression, environment, and store pub fn get_evaluation_frames( &self, - expr: Ptr, - env: Ptr, - store: &mut Store, + expr: Ptr, + env: Ptr, + store: &mut Store, limit: usize, - lang: &Lang, - ) -> Result, Witness, C>>, ProofError> { + lang: &Lang, + ) -> Result, Witness, C>>, ProofError> { let padding_predicate = |count| self.needs_frame_padding(count); let frames = Evaluator::generate_frames(expr, env, store, limit, padding_predicate, lang)?; @@ -149,11 +209,11 @@ impl> NovaProver { /// Proves the computation given the public parameters, frames, and store. pub fn prove<'a>( &'a self, - pp: &'a PublicParams<'_, C>, - frames: &[Frame, Witness, C>], - store: &'a mut Store, - lang: Arc>, - ) -> Result<(Proof<'_, C>, Vec, Vec, usize), ProofError> { + pp: &'a PublicParams<'_, F, C>, + frames: &[Frame, Witness, C>], + store: &'a mut Store, + lang: Arc>, + ) -> Result<(Proof<'_, F, C>, Vec, Vec, usize), ProofError> { let z0 = frames[0].input.to_vector(store)?; let zi = frames.last().unwrap().output.to_vector(store)?; let circuits = MultiFrame::from_frames(self.reduction_count(), frames, store, &lang); @@ -167,13 +227,13 @@ impl> NovaProver { /// Evaluates and proves the computation given the public parameters, expression, environment, and store. pub fn evaluate_and_prove<'a>( &'a self, - pp: &'a PublicParams<'_, C>, - expr: Ptr, - env: Ptr, - store: &'a mut Store, + pp: &'a PublicParams<'_, F, C>, + expr: Ptr, + env: Ptr, + store: &'a mut Store, limit: usize, - lang: Arc>, - ) -> Result<(Proof<'_, C>, Vec, Vec, usize), ProofError> { + lang: Arc>, + ) -> Result<(Proof<'_, F, C>, Vec, Vec, usize), ProofError> { let frames = self.get_evaluation_frames(expr, env, store, limit, &lang)?; self.prove(pp, &frames, store, lang) } @@ -240,15 +300,15 @@ impl<'a, F: LurkField, C: Coprocessor> StepCircuit } } -impl<'a: 'b, 'b, C: Coprocessor> Proof<'a, C> { +impl<'a: 'b, 'b, F: CurveCycleEquipped, C: Coprocessor> Proof<'a, F, C> { /// Proves the computation recursively, generating a recursive SNARK proof. pub fn prove_recursively( - pp: &'a PublicParams<'_, C>, - store: &'a Store, - circuits: &[C1<'a, C>], + pp: &'a PublicParams<'_, F, C>, + store: &'a Store, + circuits: &[C1<'a, F, C>], num_iters_per_step: usize, - z0: Vec, - lang: Arc>, + z0: Vec, + lang: Arc>, ) -> Result { assert!(!circuits.is_empty()); assert_eq!(circuits[0].arity(), z0.len()); @@ -261,11 +321,11 @@ impl<'a: 'b, 'b, C: Coprocessor> Proof<'a, C> { num_iters_per_step ); let (_circuit_primary, circuit_secondary): ( - MultiFrame<'_, S1, IO, Witness, C>, - TrivialTestCircuit, + MultiFrame<'_, F, IO, Witness, C>, + TrivialTestCircuit< as Group>::Scalar>, ) = C1::<'a>::circuits(num_iters_per_step, lang); // produce a recursive SNARK - let mut recursive_snark: Option, C2>> = None; + let mut recursive_snark: Option, G2, C1<'a, F, C>, C2>> = None; for circuit_primary in circuits.iter() { assert_eq!( @@ -275,7 +335,7 @@ impl<'a: 'b, 'b, C: Coprocessor> Proof<'a, C> { if debug { // For debugging purposes, synthesize the circuit and check that the constraint system is satisfied. use bellperson::util_cs::test_cs::TestConstraintSystem; - let mut cs = TestConstraintSystem::<::Scalar>::new(); + let mut cs = TestConstraintSystem::< as Group>::Scalar>::new(); let zi = circuit_primary.frames.as_ref().unwrap()[0] .input @@ -318,15 +378,15 @@ impl<'a: 'b, 'b, C: Coprocessor> Proof<'a, C> { } /// Compresses the proof using a (Spartan) Snark (finishing step) - pub fn compress(self, pp: &'a PublicParams<'_, C>) -> Result { + pub fn compress(self, pp: &'a PublicParams<'_, F, C>) -> Result { match &self { Self::Recursive(recursive_snark) => Ok(Self::Compressed(Box::new(CompressedSNARK::< _, _, _, _, - SS1, - SS2, + SS1, + SS2, >::prove( &pp.pp, &pp.pk, @@ -339,10 +399,10 @@ impl<'a: 'b, 'b, C: Coprocessor> Proof<'a, C> { /// Verifies the proof given the public parameters, the number of steps, and the input and output values. pub fn verify( &self, - pp: &PublicParams<'_, C>, + pp: &PublicParams<'_, F, C>, num_steps: usize, - z0: &[S1], - zi: &[S1], + z0: &[F], + zi: &[F], ) -> Result { let (z0_primary, zi_primary) = (z0, zi); let z0_secondary = Self::z0_secondary(); @@ -356,8 +416,8 @@ impl<'a: 'b, 'b, C: Coprocessor> Proof<'a, C> { Ok(zi_primary == zi_primary_verified && zi_secondary == zi_secondary_verified) } - fn z0_secondary() -> Vec { - vec![::Scalar::zero()] + fn z0_secondary() -> Vec<::Scalar> { + vec![ as Group>::Scalar::ZERO] } } diff --git a/src/public_parameters/mod.rs b/src/public_parameters/mod.rs index 095f40f4ff..b9faa0d43d 100644 --- a/src/public_parameters/mod.rs +++ b/src/public_parameters/mod.rs @@ -4,11 +4,11 @@ use std::path::Path; use std::sync::Arc; use crate::coprocessor::Coprocessor; +use crate::proof::nova::CurveCycleEquipped; use crate::{ eval::lang::Lang, proof::nova::{self, PublicParams}, }; -use pasta_curves::pallas; use serde::{Deserialize, Serialize}; pub mod error; @@ -17,13 +17,15 @@ mod registry; use crate::public_parameters::error::Error; -pub type S1 = pallas::Scalar; - -pub fn public_params + 'static>( +pub fn public_params + 'static>( rc: usize, - lang: Arc>, -) -> Result>, Error> { - let f = |lang: Arc>| Arc::new(nova::public_params(rc, lang)); + lang: Arc>, +) -> Result>, Error> +where + F::CK1: Sync + Send, + F::CK2: Sync + Send, +{ + let f = |lang: Arc>| Arc::new(nova::public_params(rc, lang)); registry::CACHE_REG.get_coprocessor_or_update_with(rc, f, lang) } pub trait FileStore diff --git a/src/public_parameters/registry.rs b/src/public_parameters/registry.rs index e4c45b5ba6..0a8fab9550 100644 --- a/src/public_parameters/registry.rs +++ b/src/public_parameters/registry.rs @@ -5,17 +5,15 @@ use std::{ use log::info; use once_cell::sync::Lazy; -use pasta_curves::pallas; use tap::TapFallible; -use crate::public_parameters::error::Error; use crate::{coprocessor::Coprocessor, eval::lang::Lang, proof::nova::PublicParams}; +use crate::{proof::nova::CurveCycleEquipped, public_parameters::error::Error}; use super::file_map::FileIndex; -type S1 = pallas::Scalar; type AnyMap = anymap::Map; -type PublicParamMemCache = HashMap>>; +type PublicParamMemCache = HashMap>>; /// This is a global registry for Coproc-specific parameters. /// It is used to cache parameters for each Coproc, so that they are not @@ -33,14 +31,15 @@ pub(crate) static CACHE_REG: Lazy = Lazy::new(|| Registry { impl Registry { fn get_from_file_cache_or_update_with< - C: Coprocessor + 'static, - F: FnOnce(Arc>) -> Arc>, + F: CurveCycleEquipped, + C: Coprocessor + 'static, + Fn: FnOnce(Arc>) -> Arc>, >( &'static self, rc: usize, - default: F, - lang: Arc>, - ) -> Result>, Error> { + default: Fn, + lang: Arc>, + ) -> Result>, Error> { // subdirectory search let disk_cache = FileIndex::new("public_params").unwrap(); // use the cached language key @@ -49,7 +48,7 @@ impl Registry { // for this lang/coprocessor. let key = format!("public-params-rc-{rc}-coproc-{lang_key}"); // read the file if it exists, otherwise initialize - if let Some(pp) = disk_cache.get::>(&key) { + if let Some(pp) = disk_cache.get::>(&key) { info!("Using disk-cached public params for lang {lang_key}"); Ok(Arc::new(pp)) } else { @@ -65,18 +64,23 @@ impl Registry { /// Check if params for this Coproc are in registry, if so, return them. /// Otherwise, initialize with the passed in function. pub(crate) fn get_coprocessor_or_update_with< - C: Coprocessor + 'static, - F: FnOnce(Arc>) -> Arc>, + F: CurveCycleEquipped, + C: Coprocessor + 'static, + Fn: FnOnce(Arc>) -> Arc>, >( &'static self, rc: usize, - default: F, - lang: Arc>, - ) -> Result>, Error> { + default: Fn, + lang: Arc>, + ) -> Result>, Error> + where + F::CK1: Sync + Send, + F::CK2: Sync + Send, + { // re-grab the lock let mut registry = self.registry.lock().unwrap(); // retrieve the per-Coproc public param table - let entry = registry.entry::>(); + let entry = registry.entry::>(); // deduce the map and populate it if needed let param_entry = entry.or_insert_with(HashMap::new); match param_entry.entry(rc) { diff --git a/tests/lurk-tests.rs b/tests/lurk-tests.rs index 05f137a1d9..279a64e338 100644 --- a/tests/lurk-tests.rs +++ b/tests/lurk-tests.rs @@ -1,8 +1,8 @@ use lurk::{ eval::lang::{Coproc, Lang}, - proof::nova, repl::{repl, ReplState}, }; +use pasta_curves::pallas::Scalar as S1; use std::path::Path; #[test] @@ -37,10 +37,6 @@ fn lurk_tests() { for f in test_files { let joined = example_dir.join(f); - repl::>, _, Coproc>( - Some(joined), - Lang::new(), - ) - .unwrap(); + repl::>, _, Coproc>(Some(joined), Lang::new()).unwrap(); } }