From acfd83236fd34df4596ad68ff1b48938f35083b3 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Sat, 17 Apr 2021 10:06:06 -0700 Subject: [PATCH 01/23] Add `Relation` traits --- relations/src/lib.rs | 18 ++++ relations/src/r1cs/constraint_system.rs | 32 +------ relations/src/r1cs/mod.rs | 110 ++++++++++++++++++++++-- 3 files changed, 123 insertions(+), 37 deletions(-) diff --git a/relations/src/lib.rs b/relations/src/lib.rs index cf249f777..19bea59a4 100644 --- a/relations/src/lib.rs +++ b/relations/src/lib.rs @@ -16,3 +16,21 @@ extern crate ark_std; pub mod r1cs; + +/// An *indexed relation* is a set of triples of the form `(index, instance, witness)`. +pub trait Relation { + /// The index is a "large" but static part of the triple. Examples include + /// the circuit in the circuit satisfiability relation, and constraint + /// matrices in the R1CS relation. + type Index: Eq; + /// The instance is a "small" part of the triple. Like the index, it is publicly known. + type Instance: Eq; + /// The instance is a "large" but private part of the triple. + type Witness: Eq; +} + +/// An *indexed NP relation* is a relation with an efficient membership check. +pub trait NPRelation: Relation { + /// Checks whether the triple `(index, instance, witness)` is a member of the relation. + fn check_membership(index: &Self::Index, instance: &Self::Instance, witness: &Self::Witness) -> bool; +} diff --git a/relations/src/r1cs/constraint_system.rs b/relations/src/r1cs/constraint_system.rs index f3e7bd5eb..d80c51d45 100644 --- a/relations/src/r1cs/constraint_system.rs +++ b/relations/src/r1cs/constraint_system.rs @@ -1,6 +1,6 @@ #[cfg(feature = "std")] use crate::r1cs::ConstraintTrace; -use crate::r1cs::{LcIndex, LinearCombination, Matrix, SynthesisError, Variable}; +use crate::r1cs::{LcIndex, LinearCombination, SynthesisError, Variable, ConstraintMatrices}; use ark_ff::Field; use ark_std::{ any::{Any, TypeId}, @@ -643,36 +643,6 @@ impl ConstraintSystem { } } } -/// The A, B and C matrices of a Rank-One `ConstraintSystem`. -/// Also contains metadata on the structure of the constraint system -/// and the matrices. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ConstraintMatrices { - /// The number of variables that are "public instances" to the constraint - /// system. - pub num_instance_variables: usize, - /// The number of variables that are "private witnesses" to the constraint - /// system. - pub num_witness_variables: usize, - /// The number of constraints in the constraint system. - pub num_constraints: usize, - /// The number of non_zero entries in the A matrix. - pub a_num_non_zero: usize, - /// The number of non_zero entries in the B matrix. - pub b_num_non_zero: usize, - /// The number of non_zero entries in the C matrix. - pub c_num_non_zero: usize, - - /// The A constraint matrix. This is empty when - /// `self.mode == SynthesisMode::Prove { construct_matrices = false }`. - pub a: Matrix, - /// The B constraint matrix. This is empty when - /// `self.mode == SynthesisMode::Prove { construct_matrices = false }`. - pub b: Matrix, - /// The C constraint matrix. This is empty when - /// `self.mode == SynthesisMode::Prove { construct_matrices = false }`. - pub c: Matrix, -} /// A shared reference to a constraint system that can be stored in high level /// variables. diff --git a/relations/src/r1cs/mod.rs b/relations/src/r1cs/mod.rs index 69adfa3f5..bd6a84fc8 100644 --- a/relations/src/r1cs/mod.rs +++ b/relations/src/r1cs/mod.rs @@ -1,9 +1,106 @@ -//! Core interface for working with Rank-1 Constraint Systems (R1CS). +//! Core interfaces for working with Rank-1 Constraint Systems (R1CS), which is +//! an indexed NP relation. -use ark_std::vec::Vec; +use crate::{Relation, NPRelation}; +use ark_std::{vec::Vec, marker::PhantomData, cmp::Ordering}; -/// A result type specialized to `SynthesisError`. -pub type Result = core::result::Result; +/// An *indexed NP relation* is a relation with an efficient membership check. +pub struct R1CS { + f: PhantomData +} + +/// An R1CS index consists of three matrices, as well as the number of instance variables +/// and number of witness variables. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ConstraintMatrices { + /// The number of variables that are "public instances" to the constraint + /// system. + pub num_instance_variables: usize, + /// The number of variables that are "private witnesses" to the constraint + /// system. + pub num_witness_variables: usize, + /// The number of constraints in the constraint system. + pub num_constraints: usize, + /// The number of non_zero entries in the A matrix. + pub a_num_non_zero: usize, + /// The number of non_zero entries in the B matrix. + pub b_num_non_zero: usize, + /// The number of non_zero entries in the C matrix. + pub c_num_non_zero: usize, + + /// The A constraint matrix. + /// `self.mode == SynthesisMode::Prove { construct_matrices = false }`. + pub a: Matrix, + /// The B constraint matrix. + pub b: Matrix, + /// The C constraint matrix. + pub c: Matrix, +} + +/// An R1CS instance consists of variable assignments to the instance variables. +/// The first variable must be assigned a value of `F::one()`. +#[derive(Eq, PartialEq, Debug, Hash)] +pub struct Instance(pub Vec); + +/// An R1CS instance consists of variable assignments to the witness variables. +#[derive(Eq, PartialEq, Debug, Hash)] +pub struct Witness(pub Vec); + +impl Relation for R1CS { + type Index = ConstraintMatrices; + type Instance = Instance; + type Witness = Witness; +} + +impl NPRelation for R1CS { + fn check_membership(index: &Self::Index, instance: &Self::Instance, witness: &Self::Witness) -> bool { + // The number of instance variables does not match. + if instance.0.len() != index.num_instance_variables { + return false; + } + // The number of witness variables does not match. + if witness.0.len() != index.num_witness_variables { + return false; + } + // The first instance variable must be 1. + if instance.0[0] != F::one() { + return false; + } + + cfg_iter!(&index.a) + .zip(&index.b) + .zip(&index.c) + .all(|((a_row, b_row), c_row)| { + let a = inner_product(&a_row, index.num_instance_variables, &instance.0, &witness.0); + let b = inner_product(&b_row, index.num_instance_variables, &instance.0, &witness.0); + let c = inner_product(&c_row, index.num_instance_variables, &instance.0, &witness.0); + a * b == c + }) + } +} + +// Compute the inner product of `row` with `instance.concat(witness)`. +fn inner_product( + row: &[(F, usize)], + num_instance_variables: usize, + instance: &[F], + witness: &[F] +) -> F { + let mut acc = F::zero(); + for &(ref coeff, i) in row { + let tmp = if i < num_instance_variables { + instance[i] + } else { + witness[i - num_instance_variables] + }; + acc += &(if coeff.is_one() { tmp } else { tmp * coeff }); + } + acc +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// #[macro_use] mod impl_lc; @@ -19,12 +116,13 @@ pub use tracing::info_span; pub use ark_ff::{Field, ToConstraintField}; pub use constraint_system::{ - ConstraintMatrices, ConstraintSynthesizer, ConstraintSystem, ConstraintSystemRef, Namespace, + ConstraintSynthesizer, ConstraintSystem, ConstraintSystemRef, Namespace, OptimizationGoal, SynthesisMode, }; pub use error::SynthesisError; +/// A result type specialized to `SynthesisError`. +pub type Result = core::result::Result; -use core::cmp::Ordering; /// A sparse representation of constraint matrices. pub type Matrix = Vec>; From 9c95420b510ef3cbdd85cf8ef8a0927b7c1defce Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Mon, 19 Apr 2021 18:10:46 -0700 Subject: [PATCH 02/23] Update `SNARK` trait --- relations/src/r1cs/constraint_system.rs | 2 +- snark/src/lib.rs | 87 +++++++++++++++---------- snark/src/r1cs.rs | 70 ++++++++++++++++++++ 3 files changed, 123 insertions(+), 36 deletions(-) create mode 100644 snark/src/r1cs.rs diff --git a/relations/src/r1cs/constraint_system.rs b/relations/src/r1cs/constraint_system.rs index d80c51d45..336004c4b 100644 --- a/relations/src/r1cs/constraint_system.rs +++ b/relations/src/r1cs/constraint_system.rs @@ -20,7 +20,7 @@ use ark_std::{ // TODO: Think: should we replace this with just a closure? pub trait ConstraintSynthesizer { /// Drives generation of new constraints inside `cs`. - fn generate_constraints(self, cs: ConstraintSystemRef) -> crate::r1cs::Result<()>; + fn generate_constraints(&self, cs: ConstraintSystemRef) -> crate::r1cs::Result<()>; } /// An Rank-One `ConstraintSystem`. Enforces constraints of the form diff --git a/snark/src/lib.rs b/snark/src/lib.rs index 7832f3e81..8b322507b 100644 --- a/snark/src/lib.rs +++ b/snark/src/lib.rs @@ -10,13 +10,13 @@ )] #![forbid(unsafe_code)] -use ark_ff::{PrimeField, ToBytes}; -use ark_relations::r1cs::ConstraintSynthesizer; +use ark_relations::NPRelation; +use ark_ff::ToBytes; use ark_std::rand::{CryptoRng, RngCore}; use core::fmt::Debug; /// The basic functionality for a SNARK. -pub trait SNARK { +pub trait SNARK { /// The information required by the prover to produce a proof for a specific /// circuit *C*. type ProvingKey: Clone; @@ -35,19 +35,13 @@ pub trait SNARK { /// Errors encountered during setup, proving, or verification. type Error: 'static + ark_std::error::Error; - /// Takes in a description of a computation (specified in R1CS constraints), - /// and samples proving and verification keys for that circuit. - fn circuit_specific_setup, R: RngCore + CryptoRng>( - circuit: C, - rng: &mut R, - ) -> Result<(Self::ProvingKey, Self::VerifyingKey), Self::Error>; - /// Generates a proof of satisfaction of the arithmetic circuit C (specified /// as R1CS constraints). - fn prove, R: RngCore + CryptoRng>( + fn prove( circuit_pk: &Self::ProvingKey, - circuit: C, - rng: &mut R, + instance: &R::Instance, + witness: &R::Witness, + rng: &mut Rng, ) -> Result; /// Checks that `proof` is a valid proof of the satisfaction of circuit @@ -55,11 +49,11 @@ pub trait SNARK { /// specified as R1CS constraints. fn verify( circuit_vk: &Self::VerifyingKey, - public_input: &[F], + instance: &R::Instance, proof: &Self::Proof, ) -> Result { let pvk = Self::process_vk(circuit_vk)?; - Self::verify_with_processed_vk(&pvk, public_input, proof) + Self::verify_with_processed_vk(&pvk, instance, proof) } /// Preprocesses `circuit_vk` to enable faster verification. @@ -72,26 +66,23 @@ pub trait SNARK { /// specified as R1CS constraints. fn verify_with_processed_vk( circuit_pvk: &Self::ProcessedVerifyingKey, - public_input: &[F], + instance: &R::Instance, proof: &Self::Proof, ) -> Result; } /// A SNARK with (only) circuit-specific setup. -pub trait CircuitSpecificSetupSNARK: SNARK { - /// The setup algorithm for circuit-specific SNARKs. By default, this - /// just invokes `>::circuit_specific_setup(...)`. - fn setup, R: RngCore + CryptoRng>( - circuit: C, - rng: &mut R, - ) -> Result<(Self::ProvingKey, Self::VerifyingKey), Self::Error> { - >::circuit_specific_setup(circuit, rng) - } +pub trait CircuitSpecificSetupSNARK: SNARK { + /// The setup algorithm for circuit-specific SNARKs. + fn setup( + index: &R::Index, + rng: &mut Rng, + ) -> Result<(Self::ProvingKey, Self::VerifyingKey), Self::Error>; } /// A helper type for universal-setup SNARKs, which must infer their computation /// size bounds. -pub enum UniversalSetupIndexError { +pub enum IndexingError { /// The provided universal public parameters were insufficient to encode /// the given circuit. NeedLargerBound(Bound), @@ -101,30 +92,56 @@ pub enum UniversalSetupIndexError { /// A SNARK with universal setup. That is, a SNARK where the trusted setup is /// circuit-independent. -pub trait UniversalSetupSNARK: SNARK { +pub trait UniversalSetupSNARK: SNARK { /// Specifies how to bound the size of public parameters required to /// generate the index proving and verification keys for a given /// circuit. - type ComputationBound: Clone + Default + Debug; + type IndexBound: Clone + Default + Debug; /// Specifies the type of universal public parameters. type PublicParameters: Clone + Debug; + /// Specifies the bound size that is necessary and sufficient to + /// generate public parameters for `index`. + fn bound_for_index(index: &R::Index) -> Self::IndexBound; + /// Specifies how to bound the size of public parameters required to /// generate the index proving and verification keys for a given /// circuit. - fn universal_setup( - compute_bound: &Self::ComputationBound, - rng: &mut R, + fn universal_setup( + compute_bound: &Self::IndexBound, + rng: &mut Rng, ) -> Result; /// Indexes the public parameters according to the circuit `circuit`, and /// outputs circuit-specific proving and verification keys. - fn index, R: RngCore + CryptoRng>( + /// + /// This is a *deterministic* method. + fn index( pp: &Self::PublicParameters, - circuit: C, - rng: &mut R, + index: &R::Index, ) -> Result< (Self::ProvingKey, Self::VerifyingKey), - UniversalSetupIndexError, + IndexingError, >; } + +impl CircuitSpecificSetupSNARK for S +where + S: UniversalSetupSNARK +{ + /// The setup algorithm for circuit-specific SNARKs. + fn setup( + index: &R::Index, + rng: &mut Rng, + ) -> Result<(Self::ProvingKey, Self::VerifyingKey), Self::Error> { + let bound = Self::bound_for_index(index); + let pp = Self::universal_setup(&bound, rng)?; + Self::index(&pp, index).map_err(|e| { + if let IndexingError::Other(e) = e { + e + } else { + panic!("`bound_for_index` returned bound that is insufficient for indexing") + } + }) + } +} diff --git a/snark/src/r1cs.rs b/snark/src/r1cs.rs new file mode 100644 index 000000000..3b8558b3d --- /dev/null +++ b/snark/src/r1cs.rs @@ -0,0 +1,70 @@ +use ark_relations::r1cs::{R1CS, ConstraintSynthesizer}; + +/// The basic functionality for a SNARK. +pub trait SNARKForR1CS: SNARK> { + /// Generates a proof of satisfaction of the arithmetic circuit C (specified + /// as R1CS constraints). + fn prove, Rng: RngCore + CryptoRng>( + circuit_pk: &Self::ProvingKey, + witness_generator: C, + rng: &mut Rng, + ) -> Result; + + /// Checks that `proof` is a valid proof of the satisfaction of circuit + /// encoded in `circuit_vk`, with respect to the public input `public_input`, + /// specified as R1CS constraints. + fn verify>( + circuit_vk: &Self::VerifyingKey, + public_input_generator: C, + proof: &Self::Proof, + ) -> Result { + let pvk = Self::process_vk(circuit_vk)?; + Self::verify_with_processed_vk(&pvk, public_input_generator, proof) + } + + /// Preprocesses `circuit_vk` to enable faster verification. + fn process_vk( + circuit_vk: &Self::VerifyingKey, + ) -> Result; + + /// Checks that `proof` is a valid proof of the satisfaction of circuit + /// encoded in `circuit_pvk`, with respect to the public input `public_input`, + /// specified as R1CS constraints. + fn verify_with_processed_vk>( + circuit_pvk: &Self::ProcessedVerifyingKey, + public_input_generator: C, + proof: &Self::Proof, + ) -> Result; +} + +/// A SNARK with (only) circuit-specific setup. +pub trait CircuitSpecificSetupSNARKForR1CS: CircuitSpecificSetupSNARK> + SNARK> { + /// The setup algorithm for circuit-specific SNARKs. + fn setup, Rng: RngCore + CryptoRng>( + index_generator: C, + rng: &mut Rng, + ) -> Result<(Self::ProvingKey, Self::VerifyingKey), Self::Error>; +} + +/// A SNARK with universal setup. That is, a SNARK where the trusted setup is +/// circuit-independent. +pub trait UniversalSetupSNARKForR1CS: UniversalSetupSNARK> + SNARKForR1CS { + /// Specifies how to bound the size of public parameters required to + /// generate the index proving and verification keys for a given + /// circuit. + fn universal_setup( + compute_bound: &Self::ComputationBound, + rng: &mut Rng, + ) -> Result; + + /// Indexes the public parameters according to the circuit `circuit`, and + /// outputs circuit-specific proving and verification keys. + fn index>( + pp: &Self::PublicParameters, + index_generator: C, + rng: &mut Rng, + ) -> Result< + (Self::ProvingKey, Self::VerifyingKey), + IndexingError, + >; +} From 77573c412f96f61f0be3a0b4abfe4fdd1bbcc1ec Mon Sep 17 00:00:00 2001 From: weikeng Date: Mon, 19 Apr 2021 21:58:44 -0700 Subject: [PATCH 03/23] fmt --- relations/src/lib.rs | 10 +++++-- relations/src/r1cs/constraint_system.rs | 2 +- relations/src/r1cs/mod.rs | 40 ++++++++++++++++++------- snark/src/lib.rs | 11 +++---- 4 files changed, 41 insertions(+), 22 deletions(-) diff --git a/relations/src/lib.rs b/relations/src/lib.rs index 19bea59a4..6177a081f 100644 --- a/relations/src/lib.rs +++ b/relations/src/lib.rs @@ -19,8 +19,8 @@ pub mod r1cs; /// An *indexed relation* is a set of triples of the form `(index, instance, witness)`. pub trait Relation { - /// The index is a "large" but static part of the triple. Examples include - /// the circuit in the circuit satisfiability relation, and constraint + /// The index is a "large" but static part of the triple. Examples include + /// the circuit in the circuit satisfiability relation, and constraint /// matrices in the R1CS relation. type Index: Eq; /// The instance is a "small" part of the triple. Like the index, it is publicly known. @@ -32,5 +32,9 @@ pub trait Relation { /// An *indexed NP relation* is a relation with an efficient membership check. pub trait NPRelation: Relation { /// Checks whether the triple `(index, instance, witness)` is a member of the relation. - fn check_membership(index: &Self::Index, instance: &Self::Instance, witness: &Self::Witness) -> bool; + fn check_membership( + index: &Self::Index, + instance: &Self::Instance, + witness: &Self::Witness, + ) -> bool; } diff --git a/relations/src/r1cs/constraint_system.rs b/relations/src/r1cs/constraint_system.rs index 336004c4b..db0d27c98 100644 --- a/relations/src/r1cs/constraint_system.rs +++ b/relations/src/r1cs/constraint_system.rs @@ -1,6 +1,6 @@ #[cfg(feature = "std")] use crate::r1cs::ConstraintTrace; -use crate::r1cs::{LcIndex, LinearCombination, SynthesisError, Variable, ConstraintMatrices}; +use crate::r1cs::{ConstraintMatrices, LcIndex, LinearCombination, SynthesisError, Variable}; use ark_ff::Field; use ark_std::{ any::{Any, TypeId}, diff --git a/relations/src/r1cs/mod.rs b/relations/src/r1cs/mod.rs index bd6a84fc8..5512995f6 100644 --- a/relations/src/r1cs/mod.rs +++ b/relations/src/r1cs/mod.rs @@ -1,12 +1,12 @@ //! Core interfaces for working with Rank-1 Constraint Systems (R1CS), which is //! an indexed NP relation. -use crate::{Relation, NPRelation}; -use ark_std::{vec::Vec, marker::PhantomData, cmp::Ordering}; +use crate::{NPRelation, Relation}; +use ark_std::{cmp::Ordering, marker::PhantomData, vec::Vec}; /// An *indexed NP relation* is a relation with an efficient membership check. pub struct R1CS { - f: PhantomData + f: PhantomData, } /// An R1CS index consists of three matrices, as well as the number of instance variables @@ -53,7 +53,11 @@ impl Relation for R1CS { } impl NPRelation for R1CS { - fn check_membership(index: &Self::Index, instance: &Self::Instance, witness: &Self::Witness) -> bool { + fn check_membership( + index: &Self::Index, + instance: &Self::Instance, + witness: &Self::Witness, + ) -> bool { // The number of instance variables does not match. if instance.0.len() != index.num_instance_variables { return false; @@ -71,9 +75,24 @@ impl NPRelation for R1CS { .zip(&index.b) .zip(&index.c) .all(|((a_row, b_row), c_row)| { - let a = inner_product(&a_row, index.num_instance_variables, &instance.0, &witness.0); - let b = inner_product(&b_row, index.num_instance_variables, &instance.0, &witness.0); - let c = inner_product(&c_row, index.num_instance_variables, &instance.0, &witness.0); + let a = inner_product( + &a_row, + index.num_instance_variables, + &instance.0, + &witness.0, + ); + let b = inner_product( + &b_row, + index.num_instance_variables, + &instance.0, + &witness.0, + ); + let c = inner_product( + &c_row, + index.num_instance_variables, + &instance.0, + &witness.0, + ); a * b == c }) } @@ -84,7 +103,7 @@ fn inner_product( row: &[(F, usize)], num_instance_variables: usize, instance: &[F], - witness: &[F] + witness: &[F], ) -> F { let mut acc = F::zero(); for &(ref coeff, i) in row { @@ -116,14 +135,13 @@ pub use tracing::info_span; pub use ark_ff::{Field, ToConstraintField}; pub use constraint_system::{ - ConstraintSynthesizer, ConstraintSystem, ConstraintSystemRef, Namespace, - OptimizationGoal, SynthesisMode, + ConstraintSynthesizer, ConstraintSystem, ConstraintSystemRef, Namespace, OptimizationGoal, + SynthesisMode, }; pub use error::SynthesisError; /// A result type specialized to `SynthesisError`. pub type Result = core::result::Result; - /// A sparse representation of constraint matrices. pub type Matrix = Vec>; diff --git a/snark/src/lib.rs b/snark/src/lib.rs index 8b322507b..5448e6648 100644 --- a/snark/src/lib.rs +++ b/snark/src/lib.rs @@ -10,8 +10,8 @@ )] #![forbid(unsafe_code)] -use ark_relations::NPRelation; use ark_ff::ToBytes; +use ark_relations::NPRelation; use ark_std::rand::{CryptoRng, RngCore}; use core::fmt::Debug; @@ -100,7 +100,7 @@ pub trait UniversalSetupSNARK: SNARK { /// Specifies the type of universal public parameters. type PublicParameters: Clone + Debug; - /// Specifies the bound size that is necessary and sufficient to + /// Specifies the bound size that is necessary and sufficient to /// generate public parameters for `index`. fn bound_for_index(index: &R::Index) -> Self::IndexBound; @@ -119,15 +119,12 @@ pub trait UniversalSetupSNARK: SNARK { fn index( pp: &Self::PublicParameters, index: &R::Index, - ) -> Result< - (Self::ProvingKey, Self::VerifyingKey), - IndexingError, - >; + ) -> Result<(Self::ProvingKey, Self::VerifyingKey), IndexingError>; } impl CircuitSpecificSetupSNARK for S where - S: UniversalSetupSNARK + S: UniversalSetupSNARK, { /// The setup algorithm for circuit-specific SNARKs. fn setup( From 717e834d69f6cdf8d19b932af078492ca6712ab5 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Tue, 20 Apr 2021 13:46:38 -0700 Subject: [PATCH 04/23] Work --- relations/src/r1cs/constraint_system.rs | 10 +-- relations/src/r1cs/mod.rs | 4 +- snark/src/lib.rs | 23 +++--- snark/src/r1cs.rs | 104 ++++++++++-------------- 4 files changed, 64 insertions(+), 77 deletions(-) diff --git a/relations/src/r1cs/constraint_system.rs b/relations/src/r1cs/constraint_system.rs index db0d27c98..fc5be7550 100644 --- a/relations/src/r1cs/constraint_system.rs +++ b/relations/src/r1cs/constraint_system.rs @@ -510,9 +510,9 @@ impl ConstraintSystem { } } - /// Finalize the constraint system (either by outlining or inlining, + /// Optimize the constraint system (either by outlining or inlining, /// if an optimization goal is set). - pub fn finalize(&mut self) { + pub fn optimize(&mut self) { match self.optimization_goal { OptimizationGoal::None => self.inline_all_lcs(), OptimizationGoal::Constraints => self.inline_all_lcs(), @@ -896,11 +896,11 @@ impl ConstraintSystemRef { } } - /// Finalize the constraint system (either by outlining or inlining, + /// Optimize the constraint system (either by outlining or inlining, /// if an optimization goal is set). - pub fn finalize(&self) { + pub fn optimize(&self) { if let Some(cs) = self.inner() { - cs.borrow_mut().finalize() + cs.borrow_mut().optimize() } } diff --git a/relations/src/r1cs/mod.rs b/relations/src/r1cs/mod.rs index 5512995f6..946f277ff 100644 --- a/relations/src/r1cs/mod.rs +++ b/relations/src/r1cs/mod.rs @@ -39,11 +39,11 @@ pub struct ConstraintMatrices { /// An R1CS instance consists of variable assignments to the instance variables. /// The first variable must be assigned a value of `F::one()`. -#[derive(Eq, PartialEq, Debug, Hash)] +#[derive(Eq, PartialEq, Debug, Hash, Clone)] pub struct Instance(pub Vec); /// An R1CS instance consists of variable assignments to the witness variables. -#[derive(Eq, PartialEq, Debug, Hash)] +#[derive(Eq, PartialEq, Debug, Hash, Clone)] pub struct Witness(pub Vec); impl Relation for R1CS { diff --git a/snark/src/lib.rs b/snark/src/lib.rs index 5448e6648..27269f4ad 100644 --- a/snark/src/lib.rs +++ b/snark/src/lib.rs @@ -15,6 +15,9 @@ use ark_relations::NPRelation; use ark_std::rand::{CryptoRng, RngCore}; use core::fmt::Debug; +/// Specialized interface for R1CS-based SNARKs. +pub mod r1cs; + /// The basic functionality for a SNARK. pub trait SNARK { /// The information required by the prover to produce a proof for a specific @@ -38,34 +41,34 @@ pub trait SNARK { /// Generates a proof of satisfaction of the arithmetic circuit C (specified /// as R1CS constraints). fn prove( - circuit_pk: &Self::ProvingKey, + pk: &Self::ProvingKey, instance: &R::Instance, witness: &R::Witness, rng: &mut Rng, ) -> Result; /// Checks that `proof` is a valid proof of the satisfaction of circuit - /// encoded in `circuit_vk`, with respect to the public input `public_input`, + /// encoded in `vk`, with respect to the public input `public_input`, /// specified as R1CS constraints. fn verify( - circuit_vk: &Self::VerifyingKey, + vk: &Self::VerifyingKey, instance: &R::Instance, proof: &Self::Proof, ) -> Result { - let pvk = Self::process_vk(circuit_vk)?; + let pvk = Self::process_vk(vk)?; Self::verify_with_processed_vk(&pvk, instance, proof) } - /// Preprocesses `circuit_vk` to enable faster verification. + /// Preprocesses `vk` to enable faster verification. fn process_vk( - circuit_vk: &Self::VerifyingKey, + vk: &Self::VerifyingKey, ) -> Result; /// Checks that `proof` is a valid proof of the satisfaction of circuit - /// encoded in `circuit_pvk`, with respect to the public input `public_input`, + /// encoded in `pvk`, with respect to the public input `public_input`, /// specified as R1CS constraints. fn verify_with_processed_vk( - circuit_pvk: &Self::ProcessedVerifyingKey, + pvk: &Self::ProcessedVerifyingKey, instance: &R::Instance, proof: &Self::Proof, ) -> Result; @@ -74,7 +77,7 @@ pub trait SNARK { /// A SNARK with (only) circuit-specific setup. pub trait CircuitSpecificSetupSNARK: SNARK { /// The setup algorithm for circuit-specific SNARKs. - fn setup( + fn circuit_specific_setup( index: &R::Index, rng: &mut Rng, ) -> Result<(Self::ProvingKey, Self::VerifyingKey), Self::Error>; @@ -127,7 +130,7 @@ where S: UniversalSetupSNARK, { /// The setup algorithm for circuit-specific SNARKs. - fn setup( + fn circuit_specific_setup( index: &R::Index, rng: &mut Rng, ) -> Result<(Self::ProvingKey, Self::VerifyingKey), Self::Error> { diff --git a/snark/src/r1cs.rs b/snark/src/r1cs.rs index 3b8558b3d..27f7081f9 100644 --- a/snark/src/r1cs.rs +++ b/snark/src/r1cs.rs @@ -1,70 +1,54 @@ -use ark_relations::r1cs::{R1CS, ConstraintSynthesizer}; +use ark_std::rand::{RngCore, CryptoRng}; +use ark_ff::Field; +use ark_relations::r1cs::{R1CS, ConstraintMatrices, Instance, Witness, ConstraintSynthesizer}; +use crate::SNARK; -/// The basic functionality for a SNARK. +/// A [`SNARKForR1CS`] is a [`SNARK`] for the [`R1CS`] relation. pub trait SNARKForR1CS: SNARK> { - /// Generates a proof of satisfaction of the arithmetic circuit C (specified - /// as R1CS constraints). - fn prove, Rng: RngCore + CryptoRng>( - circuit_pk: &Self::ProvingKey, - witness_generator: C, + /// Generate inputs for the SNARK indexer from [`cs`]. + fn indexer_inputs>(cs: &CS) -> ConstraintMatrices; + + /// Generate inputs for the SNARK prover from [`cs`]. + fn prover_inputs>( + cs: &CS, + ) -> ( + Instance, + Witness, + ); + + /// Generate inputs for the SNARK verifier from [`cs`]. + fn verifier_inputs>(cs: &CS) -> Instance; + + /// Generates a proof of satisfaction of the constraint system induced by [`cs`]. + fn prove_with_cs, Rng: RngCore + CryptoRng>( + pk: &Self::ProvingKey, + c: CS, rng: &mut Rng, - ) -> Result; + ) -> Result { + let (instance, witness) = Self::prover_inputs(&c); + Self::prove(pk, &instance, &witness, rng) + } - /// Checks that `proof` is a valid proof of the satisfaction of circuit - /// encoded in `circuit_vk`, with respect to the public input `public_input`, - /// specified as R1CS constraints. - fn verify>( - circuit_vk: &Self::VerifyingKey, - public_input_generator: C, + + /// Verify that [`proof`] is a valid proof with respect to [`vk`] and to the + /// instance induced by [`cs`]. + fn verify_with_cs>( + vk: &Self::VerifyingKey, + cs: CS, proof: &Self::Proof, ) -> Result { - let pvk = Self::process_vk(circuit_vk)?; - Self::verify_with_processed_vk(&pvk, public_input_generator, proof) + let instance = Self::verifier_inputs(&cs); + Self::verify(vk, &instance, proof) } - /// Preprocesses `circuit_vk` to enable faster verification. - fn process_vk( - circuit_vk: &Self::VerifyingKey, - ) -> Result; - - /// Checks that `proof` is a valid proof of the satisfaction of circuit - /// encoded in `circuit_pvk`, with respect to the public input `public_input`, - /// specified as R1CS constraints. - fn verify_with_processed_vk>( - circuit_pvk: &Self::ProcessedVerifyingKey, - public_input_generator: C, + /// Checks that [`proof`] is a valid proof of with respect to [`pvk`] and + /// the instance induced by [`cs`]. + fn verify_with_cs_and_processed_vk>( + pvk: &Self::ProcessedVerifyingKey, + cs: CS, proof: &Self::Proof, - ) -> Result; -} - -/// A SNARK with (only) circuit-specific setup. -pub trait CircuitSpecificSetupSNARKForR1CS: CircuitSpecificSetupSNARK> + SNARK> { - /// The setup algorithm for circuit-specific SNARKs. - fn setup, Rng: RngCore + CryptoRng>( - index_generator: C, - rng: &mut Rng, - ) -> Result<(Self::ProvingKey, Self::VerifyingKey), Self::Error>; -} - -/// A SNARK with universal setup. That is, a SNARK where the trusted setup is -/// circuit-independent. -pub trait UniversalSetupSNARKForR1CS: UniversalSetupSNARK> + SNARKForR1CS { - /// Specifies how to bound the size of public parameters required to - /// generate the index proving and verification keys for a given - /// circuit. - fn universal_setup( - compute_bound: &Self::ComputationBound, - rng: &mut Rng, - ) -> Result; - - /// Indexes the public parameters according to the circuit `circuit`, and - /// outputs circuit-specific proving and verification keys. - fn index>( - pp: &Self::PublicParameters, - index_generator: C, - rng: &mut Rng, - ) -> Result< - (Self::ProvingKey, Self::VerifyingKey), - IndexingError, - >; + ) -> Result { + let instance = Self::verifier_inputs(&cs); + Self::verify_with_processed_vk(pvk, &instance, proof) + } } From 8e07b845c3cc41bb603c4c777e0c83723c8e4821 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Tue, 20 Apr 2021 13:46:49 -0700 Subject: [PATCH 05/23] Format --- snark/src/lib.rs | 4 +--- snark/src/r1cs.rs | 14 ++++---------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/snark/src/lib.rs b/snark/src/lib.rs index 27269f4ad..378a4f77d 100644 --- a/snark/src/lib.rs +++ b/snark/src/lib.rs @@ -60,9 +60,7 @@ pub trait SNARK { } /// Preprocesses `vk` to enable faster verification. - fn process_vk( - vk: &Self::VerifyingKey, - ) -> Result; + fn process_vk(vk: &Self::VerifyingKey) -> Result; /// Checks that `proof` is a valid proof of the satisfaction of circuit /// encoded in `pvk`, with respect to the public input `public_input`, diff --git a/snark/src/r1cs.rs b/snark/src/r1cs.rs index 27f7081f9..c73df4983 100644 --- a/snark/src/r1cs.rs +++ b/snark/src/r1cs.rs @@ -1,7 +1,7 @@ -use ark_std::rand::{RngCore, CryptoRng}; -use ark_ff::Field; -use ark_relations::r1cs::{R1CS, ConstraintMatrices, Instance, Witness, ConstraintSynthesizer}; use crate::SNARK; +use ark_ff::Field; +use ark_relations::r1cs::{ConstraintMatrices, ConstraintSynthesizer, Instance, Witness, R1CS}; +use ark_std::rand::{CryptoRng, RngCore}; /// A [`SNARKForR1CS`] is a [`SNARK`] for the [`R1CS`] relation. pub trait SNARKForR1CS: SNARK> { @@ -9,12 +9,7 @@ pub trait SNARKForR1CS: SNARK> { fn indexer_inputs>(cs: &CS) -> ConstraintMatrices; /// Generate inputs for the SNARK prover from [`cs`]. - fn prover_inputs>( - cs: &CS, - ) -> ( - Instance, - Witness, - ); + fn prover_inputs>(cs: &CS) -> (Instance, Witness); /// Generate inputs for the SNARK verifier from [`cs`]. fn verifier_inputs>(cs: &CS) -> Instance; @@ -29,7 +24,6 @@ pub trait SNARKForR1CS: SNARK> { Self::prove(pk, &instance, &witness, rng) } - /// Verify that [`proof`] is a valid proof with respect to [`vk`] and to the /// instance induced by [`cs`]. fn verify_with_cs>( From 3fdf36e2b8189bd71703c7f644f7e529cd2b8de6 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Tue, 20 Apr 2021 23:09:32 -0700 Subject: [PATCH 06/23] Work --- snark/src/r1cs.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/snark/src/r1cs.rs b/snark/src/r1cs.rs index c73df4983..fa4a15d68 100644 --- a/snark/src/r1cs.rs +++ b/snark/src/r1cs.rs @@ -6,12 +6,15 @@ use ark_std::rand::{CryptoRng, RngCore}; /// A [`SNARKForR1CS`] is a [`SNARK`] for the [`R1CS`] relation. pub trait SNARKForR1CS: SNARK> { /// Generate inputs for the SNARK indexer from [`cs`]. + /// These inputs consist of the constraint matrices. fn indexer_inputs>(cs: &CS) -> ConstraintMatrices; /// Generate inputs for the SNARK prover from [`cs`]. + /// These inputs consist of the instance and witness. fn prover_inputs>(cs: &CS) -> (Instance, Witness); /// Generate inputs for the SNARK verifier from [`cs`]. + /// This input consists of the instance. fn verifier_inputs>(cs: &CS) -> Instance; /// Generates a proof of satisfaction of the constraint system induced by [`cs`]. From ce0406ef8c92b570bdcfdff148fdae50210a49c1 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Tue, 20 Apr 2021 14:46:43 -0700 Subject: [PATCH 07/23] Apply suggestions from code review Co-authored-by: Dev Ojha --- relations/src/r1cs/mod.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/relations/src/r1cs/mod.rs b/relations/src/r1cs/mod.rs index 946f277ff..f13ae716b 100644 --- a/relations/src/r1cs/mod.rs +++ b/relations/src/r1cs/mod.rs @@ -4,7 +4,10 @@ use crate::{NPRelation, Relation}; use ark_std::{cmp::Ordering, marker::PhantomData, vec::Vec}; -/// An *indexed NP relation* is a relation with an efficient membership check. +/// R1CS is an *indexed NP relation*. +/// An index consists of three matrices (A, B, C), +/// while the instance *x* and witness *w* are vectors of field elements +/// such that, for z := (x||w), Az ○ Bz = Cz pub struct R1CS { f: PhantomData, } @@ -29,7 +32,6 @@ pub struct ConstraintMatrices { pub c_num_non_zero: usize, /// The A constraint matrix. - /// `self.mode == SynthesisMode::Prove { construct_matrices = false }`. pub a: Matrix, /// The B constraint matrix. pub b: Matrix, @@ -71,6 +73,11 @@ impl NPRelation for R1CS { return false; } + // Let z = instance || witness. Check that Az ○ Bz = Cz, where ○ is the Hadamard product. + // The Hadamard product of two vectors is the product of them entry-wise, so + // [ 2 ] [ 3 ] [ 6 ] + // [ 3 ] ○ [ 6 ] = [ 18 ] + // [ 4 ] [ 7 ] [ 28 ] cfg_iter!(&index.a) .zip(&index.b) .zip(&index.c) From 7315b9a6da6a404d8091699d2a8c88fcadaa9d15 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Tue, 20 Apr 2021 23:11:45 -0700 Subject: [PATCH 08/23] Update snark/src/r1cs.rs Co-authored-by: Dev Ojha --- snark/src/r1cs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/snark/src/r1cs.rs b/snark/src/r1cs.rs index fa4a15d68..be7f041e0 100644 --- a/snark/src/r1cs.rs +++ b/snark/src/r1cs.rs @@ -17,7 +17,7 @@ pub trait SNARKForR1CS: SNARK> { /// This input consists of the instance. fn verifier_inputs>(cs: &CS) -> Instance; - /// Generates a proof of satisfaction of the constraint system induced by [`cs`]. + /// Generates a proof of satisfaction of the constraint system with inputs and witness induced by [`cs`]. fn prove_with_cs, Rng: RngCore + CryptoRng>( pk: &Self::ProvingKey, c: CS, From be5276d7dba41ff79dc340604b398ca32c611058 Mon Sep 17 00:00:00 2001 From: weikeng Date: Tue, 20 Apr 2021 23:26:22 -0700 Subject: [PATCH 09/23] fmt --- relations/src/r1cs/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/relations/src/r1cs/mod.rs b/relations/src/r1cs/mod.rs index f13ae716b..57a46dff0 100644 --- a/relations/src/r1cs/mod.rs +++ b/relations/src/r1cs/mod.rs @@ -4,9 +4,9 @@ use crate::{NPRelation, Relation}; use ark_std::{cmp::Ordering, marker::PhantomData, vec::Vec}; -/// R1CS is an *indexed NP relation*. -/// An index consists of three matrices (A, B, C), -/// while the instance *x* and witness *w* are vectors of field elements +/// R1CS is an *indexed NP relation*. +/// An index consists of three matrices (A, B, C), +/// while the instance *x* and witness *w* are vectors of field elements /// such that, for z := (x||w), Az ○ Bz = Cz pub struct R1CS { f: PhantomData, From 1511a039c83e6434e0fed4d48943a4210a87b4c7 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Wed, 21 Apr 2021 00:53:57 -0700 Subject: [PATCH 10/23] work --- relations/src/r1cs/constraint_system.rs | 26 +++++++--- relations/src/r1cs/mod.rs | 3 +- snark/src/r1cs.rs | 63 ++++++++++++++++++------- 3 files changed, 68 insertions(+), 24 deletions(-) diff --git a/relations/src/r1cs/constraint_system.rs b/relations/src/r1cs/constraint_system.rs index fc5be7550..364f6bbb9 100644 --- a/relations/src/r1cs/constraint_system.rs +++ b/relations/src/r1cs/constraint_system.rs @@ -14,13 +14,25 @@ use ark_std::{ vec::Vec, }; -/// Computations are expressed in terms of rank-1 constraint systems (R1CS). -/// The `generate_constraints` method is called to generate constraints for -/// both CRS generation and for proving. -// TODO: Think: should we replace this with just a closure? -pub trait ConstraintSynthesizer { - /// Drives generation of new constraints inside `cs`. - fn generate_constraints(&self, cs: ConstraintSystemRef) -> crate::r1cs::Result<()>; +/// Describes how to generate an R1CS index for a given high-level computation. +pub trait ConstraintGenerator { + /// Generates R1CS constraint matrices by modifying [`cs`] in place. + /// The result is stored in [`cs`]. + fn make_constraints(&self, cs: ConstraintSystemRef) -> crate::r1cs::Result<()>; +} + +/// Describes how to generate an R1CS instance for a given high-level computation. +pub trait InstanceGenerator: ConstraintGenerator { + /// Generates an R1CS instance assignment by modifying [`cs`] in place. + /// The result is stored in [`cs`]. + fn make_instance(&self, cs: ConstraintSystemRef) -> crate::r1cs::Result<()>; +} + +/// Describes how to generate an R1CS witness for a given high-level computation. +pub trait WitnessGenerator: InstanceGenerator { + /// Generates an R1CS witness assignment by modifying [`cs`] in place. + /// The result is stored in [`cs`]. + fn make_witness(&self, cs: ConstraintSystemRef) -> crate::r1cs::Result<()>; } /// An Rank-One `ConstraintSystem`. Enforces constraints of the form diff --git a/relations/src/r1cs/mod.rs b/relations/src/r1cs/mod.rs index 57a46dff0..66b9e9c98 100644 --- a/relations/src/r1cs/mod.rs +++ b/relations/src/r1cs/mod.rs @@ -142,7 +142,8 @@ pub use tracing::info_span; pub use ark_ff::{Field, ToConstraintField}; pub use constraint_system::{ - ConstraintSynthesizer, ConstraintSystem, ConstraintSystemRef, Namespace, OptimizationGoal, + ConstraintGenerator, InstanceGenerator, WitnessGenerator, + ConstraintSystem, ConstraintSystemRef, Namespace, OptimizationGoal, SynthesisMode, }; pub use error::SynthesisError; diff --git a/snark/src/r1cs.rs b/snark/src/r1cs.rs index be7f041e0..e5ecb4021 100644 --- a/snark/src/r1cs.rs +++ b/snark/src/r1cs.rs @@ -1,51 +1,82 @@ -use crate::SNARK; +use crate::{CircuitSpecificSetupSNARK, IndexingError, UniversalSetupSNARK, SNARK}; use ark_ff::Field; -use ark_relations::r1cs::{ConstraintMatrices, ConstraintSynthesizer, Instance, Witness, R1CS}; +use ark_relations::r1cs::{ + ConstraintGenerator, ConstraintMatrices, Instance, InstanceGenerator, Witness, + WitnessGenerator, R1CS, +}; use ark_std::rand::{CryptoRng, RngCore}; /// A [`SNARKForR1CS`] is a [`SNARK`] for the [`R1CS`] relation. pub trait SNARKForR1CS: SNARK> { /// Generate inputs for the SNARK indexer from [`cs`]. /// These inputs consist of the constraint matrices. - fn indexer_inputs>(cs: &CS) -> ConstraintMatrices; + fn indexer_inputs>(cs: &CG) -> ConstraintMatrices; /// Generate inputs for the SNARK prover from [`cs`]. /// These inputs consist of the instance and witness. - fn prover_inputs>(cs: &CS) -> (Instance, Witness); + fn prover_inputs>(cs: &WG) -> (Instance, Witness); /// Generate inputs for the SNARK verifier from [`cs`]. /// This input consists of the instance. - fn verifier_inputs>(cs: &CS) -> Instance; + fn verifier_inputs>(cs: &IG) -> Instance; - /// Generates a proof of satisfaction of the constraint system with inputs and witness induced by [`cs`]. - fn prove_with_cs, Rng: RngCore + CryptoRng>( + /// Indexes the public parameters according to the circuit `circuit`, and + /// outputs circuit-specific proving and verification keys. + fn circuit_specific_setup_with_cs, Rng: RngCore + CryptoRng>( + c: &CG, + rng: &mut Rng, + ) -> Result<(Self::ProvingKey, Self::VerifyingKey), Self::Error> + where + Self: CircuitSpecificSetupSNARK>, + { + let index = Self::indexer_inputs(c); + Self::circuit_specific_setup(&index, rng) + } + + /// Indexes the public parameters according to the circuit `circuit`, and + /// outputs circuit-specific proving and verification keys. + /// + /// This is a *deterministic* method. + fn index_with_cs>( + pp: &Self::PublicParameters, + c: &CG, + ) -> Result<(Self::ProvingKey, Self::VerifyingKey), IndexingError> + where + Self: UniversalSetupSNARK>, + { + let index = Self::indexer_inputs(c); + Self::index(pp, &index) + } + + /// Generates a proof of satisfaction of the constraint system induced by [`c`]. + fn prove_with_cs, Rng: RngCore + CryptoRng>( pk: &Self::ProvingKey, - c: CS, + c: &WG, rng: &mut Rng, ) -> Result { - let (instance, witness) = Self::prover_inputs(&c); + let (instance, witness) = Self::prover_inputs(c); Self::prove(pk, &instance, &witness, rng) } /// Verify that [`proof`] is a valid proof with respect to [`vk`] and to the - /// instance induced by [`cs`]. - fn verify_with_cs>( + /// instance induced by [`c`]. + fn verify_with_cs>( vk: &Self::VerifyingKey, - cs: CS, + c: &IG, proof: &Self::Proof, ) -> Result { - let instance = Self::verifier_inputs(&cs); + let instance = Self::verifier_inputs(c); Self::verify(vk, &instance, proof) } /// Checks that [`proof`] is a valid proof of with respect to [`pvk`] and /// the instance induced by [`cs`]. - fn verify_with_cs_and_processed_vk>( + fn verify_with_cs_and_processed_vk>( pvk: &Self::ProcessedVerifyingKey, - cs: CS, + c: &IG, proof: &Self::Proof, ) -> Result { - let instance = Self::verifier_inputs(&cs); + let instance = Self::verifier_inputs(c); Self::verify_with_processed_vk(pvk, &instance, proof) } } From 741944329296151ce9279dff64de8dd7811b2285 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Wed, 21 Apr 2021 00:56:50 -0700 Subject: [PATCH 11/23] Tweaks --- relations/src/r1cs/mod.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/relations/src/r1cs/mod.rs b/relations/src/r1cs/mod.rs index 66b9e9c98..f99e8fecf 100644 --- a/relations/src/r1cs/mod.rs +++ b/relations/src/r1cs/mod.rs @@ -142,9 +142,8 @@ pub use tracing::info_span; pub use ark_ff::{Field, ToConstraintField}; pub use constraint_system::{ - ConstraintGenerator, InstanceGenerator, WitnessGenerator, - ConstraintSystem, ConstraintSystemRef, Namespace, OptimizationGoal, - SynthesisMode, + ConstraintGenerator, ConstraintSystem, ConstraintSystemRef, InstanceGenerator, Namespace, + OptimizationGoal, SynthesisMode, WitnessGenerator, }; pub use error::SynthesisError; /// A result type specialized to `SynthesisError`. From 33b72cbc390eb393071d61e7e0854487e1d059a6 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Thu, 22 Apr 2021 16:19:56 -0700 Subject: [PATCH 12/23] Tweak --- snark/src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/snark/src/lib.rs b/snark/src/lib.rs index 378a4f77d..502f00d4b 100644 --- a/snark/src/lib.rs +++ b/snark/src/lib.rs @@ -97,6 +97,10 @@ pub trait UniversalSetupSNARK: SNARK { /// Specifies how to bound the size of public parameters required to /// generate the index proving and verification keys for a given /// circuit. + /// + /// For example, for SNARKs that rely on polynomial commitments, this would + /// be the maximum degree of polynomials required to prove a given + /// instance. type IndexBound: Clone + Default + Debug; /// Specifies the type of universal public parameters. type PublicParameters: Clone + Debug; From c751061036e0c1aec403b92f6d7f47d73dabb31e Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Thu, 22 Apr 2021 16:22:30 -0700 Subject: [PATCH 13/23] Add CHANGELOG entry --- CHANGELOG.md | 4 ++++ snark/src/lib.rs | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea39951aa..783ce96cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ## Pending ### Breaking changes +- [\#348](https://github.com/arkworks-rs/snark/pull/334) Introduce a `Relation` trait, change the `SNARK` traits to use it, and break down `ConstraintSynthesizer` into three traits. ### Features - [\#347](https://github.com/arkworks-rs/snark/pull/347) Add `into_inner` function for `ConstraintSystemRef`. @@ -10,6 +11,7 @@ ### Bug fixes + ## v0.2.0 ### Breaking changes @@ -23,6 +25,8 @@ ### Bug fixes - [\#340](https://github.com/arkworks-rs/snark/pull/340) Compile with `panic='abort'` in release mode, for safety of the library across FFI boundaries. + + ## v0.1.0 This tag corresponds to the old `zexe` codebase. diff --git a/snark/src/lib.rs b/snark/src/lib.rs index 502f00d4b..96c6698ea 100644 --- a/snark/src/lib.rs +++ b/snark/src/lib.rs @@ -97,7 +97,7 @@ pub trait UniversalSetupSNARK: SNARK { /// Specifies how to bound the size of public parameters required to /// generate the index proving and verification keys for a given /// circuit. - /// + /// /// For example, for SNARKs that rely on polynomial commitments, this would /// be the maximum degree of polynomials required to prove a given /// instance. From cbff2c44df93c704ffbad82436cca7c960398aef Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Fri, 23 Apr 2021 10:02:06 -0700 Subject: [PATCH 14/23] Tweaks --- snark/src/lib.rs | 1 + snark/src/r1cs.rs | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/snark/src/lib.rs b/snark/src/lib.rs index 96c6698ea..36a7641c9 100644 --- a/snark/src/lib.rs +++ b/snark/src/lib.rs @@ -42,6 +42,7 @@ pub trait SNARK { /// as R1CS constraints). fn prove( pk: &Self::ProvingKey, + index: &Option, instance: &R::Instance, witness: &R::Witness, rng: &mut Rng, diff --git a/snark/src/r1cs.rs b/snark/src/r1cs.rs index e5ecb4021..9bbb6f3f2 100644 --- a/snark/src/r1cs.rs +++ b/snark/src/r1cs.rs @@ -8,13 +8,21 @@ use ark_std::rand::{CryptoRng, RngCore}; /// A [`SNARKForR1CS`] is a [`SNARK`] for the [`R1CS`] relation. pub trait SNARKForR1CS: SNARK> { + /// Does the proving algorithm explicitly require the matrices, or is it stored + /// in the proving key? + const PROVING_REQUIRES_MATRICES: bool; + /// Generate inputs for the SNARK indexer from [`cs`]. /// These inputs consist of the constraint matrices. fn indexer_inputs>(cs: &CG) -> ConstraintMatrices; /// Generate inputs for the SNARK prover from [`cs`]. - /// These inputs consist of the instance and witness. - fn prover_inputs>(cs: &WG) -> (Instance, Witness); + /// These inputs consist of the instance and witness. Additionally, + /// if `Self::PROVING_REQUIRES_MATRICES == true`, then this method returns + /// `Some(index)` as well. + fn prover_inputs>( + cs: &WG, + ) -> (Option>, Instance, Witness); /// Generate inputs for the SNARK verifier from [`cs`]. /// This input consists of the instance. @@ -54,8 +62,8 @@ pub trait SNARKForR1CS: SNARK> { c: &WG, rng: &mut Rng, ) -> Result { - let (instance, witness) = Self::prover_inputs(c); - Self::prove(pk, &instance, &witness, rng) + let (index, instance, witness) = Self::prover_inputs(c); + Self::prove(pk, &index, &instance, &witness, rng) } /// Verify that [`proof`] is a valid proof with respect to [`vk`] and to the From 4f7fea55dcabe701419e85ede0242564cd1abb10 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Fri, 23 Apr 2021 10:20:04 -0700 Subject: [PATCH 15/23] Tweaks --- relations/src/r1cs/constraint_system.rs | 24 +++++++++++++++++++++++- snark/src/r1cs.rs | 18 ++++++++++-------- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/relations/src/r1cs/constraint_system.rs b/relations/src/r1cs/constraint_system.rs index 364f6bbb9..41319b4ee 100644 --- a/relations/src/r1cs/constraint_system.rs +++ b/relations/src/r1cs/constraint_system.rs @@ -1,6 +1,8 @@ #[cfg(feature = "std")] use crate::r1cs::ConstraintTrace; -use crate::r1cs::{ConstraintMatrices, LcIndex, LinearCombination, SynthesisError, Variable}; +use crate::r1cs::{ + ConstraintMatrices, Instance, LcIndex, LinearCombination, SynthesisError, Variable, Witness, +}; use ark_ff::Field; use ark_std::{ any::{Any, TypeId}, @@ -924,6 +926,26 @@ impl ConstraintSystemRef { self.inner().and_then(|cs| cs.borrow().to_matrices()) } + /// This step must be called after constraint generation has completed, and + /// after all symbolic LCs have been inlined into the places that they + /// are used. + #[inline] + pub fn instance_assignment(&self) -> Option> { + self.inner() + .map(|cs| cs.borrow().instance_assignment.clone()) + .map(Instance) + } + + /// This step must be called after constraint generation has completed, and + /// after all symbolic LCs have been inlined into the places that they + /// are used. + #[inline] + pub fn witness_assignment(&self) -> Option> { + self.inner() + .map(|cs| cs.borrow().witness_assignment.clone()) + .map(Witness) + } + /// If `self` is satisfied, outputs `Ok(true)`. /// If `self` is unsatisfied, outputs `Ok(false)`. /// If `self.is_in_setup_mode()` or if `self == None`, outputs `Err(())`. diff --git a/snark/src/r1cs.rs b/snark/src/r1cs.rs index 9bbb6f3f2..eec3ab00c 100644 --- a/snark/src/r1cs.rs +++ b/snark/src/r1cs.rs @@ -14,7 +14,9 @@ pub trait SNARKForR1CS: SNARK> { /// Generate inputs for the SNARK indexer from [`cs`]. /// These inputs consist of the constraint matrices. - fn indexer_inputs>(cs: &CG) -> ConstraintMatrices; + fn indexer_inputs>( + cs: &CG, + ) -> Result, Self::Error>; /// Generate inputs for the SNARK prover from [`cs`]. /// These inputs consist of the instance and witness. Additionally, @@ -22,11 +24,11 @@ pub trait SNARKForR1CS: SNARK> { /// `Some(index)` as well. fn prover_inputs>( cs: &WG, - ) -> (Option>, Instance, Witness); + ) -> Result<(Option>, Instance, Witness), Self::Error>; /// Generate inputs for the SNARK verifier from [`cs`]. /// This input consists of the instance. - fn verifier_inputs>(cs: &IG) -> Instance; + fn verifier_inputs>(cs: &IG) -> Result, Self::Error>; /// Indexes the public parameters according to the circuit `circuit`, and /// outputs circuit-specific proving and verification keys. @@ -37,7 +39,7 @@ pub trait SNARKForR1CS: SNARK> { where Self: CircuitSpecificSetupSNARK>, { - let index = Self::indexer_inputs(c); + let index = Self::indexer_inputs(c)?; Self::circuit_specific_setup(&index, rng) } @@ -52,7 +54,7 @@ pub trait SNARKForR1CS: SNARK> { where Self: UniversalSetupSNARK>, { - let index = Self::indexer_inputs(c); + let index = Self::indexer_inputs(c).map_err(IndexingError::Other)?; Self::index(pp, &index) } @@ -62,7 +64,7 @@ pub trait SNARKForR1CS: SNARK> { c: &WG, rng: &mut Rng, ) -> Result { - let (index, instance, witness) = Self::prover_inputs(c); + let (index, instance, witness) = Self::prover_inputs(c)?; Self::prove(pk, &index, &instance, &witness, rng) } @@ -73,7 +75,7 @@ pub trait SNARKForR1CS: SNARK> { c: &IG, proof: &Self::Proof, ) -> Result { - let instance = Self::verifier_inputs(c); + let instance = Self::verifier_inputs(c)?; Self::verify(vk, &instance, proof) } @@ -84,7 +86,7 @@ pub trait SNARKForR1CS: SNARK> { c: &IG, proof: &Self::Proof, ) -> Result { - let instance = Self::verifier_inputs(c); + let instance = Self::verifier_inputs(c)?; Self::verify_with_processed_vk(pvk, &instance, proof) } } From afdb17afb2a235b795febd1f76abd3898444f981 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Fri, 23 Apr 2021 10:42:22 -0700 Subject: [PATCH 16/23] Work --- relations/src/r1cs/constraint_system.rs | 52 +++++++++++++++++-------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/relations/src/r1cs/constraint_system.rs b/relations/src/r1cs/constraint_system.rs index 41319b4ee..e35a3b0d4 100644 --- a/relations/src/r1cs/constraint_system.rs +++ b/relations/src/r1cs/constraint_system.rs @@ -44,9 +44,11 @@ pub trait WitnessGenerator: InstanceGenerator { #[derive(Debug, Clone)] pub struct ConstraintSystem { /// The mode in which the constraint system is operating. `self` can either - /// be in setup mode (i.e., `self.mode == SynthesisMode::Setup`) or in - /// proving mode (i.e., `self.mode == SynthesisMode::Prove`). If we are - /// in proving mode, then we have the additional option of whether or + /// be in setup mode (`self.mode == SynthesisMode::Setup`), in + /// proving mode (`self.mode == SynthesisMode::Prove`), or in verifying mode + /// (`self.mode == SynthesisMode::Verify`). + /// + /// If we are in proving mode, then we have the additional option of whether or /// not to construct the A, B, and C matrices of the constraint system /// (see below). pub mode: SynthesisMode, @@ -99,7 +101,7 @@ pub enum SynthesisMode { /// Indicate to the `ConstraintSystem` that it should only generate /// constraint matrices and not populate the variable assignments. Setup, - /// Indicate to the `ConstraintSystem` that it populate the variable + /// Indicate to the `ConstraintSystem` that it should populate the witnessvariable /// assignments. If additionally `construct_matrices == true`, then generate /// the matrices as in the `Setup` case. Prove { @@ -107,6 +109,9 @@ pub enum SynthesisMode { /// the matrices as in the `Setup` case. construct_matrices: bool, }, + /// Indicate to the `ConstraintSystem` that it populate the instance variable + /// assignments. + Verify, } /// Defines the parameter to optimize for a `ConstraintSystem`. @@ -181,6 +186,11 @@ impl ConstraintSystem { self.mode == SynthesisMode::Setup } + /// Check whether `self.mode == SynthesisMode::Verify`. + pub fn is_in_verify_mode(&self) -> bool { + self.mode == SynthesisMode::Verify + } + /// Check whether this constraint system aims to optimize weight, /// number of constraints, or neither. pub fn optimization_goal(&self) -> OptimizationGoal { @@ -204,6 +214,7 @@ impl ConstraintSystem { match self.mode { SynthesisMode::Setup => true, SynthesisMode::Prove { construct_matrices } => construct_matrices, + SynthesisMode::Verify => false, } } @@ -230,6 +241,8 @@ impl ConstraintSystem { let index = self.num_instance_variables; self.num_instance_variables += 1; + // Only generate instance variable assignments when `self.mode` is either + // `SynthesisMode::Prove` or `SynthesisMode::Verify`. if !self.is_in_setup_mode() { self.instance_assignment.push(f()?); } @@ -245,7 +258,7 @@ impl ConstraintSystem { let index = self.num_witness_variables; self.num_witness_variables += 1; - if !self.is_in_setup_mode() { + if !(self.is_in_setup_mode() || self.is_in_verify_mode()) { self.witness_assignment.push(f()?); } Ok(Variable::Witness(index)) @@ -278,13 +291,14 @@ impl ConstraintSystem { self.a_constraints.push(a_index); self.b_constraints.push(b_index); self.c_constraints.push(c_index); + #[cfg(feature = "std")] + { + let trace = ConstraintTrace::capture(); + self.constraint_traces.push(trace); + } } self.num_constraints += 1; - #[cfg(feature = "std")] - { - let trace = ConstraintTrace::capture(); - self.constraint_traces.push(trace); - } + Ok(()) } @@ -538,10 +552,7 @@ impl ConstraintSystem { /// after all symbolic LCs have been inlined into the places that they /// are used. pub fn to_matrices(&self) -> Option> { - if let SynthesisMode::Prove { - construct_matrices: false, - } = self.mode - { + if !self.should_construct_matrices() { None } else { let a: Vec<_> = self @@ -601,7 +612,7 @@ impl ConstraintSystem { /// the first unsatisfied constraint. If `self.is_in_setup_mode()`, outputs /// `Err(())`. pub fn which_is_unsatisfied(&self) -> crate::r1cs::Result> { - if self.is_in_setup_mode() { + if self.is_in_setup_mode() || self.is_in_verify_mode() { Err(SynthesisError::AssignmentMissing) } else { for i in 0..self.num_constraints { @@ -753,7 +764,7 @@ impl ConstraintSystemRef { /// Consumes self to return the inner `ConstraintSystem`. Returns /// `None` if `Self::CS` is `None` or if any other references to - /// `Self::CS` exist. + /// `Self::CS` exist. pub fn into_inner(self) -> Option> { match self { Self::CS(a) => Rc::try_unwrap(a).ok().map(|s| s.into_inner()), @@ -791,6 +802,13 @@ impl ConstraintSystemRef { .map_or(false, |cs| cs.borrow().is_in_setup_mode()) } + /// Check whether `self.mode == SynthesisMode::Verify`. + #[inline] + pub fn is_in_verify_mode(&self) -> bool { + self.inner() + .map_or(false, |cs| cs.borrow().is_in_verify_mode()) + } + /// Returns the number of constraints. #[inline] pub fn num_constraints(&self) -> usize { @@ -864,7 +882,7 @@ impl ConstraintSystemRef { self.inner() .ok_or(SynthesisError::MissingCS) .and_then(|cs| { - if !self.is_in_setup_mode() { + if !(self.is_in_setup_mode() || self.is_in_verify_mode()) { // This is needed to avoid double-borrows, because `f` // might itself mutably borrow `cs` (eg: `f = || g.value()`). let value = f(); From ce62440cbb6f0c70026a36b8d5d114e06314dbf2 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Fri, 23 Apr 2021 10:45:45 -0700 Subject: [PATCH 17/23] Work --- relations/src/r1cs/constraint_system.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/relations/src/r1cs/constraint_system.rs b/relations/src/r1cs/constraint_system.rs index e35a3b0d4..53bf7bae0 100644 --- a/relations/src/r1cs/constraint_system.rs +++ b/relations/src/r1cs/constraint_system.rs @@ -298,7 +298,7 @@ impl ConstraintSystem { } } self.num_constraints += 1; - + Ok(()) } @@ -541,11 +541,15 @@ impl ConstraintSystem { /// Optimize the constraint system (either by outlining or inlining, /// if an optimization goal is set). pub fn optimize(&mut self) { - match self.optimization_goal { - OptimizationGoal::None => self.inline_all_lcs(), - OptimizationGoal::Constraints => self.inline_all_lcs(), - OptimizationGoal::Weight => self.outline_lcs(), - }; + // In verify mode we don't have any linear combinations; all variables + // are instance variables, and there are no generated constraints + if !self.is_in_verify_mode() { + match self.optimization_goal { + OptimizationGoal::None => self.inline_all_lcs(), + OptimizationGoal::Constraints => self.inline_all_lcs(), + OptimizationGoal::Weight => self.outline_lcs(), + }; + } } /// This step must be called after constraint generation has completed, and From 11cee0f818b77aa3f160f87342957538598f1ceb Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Fri, 23 Apr 2021 13:44:47 -0700 Subject: [PATCH 18/23] Simplify `*Generator` --- relations/src/r1cs/constraint_system.rs | 23 +++++++++-------------- relations/src/r1cs/mod.rs | 4 ++-- snark/src/r1cs.rs | 23 ++++++++++------------- 3 files changed, 21 insertions(+), 29 deletions(-) diff --git a/relations/src/r1cs/constraint_system.rs b/relations/src/r1cs/constraint_system.rs index 53bf7bae0..69fad2435 100644 --- a/relations/src/r1cs/constraint_system.rs +++ b/relations/src/r1cs/constraint_system.rs @@ -18,23 +18,18 @@ use ark_std::{ /// Describes how to generate an R1CS index for a given high-level computation. pub trait ConstraintGenerator { - /// Generates R1CS constraint matrices by modifying [`cs`] in place. - /// The result is stored in [`cs`]. - fn make_constraints(&self, cs: ConstraintSystemRef) -> crate::r1cs::Result<()>; -} + /// Generates R1CS constraint matrices, and, optionally, the variable assignments + /// by modifying [`cs`] in place. The result is stored in [`cs`]. + /// + /// Variable assignments are generated if `!cs.is_in_setup_mode()`. + fn generate_constraints_and_variable_assignments( + &self, + cs: ConstraintSystemRef, + ) -> crate::r1cs::Result<()>; -/// Describes how to generate an R1CS instance for a given high-level computation. -pub trait InstanceGenerator: ConstraintGenerator { /// Generates an R1CS instance assignment by modifying [`cs`] in place. /// The result is stored in [`cs`]. - fn make_instance(&self, cs: ConstraintSystemRef) -> crate::r1cs::Result<()>; -} - -/// Describes how to generate an R1CS witness for a given high-level computation. -pub trait WitnessGenerator: InstanceGenerator { - /// Generates an R1CS witness assignment by modifying [`cs`] in place. - /// The result is stored in [`cs`]. - fn make_witness(&self, cs: ConstraintSystemRef) -> crate::r1cs::Result<()>; + fn generate_instance_assignment(&self, cs: ConstraintSystemRef) -> crate::r1cs::Result<()>; } /// An Rank-One `ConstraintSystem`. Enforces constraints of the form diff --git a/relations/src/r1cs/mod.rs b/relations/src/r1cs/mod.rs index f99e8fecf..19feaf8d6 100644 --- a/relations/src/r1cs/mod.rs +++ b/relations/src/r1cs/mod.rs @@ -142,8 +142,8 @@ pub use tracing::info_span; pub use ark_ff::{Field, ToConstraintField}; pub use constraint_system::{ - ConstraintGenerator, ConstraintSystem, ConstraintSystemRef, InstanceGenerator, Namespace, - OptimizationGoal, SynthesisMode, WitnessGenerator, + ConstraintGenerator, ConstraintSystem, ConstraintSystemRef, Namespace, OptimizationGoal, + SynthesisMode, }; pub use error::SynthesisError; /// A result type specialized to `SynthesisError`. diff --git a/snark/src/r1cs.rs b/snark/src/r1cs.rs index eec3ab00c..b690837f0 100644 --- a/snark/src/r1cs.rs +++ b/snark/src/r1cs.rs @@ -1,9 +1,6 @@ use crate::{CircuitSpecificSetupSNARK, IndexingError, UniversalSetupSNARK, SNARK}; use ark_ff::Field; -use ark_relations::r1cs::{ - ConstraintGenerator, ConstraintMatrices, Instance, InstanceGenerator, Witness, - WitnessGenerator, R1CS, -}; +use ark_relations::r1cs::{ConstraintGenerator, ConstraintMatrices, Instance, Witness, R1CS}; use ark_std::rand::{CryptoRng, RngCore}; /// A [`SNARKForR1CS`] is a [`SNARK`] for the [`R1CS`] relation. @@ -22,13 +19,13 @@ pub trait SNARKForR1CS: SNARK> { /// These inputs consist of the instance and witness. Additionally, /// if `Self::PROVING_REQUIRES_MATRICES == true`, then this method returns /// `Some(index)` as well. - fn prover_inputs>( - cs: &WG, + fn prover_inputs>( + cs: &CG, ) -> Result<(Option>, Instance, Witness), Self::Error>; /// Generate inputs for the SNARK verifier from [`cs`]. /// This input consists of the instance. - fn verifier_inputs>(cs: &IG) -> Result, Self::Error>; + fn verifier_inputs>(cs: &CG) -> Result, Self::Error>; /// Indexes the public parameters according to the circuit `circuit`, and /// outputs circuit-specific proving and verification keys. @@ -59,9 +56,9 @@ pub trait SNARKForR1CS: SNARK> { } /// Generates a proof of satisfaction of the constraint system induced by [`c`]. - fn prove_with_cs, Rng: RngCore + CryptoRng>( + fn prove_with_cs, Rng: RngCore + CryptoRng>( pk: &Self::ProvingKey, - c: &WG, + c: &CG, rng: &mut Rng, ) -> Result { let (index, instance, witness) = Self::prover_inputs(c)?; @@ -70,9 +67,9 @@ pub trait SNARKForR1CS: SNARK> { /// Verify that [`proof`] is a valid proof with respect to [`vk`] and to the /// instance induced by [`c`]. - fn verify_with_cs>( + fn verify_with_cs>( vk: &Self::VerifyingKey, - c: &IG, + c: &CG, proof: &Self::Proof, ) -> Result { let instance = Self::verifier_inputs(c)?; @@ -81,9 +78,9 @@ pub trait SNARKForR1CS: SNARK> { /// Checks that [`proof`] is a valid proof of with respect to [`pvk`] and /// the instance induced by [`cs`]. - fn verify_with_cs_and_processed_vk>( + fn verify_with_cs_and_processed_vk>( pvk: &Self::ProcessedVerifyingKey, - c: &IG, + c: &CG, proof: &Self::Proof, ) -> Result { let instance = Self::verifier_inputs(c)?; From 03cea28b9f0507471dbc258abb313ba9d8c1457a Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Fri, 23 Apr 2021 16:22:01 -0700 Subject: [PATCH 19/23] Tweaks --- relations/src/r1cs/constraint_system.rs | 12 ++++++--- relations/src/r1cs/mod.rs | 34 ++++++------------------- 2 files changed, 17 insertions(+), 29 deletions(-) diff --git a/relations/src/r1cs/constraint_system.rs b/relations/src/r1cs/constraint_system.rs index 69fad2435..7aefbe6fa 100644 --- a/relations/src/r1cs/constraint_system.rs +++ b/relations/src/r1cs/constraint_system.rs @@ -64,10 +64,10 @@ pub struct ConstraintSystem { /// Assignments to the public input variables. This is empty if `self.mode /// == SynthesisMode::Setup`. - pub instance_assignment: Vec, + instance_assignment: Vec, /// Assignments to the private input variables. This is empty if `self.mode /// == SynthesisMode::Setup`. - pub witness_assignment: Vec, + witness_assignment: Vec, /// Map for gadgets to cache computation results. pub cache_map: Rc>>>, @@ -949,7 +949,13 @@ impl ConstraintSystemRef { #[inline] pub fn instance_assignment(&self) -> Option> { self.inner() - .map(|cs| cs.borrow().instance_assignment.clone()) + .map(|cs| { + // Drop the leading 1 before returning the assignment. + let mut inst = cs.borrow().instance_assignment.clone(); + inst.remove(0); + assert_eq!(inst.len(), cs.borrow().num_instance_variables - 1); + inst + }) .map(Instance) } diff --git a/relations/src/r1cs/mod.rs b/relations/src/r1cs/mod.rs index 19feaf8d6..75e1a74b0 100644 --- a/relations/src/r1cs/mod.rs +++ b/relations/src/r1cs/mod.rs @@ -7,7 +7,7 @@ use ark_std::{cmp::Ordering, marker::PhantomData, vec::Vec}; /// R1CS is an *indexed NP relation*. /// An index consists of three matrices (A, B, C), /// while the instance *x* and witness *w* are vectors of field elements -/// such that, for z := (x||w), Az ○ Bz = Cz +/// such that, for z := (1|| x || w), Az ○ Bz = Cz. pub struct R1CS { f: PhantomData, } @@ -17,7 +17,7 @@ pub struct R1CS { #[derive(Debug, Clone, PartialEq, Eq)] pub struct ConstraintMatrices { /// The number of variables that are "public instances" to the constraint - /// system. + /// system. This includes the one variable. pub num_instance_variables: usize, /// The number of variables that are "private witnesses" to the constraint /// system. @@ -40,7 +40,6 @@ pub struct ConstraintMatrices { } /// An R1CS instance consists of variable assignments to the instance variables. -/// The first variable must be assigned a value of `F::one()`. #[derive(Eq, PartialEq, Debug, Hash, Clone)] pub struct Instance(pub Vec); @@ -60,18 +59,16 @@ impl NPRelation for R1CS { instance: &Self::Instance, witness: &Self::Witness, ) -> bool { + let mut instance = instance.0.to_vec(); + instance.insert(0, F::one()); // The number of instance variables does not match. - if instance.0.len() != index.num_instance_variables { + if instance.len() != index.num_instance_variables { return false; } // The number of witness variables does not match. if witness.0.len() != index.num_witness_variables { return false; } - // The first instance variable must be 1. - if instance.0[0] != F::one() { - return false; - } // Let z = instance || witness. Check that Az ○ Bz = Cz, where ○ is the Hadamard product. // The Hadamard product of two vectors is the product of them entry-wise, so @@ -82,24 +79,9 @@ impl NPRelation for R1CS { .zip(&index.b) .zip(&index.c) .all(|((a_row, b_row), c_row)| { - let a = inner_product( - &a_row, - index.num_instance_variables, - &instance.0, - &witness.0, - ); - let b = inner_product( - &b_row, - index.num_instance_variables, - &instance.0, - &witness.0, - ); - let c = inner_product( - &c_row, - index.num_instance_variables, - &instance.0, - &witness.0, - ); + let a = inner_product(&a_row, index.num_instance_variables, &instance, &witness.0); + let b = inner_product(&b_row, index.num_instance_variables, &instance, &witness.0); + let c = inner_product(&c_row, index.num_instance_variables, &instance, &witness.0); a * b == c }) } From 193bb5ef2c0d3aa3125201439ee43d5fc1887284 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Fri, 23 Apr 2021 16:28:32 -0700 Subject: [PATCH 20/23] Work --- relations/src/r1cs/constraint_system.rs | 4 ++-- relations/src/r1cs/mod.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/relations/src/r1cs/constraint_system.rs b/relations/src/r1cs/constraint_system.rs index 7aefbe6fa..d4e7c8395 100644 --- a/relations/src/r1cs/constraint_system.rs +++ b/relations/src/r1cs/constraint_system.rs @@ -48,8 +48,8 @@ pub struct ConstraintSystem { /// (see below). pub mode: SynthesisMode, /// The number of variables that are "public inputs" to the constraint - /// system. - pub num_instance_variables: usize, + /// system. This includes the 1 variable. + num_instance_variables: usize, /// The number of variables that are "private inputs" to the constraint /// system. pub num_witness_variables: usize, diff --git a/relations/src/r1cs/mod.rs b/relations/src/r1cs/mod.rs index 75e1a74b0..83122be61 100644 --- a/relations/src/r1cs/mod.rs +++ b/relations/src/r1cs/mod.rs @@ -17,7 +17,7 @@ pub struct R1CS { #[derive(Debug, Clone, PartialEq, Eq)] pub struct ConstraintMatrices { /// The number of variables that are "public instances" to the constraint - /// system. This includes the one variable. + /// system. This *does not* include the one variable. pub num_instance_variables: usize, /// The number of variables that are "private witnesses" to the constraint /// system. @@ -62,7 +62,7 @@ impl NPRelation for R1CS { let mut instance = instance.0.to_vec(); instance.insert(0, F::one()); // The number of instance variables does not match. - if instance.len() != index.num_instance_variables { + if instance.len() != index.num_instance_variables + 1 { return false; } // The number of witness variables does not match. From fdfcfcf80961d3036bca7723ae1f45d7664389c4 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Fri, 23 Apr 2021 16:31:02 -0700 Subject: [PATCH 21/23] Tweak --- relations/src/r1cs/mod.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/relations/src/r1cs/mod.rs b/relations/src/r1cs/mod.rs index 83122be61..8b6edfd2f 100644 --- a/relations/src/r1cs/mod.rs +++ b/relations/src/r1cs/mod.rs @@ -7,17 +7,18 @@ use ark_std::{cmp::Ordering, marker::PhantomData, vec::Vec}; /// R1CS is an *indexed NP relation*. /// An index consists of three matrices (A, B, C), /// while the instance *x* and witness *w* are vectors of field elements -/// such that, for z := (1|| x || w), Az ○ Bz = Cz. +/// such that, for z := (1 || x || w), Az ○ Bz = Cz. pub struct R1CS { f: PhantomData, } /// An R1CS index consists of three matrices, as well as the number of instance variables -/// and number of witness variables. +/// and number of witness variables. The "one" variable is treated as a defacto instance +/// variable for the purposes of counting. #[derive(Debug, Clone, PartialEq, Eq)] pub struct ConstraintMatrices { /// The number of variables that are "public instances" to the constraint - /// system. This *does not* include the one variable. + /// system. This includes the one variable. pub num_instance_variables: usize, /// The number of variables that are "private witnesses" to the constraint /// system. From 8ae8b8a3cc296b3e4d597f8c4e62848aafe80ed4 Mon Sep 17 00:00:00 2001 From: Weikeng Chen Date: Tue, 18 May 2021 21:59:41 -0700 Subject: [PATCH 22/23] Update lib.rs --- relations/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/relations/src/lib.rs b/relations/src/lib.rs index 6177a081f..ca57b78f2 100644 --- a/relations/src/lib.rs +++ b/relations/src/lib.rs @@ -25,7 +25,7 @@ pub trait Relation { type Index: Eq; /// The instance is a "small" part of the triple. Like the index, it is publicly known. type Instance: Eq; - /// The instance is a "large" but private part of the triple. + /// The witness is a "large" but private part of the triple. type Witness: Eq; } From 283ac530f8f94b5db332722039255e6144777f75 Mon Sep 17 00:00:00 2001 From: Weikeng Chen Date: Tue, 18 May 2021 22:01:40 -0700 Subject: [PATCH 23/23] Update constraint_system.rs --- relations/src/r1cs/constraint_system.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/relations/src/r1cs/constraint_system.rs b/relations/src/r1cs/constraint_system.rs index d4e7c8395..b5fb3f998 100644 --- a/relations/src/r1cs/constraint_system.rs +++ b/relations/src/r1cs/constraint_system.rs @@ -96,7 +96,7 @@ pub enum SynthesisMode { /// Indicate to the `ConstraintSystem` that it should only generate /// constraint matrices and not populate the variable assignments. Setup, - /// Indicate to the `ConstraintSystem` that it should populate the witnessvariable + /// Indicate to the `ConstraintSystem` that it should populate the witness variable /// assignments. If additionally `construct_matrices == true`, then generate /// the matrices as in the `Setup` case. Prove {