From c0e4d06dd9fbbcd6dbbc0c6051d61c524397f14c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Miko=C5=82ajczyk?= Date: Wed, 26 Oct 2022 15:08:05 +0200 Subject: [PATCH] Marlin (#9) --- house-snark/Cargo.lock | 37 +++++++ house-snark/Cargo.toml | 4 + house-snark/README.md | 1 + house-snark/src/config.rs | 16 ++- house-snark/src/environment.rs | 184 ++++++++++++++++++++++++--------- house-snark/src/main.rs | 9 +- 6 files changed, 198 insertions(+), 53 deletions(-) diff --git a/house-snark/Cargo.lock b/house-snark/Cargo.lock index 78b3f8f..af29230 100644 --- a/house-snark/Cargo.lock +++ b/house-snark/Cargo.lock @@ -171,6 +171,23 @@ dependencies = [ "ark-std", ] +[[package]] +name = "ark-marlin" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caa8510faa8e64f0a6841ee4b58efe2d56f7a80d86fa0ce9891bbb3aa20166d9" +dependencies = [ + "ark-ff", + "ark-poly", + "ark-poly-commit", + "ark-relations", + "ark-serialize", + "ark-std", + "derivative", + "digest", + "rand_chacha", +] + [[package]] name = "ark-nonnative-field" version = "0.3.0" @@ -202,6 +219,22 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "ark-poly-commit" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a71ddfa72bad1446cab7bbecb6018dbbdc9abcbc3a0065483ae5186ad2a64dcd" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "derivative", + "digest", + "tracing", +] + [[package]] name = "ark-r1cs-std" version = "0.3.1" @@ -514,11 +547,15 @@ dependencies = [ "ark-ff", "ark-gm17", "ark-groth16", + "ark-marlin", + "ark-poly", + "ark-poly-commit", "ark-r1cs-std", "ark-relations", "ark-serialize", "ark-snark", "ark-std", + "blake2", "clap", "color-eyre", "env_logger", diff --git a/house-snark/Cargo.toml b/house-snark/Cargo.toml index 6f68b82..c8ec7be 100644 --- a/house-snark/Cargo.toml +++ b/house-snark/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" [dependencies] anyhow = "1.0" +blake2 = "0.9.2" clap = { version = "4.0", features = ["derive"] } color-eyre = "0.6" env_logger = "0.9.0" @@ -13,6 +14,8 @@ log = "0.4" ark-crypto-primitives = { version = "^0.3.0", default-features = true, features = [ "r1cs" ] } ark-ec = { version = "^0.3.0", default-features = false } ark-ff = { version = "^0.3.0", default-features = false } +ark-poly = { version = "^0.3.0", default-features = false } +ark-poly-commit = { version = "^0.3.0", default-features = false } ark-std = { version = "^0.3.0", default-features = false } ark-serialize = { version = "^0.3.0", default-features = false } ark-relations = { version = "^0.3.0", default-features = false } @@ -24,6 +27,7 @@ ark-ed-on-bls12-381 = { version = "^0.3.0", features = ["r1cs"] } ark-bls12-381 = { version = "^0.3.0" } ark-groth16 = { version = "^0.3.0", default-features = false } ark-gm17 = { version = "^0.3.0", default-features = false } +ark-marlin = { version = "^0.3.0", default-features = false } [features] default = ["std"] diff --git a/house-snark/README.md b/house-snark/README.md index 7bf8b64..d1bc84b 100644 --- a/house-snark/README.md +++ b/house-snark/README.md @@ -36,6 +36,7 @@ For now, default public input is returned together with a proof. Currently supported relations are: - `xor` - `linear-equation` + - `merkle-tree` The files will be named according to the pattern: `.(vk|pk|proof|input).bytes`. They can be directly sent to the pallet. diff --git a/house-snark/src/config.rs b/house-snark/src/config.rs index 7542d0b..64e9907 100644 --- a/house-snark/src/config.rs +++ b/house-snark/src/config.rs @@ -38,8 +38,20 @@ pub enum Command { #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Args)] pub struct GenerateSrsCmd { /// Proving system to use. - #[clap(long, short, value_enum, default_value = "unimplemented")] + #[clap(long, short, value_enum, default_value = "marlin")] pub system: UniversalProvingSystem, + + /// Maximum supported number of constraints. + #[clap(long, default_value = "100")] + pub num_constraints: usize, + + /// Maximum supported number of variables. + #[clap(long, default_value = "100")] + pub num_variables: usize, + + /// Maximum supported polynomial degree. + #[clap(long, default_value = "100")] + pub degree: usize, } #[derive(Clone, Eq, PartialEq, Hash, Debug, Args)] @@ -49,7 +61,7 @@ pub struct GenerateKeysFromSrsCmd { pub relation: Relation, /// Proving system to use. - #[clap(long, short, value_enum, default_value = "unimplemented")] + #[clap(long, short, value_enum, default_value = "marlin")] pub system: UniversalProvingSystem, /// Path to a file containing SRS. diff --git a/house-snark/src/environment.rs b/house-snark/src/environment.rs index fd6b096..d4918ba 100644 --- a/house-snark/src/environment.rs +++ b/house-snark/src/environment.rs @@ -1,18 +1,27 @@ use std::fmt::Debug; -use ark_gm17::GM17; -use ark_groth16::Groth16; +use ark_poly::univariate::DensePolynomial; +use ark_poly_commit::marlin_pc::MarlinKZG10; use ark_relations::r1cs::ConstraintSynthesizer; use ark_serialize::CanonicalDeserialize; +use blake2::Blake2s; use clap::ValueEnum; use traits::{NonUniversalSystem, ProvingSystem}; -use crate::serialization::serialize; +use crate::{environment::traits::UniversalSystem, serialization::serialize}; -/// For now, we can settle with this curve and its scalar field. +// For now, we can settle with these types. +/// Common pairing engine. pub type PairingEngine = ark_bls12_381::Bls12_381; +/// Common scalar field. pub type CircuitField = ark_bls12_381::Fr; +// Systems with hardcoded parameters. +type Groth16 = ark_groth16::Groth16; +type GM17 = ark_gm17::GM17; +type MarlinPolynomialCommitment = MarlinKZG10>; +type Marlin = ark_marlin::Marlin; + /// All available non universal proving systems. #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, ValueEnum)] pub enum NonUniversalProvingSystem { @@ -23,7 +32,7 @@ pub enum NonUniversalProvingSystem { /// All available universal proving systems. #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, ValueEnum)] pub enum UniversalProvingSystem { - Unimplemented, + Marlin, } /// Any proving system. @@ -52,12 +61,10 @@ impl SomeProvingSystem { match self { NonUniversal(NonUniversalProvingSystem::Groth16) => { - self._prove::<_, Groth16>(circuit, pk) - } - NonUniversal(NonUniversalProvingSystem::Gm17) => { - self._prove::<_, GM17>(circuit, pk) + self._prove::<_, Groth16>(circuit, pk) } - _ => unimplemented!(), + NonUniversal(NonUniversalProvingSystem::Gm17) => self._prove::<_, GM17>(circuit, pk), + Universal(UniversalProvingSystem::Marlin) => self._prove::<_, Marlin>(circuit, pk), } } @@ -87,12 +94,8 @@ impl NonUniversalProvingSystem { /// Generates proving and verifying key for `circuit`. Returns serialized keys. pub fn generate_keys>(&self, circuit: C) -> RawKeys { match self { - NonUniversalProvingSystem::Groth16 => { - self._generate_keys::<_, Groth16>(circuit) - } - NonUniversalProvingSystem::Gm17 => { - self._generate_keys::<_, GM17>(circuit) - } + NonUniversalProvingSystem::Groth16 => self._generate_keys::<_, Groth16>(circuit), + NonUniversalProvingSystem::Gm17 => self._generate_keys::<_, GM17>(circuit), } } @@ -115,24 +118,51 @@ impl UniversalProvingSystem { } /// Generates SRS. Returns in serialized version. - pub fn generate_srs(&self) -> Vec { + pub fn generate_srs( + &self, + num_constraints: usize, + num_variables: usize, + degree: usize, + ) -> Vec { match self { - UniversalProvingSystem::Unimplemented => { - unimplemented!() + UniversalProvingSystem::Marlin => { + self._generate_srs::(num_constraints, num_variables, degree) } } } + fn _generate_srs( + &self, + num_constraints: usize, + num_variables: usize, + degree: usize, + ) -> Vec { + let srs = S::generate_srs(num_constraints, num_variables, degree); + serialize(&srs) + } + /// Generates proving and verifying key for `circuit` using `srs`. Returns serialized keys. pub fn generate_keys>( &self, - _circuit: C, - _srs: Vec, + circuit: C, + srs: Vec, ) -> RawKeys { match self { - UniversalProvingSystem::Unimplemented => { - unimplemented!() - } + UniversalProvingSystem::Marlin => self._generate_keys::<_, Marlin>(circuit, srs), + } + } + + fn _generate_keys, S: UniversalSystem>( + &self, + circuit: C, + srs: Vec, + ) -> RawKeys { + let srs = + <::Srs>::deserialize(&*srs).expect("Failed to deserialize srs"); + let (pk, vk) = S::generate_keys(circuit, &srs); + RawKeys { + pk: serialize(&pk), + vk: serialize(&vk), } } } @@ -140,8 +170,6 @@ impl UniversalProvingSystem { pub mod traits { use ark_relations::r1cs::ConstraintSynthesizer; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; - use ark_snark::SNARK; - use ark_std::rand::{rngs::StdRng, SeedableRng}; use super::CircuitField; @@ -163,12 +191,12 @@ pub mod traits { type Srs: CanonicalSerialize + CanonicalDeserialize; /// Generates SRS. - fn generate_srs() -> Self::Srs; + fn generate_srs(num_constraints: usize, num_variables: usize, degree: usize) -> Self::Srs; /// Generates proving and verifying key for `circuit` using `srs`. fn generate_keys>( - srs: &Self::Srs, circuit: C, + srs: &Self::Srs, ) -> (Self::ProvingKey, Self::VerifyingKey); } @@ -179,39 +207,97 @@ pub mod traits { circuit: C, ) -> (Self::ProvingKey, Self::VerifyingKey); } +} + +mod trait_implementations { + use ark_relations::r1cs::ConstraintSynthesizer; + use ark_snark::SNARK; + use ark_std::rand::{rngs::StdRng, SeedableRng}; + + use crate::{ + environment::{ + traits::{NonUniversalSystem, ProvingSystem, UniversalSystem}, + Groth16, Marlin, MarlinPolynomialCommitment, GM17, + }, + CircuitField, + }; + + fn dummy_rng() -> StdRng { + StdRng::from_seed([0u8; 32]) + } + + // Unfortunately, Groth16, GM17 and Marlin don't have any common supertrait, and therefore, + // we cannot provide any blanket implementation without running into damned `upstream crates may + // add a new impl of trait` error (see https://github.com/rust-lang/rfcs/issues/2758). + // Tfu. Disgusting. + + /// This macro takes a type `system` as the only argument and provides `ProvingSystem` and + /// `NonUniversalSystem` implementations for it. + /// + /// `system` should implement `SNARK` trait. + macro_rules! impl_non_universal_system_for_snark { + ($system:ty) => { + impl ProvingSystem for $system { + type Proof = <$system as SNARK>::Proof; + type ProvingKey = <$system as SNARK>::ProvingKey; + type VerifyingKey = <$system as SNARK>::VerifyingKey; + + fn prove>( + pk: &Self::ProvingKey, + circuit: C, + ) -> Self::Proof { + let mut rng = dummy_rng(); + <$system as SNARK>::prove(pk, circuit, &mut rng) + .expect("Failed to generate keys") + } + } + + impl NonUniversalSystem for $system { + fn generate_keys>( + circuit: C, + ) -> (Self::ProvingKey, Self::VerifyingKey) { + let mut rng = dummy_rng(); + <$system as SNARK>::circuit_specific_setup(circuit, &mut rng) + .expect("Failed to generate keys") + } + } + }; + } - impl> ProvingSystem for S - where - >::Proof: CanonicalSerialize + CanonicalDeserialize, - >::ProvingKey: CanonicalSerialize + CanonicalDeserialize, - >::VerifyingKey: CanonicalSerialize + CanonicalDeserialize, - { - type Proof = >::Proof; - type ProvingKey = >::ProvingKey; - type VerifyingKey = >::VerifyingKey; + impl_non_universal_system_for_snark!(Groth16); + impl_non_universal_system_for_snark!(GM17); + + impl ProvingSystem for Marlin { + type Proof = ark_marlin::Proof; + type ProvingKey = ark_marlin::IndexProverKey; + type VerifyingKey = ark_marlin::IndexVerifierKey; fn prove>( pk: &Self::ProvingKey, circuit: C, ) -> Self::Proof { - let mut rng = StdRng::from_seed([0u8; 32]); - >::prove(pk, circuit, &mut rng) - .expect("Failed to generate keys") + let mut rng = dummy_rng(); + Marlin::prove(pk, circuit, &mut rng).expect("Failed to generate proof") } } - impl> NonUniversalSystem for S - where - >::Proof: CanonicalSerialize + CanonicalDeserialize, - >::ProvingKey: CanonicalSerialize + CanonicalDeserialize, - >::VerifyingKey: CanonicalSerialize + CanonicalDeserialize, - { + impl UniversalSystem for Marlin { + type Srs = ark_marlin::UniversalSRS; + + fn generate_srs(num_constraints: usize, num_variables: usize, degree: usize) -> Self::Srs { + let mut rng = dummy_rng(); + Marlin::universal_setup(num_constraints, num_variables, degree, &mut rng) + .expect("Failed to generate SRS") + } + fn generate_keys>( circuit: C, + srs: &Self::Srs, ) -> (Self::ProvingKey, Self::VerifyingKey) { - let mut rng = StdRng::from_seed([0u8; 32]); - >::circuit_specific_setup(circuit, &mut rng) - .expect("Failed to generate keys") + Marlin::index(srs, circuit).expect( + "Failed to generate keys from SRS (it might be the case, that the circuit is \ + larger than the SRS allows).", + ) } } } diff --git a/house-snark/src/main.rs b/house-snark/src/main.rs index 4f546bf..b8331b9 100644 --- a/house-snark/src/main.rs +++ b/house-snark/src/main.rs @@ -33,8 +33,13 @@ fn main() { let cli: Cli = Cli::parse(); match cli.command { - Command::GenerateSrs(GenerateSrsCmd { system }) => { - let srs = system.generate_srs(); + Command::GenerateSrs(GenerateSrsCmd { + system, + num_constraints, + num_variables, + degree, + }) => { + let srs = system.generate_srs(num_constraints, num_variables, degree); save_srs(&srs, &system.id()); }