arnaucube
arnaucube/ark-r1cs-stdPublic Self-hosted repository
Document `r1cs-std`
Pratyush Mishra pratyushmishra@berkeley.edu
Thu, 10 Sep 2020 01:16:01 -0700
commit

370fbcdd3b87ef46a726b0c25c78d7e50c318015

parent

c21d0b279689f13adb40ce01900221cf8470535b

61 files changed, 691 insertions(+), 211 deletions(-)

jump to
M r1cs-std/src/alloc.rs → r1cs-std/src/alloc.rs

@@ -3,15 +3,26 @@ use algebra::Field;

use core::borrow::Borrow; use r1cs_core::{Namespace, SynthesisError}; +/// Describes the mode that a variable should be allocated in within +/// a `ConstraintSystem`. #[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Copy, Clone)] pub enum AllocationMode { + /// Indicate to the `ConstraintSystem` that the high-level variable should + /// be allocated as a constant. That is, no `Variable`s should be + /// generated. Constant = 0, + + /// Indicate to the `ConstraintSystem` that the high-level variable should + /// be allocated as a public input to the `ConstraintSystem`. Input = 1, + + /// Indicate to the `ConstraintSystem` that the high-level variable should + /// be allocated as a private witness to the `ConstraintSystem`. Witness = 2, } impl AllocationMode { - // Outputs the maximum according to the relation `Constant < Input < Witness`. + /// Outputs the maximum according to the relation `Constant < Input < Witness`. pub fn max(&self, other: Self) -> Self { use AllocationMode::*; match (self, other) {

@@ -23,17 +34,21 @@ }

} } +/// Specifies how variables of type `Self` should be allocated in a `ConstraintSystem`. pub trait AllocVar<V, F: Field> where Self: Sized, V: ?Sized, { + /// Allocates a new variable of type `Self` in the `ConstraintSystem`. + /// The mode of allocation is decided by `mode`. fn new_variable<T: Borrow<V>>( cs: impl Into<Namespace<F>>, f: impl FnOnce() -> Result<T, SynthesisError>, mode: AllocationMode, ) -> Result<Self, SynthesisError>; + /// Allocates a new constant of type `Self` in the `ConstraintSystem`. #[tracing::instrument(target = "r1cs", skip(cs, t))] fn new_constant( cs: impl Into<Namespace<F>>,

@@ -42,6 +57,7 @@ ) -> Result<Self, SynthesisError> {

Self::new_variable(cs, || Ok(t), AllocationMode::Constant) } + /// Allocates a new public input of type `Self` in the `ConstraintSystem`. #[tracing::instrument(target = "r1cs", skip(cs, f))] fn new_input<T: Borrow<V>>( cs: impl Into<Namespace<F>>,

@@ -50,6 +66,7 @@ ) -> Result<Self, SynthesisError> {

Self::new_variable(cs, f, AllocationMode::Input) } + /// Allocates a new private witness of type `Self` in the `ConstraintSystem`. #[tracing::instrument(target = "r1cs", skip(cs, f))] fn new_witness<T: Borrow<V>>( cs: impl Into<Namespace<F>>,
M r1cs-std/src/bits/boolean.rs → r1cs-std/src/bits/boolean.rs

@@ -254,6 +254,10 @@

/// Returns the constrant `false`. pub const FALSE: Self = Boolean::Constant(false); + /// Constructs a `LinearCombination` from `Self`'s variables. + /// + /// * `Boolean::Is(v) => lc!() + v.variable()` + /// * `Boolean::Not(v) => lc!() + Variable::One - v.variable()` pub fn lc(&self) -> LinearCombination<F> { match self { Boolean::Constant(false) => lc!(),

@@ -263,7 +267,9 @@ Boolean::Not(v) => lc!() + Variable::One - v.variable(),

} } - /// Construct a boolean vector from a vector of u8 + /// Constructs a `Boolean` vector from a slice of constant `u8`. + /// + /// This *does not* create any new variables. pub fn constant_vec_from_bytes(values: &[u8]) -> Vec<Self> { let mut input_bits = vec![]; for input_byte in values {

@@ -274,12 +280,12 @@ }

input_bits } - /// Construct a boolean from a known constant + /// Constructs a constant `Boolean` with value `b`. pub fn constant(b: bool) -> Self { Boolean::Constant(b) } - /// Return a negated interpretation of this boolean. + /// Negates `self`. pub fn not(&self) -> Self { match *self { Boolean::Constant(c) => Boolean::Constant(!c),

@@ -290,11 +296,14 @@ }

} impl<F: Field> Boolean<F> { - /// Perform XOR over two boolean operands + /// Outputs `self ^ other`. + /// + /// If at least one of `self` and `other` are constants, then this method + /// *does not* create any constraints or variables. #[tracing::instrument(target = "r1cs")] - pub fn xor<'a>(&'a self, b: &'a Self) -> Result<Self, SynthesisError> { + pub fn xor<'a>(&'a self, other: &'a Self) -> Result<Self, SynthesisError> { use Boolean::*; - match (self, b) { + match (self, other) { (&Constant(false), x) | (x, &Constant(false)) => Ok(x.clone()), (&Constant(true), x) | (x, &Constant(true)) => Ok(x.not()), // a XOR (NOT b) = NOT(a XOR b)

@@ -306,11 +315,14 @@ (&Is(ref a), &Is(ref b)) | (&Not(ref a), &Not(ref b)) => Ok(Is(a.xor(b)?)),

} } - /// Perform OR over two boolean operands + /// Outputs `self | other`. + /// + /// If at least one of `self` and `other` are constants, then this method + /// *does not* create any constraints or variables. #[tracing::instrument(target = "r1cs")] - pub fn or<'a>(&'a self, b: &'a Self) -> Result<Self, SynthesisError> { + pub fn or<'a>(&'a self, other: &'a Self) -> Result<Self, SynthesisError> { use Boolean::*; - match (self, b) { + match (self, other) { (&Constant(false), x) | (x, &Constant(false)) => Ok(x.clone()), (&Constant(true), _) | (_, &Constant(true)) => Ok(Constant(true)), // a OR b = NOT ((NOT a) AND b)

@@ -321,11 +333,14 @@ (&Is(ref a), &Is(ref b)) => a.or(b).map(From::from),

} } - /// Perform AND over two boolean operands + /// Outputs `self & other`. + /// + /// If at least one of `self` and `other` are constants, then this method + /// *does not* create any constraints or variables. #[tracing::instrument(target = "r1cs")] - pub fn and<'a>(&'a self, b: &'a Self) -> Result<Self, SynthesisError> { + pub fn and<'a>(&'a self, other: &'a Self) -> Result<Self, SynthesisError> { use Boolean::*; - match (self, b) { + match (self, other) { // false AND x is always false (&Constant(false), _) | (_, &Constant(false)) => Ok(Constant(false)), // true AND x is always x

@@ -339,6 +354,7 @@ (&Is(ref a), &Is(ref b)) => Ok(Is(a.and(b)?)),

} } + /// Outputs `bits[0] & bits[1] & ... & bits.last().unwrap()`. #[tracing::instrument(target = "r1cs")] pub fn kary_and(bits: &[Self]) -> Result<Self, SynthesisError> { assert!(!bits.is_empty());

@@ -354,6 +370,7 @@

Ok(cur.expect("should not be 0")) } + /// Outputs `bits[0] | bits[1] | ... | bits.last().unwrap()`. #[tracing::instrument(target = "r1cs")] pub fn kary_or(bits: &[Self]) -> Result<Self, SynthesisError> { assert!(!bits.is_empty());

@@ -369,12 +386,15 @@

Ok(cur.expect("should not be 0")) } + /// Outputs `(bits[0] & bits[1] & ... & bits.last().unwrap()).not()`. #[tracing::instrument(target = "r1cs")] pub fn kary_nand(bits: &[Self]) -> Result<Self, SynthesisError> { Ok(Self::kary_and(bits)?.not()) } - /// Assert that at least one input is false. + /// Enforces that `Self::kary_nand(bits).is_eq(&Boolean::TRUE)`. + /// + /// Informally, this means that at least one element in `bits` must be `false`. #[tracing::instrument(target = "r1cs")] fn enforce_kary_nand(bits: &[Self]) -> Result<(), SynthesisError> { use Boolean::*;

@@ -392,7 +412,7 @@ }

/// Enforces that `bits`, when interpreted as a integer, is less than `F::characteristic()`, /// That is, interpret bits as a little-endian integer, and enforce that this integer - /// is "in the field F". + /// is "in the field Z_p", where `p = F::characteristic()` . #[tracing::instrument(target = "r1cs")] pub fn enforce_in_field_le(bits: &[Self]) -> Result<(), SynthesisError> { // `bits` < F::characteristic() <==> `bits` <= F::characteristic() -1

@@ -466,6 +486,9 @@

Ok(current_run) } + /// Conditionally selects one of `first` and `second` based on the value of `self`: + /// + /// If `self.is_eq(&Boolean::TRUE)`, this outputs `first`; else, it outputs `second`. #[tracing::instrument(target = "r1cs", skip(first, second))] pub fn select<T: CondSelectGadget<F>>( &self,
M r1cs-std/src/bits/mod.rs → r1cs-std/src/bits/mod.rs

@@ -5,15 +5,20 @@ };

use algebra::Field; use r1cs_core::SynthesisError; +/// This module contains `Boolean`, a R1CS equivalent of the `bool` type. pub mod boolean; +/// This module contains `UInt8`, a R1CS equivalent of the `u8` type. pub mod uint8; +/// This module contains a macro for generating `UIntN` types, which are R1CS equivalents of +/// `N`-bit unsigned integers. #[macro_use] pub mod uint; -make_uint!(UInt16, 16, u16, uint16); -make_uint!(UInt32, 32, u32, uint32); -make_uint!(UInt64, 64, u64, uint64); +make_uint!(UInt16, 16, u16, uint16, "16"); +make_uint!(UInt32, 32, u32, uint32, "32"); +make_uint!(UInt64, 64, u64, uint64, "64"); +/// Specifies constraints for conversion to a little-endian bit representation of `self`. pub trait ToBitsGadget<F: Field> { /// Outputs the canonical little-endian bit-wise representation of `self`. ///

@@ -70,6 +75,7 @@ self.as_slice().to_non_unique_bits_le().map(|v| v.to_vec())

} } +/// Specifies constraints for conversion to a little-endian byte representation of `self`. pub trait ToBytesGadget<F: Field> { /// Outputs a canonical, little-endian, byte decomposition of `self`. ///
M r1cs-std/src/bits/uint.rs → r1cs-std/src/bits/uint.rs

@@ -1,5 +1,10 @@

macro_rules! make_uint { - ($name:ident, $size:expr, $native:ident, $mod_name:ident) => { + ($name:ident, $size:expr, $native:ident, $mod_name:ident, $native_doc_name:expr) => { + #[doc = "This module contains a `UInt"] + #[doc = $native_doc_name] + #[doc = "`, a R1CS equivalent of the `u"] + #[doc = $native_doc_name] + #[doc = "`type."] pub mod $mod_name { use algebra::{Field, FpParameters, PrimeField}; use core::borrow::Borrow;

@@ -15,8 +20,14 @@ prelude::*,

Assignment, Vec, }; - /// Represents an interpretation of `Boolean` objects as an - /// unsigned integer. + #[doc = "This struct represent an unsigned"] + #[doc = $native_doc_name] + #[doc = "-bit integer as a sequence of "] + #[doc = $native_doc_name] + #[doc = " `Boolean`s\n"] + #[doc = "This is the R1CS equivalent of the native `u"] + #[doc = $native_doc_name] + #[doc = "` unsigned integer type."] #[derive(Clone, Debug)] pub struct $name<F: Field> { // Least significant bit first

@@ -46,7 +57,11 @@ }

} impl<F: Field> $name<F> { - /// Construct a constant `$name` from a `$native` + #[doc = "Construct a constant `UInt"] + #[doc = $native_doc_name] + #[doc = "` from the native `u"] + #[doc = $native_doc_name] + #[doc = "` type."] pub fn constant(value: $native) -> Self { let mut bits = Vec::with_capacity($size);

@@ -67,13 +82,18 @@ value: Some(value),

} } - /// Turns this `$name` into its little-endian byte order representation. + /// Turns `self` into the underlying little-endian bits. pub fn to_bits_le(&self) -> Vec<Boolean<F>> { self.bits.clone() } - /// Converts a little-endian byte order representation of bits into a - /// `$name`. + /// Construct `Self` from a slice of `Boolean`s. + /// + /// # Panics + /// + /// This method panics if `bits.len() != u + #[doc($native_doc_name)] + #[doc("`.")] pub fn from_bits_le(bits: &[Boolean<F>]) -> Self { assert_eq!(bits.len(), $size);

@@ -105,6 +125,7 @@

Self { value, bits } } + /// Rotates `self` to the right by `by` steps, wrapping around. #[tracing::instrument(target = "r1cs", skip(self))] pub fn rotr(&self, by: usize) -> Self { let by = by % $size;

@@ -126,8 +147,11 @@ .map(|v| v.rotate_right(u32::try_from(by).unwrap())),

} } - /// XOR this `$name` with another `$name` - #[tracing::instrument(target = "r1cs", skip(self))] + /// Outputs `self ^ other`. + /// + /// If at least one of `self` and `other` are constants, then this method + /// *does not* create any constraints or variables. + #[tracing::instrument(target = "r1cs", skip(self, other))] pub fn xor(&self, other: &Self) -> Result<Self, SynthesisError> { let new_value = match (self.value, other.value) { (Some(a), Some(b)) => Some(a ^ b),

@@ -147,8 +171,10 @@ value: new_value,

}) } - /// Perform modular addition of several `$name` objects. - #[tracing::instrument(target = "r1cs")] + /// Perform modular addition of `operands`. + /// + /// The user must ensure that overflow does not occur. + #[tracing::instrument(target = "r1cs", skip(operands))] pub fn addmany(operands: &[Self]) -> Result<Self, SynthesisError> where F: PrimeField,
M r1cs-std/src/bits/uint8.rs → r1cs-std/src/bits/uint8.rs

@@ -64,6 +64,7 @@ value: Some(value),

} } + /// Allocates a slice of `u8`'s as private witnesses. pub fn new_witness_vec( cs: impl Into<Namespace<F>>, values: &[impl Into<Option<u8>> + Copy],

@@ -78,10 +79,13 @@ }

Ok(output_vec) } - /// Allocates a vector of `u8`'s by first converting (chunks of) them to - /// `ConstraintF` elements, (thus reducing the number of input allocations), - /// and then converts this list of `ConstraintF` gadgets back into + /// Allocates a slice of `u8`'s as public inputs by first packing them into + /// `F` elements, (thus reducing the number of input allocations), + /// and then converts this list of `AllocatedFp<F>` variables back into /// bytes. + /// + /// From a user perspective, this trade-off adds constraints, but improves + /// verifier time and verification key size. pub fn new_input_vec( cs: impl Into<Namespace<F>>, values: &[u8],

@@ -134,7 +138,10 @@

Self { value, bits } } - /// XOR this `UInt8` with another `UInt8` + /// Outputs `self ^ other`. + /// + /// If at least one of `self` and `other` are constants, then this method + /// *does not* create any constraints or variables. #[tracing::instrument(target = "r1cs")] pub fn xor(&self, other: &Self) -> Result<Self, SynthesisError> { let new_value = match (self.value, other.value) {
M r1cs-std/src/eq.rs → r1cs-std/src/eq.rs

@@ -2,17 +2,26 @@ use crate::{prelude::*, Vec};

use algebra::Field; use r1cs_core::SynthesisError; +/// Specifies how to generate constraints that check for equality for two variables of type `Self`. pub trait EqGadget<F: Field> { /// Output a `Boolean` value representing whether `self.value() == other.value()`. fn is_eq(&self, other: &Self) -> Result<Boolean<F>, SynthesisError>; /// Output a `Boolean` value representing whether `self.value() != other.value()`. + /// + /// By default, this is defined as `self.is_eq(other)?.not()`. fn is_neq(&self, other: &Self) -> Result<Boolean<F>, SynthesisError> { Ok(self.is_eq(other)?.not()) } /// If `should_enforce == true`, enforce that `self` and `other` are equal; else, /// enforce a vacuously true statement. + /// + /// A safe default implementation is provided that generates the following constraints: + /// `self.is_eq(other)?.conditional_enforce_equal(&Boolean::TRUE, should_enforce)`. + /// + /// More efficient specialized implementation may be possible; implementors + /// are encouraged to carefully analyze the efficiency and safety of these. #[tracing::instrument(target = "r1cs", skip(self, other))] fn conditional_enforce_equal( &self,

@@ -24,13 +33,25 @@ .conditional_enforce_equal(&Boolean::constant(true), should_enforce)

} /// Enforce that `self` and `other` are equal. + /// + /// A safe default implementation is provided that generates the following constraints: + /// `self.conditional_enforce_equal(other, &Boolean::TRUE)`. + /// + /// More efficient specialized implementation may be possible; implementors + /// are encouraged to carefully analyze the efficiency and safety of these. #[tracing::instrument(target = "r1cs", skip(self, other))] fn enforce_equal(&self, other: &Self) -> Result<(), SynthesisError> { self.conditional_enforce_equal(other, &Boolean::constant(true)) } - /// If `should_enforce == true`, enforce that `self` and `other` are not equal; else, + /// If `should_enforce == true`, enforce that `self` and `other` are *not* equal; else, /// enforce a vacuously true statement. + /// + /// A safe default implementation is provided that generates the following constraints: + /// `self.is_neq(other)?.conditional_enforce_equal(&Boolean::TRUE, should_enforce)`. + /// + /// More efficient specialized implementation may be possible; implementors + /// are encouraged to carefully analyze the efficiency and safety of these. #[tracing::instrument(target = "r1cs", skip(self, other))] fn conditional_enforce_not_equal( &self,

@@ -41,7 +62,13 @@ self.is_neq(&other)?

.conditional_enforce_equal(&Boolean::constant(true), should_enforce) } - /// Enforce that `self` and `other` are not equal. + /// Enforce that `self` and `other` are *not* equal. + /// + /// A safe default implementation is provided that generates the following constraints: + /// `self.conditional_enforce_not_equal(other, &Boolean::TRUE)`. + /// + /// More efficient specialized implementation may be possible; implementors + /// are encouraged to carefully analyze the efficiency and safety of these. #[tracing::instrument(target = "r1cs", skip(self, other))] fn enforce_not_equal(&self, other: &Self) -> Result<(), SynthesisError> { self.conditional_enforce_not_equal(other, &Boolean::constant(true))
M r1cs-std/src/fields/cubic_extension.rs → r1cs-std/src/fields/cubic_extension.rs

@@ -12,6 +12,8 @@ prelude::*,

Assignment, ToConstraintFieldGadget, Vec, }; +/// This struct is the `R1CS` equivalent of the cubic extension field type +/// in `algebra-core`, i.e. `algebra_core::CubicExtField`. #[derive(Derivative)] #[derivative(Debug(bound = "BF: core::fmt::Debug"), Clone(bound = "BF: Clone"))] #[must_use]

@@ -19,18 +21,24 @@ pub struct CubicExtVar<BF: FieldVar<P::BaseField, P::BasePrimeField>, P: CubicExtVarParams<BF>>

where for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>, { + /// The zero-th coefficient of this field element. pub c0: BF, + /// The first coefficient of this field element. pub c1: BF, + /// The second coefficient of this field element. pub c2: BF, #[derivative(Debug = "ignore")] _params: PhantomData<P>, } +/// This trait describes parameters that are used to implement arithmetic for `CubicExtVar`. pub trait CubicExtVarParams<BF: FieldVar<Self::BaseField, Self::BasePrimeField>>: CubicExtParameters where for<'a> &'a BF: FieldOpsBounds<'a, Self::BaseField, BF>, { + /// Multiply the base field of the `CubicExtVar` by the appropriate Frobenius coefficient. + /// This is equivalent to `Self::mul_base_field_by_frob_coeff(c1, c2, power)`. fn mul_base_field_vars_by_frob_coeff(c1: &mut BF, c2: &mut BF, power: usize); }

@@ -38,6 +46,7 @@ impl<BF: FieldVar<P::BaseField, P::BasePrimeField>, P: CubicExtVarParams<BF>> CubicExtVar<BF, P>

where for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>, { + /// Constructs a `CubicExtVar` from the underlying coefficients. #[inline] pub fn new(c0: BF, c1: BF, c2: BF) -> Self { let _params = PhantomData;

@@ -49,13 +58,14 @@ _params,

} } - /// Multiply a BF by cubic nonresidue P::NONRESIDUE. + /// Multiplies a variable of the base field by the cubic nonresidue `P::NONRESIDUE` that + /// is used to construct the extension field. #[inline] pub fn mul_base_field_by_nonresidue(fe: &BF) -> Result<BF, SynthesisError> { Ok(fe * P::NONRESIDUE) } - /// Multiply a CubicExtVar by an element of `P::BaseField`. + /// Multiplies `self` by a constant from the base field. #[inline] pub fn mul_by_base_field_constant(&self, fe: P::BaseField) -> Self { let c0 = &self.c0 * fe;

@@ -64,6 +74,7 @@ let c2 = &self.c2 * fe;

Self::new(c0, c1, c2) } + /// Sets `self = self.mul_by_base_field_constant(fe)`. #[inline] pub fn mul_assign_by_base_field_constant(&mut self, fe: P::BaseField) { *self = (&*self).mul_by_base_field_constant(fe);
M r1cs-std/src/fields/fp/cmp.rs → r1cs-std/src/fields/fp/cmp.rs

@@ -95,7 +95,7 @@

Ok((left.clone(), right_for_check)) } - // Helper function to enforce `self <= (p-1)/2`. + /// Helper function to enforce that `self <= (p-1)/2`. #[tracing::instrument(target = "r1cs")] pub fn enforce_smaller_or_equal_than_mod_minus_one_div_two( &self,
M r1cs-std/src/fields/fp/mod.rs → r1cs-std/src/fields/fp/mod.rs

@@ -6,17 +6,23 @@

use crate::fields::{FieldOpsBounds, FieldVar}; use crate::{prelude::*, Assignment, ToConstraintFieldGadget, Vec}; -pub mod cmp; +mod cmp; +/// Represents a variable in the constraint system whose +/// value can be an arbitrary field element. #[derive(Debug, Clone)] #[must_use] pub struct AllocatedFp<F: PrimeField> { pub(crate) value: Option<F>, + /// The allocated variable corresponding to `self` in `self.cs`. pub variable: Variable, + /// The constraint system that `self` was allocated in. pub cs: ConstraintSystemRef<F>, } impl<F: PrimeField> AllocatedFp<F> { + /// Constructs a new `AllocatedFp` from a (optional) value, a low-level Variable, + /// and a `ConstraintSystemRef`. pub fn new(value: Option<F>, variable: Variable, cs: ConstraintSystemRef<F>) -> Self { Self { value,

@@ -26,11 +32,14 @@ }

} } -/// Represent variables corresponding to the field `F`. +/// Represent variables corresponding to a field element in `F`. #[derive(Clone, Debug)] #[must_use] pub enum FpVar<F: PrimeField> { + /// Represents a constant in the constraint system, which means that + /// it does not have a corresponding variable. Constant(F), + /// Represents an allocated variable constant in the constraint system. Var(AllocatedFp<F>), }

@@ -79,6 +88,7 @@ impl<'a, F: PrimeField> FieldOpsBounds<'a, F, Self> for FpVar<F> {}

impl<'a, F: PrimeField> FieldOpsBounds<'a, F, FpVar<F>> for &'a FpVar<F> {} impl<F: PrimeField> AllocatedFp<F> { + /// Constructs `Self` from a `Boolean`: if `other` is false, this outputs `zero`, else it outputs `one`. pub fn from(other: Boolean<F>) -> Self { if let Some(cs) = other.cs() { let variable = cs.new_lc(other.lc()).unwrap();

@@ -88,10 +98,15 @@ unreachable!("Cannot create a constant value")

} } + /// Returns the value assigned to `self` in the underlying constraint system + /// (if a value was assigned). pub fn value(&self) -> Result<F, SynthesisError> { self.cs.assigned_value(self.variable).get() } + /// Outputs `self + other`. + /// + /// This does not create any constraints. #[tracing::instrument(target = "r1cs")] pub fn add(&self, other: &Self) -> Self { let value = match (self.value, other.value) {

@@ -106,6 +121,9 @@ .unwrap();

AllocatedFp::new(value, variable, self.cs.clone()) } + /// Outputs `self - other`. + /// + /// This does not create any constraints. #[tracing::instrument(target = "r1cs")] pub fn sub(&self, other: &Self) -> Self { let value = match (self.value, other.value) {

@@ -120,6 +138,9 @@ .unwrap();

AllocatedFp::new(value, variable, self.cs.clone()) } + /// Outputs `self * other`. + /// + /// This requires *one* constraint. #[tracing::instrument(target = "r1cs")] pub fn mul(&self, other: &Self) -> Self { let product = AllocatedFp::new_witness(self.cs.clone(), || {

@@ -136,6 +157,9 @@ .unwrap();

product } + /// Output `self + other` + /// + /// This does not create any constraints. #[tracing::instrument(target = "r1cs")] pub fn add_constant(&self, other: F) -> Self { if other.is_zero() {

@@ -150,11 +174,17 @@ AllocatedFp::new(value, variable, self.cs.clone())

} } + /// Output `self - other` + /// + /// This does not create any constraints. #[tracing::instrument(target = "r1cs")] pub fn sub_constant(&self, other: F) -> Self { self.add_constant(-other) } + /// Output `self * other` + /// + /// This does not create any constraints. #[tracing::instrument(target = "r1cs")] pub fn mul_constant(&self, other: F) -> Self { if other.is_one() {

@@ -166,6 +196,9 @@ AllocatedFp::new(value, variable, self.cs.clone())

} } + /// Output `self + self` + /// + /// This does not create any constraints. #[tracing::instrument(target = "r1cs")] pub fn double(&self) -> Result<Self, SynthesisError> { let value = self.value.map(|val| val.double());

@@ -173,6 +206,9 @@ let variable = self.cs.new_lc(lc!() + self.variable + self.variable)?;

Ok(Self::new(value, variable, self.cs.clone())) } + /// Output `-self` + /// + /// This does not create any constraints. #[tracing::instrument(target = "r1cs")] pub fn negate(&self) -> Self { let mut result = self.clone();

@@ -180,6 +216,9 @@ result.negate_in_place();

result } + /// Sets `self = -self` + /// + /// This does not create any constraints. #[tracing::instrument(target = "r1cs")] pub fn negate_in_place(&mut self) -> &mut Self { self.value.as_mut().map(|val| *val = -(*val));

@@ -187,11 +226,17 @@ self.variable = self.cs.new_lc(lc!() - self.variable).unwrap();

self } + /// Outputs `self * self` + /// + /// This requires *one* constraint. #[tracing::instrument(target = "r1cs")] pub fn square(&self) -> Result<Self, SynthesisError> { Ok(self.mul(self)) } + /// Outputs `result` such that `result * self = 1`. + /// + /// This requires *one* constraint. #[tracing::instrument(target = "r1cs")] pub fn inverse(&self) -> Result<Self, SynthesisError> { let inverse = Self::new_witness(self.cs.clone(), || {

@@ -206,11 +251,15 @@ )?;

Ok(inverse) } + /// This is a no-op for prime fields. #[tracing::instrument(target = "r1cs")] pub fn frobenius_map(&self, _: usize) -> Result<Self, SynthesisError> { Ok(self.clone()) } + /// Enforces that `self * other = result`. + /// + /// This requires *one* constraint. #[tracing::instrument(target = "r1cs")] pub fn mul_equals(&self, other: &Self, result: &Self) -> Result<(), SynthesisError> { self.cs.enforce_constraint(

@@ -220,6 +269,9 @@ lc!() + result.variable,

) } + /// Enforces that `self * self = result`. + /// + /// This requires *one* constraint. #[tracing::instrument(target = "r1cs")] pub fn square_equals(&self, result: &Self) -> Result<(), SynthesisError> { self.cs.enforce_constraint(

@@ -231,9 +283,7 @@ }

/// Outputs the bit `self == other`. /// - /// # Constraint cost - /// - /// Consumes three constraints + /// This requires three constraints. #[tracing::instrument(target = "r1cs")] pub fn is_eq(&self, other: &Self) -> Result<Boolean<F>, SynthesisError> { Ok(self.is_neq(other)?.not())

@@ -241,9 +291,7 @@ }

/// Outputs the bit `self != other`. /// - /// # Constraint cost - /// - /// Consumes three constraints + /// This requires three constraints. #[tracing::instrument(target = "r1cs")] pub fn is_neq(&self, other: &Self) -> Result<Boolean<F>, SynthesisError> { let is_not_equal = Boolean::new_witness(self.cs.clone(), || {

@@ -311,6 +359,9 @@ )?;

Ok(is_not_equal) } + /// Enforces that self == other if `should_enforce.is_eq(&Boolean::TRUE)`. + /// + /// This requires one constraint. #[tracing::instrument(target = "r1cs")] pub fn conditional_enforce_equal( &self,

@@ -324,6 +375,9 @@ lc!(),

) } + /// Enforces that self != other if `should_enforce.is_eq(&Boolean::TRUE)`. + /// + /// This requires one constraint. #[tracing::instrument(target = "r1cs")] pub fn conditional_enforce_not_equal( &self,

@@ -353,6 +407,9 @@

impl<F: PrimeField> ToBitsGadget<F> for AllocatedFp<F> { /// Outputs the unique bit-wise decomposition of `self` in *little-endian* /// form. + /// + /// This method enforces that the output is in the field, i.e. + /// it invokes `Boolean::enforce_in_field_le` on the bit decomposition. #[tracing::instrument(target = "r1cs")] fn to_bits_le(&self) -> Result<Vec<Boolean<F>>, SynthesisError> { let bits = self.to_non_unique_bits_le()?;

@@ -405,6 +462,9 @@

impl<F: PrimeField> ToBytesGadget<F> for AllocatedFp<F> { /// Outputs the unique byte decomposition of `self` in *little-endian* /// form. + /// + /// This method enforces that the decomposition represents + /// an integer that is less than `F::MODULUS`. #[tracing::instrument(target = "r1cs")] fn to_bytes(&self) -> Result<Vec<UInt8<F>>, SynthesisError> { let num_bits = F::BigInt::NUM_LIMBS * 64;
M r1cs-std/src/fields/fp12.rs → r1cs-std/src/fields/fp12.rs

@@ -2,6 +2,9 @@ use crate::fields::{fp2::Fp2Var, fp6_3over2::Fp6Var, quadratic_extension::*, FieldVar};

use algebra::fields::{fp12_2over3over2::*, fp6_3over2::Fp6Parameters, Field, QuadExtParameters}; use r1cs_core::SynthesisError; +/// A degree-12 extension field constructed as the tower of a +/// quadratic extension over a cubic extension over a quadratic extension field. +/// This is the R1CS equivalent of `algebra_core::fp12_2over3over2::Fp12<P>`. pub type Fp12Var<P> = QuadExtVar<Fp6Var<<P as Fp12Parameters>::Fp6Params>, Fp12ParamsWrapper<P>>; type Fp2Params<P> = <<P as Fp12Parameters>::Fp6Params as Fp6Parameters>::Fp2Params;

@@ -15,7 +18,7 @@ }

} impl<P: Fp12Parameters> Fp12Var<P> { - /// Multiplies by an element of the form (c0 = (c0, c1, 0), c1 = (0, d1, 0)) + /// Multiplies by a sparse element of the form `(c0 = (c0, c1, 0), c1 = (0, d1, 0))`. #[inline] pub fn mul_by_014( &self,

@@ -31,7 +34,7 @@ let new_c1 = (&self.c0 + &self.c1).mul_by_c0_c1_0(&c0, &(c1 + d1))? - &v0 - &v1;

Ok(Self::new(new_c0, new_c1)) } - /// Multiplies by an element of the form (c0 = (c0, 0, 0), c1 = (d0, d1, 0)) + /// Multiplies by a sparse element of the form `(c0 = (c0, 0, 0), c1 = (d0, d1, 0))`. #[inline] pub fn mul_by_034( &self,

@@ -54,6 +57,7 @@

Ok(Self::new(new_c0, new_c1)) } + /// Squares `self` when `self` is in the cyclotomic subgroup. pub fn cyclotomic_square(&self) -> Result<Self, SynthesisError> { if characteristic_square_mod_6_is_one(Fp12::<P>::characteristic()) { let fp2_nr = <P::Fp6Params as Fp6Parameters>::NONRESIDUE;

@@ -132,7 +136,7 @@ self.square()

} } - /// Like `Self::cyclotomic_exp, but additionally uses cyclotomic squaring. + /// Like `Self::cyclotomic_exp`, but additionally uses cyclotomic squaring. pub fn optimized_cyclotomic_exp( &self, exponent: impl AsRef<[u64]>,
M r1cs-std/src/fields/fp2.rs → r1cs-std/src/fields/fp2.rs

@@ -1,6 +1,8 @@

use crate::fields::{fp::FpVar, quadratic_extension::*}; use algebra::fields::{Fp2Parameters, Fp2ParamsWrapper, QuadExtParameters}; +/// A quadratic extension field constructed over a prime field. +/// This is the R1CS equivalent of `algebra_core::Fp2<P>`. pub type Fp2Var<P> = QuadExtVar<FpVar<<P as Fp2Parameters>::Fp>, Fp2ParamsWrapper<P>>; impl<P: Fp2Parameters> QuadExtVarParams<FpVar<P::Fp>> for Fp2ParamsWrapper<P> {
M r1cs-std/src/fields/fp3.rs → r1cs-std/src/fields/fp3.rs

@@ -1,6 +1,8 @@

use crate::fields::{cubic_extension::*, fp::FpVar}; use algebra::fields::{CubicExtParameters, Fp3Parameters, Fp3ParamsWrapper}; +/// A cubic extension field constructed over a prime field. +/// This is the R1CS equivalent of `algebra_core::Fp3<P>`. pub type Fp3Var<P> = CubicExtVar<FpVar<<P as Fp3Parameters>::Fp>, Fp3ParamsWrapper<P>>; impl<P: Fp3Parameters> CubicExtVarParams<FpVar<P::Fp>> for Fp3ParamsWrapper<P> {
M r1cs-std/src/fields/fp4.rs → r1cs-std/src/fields/fp4.rs

@@ -1,6 +1,9 @@

use crate::fields::{fp2::Fp2Var, quadratic_extension::*}; use algebra::fields::{Fp4Parameters, Fp4ParamsWrapper, QuadExtParameters}; +/// A quartic extension field constructed as the tower of a +/// quadratic extension over a quadratic extension field. +/// This is the R1CS equivalent of `algebra_core::Fp4<P>`. pub type Fp4Var<P> = QuadExtVar<Fp2Var<<P as Fp4Parameters>::Fp2Params>, Fp4ParamsWrapper<P>>; impl<P: Fp4Parameters> QuadExtVarParams<Fp2Var<P::Fp2Params>> for Fp4ParamsWrapper<P> {
M r1cs-std/src/fields/fp6_2over3.rs → r1cs-std/src/fields/fp6_2over3.rs

@@ -1,6 +1,9 @@

use crate::fields::{fp3::Fp3Var, quadratic_extension::*}; use algebra::fields::{fp6_2over3::*, QuadExtParameters}; +/// A sextic extension field constructed as the tower of a +/// quadratic extension over a cubic extension field. +/// This is the R1CS equivalent of `algebra_core::fp6_2over3::Fp6<P>`. pub type Fp6Var<P> = QuadExtVar<Fp3Var<<P as Fp6Parameters>::Fp3Params>, Fp6ParamsWrapper<P>>; impl<P: Fp6Parameters> QuadExtVarParams<Fp3Var<P::Fp3Params>> for Fp6ParamsWrapper<P> {
M r1cs-std/src/fields/fp6_3over2.rs → r1cs-std/src/fields/fp6_3over2.rs

@@ -3,6 +3,9 @@ use algebra::fields::{fp6_3over2::*, CubicExtParameters, Fp2};

use core::ops::MulAssign; use r1cs_core::SynthesisError; +/// A sextic extension field constructed as the tower of a +/// cubic extension over a quadratic extension field. +/// This is the R1CS equivalent of `algebra_core::fp6_3over3::Fp6<P>`. pub type Fp6Var<P> = CubicExtVar<Fp2Var<<P as Fp6Parameters>::Fp2Params>, Fp6ParamsWrapper<P>>; impl<P: Fp6Parameters> CubicExtVarParams<Fp2Var<P::Fp2Params>> for Fp6ParamsWrapper<P> {

@@ -17,6 +20,7 @@ }

} impl<P: Fp6Parameters> Fp6Var<P> { + /// Multiplies `self` by a sparse element which has `c0 == c2 == zero`. pub fn mul_by_0_c1_0(&self, c1: &Fp2Var<P::Fp2Params>) -> Result<Self, SynthesisError> { // Karatsuba multiplication // v0 = a0 * b0 = 0

@@ -44,7 +48,7 @@ let c2 = v1;

Ok(Self::new(c0, c1, c2)) } - // #[inline] + /// Multiplies `self` by a sparse element which has `c2 == zero`. pub fn mul_by_c0_c1_0( &self, c0: &Fp2Var<P::Fp2Params>,
M r1cs-std/src/fields/mod.rs → r1cs-std/src/fields/mod.rs

@@ -7,18 +7,37 @@ use r1cs_core::SynthesisError;

use crate::{prelude::*, Assignment}; +/// This module contains a generic implementation of cubic extension field variables. +/// That is, it implements the R1CS equivalent of `algebra_core::CubicExtField`. pub mod cubic_extension; +/// This module contains a generic implementation of quadratic extension field variables. +/// That is, it implements the R1CS equivalent of `algebra_core::QuadExtField`. pub mod quadratic_extension; +/// This module contains a generic implementation of prime field variables. +/// That is, it implements the R1CS equivalent of `algebra_core::Fp*`. pub mod fp; + +/// This module contains a generic implementation of the degree-12 tower extension field. +/// That is, it implements the R1CS equivalent of `algebra_core::Fp12` pub mod fp12; +/// This module contains a generic implementation of the degree-2 tower extension field. +/// That is, it implements the R1CS equivalent of `algebra_core::Fp2` pub mod fp2; +/// This module contains a generic implementation of the degree-3 tower extension field. +/// That is, it implements the R1CS equivalent of `algebra_core::Fp3` pub mod fp3; +/// This module contains a generic implementation of the degree-4 tower extension field. +/// That is, it implements the R1CS equivalent of `algebra_core::Fp4` pub mod fp4; +/// This module contains a generic implementation of the degree-6 tower extension field. +/// That is, it implements the R1CS equivalent of `algebra_core::fp6_2over3::Fp6` pub mod fp6_2over3; +/// This module contains a generic implementation of the degree-6 tower extension field. +/// That is, it implements the R1CS equivalent of `algebra_core::fp6_3over2::Fp6` pub mod fp6_3over2; -/// A hack used to work around the lack of implied bounds. +/// This trait is a hack used to work around the lack of implied bounds. pub trait FieldOpsBounds<'a, F, T: 'a>: Sized + Add<&'a T, Output = T>

@@ -56,62 +75,80 @@ + SubAssign<F>

+ MulAssign<F> + Debug { + /// Returns the constant `F::zero()`. fn zero() -> Self; + /// Returns a `Boolean` representing whether `self == Self::zero()`. fn is_zero(&self) -> Result<Boolean<ConstraintF>, SynthesisError> { self.is_eq(&Self::zero()) } + /// Returns the constant `F::one()`. fn one() -> Self; + /// Returns a `Boolean` representing whether `self == Self::one()`. fn is_one(&self) -> Result<Boolean<ConstraintF>, SynthesisError> { self.is_eq(&Self::one()) } + /// Returns a constant with value `v`. + /// + /// This *should not* allocate any variables. fn constant(v: F) -> Self; + /// Computes `self + self`. fn double(&self) -> Result<Self, SynthesisError> { Ok(self.clone() + self) } + /// Sets `self = self + self`. fn double_in_place(&mut self) -> Result<&mut Self, SynthesisError> { *self += self.double()?; Ok(self) } + /// Coputes `-self`. fn negate(&self) -> Result<Self, SynthesisError>; + /// Sets `self = -self`. #[inline] fn negate_in_place(&mut self) -> Result<&mut Self, SynthesisError> { *self = self.negate()?; Ok(self) } + /// Computes `self * self`. + /// + /// A default implementation is provided which just invokes the underlying + /// multiplication routine. However, this method should be specialized + /// for extension fields, where faster algorithms exist for squaring. fn square(&self) -> Result<Self, SynthesisError> { Ok(self.clone() * self) } + /// Sets `self = self.square()`. fn square_in_place(&mut self) -> Result<&mut Self, SynthesisError> { *self = self.square()?; Ok(self) } - /// Enforce that `self * other == result`. + /// Enforces that `self * other == result`. fn mul_equals(&self, other: &Self, result: &Self) -> Result<(), SynthesisError> { let actual_result = self.clone() * other; result.enforce_equal(&actual_result) } - /// Enforce that `self * self == result`. + /// Enforces that `self * self == result`. fn square_equals(&self, result: &Self) -> Result<(), SynthesisError> { let actual_result = self.square()?; result.enforce_equal(&actual_result) } + /// Computes `result` such that `self * result == Self::one()`. fn inverse(&self) -> Result<Self, SynthesisError>; - /// Returns (self / denominator), but requires fewer constraints than - /// self * denominator.inverse() + /// Returns `(self / denominator)`. but requires fewer constraints than + /// `self * denominator.inverse()`. /// It is up to the caller to ensure that denominator is non-zero, /// since in that case the result is unconstrained. fn mul_by_inverse(&self, denominator: &Self) -> Result<Self, SynthesisError> {

@@ -125,8 +162,10 @@

Ok(result) } + /// Computes the frobenius map over `self`. fn frobenius_map(&self, power: usize) -> Result<Self, SynthesisError>; + /// Sets `self = self.frobenius_map()`. fn frobenius_map_in_place(&mut self, power: usize) -> Result<&mut Self, SynthesisError> { *self = self.frobenius_map(power)?; Ok(self)

@@ -145,7 +184,8 @@ }

Ok(res) } - /// Computes `self^S`, where S is interpreted as an integer. + /// Computes `self^S`, where S is interpreted as an little-endian u64-decomposition of + /// an integer. fn pow_by_constant<S: AsRef<[u64]>>(&self, exp: S) -> Result<Self, SynthesisError> { let mut res = Self::one(); for i in BitIteratorBE::without_leading_zeros(exp) {
M r1cs-std/src/fields/quadratic_extension.rs → r1cs-std/src/fields/quadratic_extension.rs

@@ -12,6 +12,8 @@ prelude::*,

Assignment, ToConstraintFieldGadget, Vec, }; +/// This struct is the `R1CS` equivalent of the quadratic extension field type +/// in `algebra-core`, i.e. `algebra_core::QuadExtField`. #[derive(Derivative)] #[derivative(Debug(bound = "BF: core::fmt::Debug"), Clone(bound = "BF: Clone"))] #[must_use]

@@ -19,17 +21,22 @@ pub struct QuadExtVar<BF: FieldVar<P::BaseField, P::BasePrimeField>, P: QuadExtVarParams<BF>>

where for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>, { + /// The zero-th coefficient of this field element. pub c0: BF, + /// The first coefficient of this field element. pub c1: BF, #[derivative(Debug = "ignore")] _params: PhantomData<P>, } +/// This trait describes parameters that are used to implement arithmetic for `QuadExtVar`. pub trait QuadExtVarParams<BF: FieldVar<Self::BaseField, Self::BasePrimeField>>: QuadExtParameters where for<'a> &'a BF: FieldOpsBounds<'a, Self::BaseField, BF>, { + /// Multiply the base field of the `QuadExtVar` by the appropriate Frobenius coefficient. + /// This is equivalent to `Self::mul_base_field_by_frob_coeff(power)`. fn mul_base_field_var_by_frob_coeff(fe: &mut BF, power: usize); }

@@ -37,6 +44,7 @@ impl<BF: FieldVar<P::BaseField, P::BasePrimeField>, P: QuadExtVarParams<BF>> QuadExtVar<BF, P>

where for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>, { + /// Constructs a `QuadExtVar` from the underlying coefficients. pub fn new(c0: BF, c1: BF) -> Self { Self { c0,

@@ -45,12 +53,14 @@ _params: PhantomData,

} } - /// Multiply a BF by quadratic nonresidue P::NONRESIDUE. + /// Multiplies a variable of the base field by the quadratic nonresidue `P::NONRESIDUE` that + /// is used to construct the extension field. #[inline] pub fn mul_base_field_by_nonresidue(fe: &BF) -> Result<BF, SynthesisError> { Ok(fe * P::NONRESIDUE) } + /// Multiplies `self` by a constant from the base field. #[inline] pub fn mul_by_base_field_constant(&self, fe: P::BaseField) -> Self { let c0 = self.c0.clone() * fe;

@@ -58,6 +68,7 @@ let c1 = self.c1.clone() * fe;

QuadExtVar::new(c0, c1) } + /// Sets `self = self.mul_by_base_field_constant(fe)`. #[inline] pub fn mul_assign_by_base_field_constant(&mut self, fe: P::BaseField) { *self = (&*self).mul_by_base_field_constant(fe);
M r1cs-std/src/groups/curves/mod.rs → r1cs-std/src/groups/curves/mod.rs

@@ -1,2 +1,9 @@

+/// This module generically implements arithmetic for Short +/// Weierstrass elliptic curves by following the complete formulae of +/// [[Renes, Costello, Batina 2015]](https://eprint.iacr.org/2015/1060). pub mod short_weierstrass; + +/// This module generically implements arithmetic for Twisted +/// Edwards elliptic curves by following the complete formulae described in the +/// [EFD](https://www.hyperelliptic.org/EFD/g1p/auto-twisted.html). pub mod twisted_edwards;
M r1cs-std/src/groups/curves/short_weierstrass/bls12/mod.rs → r1cs-std/src/groups/curves/short_weierstrass/bls12/mod.rs

@@ -16,19 +16,29 @@ };

use core::fmt::Debug; +/// Represents a projective point in G1. pub type G1Var<P> = ProjectiveVar<<P as Bls12Parameters>::G1Parameters, FpVar<<P as Bls12Parameters>::Fp>>; + +/// Represents an affine point on G1. Should be used only for comparison and when +/// a canonical representation of a point is required, and not for arithmetic. pub type G1AffineVar<P> = AffineVar<<P as Bls12Parameters>::G1Parameters, FpVar<<P as Bls12Parameters>::Fp>>; +/// Represents a projective point in G2. pub type G2Var<P> = ProjectiveVar<<P as Bls12Parameters>::G2Parameters, Fp2G<P>>; +/// Represents an affine point on G2. Should be used only for comparison and when +/// a canonical representation of a point is required, and not for arithmetic. pub type G2AffineVar<P> = AffineVar<<P as Bls12Parameters>::G2Parameters, Fp2G<P>>; +/// Represents the cached precomputation that can be performed on a G1 element +/// which enables speeding up pairing computation. #[derive(Derivative)] #[derivative(Clone(bound = "G1Var<P>: Clone"), Debug(bound = "G1Var<P>: Debug"))] pub struct G1PreparedVar<P: Bls12Parameters>(pub AffineVar<P::G1Parameters, FpVar<P::Fp>>); impl<P: Bls12Parameters> G1PreparedVar<P> { + /// Returns the value assigned to `self` in the underlying constraint system. pub fn value(&self) -> Result<G1Prepared<P>, SynthesisError> { let x = self.0.x.value()?; let y = self.0.y.value()?;

@@ -37,6 +47,7 @@ let g = GroupAffine::new(x, y, infinity);

Ok(g.into()) } + /// Constructs `Self` from a `G1Var`. pub fn from_group_var(q: &G1Var<P>) -> Result<Self, SynthesisError> { let g = q.to_affine()?; Ok(Self(g))

@@ -90,12 +101,15 @@ }

type Fp2G<P> = Fp2Var<<P as Bls12Parameters>::Fp2Params>; type LCoeff<P> = (Fp2G<P>, Fp2G<P>); +/// Represents the cached precomputation that can be performed on a G2 element +/// which enables speeding up pairing computation. #[derive(Derivative)] #[derivative( Clone(bound = "Fp2Var<P::Fp2Params>: Clone"), Debug(bound = "Fp2Var<P::Fp2Params>: Debug") )] pub struct G2PreparedVar<P: Bls12Parameters> { + #[doc(hidden)] pub ell_coeffs: Vec<LCoeff<P>>, }

@@ -165,6 +179,7 @@ }

} impl<P: Bls12Parameters> G2PreparedVar<P> { + /// Constructs `Self` from a `G2Var`. #[tracing::instrument(target = "r1cs")] pub fn from_group_var(q: &G2Var<P>) -> Result<Self, SynthesisError> { let q = q.to_affine()?;
M r1cs-std/src/groups/curves/short_weierstrass/mnt4/mod.rs → r1cs-std/src/groups/curves/short_weierstrass/mnt4/mod.rs

@@ -16,17 +16,25 @@ Vec,

}; use core::borrow::Borrow; +/// Represents a projective point in G1. pub type G1Var<P> = ProjectiveVar<<P as MNT4Parameters>::G1Parameters, FpVar<<P as MNT4Parameters>::Fp>>; +/// Represents a projective point in G2. pub type G2Var<P> = ProjectiveVar<<P as MNT4Parameters>::G2Parameters, Fp2G<P>>; +/// Represents the cached precomputation that can be performed on a G1 element +/// which enables speeding up pairing computation. #[derive(Derivative)] #[derivative(Clone(bound = "P: MNT4Parameters"), Debug(bound = "P: MNT4Parameters"))] pub struct G1PreparedVar<P: MNT4Parameters> { + #[doc(hidden)] pub x: FpVar<P::Fp>, + #[doc(hidden)] pub y: FpVar<P::Fp>, + #[doc(hidden)] pub x_twist: Fp2Var<P::Fp2Params>, + #[doc(hidden)] pub y_twist: Fp2Var<P::Fp2Params>, }

@@ -64,6 +72,7 @@ }

} impl<P: MNT4Parameters> G1PreparedVar<P> { + /// Returns the value assigned to `self` in the underlying constraint system. pub fn value(&self) -> Result<G1Prepared<P>, SynthesisError> { let (x, y, x_twist, y_twist) = ( self.x.value()?,

@@ -79,6 +88,7 @@ y_twist,

}) } + /// Constructs `Self` from a `G1Var`. #[tracing::instrument(target = "r1cs")] pub fn from_group_var(q: &G1Var<P>) -> Result<Self, SynthesisError> { let q = q.to_affine()?;

@@ -124,14 +134,22 @@ }

type Fp2G<P> = Fp2Var<<P as MNT4Parameters>::Fp2Params>; +/// Represents the cached precomputation that can be performed on a G2 element +/// which enables speeding up pairing computation. #[derive(Derivative)] #[derivative(Clone(bound = "P: MNT4Parameters"), Debug(bound = "P: MNT4Parameters"))] pub struct G2PreparedVar<P: MNT4Parameters> { + #[doc(hidden)] pub x: Fp2Var<P::Fp2Params>, + #[doc(hidden)] pub y: Fp2Var<P::Fp2Params>, + #[doc(hidden)] pub x_over_twist: Fp2Var<P::Fp2Params>, + #[doc(hidden)] pub y_over_twist: Fp2Var<P::Fp2Params>, + #[doc(hidden)] pub double_coefficients: Vec<AteDoubleCoefficientsVar<P>>, + #[doc(hidden)] pub addition_coefficients: Vec<AteAdditionCoefficientsVar<P>>, }

@@ -225,6 +243,7 @@ }

} impl<P: MNT4Parameters> G2PreparedVar<P> { + /// Returns the value assigned to `self` in the underlying constraint system. pub fn value(&self) -> Result<G2Prepared<P>, SynthesisError> { let x = self.x.value()?; let y = self.y.value()?;

@@ -250,6 +269,7 @@ addition_coefficients,

}) } + /// Constructs `Self` from a `G2Var`. #[tracing::instrument(target = "r1cs")] pub fn from_group_var(q: &G2Var<P>) -> Result<Self, SynthesisError> { let twist_inv = P::TWIST.inverse().unwrap();

@@ -320,6 +340,7 @@ Ok(g2p)

} } +#[doc(hidden)] #[derive(Derivative)] #[derivative(Clone(bound = "P: MNT4Parameters"), Debug(bound = "P: MNT4Parameters"))] pub struct AteDoubleCoefficientsVar<P: MNT4Parameters> {

@@ -385,6 +406,7 @@ }

} impl<P: MNT4Parameters> AteDoubleCoefficientsVar<P> { + /// Returns the value assigned to `self` in the underlying constraint system. pub fn value(&self) -> Result<AteDoubleCoefficients<P>, SynthesisError> { let (c_h, c_4c, c_j, c_l) = ( self.c_l.value()?,

@@ -401,6 +423,7 @@ })

} } +#[doc(hidden)] #[derive(Derivative)] #[derivative(Clone(bound = "P: MNT4Parameters"), Debug(bound = "P: MNT4Parameters"))] pub struct AteAdditionCoefficientsVar<P: MNT4Parameters> {

@@ -451,12 +474,14 @@ }

} impl<P: MNT4Parameters> AteAdditionCoefficientsVar<P> { + /// Returns the value assigned to `self` in the underlying constraint system. pub fn value(&self) -> Result<AteAdditionCoefficients<P>, SynthesisError> { let (c_l1, c_rz) = (self.c_l1.value()?, self.c_rz.value()?); Ok(AteAdditionCoefficients { c_l1, c_rz }) } } +#[doc(hidden)] pub struct G2ProjectiveExtendedVar<P: MNT4Parameters> { pub x: Fp2Var<P::Fp2Params>, pub y: Fp2Var<P::Fp2Params>,
M r1cs-std/src/groups/curves/short_weierstrass/mnt6/mod.rs → r1cs-std/src/groups/curves/short_weierstrass/mnt6/mod.rs

@@ -16,21 +16,30 @@ Vec,

}; use core::borrow::Borrow; +/// Represents a projective point in G1. pub type G1Var<P> = ProjectiveVar<<P as MNT6Parameters>::G1Parameters, FpVar<<P as MNT6Parameters>::Fp>>; +/// Represents a projective point in G2. pub type G2Var<P> = ProjectiveVar<<P as MNT6Parameters>::G2Parameters, Fp3G<P>>; +/// Represents the cached precomputation that can be performed on a G1 element +/// which enables speeding up pairing computation. #[derive(Derivative)] #[derivative(Clone(bound = "P: MNT6Parameters"), Debug(bound = "P: MNT6Parameters"))] pub struct G1PreparedVar<P: MNT6Parameters> { + #[doc(hidden)] pub x: FpVar<P::Fp>, + #[doc(hidden)] pub y: FpVar<P::Fp>, + #[doc(hidden)] pub x_twist: Fp3Var<P::Fp3Params>, + #[doc(hidden)] pub y_twist: Fp3Var<P::Fp3Params>, } impl<P: MNT6Parameters> G1PreparedVar<P> { + /// Returns the value assigned to `self` in the underlying constraint system. pub fn value(&self) -> Result<G1Prepared<P>, SynthesisError> { let x = self.x.value()?; let y = self.y.value()?;

@@ -44,6 +53,7 @@ y_twist,

}) } + /// Constructs `Self` from a `G1Var`. #[tracing::instrument(target = "r1cs")] pub fn from_group_var(q: &G1Var<P>) -> Result<Self, SynthesisError> { let q = q.to_affine()?;

@@ -123,14 +133,23 @@ }

} type Fp3G<P> = Fp3Var<<P as MNT6Parameters>::Fp3Params>; + +/// Represents the cached precomputation that can be performed on a G2 element +/// which enables speeding up pairing computation. #[derive(Derivative)] #[derivative(Clone(bound = "P: MNT6Parameters"), Debug(bound = "P: MNT6Parameters"))] pub struct G2PreparedVar<P: MNT6Parameters> { + #[doc(hidden)] pub x: Fp3Var<P::Fp3Params>, + #[doc(hidden)] pub y: Fp3Var<P::Fp3Params>, + #[doc(hidden)] pub x_over_twist: Fp3Var<P::Fp3Params>, + #[doc(hidden)] pub y_over_twist: Fp3Var<P::Fp3Params>, + #[doc(hidden)] pub double_coefficients: Vec<AteDoubleCoefficientsVar<P>>, + #[doc(hidden)] pub addition_coefficients: Vec<AteAdditionCoefficientsVar<P>>, }

@@ -224,6 +243,7 @@ }

} impl<P: MNT6Parameters> G2PreparedVar<P> { + /// Returns the value assigned to `self` in the underlying constraint system. pub fn value(&self) -> Result<G2Prepared<P>, SynthesisError> { let x = self.x.value()?; let y = self.y.value()?;

@@ -249,6 +269,7 @@ addition_coefficients,

}) } + /// Constructs `Self` from a `G2Var`. #[tracing::instrument(target = "r1cs")] pub fn from_group_var(q: &G2Var<P>) -> Result<Self, SynthesisError> { let q = q.to_affine()?;

@@ -319,6 +340,7 @@ Ok(g2p)

} } +#[doc(hidden)] #[derive(Derivative)] #[derivative(Clone(bound = "P: MNT6Parameters"), Debug(bound = "P: MNT6Parameters"))] pub struct AteDoubleCoefficientsVar<P: MNT6Parameters> {

@@ -384,6 +406,7 @@ }

} impl<P: MNT6Parameters> AteDoubleCoefficientsVar<P> { + /// Returns the value assigned to `self` in the underlying constraint system. pub fn value(&self) -> Result<AteDoubleCoefficients<P>, SynthesisError> { let c_h = self.c_h.value()?; let c_4c = self.c_4c.value()?;

@@ -398,6 +421,7 @@ })

} } +#[doc(hidden)] #[derive(Derivative)] #[derivative(Clone(bound = "P: MNT6Parameters"), Debug(bound = "P: MNT6Parameters"))] pub struct AteAdditionCoefficientsVar<P: MNT6Parameters> {

@@ -448,6 +472,7 @@ }

} impl<P: MNT6Parameters> AteAdditionCoefficientsVar<P> { + /// Returns the value assigned to `self` in the underlying constraint system. pub fn value(&self) -> Result<AteAdditionCoefficients<P>, SynthesisError> { let c_l1 = self.c_l1.value()?; let c_rz = self.c_rz.value()?;

@@ -455,6 +480,7 @@ Ok(AteAdditionCoefficients { c_l1, c_rz })

} } +#[doc(hidden)] pub struct G2ProjectiveExtendedVar<P: MNT6Parameters> { pub x: Fp3Var<P::Fp3Params>, pub y: Fp3Var<P::Fp3Params>,
M r1cs-std/src/groups/curves/short_weierstrass/mod.rs → r1cs-std/src/groups/curves/short_weierstrass/mod.rs

@@ -11,8 +11,17 @@

use crate::fields::fp::FpVar; use crate::{prelude::*, ToConstraintFieldGadget, Vec}; +/// This module provides a generic implementation of G1 and G2 for +/// the [[BLS12]](https://eprint.iacr.org/2002/088.pdf) family of bilinear groups. pub mod bls12; + +/// This module provides a generic implementation of G1 and G2 for +/// the [[MNT4]](https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.20.8113&rep=rep1&type=pdf) +/// family of bilinear groups. pub mod mnt4; +/// This module provides a generic implementation of G1 and G2 for +/// the [[MNT6]](https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.20.8113&rep=rep1&type=pdf) +/// family of bilinear groups. pub mod mnt6; /// An implementation of arithmetic for Short Weierstrass curves that relies on

@@ -72,6 +81,8 @@ _params: PhantomData,

} } + /// Returns the value assigned to `self` in the underlying + /// constraint system. pub fn value(&self) -> Result<SWAffine<P>, SynthesisError> { Ok(SWAffine::new( self.x.value()?,

@@ -128,6 +139,7 @@ ProjectiveVar<P, F>

where for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, { + /// Constructs `Self` from an `(x, y, z)` coordinate triple. pub fn new(x: F, y: F, z: F) -> Self { Self { x,
M r1cs-std/src/groups/curves/twisted_edwards/mod.rs → r1cs-std/src/groups/curves/twisted_edwards/mod.rs

@@ -13,6 +13,12 @@

use crate::fields::fp::FpVar; use core::{borrow::Borrow, marker::PhantomData}; +/// An implementation of arithmetic for Montgomery curves that relies on +/// incomplete addition formulae for the affine model, as outlined in the +/// [EFD](https://www.hyperelliptic.org/EFD/g1p/auto-montgom.html). +/// +/// This is intended for use primarily for implementing efficient +/// multi-scalar-multiplication in the Bowe-Hopwood-Pedersen hash. #[derive(Derivative)] #[derivative(Debug, Clone)] #[must_use]

@@ -22,7 +28,9 @@ F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,

> where for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, { + /// The x-coordinate. pub x: F, + /// The y-coordinate. pub y: F, #[derivative(Debug = "ignore")] _params: PhantomData<P>,

@@ -59,6 +67,7 @@ > MontgomeryAffineVar<P, F>

where for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, { + /// Constructs `Self` from an `(x, y)` coordinate pair. pub fn new(x: F, y: F) -> Self { Self { x,

@@ -67,6 +76,8 @@ _params: PhantomData,

} } + /// Converts a Twisted Edwards curve point to coordinates for the corresponding affine + /// Montgomery curve point. #[tracing::instrument(target = "r1cs")] pub fn from_edwards_to_coords( p: &TEAffine<P>,

@@ -85,6 +96,8 @@

Ok((montgomery_point.x, montgomery_point.y)) } + /// Converts a Twisted Edwards curve point to coordinates for the corresponding affine + /// Montgomery curve point. #[tracing::instrument(target = "r1cs")] pub fn new_witness_from_edwards( cs: ConstraintSystemRef<<P::BaseField as Field>::BasePrimeField>,

@@ -96,6 +109,7 @@ let v = F::new_witness(r1cs_core::ns!(cs, "v"), || Ok(montgomery_coords.1))?;

Ok(Self::new(u, v)) } + /// Converts `self` into a Twisted Edwards curve point variable. #[tracing::instrument(target = "r1cs")] pub fn into_edwards(&self) -> Result<AffineVar<P, F>, SynthesisError> { let cs = self.cs().unwrap_or(ConstraintSystemRef::None);

@@ -199,6 +213,9 @@ }

} } +/// An implementation of arithmetic for Twisted Edwards curves that relies on +/// the complete formulae for the affine model, as outlined in the +/// [EFD](https://www.hyperelliptic.org/EFD/g1p/auto-twisted.html). #[derive(Derivative)] #[derivative(Debug, Clone)] #[must_use]

@@ -208,7 +225,9 @@ F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,

> where for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, { + /// The x-coordinate. pub x: F, + /// The y-coordinate. pub y: F, #[derivative(Debug = "ignore")] _params: PhantomData<P>,

@@ -219,6 +238,7 @@ AffineVar<P, F>

where for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, { + /// Constructs `Self` from an `(x, y)` coordinate triple. pub fn new(x: F, y: F) -> Self { Self { x,

@@ -257,6 +277,99 @@ Ok(Self::new(x, y))

} } +impl<P: TEModelParameters, F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>> + AffineVar<P, F> +where + P: TEModelParameters, + F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField> + + TwoBitLookupGadget<<P::BaseField as Field>::BasePrimeField, TableConstant = P::BaseField> + + ThreeBitCondNegLookupGadget< + <P::BaseField as Field>::BasePrimeField, + TableConstant = P::BaseField, + >, + for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, +{ + /// Compute a scalar multiplication of `bases` with respect to `scalars`, + /// where the elements of `scalars` are length-three slices of bits, and which + /// such that the first two bits are use to select one of the bases, + /// while the third bit is used to conditionally negate the selection. + #[tracing::instrument(target = "r1cs", skip(bases, scalars))] + pub fn precomputed_base_3_bit_signed_digit_scalar_mul<J>( + bases: &[impl Borrow<[TEProjective<P>]>], + scalars: &[impl Borrow<[J]>], + ) -> Result<Self, SynthesisError> + where + J: Borrow<[Boolean<<P::BaseField as Field>::BasePrimeField>]>, + { + const CHUNK_SIZE: usize = 3; + let mut ed_result: Option<AffineVar<P, F>> = None; + let mut result: Option<MontgomeryAffineVar<P, F>> = None; + + let mut process_segment_result = |result: &MontgomeryAffineVar<P, F>| { + let sgmt_result = result.into_edwards()?; + ed_result = match ed_result.as_ref() { + None => Some(sgmt_result), + Some(r) => Some(sgmt_result + r), + }; + Ok::<(), SynthesisError>(()) + }; + + // Compute ∏(h_i^{m_i}) for all i. + for (segment_bits_chunks, segment_powers) in scalars.iter().zip(bases) { + for (bits, base_power) in segment_bits_chunks + .borrow() + .iter() + .zip(segment_powers.borrow()) + { + let base_power = base_power.borrow(); + let mut acc_power = *base_power; + let mut coords = vec![]; + for _ in 0..4 { + coords.push(acc_power); + acc_power += base_power; + } + + let bits = bits.borrow().to_bits_le()?; + if bits.len() != CHUNK_SIZE { + return Err(SynthesisError::Unsatisfiable); + } + + let coords = coords + .iter() + .map(|p| MontgomeryAffineVar::from_edwards_to_coords(&p.into_affine())) + .collect::<Result<Vec<_>, _>>()?; + + let x_coeffs = coords.iter().map(|p| p.0).collect::<Vec<_>>(); + let y_coeffs = coords.iter().map(|p| p.1).collect::<Vec<_>>(); + + let precomp = bits[0].and(&bits[1])?; + + let x = F::zero() + + x_coeffs[0] + + F::from(bits[0].clone()) * (x_coeffs[1] - &x_coeffs[0]) + + F::from(bits[1].clone()) * (x_coeffs[2] - &x_coeffs[0]) + + F::from(precomp.clone()) + * (x_coeffs[3] - &x_coeffs[2] - &x_coeffs[1] + &x_coeffs[0]); + + let y = F::three_bit_cond_neg_lookup(&bits, &precomp, &y_coeffs)?; + + let tmp = MontgomeryAffineVar::new(x, y); + result = match result.as_ref() { + None => Some(tmp), + Some(r) => Some(tmp + r), + }; + } + + process_segment_result(&result.unwrap())?; + result = None; + } + if result.is_some() { + process_segment_result(&result.unwrap())?; + } + Ok(ed_result.unwrap()) + } +} + impl<P, F> R1CSVar<<P::BaseField as Field>::BasePrimeField> for AffineVar<P, F> where P: TEModelParameters,

@@ -281,11 +394,7 @@ impl<P, F> CurveVar<TEProjective<P>, <P::BaseField as Field>::BasePrimeField> for AffineVar<P, F>

where P: TEModelParameters, F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField> - + TwoBitLookupGadget<<P::BaseField as Field>::BasePrimeField, TableConstant = P::BaseField> - + ThreeBitCondNegLookupGadget< - <P::BaseField as Field>::BasePrimeField, - TableConstant = P::BaseField, - >, + + TwoBitLookupGadget<<P::BaseField as Field>::BasePrimeField, TableConstant = P::BaseField>, for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, { fn constant(g: TEProjective<P>) -> Self {

@@ -441,95 +550,13 @@ }

Ok(()) } - - #[tracing::instrument(target = "r1cs", skip(bases, scalars))] - fn precomputed_base_3_bit_signed_digit_scalar_mul<'a, I, J, B>( - bases: &[B], - scalars: &[J], - ) -> Result<Self, SynthesisError> - where - I: Borrow<[Boolean<<P::BaseField as Field>::BasePrimeField>]>, - J: Borrow<[I]>, - B: Borrow<[TEProjective<P>]>, - { - const CHUNK_SIZE: usize = 3; - let mut ed_result: Option<AffineVar<P, F>> = None; - let mut result: Option<MontgomeryAffineVar<P, F>> = None; - - let mut process_segment_result = |result: &MontgomeryAffineVar<P, F>| { - let sgmt_result = result.into_edwards()?; - ed_result = match ed_result.as_ref() { - None => Some(sgmt_result), - Some(r) => Some(sgmt_result + r), - }; - Ok::<(), SynthesisError>(()) - }; - - // Compute ∏(h_i^{m_i}) for all i. - for (segment_bits_chunks, segment_powers) in scalars.iter().zip(bases) { - for (bits, base_power) in segment_bits_chunks - .borrow() - .iter() - .zip(segment_powers.borrow()) - { - let base_power = base_power.borrow(); - let mut acc_power = *base_power; - let mut coords = vec![]; - for _ in 0..4 { - coords.push(acc_power); - acc_power += base_power; - } - - let bits = bits.borrow().to_bits_le()?; - if bits.len() != CHUNK_SIZE { - return Err(SynthesisError::Unsatisfiable); - } - - let coords = coords - .iter() - .map(|p| MontgomeryAffineVar::from_edwards_to_coords(&p.into_affine())) - .collect::<Result<Vec<_>, _>>()?; - - let x_coeffs = coords.iter().map(|p| p.0).collect::<Vec<_>>(); - let y_coeffs = coords.iter().map(|p| p.1).collect::<Vec<_>>(); - - let precomp = bits[0].and(&bits[1])?; - - let x = F::zero() - + x_coeffs[0] - + F::from(bits[0].clone()) * (x_coeffs[1] - &x_coeffs[0]) - + F::from(bits[1].clone()) * (x_coeffs[2] - &x_coeffs[0]) - + F::from(precomp.clone()) - * (x_coeffs[3] - &x_coeffs[2] - &x_coeffs[1] + &x_coeffs[0]); - - let y = F::three_bit_cond_neg_lookup(&bits, &precomp, &y_coeffs)?; - - let tmp = MontgomeryAffineVar::new(x, y); - result = match result.as_ref() { - None => Some(tmp), - Some(r) => Some(tmp + r), - }; - } - - process_segment_result(&result.unwrap())?; - result = None; - } - if result.is_some() { - process_segment_result(&result.unwrap())?; - } - Ok(ed_result.unwrap()) - } } impl<P, F> AllocVar<TEProjective<P>, <P::BaseField as Field>::BasePrimeField> for AffineVar<P, F> where P: TEModelParameters, F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField> - + TwoBitLookupGadget<<P::BaseField as Field>::BasePrimeField, TableConstant = P::BaseField> - + ThreeBitCondNegLookupGadget< - <P::BaseField as Field>::BasePrimeField, - TableConstant = P::BaseField, - >, + + TwoBitLookupGadget<<P::BaseField as Field>::BasePrimeField, TableConstant = P::BaseField>, for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, { #[tracing::instrument(target = "r1cs", skip(cs, f))]

@@ -630,11 +657,7 @@ impl<P, F> AllocVar<TEAffine<P>, <P::BaseField as Field>::BasePrimeField> for AffineVar<P, F>

where P: TEModelParameters, F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField> - + TwoBitLookupGadget<<P::BaseField as Field>::BasePrimeField, TableConstant = P::BaseField> - + ThreeBitCondNegLookupGadget< - <P::BaseField as Field>::BasePrimeField, - TableConstant = P::BaseField, - >, + + TwoBitLookupGadget<<P::BaseField as Field>::BasePrimeField, TableConstant = P::BaseField>, for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, { #[tracing::instrument(target = "r1cs", skip(cs, f))]

@@ -737,8 +760,7 @@ },

|this: &'a AffineVar<P, F>, other: TEProjective<P>| this + AffineVar::constant(other), ( F :FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField> - + TwoBitLookupGadget<<P::BaseField as Field>::BasePrimeField, TableConstant = P::BaseField> - + ThreeBitCondNegLookupGadget<<P::BaseField as Field>::BasePrimeField, TableConstant = P::BaseField>, + + TwoBitLookupGadget<<P::BaseField as Field>::BasePrimeField, TableConstant = P::BaseField>, P: TEModelParameters, ), for <'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>,

@@ -755,8 +777,7 @@ |this: &'a AffineVar<P, F>, other: &'a AffineVar<P, F>| this + other.negate().unwrap(),

|this: &'a AffineVar<P, F>, other: TEProjective<P>| this - AffineVar::constant(other), ( F :FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField> - + TwoBitLookupGadget<<P::BaseField as Field>::BasePrimeField, TableConstant = P::BaseField> - + ThreeBitCondNegLookupGadget<<P::BaseField as Field>::BasePrimeField, TableConstant = P::BaseField>, + + TwoBitLookupGadget<<P::BaseField as Field>::BasePrimeField, TableConstant = P::BaseField>, P: TEModelParameters, ), for <'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>

@@ -766,11 +787,7 @@ impl<'a, P, F> GroupOpsBounds<'a, TEProjective<P>, AffineVar<P, F>> for AffineVar<P, F>

where P: TEModelParameters, F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField> - + TwoBitLookupGadget<<P::BaseField as Field>::BasePrimeField, TableConstant = P::BaseField> - + ThreeBitCondNegLookupGadget< - <P::BaseField as Field>::BasePrimeField, - TableConstant = P::BaseField, - >, + + TwoBitLookupGadget<<P::BaseField as Field>::BasePrimeField, TableConstant = P::BaseField>, for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>, { }

@@ -779,11 +796,7 @@ impl<'a, P, F> GroupOpsBounds<'a, TEProjective<P>, AffineVar<P, F>> for &'a AffineVar<P, F>

where P: TEModelParameters, F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField> - + TwoBitLookupGadget<<P::BaseField as Field>::BasePrimeField, TableConstant = P::BaseField> - + ThreeBitCondNegLookupGadget< - <P::BaseField as Field>::BasePrimeField, - TableConstant = P::BaseField, - >, + + TwoBitLookupGadget<<P::BaseField as Field>::BasePrimeField, TableConstant = P::BaseField>, for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>, { }
M r1cs-std/src/groups/mod.rs → r1cs-std/src/groups/mod.rs

@@ -5,6 +5,7 @@ use r1cs_core::{Namespace, SynthesisError};

use core::{borrow::Borrow, fmt::Debug}; +/// This module contains implementations of arithmetic for various curve models. pub mod curves; pub use self::curves::short_weierstrass::bls12;

@@ -23,6 +24,8 @@ + Sub<F, Output = T>

{ } +/// A variable that represents a curve point for +/// the curve `C`. pub trait CurveVar<C: ProjectiveCurve, ConstraintF: Field>: 'static + Sized

@@ -43,17 +46,23 @@ + SubAssign<C>

+ AddAssign<Self> + SubAssign<Self> { - fn constant(other: C) -> Self; - + /// Returns the constant `F::zero()`. This is the identity + /// of the group. fn zero() -> Self; + /// Returns a `Boolean` representing whether `self == Self::zero()`. #[tracing::instrument(target = "r1cs")] fn is_zero(&self) -> Result<Boolean<ConstraintF>, SynthesisError> { self.is_eq(&Self::zero()) } - /// Allocate a variable in the subgroup without checking if it's in the - /// prime-order subgroup + /// Returns a constant with value `v`. + /// + /// This *should not* allocate any variables. + fn constant(other: C) -> Self; + + /// Allocates a variable in the subgroup without checking if it's in the + /// prime-order subgroup. fn new_variable_omit_prime_order_check( cs: impl Into<Namespace<ConstraintF>>, f: impl FnOnce() -> Result<C, SynthesisError>,

@@ -63,6 +72,7 @@

/// Enforce that `self` is in the prime-order subgroup. fn enforce_prime_order(&self) -> Result<(), SynthesisError>; + /// Computes `self + self`. #[tracing::instrument(target = "r1cs")] fn double(&self) -> Result<Self, SynthesisError> { let mut result = self.clone();

@@ -70,8 +80,10 @@ result.double_in_place()?;

Ok(result) } + /// Sets `self = self + self`. fn double_in_place(&mut self) -> Result<(), SynthesisError>; + /// Coputes `-self`. fn negate(&self) -> Result<Self, SynthesisError>; /// Computes `bits * self`, where `bits` is a little-endian

@@ -113,20 +125,7 @@ }

Ok(()) } - #[tracing::instrument(target = "r1cs")] - fn precomputed_base_3_bit_signed_digit_scalar_mul<'a, I, J, B>( - _: &[B], - _: &[J], - ) -> Result<Self, SynthesisError> - where - I: Borrow<[Boolean<ConstraintF>]>, - J: Borrow<[I]>, - B: Borrow<[C]>, - { - Err(SynthesisError::AssignmentMissing) - } - - /// Computes a `\sum I_j * B_j`, where `I_j` is a `Boolean` + /// Computes a `\sum_j I_j * B_j`, where `I_j` is a `Boolean` /// representation of the j-th scalar. #[tracing::instrument(target = "r1cs", skip(bases, scalars))] fn precomputed_base_multiscalar_mul_le<'a, T, I, B>(
M r1cs-std/src/instantiated/bls12_377/curves.rs → r1cs-std/src/instantiated/bls12_377/curves.rs

@@ -1,10 +1,16 @@

use crate::groups::bls12; use algebra::bls12_377::Parameters; +/// An element of G1 in the BLS12-377 bilinear group. pub type G1Var = bls12::G1Var<Parameters>; +/// An element of G2 in the BLS12-377 bilinear group. pub type G2Var = bls12::G2Var<Parameters>; +/// Represents the cached precomputation that can be performed on a G1 element +/// which enables speeding up pairing computation. pub type G1PreparedVar = bls12::G1PreparedVar<Parameters>; +/// Represents the cached precomputation that can be performed on a G2 element +/// which enables speeding up pairing computation. pub type G2PreparedVar = bls12::G2PreparedVar<Parameters>; #[test]
M r1cs-std/src/instantiated/bls12_377/fields.rs → r1cs-std/src/instantiated/bls12_377/fields.rs

@@ -2,9 +2,13 @@ use algebra::bls12_377::{Fq, Fq12Parameters, Fq2Parameters, Fq6Parameters};

use crate::fields::{fp::FpVar, fp12::Fp12Var, fp2::Fp2Var, fp6_3over2::Fp6Var}; +/// A variable that is the R1CS equivalent of `algebra::bls12_377::Fq`. pub type FqVar = FpVar<Fq>; +/// A variable that is the R1CS equivalent of `algebra::bls12_377::Fq2`. pub type Fq2Var = Fp2Var<Fq2Parameters>; +/// A variable that is the R1CS equivalent of `algebra::bls12_377::Fq6`. pub type Fq6Var = Fp6Var<Fq6Parameters>; +/// A variable that is the R1CS equivalent of `algebra::bls12_377::Fq12`. pub type Fq12Var = Fp12Var<Fq12Parameters>; #[test]
M r1cs-std/src/instantiated/bls12_377/pairing.rs → r1cs-std/src/instantiated/bls12_377/pairing.rs

@@ -1,5 +1,6 @@

use algebra::bls12_377::Parameters; +/// Specifies the constraints for computing a pairing in the BLS12-377 bilinear group. pub type PairingVar = crate::pairing::bls12::PairingVar<Parameters>; #[test]
M r1cs-std/src/instantiated/ed_on_bls12_377/curves.rs → r1cs-std/src/instantiated/ed_on_bls12_377/curves.rs

@@ -3,6 +3,7 @@ use algebra::ed_on_bls12_377::*;

use crate::ed_on_bls12_377::FqVar; +/// A variable that is the R1CS equivalent of `algebra::ed_on_bls12_377::EdwardsAffine`. pub type EdwardsVar = AffineVar<EdwardsParameters, FqVar>; #[test]
M r1cs-std/src/instantiated/ed_on_bls12_377/fields.rs → r1cs-std/src/instantiated/ed_on_bls12_377/fields.rs

@@ -1,6 +1,7 @@

use crate::fields::fp::FpVar; use algebra::ed_on_bls12_377::fq::Fq; +/// A variable that is the R1CS equivalent of `algebra::ed_on_bls12_377::Fq`. pub type FqVar = FpVar<Fq>; #[test]
M r1cs-std/src/instantiated/ed_on_bls12_381/curves.rs → r1cs-std/src/instantiated/ed_on_bls12_381/curves.rs

@@ -3,6 +3,7 @@ use algebra::ed_on_bls12_381::*;

use crate::ed_on_bls12_381::FqVar; +/// A variable that is the R1CS equivalent of `algebra::ed_on_bls12_381::EdwardsAffine`. pub type EdwardsVar = AffineVar<EdwardsParameters, FqVar>; #[test]
M r1cs-std/src/instantiated/ed_on_bls12_381/fields.rs → r1cs-std/src/instantiated/ed_on_bls12_381/fields.rs

@@ -1,5 +1,6 @@

use crate::fields::fp::FpVar; +/// A variable that is the R1CS equivalent of `algebra::ed_on_bls12_381::Fq`. pub type FqVar = FpVar<algebra::ed_on_bls12_381::Fq>; #[test]
M r1cs-std/src/instantiated/ed_on_bn254/curves.rs → r1cs-std/src/instantiated/ed_on_bn254/curves.rs

@@ -3,6 +3,7 @@ use algebra::ed_on_bn254::*;

use crate::ed_on_bn254::FqVar; +/// A variable that is the R1CS equivalent of `algebra::ed_on_bn254::EdwardsAffine`. pub type EdwardsVar = AffineVar<EdwardsParameters, FqVar>; #[test]
M r1cs-std/src/instantiated/ed_on_bn254/fields.rs → r1cs-std/src/instantiated/ed_on_bn254/fields.rs

@@ -1,5 +1,6 @@

use crate::fields::fp::FpVar; +/// A variable that is the R1CS equivalent of `algebra::ed_on_bn254::Fq`. pub type FqVar = FpVar<algebra::ed_on_bn254::Fq>; #[test]
D r1cs-std/src/instantiated/ed_on_bw6_761/curves.rs

@@ -1,11 +0,0 @@

-use crate::groups::curves::twisted_edwards::AffineGadget; -use algebra::ed_on_cp6_782::*; - -use crate::ed_on_cp6_782::FqGadget; - -pub type EdwardsGadget = AffineGadget<EdwardsParameters, Fq, FqGadget>; - -#[test] -fn test() { - crate::groups::curves::twisted_edwards::test::<_, EdwardsParameters, EdwardsGadget>(); -}
D r1cs-std/src/instantiated/ed_on_bw6_761/fields.rs

@@ -1,9 +0,0 @@

-use crate::fields::fp::FpGadget; -use algebra::ed_on_cp6_782::fq::Fq; - -pub type FqGadget = FpGadget<Fq>; - -#[test] -fn test() { - crate::fields::tests::field_test::<_, _, Fq, FqGadget>(); -}
M r1cs-std/src/instantiated/ed_on_cp6_782/curves.rs → r1cs-std/src/instantiated/ed_on_cp6_782/curves.rs

@@ -3,6 +3,7 @@ use algebra::ed_on_cp6_782::*;

use crate::instantiated::ed_on_cp6_782::FqVar; +/// A variable that is the R1CS equivalent of `algebra::ed_on_cp6_782::EdwardsAffine`. pub type EdwardsVar = AffineVar<EdwardsParameters, FqVar>; #[test]
M r1cs-std/src/instantiated/ed_on_cp6_782/fields.rs → r1cs-std/src/instantiated/ed_on_cp6_782/fields.rs

@@ -1,6 +1,7 @@

use crate::fields::fp::FpVar; use algebra::ed_on_cp6_782::fq::Fq; +/// A variable that is the R1CS equivalent of `algebra::ed_on_cp6_782::Fq`. pub type FqVar = FpVar<Fq>; #[test]
M r1cs-std/src/instantiated/ed_on_mnt4_298/curves.rs → r1cs-std/src/instantiated/ed_on_mnt4_298/curves.rs

@@ -3,6 +3,7 @@ use algebra::ed_on_mnt4_298::*;

use crate::instantiated::ed_on_mnt4_298::fields::FqVar; +/// A variable that is the R1CS equivalent of `algebra::ed_on_mnt4_298::EdwardsAffine`. pub type EdwardsVar = AffineVar<EdwardsParameters, FqVar>; #[test]
M r1cs-std/src/instantiated/ed_on_mnt4_298/fields.rs → r1cs-std/src/instantiated/ed_on_mnt4_298/fields.rs

@@ -1,6 +1,7 @@

use crate::fields::fp::FpVar; use algebra::ed_on_mnt4_298::fq::Fq; +/// A variable that is the R1CS equivalent of `algebra::ed_on_mnt4_298::Fq`. pub type FqVar = FpVar<Fq>; #[test]
M r1cs-std/src/instantiated/ed_on_mnt4_753/curves.rs → r1cs-std/src/instantiated/ed_on_mnt4_753/curves.rs

@@ -3,6 +3,7 @@ use algebra::ed_on_mnt4_753::*;

use crate::instantiated::ed_on_mnt4_753::fields::FqVar; +/// A variable that is the R1CS equivalent of `algebra::ed_on_mnt4_753::EdwardsAffine`. pub type EdwardsVar = AffineVar<EdwardsParameters, FqVar>; #[test]
M r1cs-std/src/instantiated/ed_on_mnt4_753/fields.rs → r1cs-std/src/instantiated/ed_on_mnt4_753/fields.rs

@@ -1,6 +1,7 @@

use crate::fields::fp::FpVar; use algebra::ed_on_mnt4_753::fq::Fq; +/// A variable that is the R1CS equivalent of `algebra::ed_on_mnt4_753::Fq`. pub type FqVar = FpVar<Fq>; #[test]
M r1cs-std/src/instantiated/mnt4_298/curves.rs → r1cs-std/src/instantiated/mnt4_298/curves.rs

@@ -1,10 +1,16 @@

use crate::groups::mnt4; use algebra::mnt4_298::Parameters; +/// An element of G1 in the MNT4-298 bilinear group. pub type G1Var = mnt4::G1Var<Parameters>; +/// An element of G2 in the MNT4-298 bilinear group. pub type G2Var = mnt4::G2Var<Parameters>; +/// Represents the cached precomputation that can be performed on a G1 element +/// which enables speeding up pairing computation. pub type G1PreparedVar = mnt4::G1PreparedVar<Parameters>; +/// Represents the cached precomputation that can be performed on a G2 element +/// which enables speeding up pairing computation. pub type G2PreparedVar = mnt4::G2PreparedVar<Parameters>; #[test]
M r1cs-std/src/instantiated/mnt4_298/fields.rs → r1cs-std/src/instantiated/mnt4_298/fields.rs

@@ -2,8 +2,11 @@ use algebra::mnt4_298::{Fq, Fq2Parameters, Fq4Parameters};

use crate::fields::{fp::FpVar, fp2::Fp2Var, fp4::Fp4Var}; +/// A variable that is the R1CS equivalent of `algebra::mnt4_298::Fq`. pub type FqVar = FpVar<Fq>; +/// A variable that is the R1CS equivalent of `algebra::mnt4_298::Fq2`. pub type Fq2Var = Fp2Var<Fq2Parameters>; +/// A variable that is the R1CS equivalent of `algebra::mnt4_298::Fq4`. pub type Fq4Var = Fp4Var<Fq4Parameters>; #[test]
M r1cs-std/src/instantiated/mnt4_298/pairing.rs → r1cs-std/src/instantiated/mnt4_298/pairing.rs

@@ -1,5 +1,6 @@

use algebra::mnt4_298::Parameters; +/// Specifies the constraints for computing a pairing in the MNT4-298 bilinear group. pub type PairingVar = crate::pairing::mnt4::PairingVar<Parameters>; #[test]
M r1cs-std/src/instantiated/mnt4_753/curves.rs → r1cs-std/src/instantiated/mnt4_753/curves.rs

@@ -1,10 +1,16 @@

use crate::groups::mnt4; use algebra::mnt4_753::Parameters; +/// An element of G1 in the MNT4-753 bilinear group. pub type G1Var = mnt4::G1Var<Parameters>; +/// An element of G2 in the MNT4-753 bilinear group. pub type G2Var = mnt4::G2Var<Parameters>; +/// Represents the cached precomputation that can be performed on a G1 element +/// which enables speeding up pairing computation. pub type G1PreparedVar = mnt4::G1PreparedVar<Parameters>; +/// Represents the cached precomputation that can be performed on a G2 element +/// which enables speeding up pairing computation. pub type G2PreparedVar = mnt4::G2PreparedVar<Parameters>; #[test]
M r1cs-std/src/instantiated/mnt4_753/fields.rs → r1cs-std/src/instantiated/mnt4_753/fields.rs

@@ -2,8 +2,11 @@ use algebra::mnt4_753::{Fq, Fq2Parameters, Fq4Parameters};

use crate::fields::{fp::FpVar, fp2::Fp2Var, fp4::Fp4Var}; +/// A variable that is the R1CS equivalent of `algebra::mnt4_753::Fq`. pub type FqVar = FpVar<Fq>; +/// A variable that is the R1CS equivalent of `algebra::mnt4_753::Fq2`. pub type Fq2Var = Fp2Var<Fq2Parameters>; +/// A variable that is the R1CS equivalent of `algebra::mnt4_753::Fq4`. pub type Fq4Var = Fp4Var<Fq4Parameters>; #[test]
M r1cs-std/src/instantiated/mnt4_753/pairing.rs → r1cs-std/src/instantiated/mnt4_753/pairing.rs

@@ -1,5 +1,6 @@

use algebra::mnt4_753::Parameters; +/// Specifies the constraints for computing a pairing in the MNT4-753 bilinear group. pub type PairingVar = crate::pairing::mnt4::PairingVar<Parameters>; #[test]
M r1cs-std/src/instantiated/mnt6_298/curves.rs → r1cs-std/src/instantiated/mnt6_298/curves.rs

@@ -1,10 +1,16 @@

use crate::groups::mnt6; use algebra::mnt6_298::Parameters; +/// An element of G1 in the MNT6-298 bilinear group. pub type G1Var = mnt6::G1Var<Parameters>; +/// An element of G2 in the MNT6-298 bilinear group. pub type G2Var = mnt6::G2Var<Parameters>; +/// Represents the cached precomputation that can be performed on a G1 element +/// which enables speeding up pairing computation. pub type G1PreparedVar = mnt6::G1PreparedVar<Parameters>; +/// Represents the cached precomputation that can be performed on a G2 element +/// which enables speeding up pairing computation. pub type G2PreparedVar = mnt6::G2PreparedVar<Parameters>; #[test]
M r1cs-std/src/instantiated/mnt6_298/fields.rs → r1cs-std/src/instantiated/mnt6_298/fields.rs

@@ -2,8 +2,11 @@ use algebra::mnt6_298::{Fq, Fq3Parameters, Fq6Parameters};

use crate::fields::{fp::FpVar, fp3::Fp3Var, fp6_2over3::Fp6Var}; +/// A variable that is the R1CS equivalent of `algebra::mnt4_298::Fq`. pub type FqVar = FpVar<Fq>; +/// A variable that is the R1CS equivalent of `algebra::mnt4_298::Fq3`. pub type Fq3Var = Fp3Var<Fq3Parameters>; +/// A variable that is the R1CS equivalent of `algebra::mnt4_298::Fq6`. pub type Fq6Var = Fp6Var<Fq6Parameters>; #[test]
M r1cs-std/src/instantiated/mnt6_298/pairing.rs → r1cs-std/src/instantiated/mnt6_298/pairing.rs

@@ -1,5 +1,6 @@

use algebra::mnt6_298::Parameters; +/// Specifies the constraints for computing a pairing in the MNT6-298 bilinear group. pub type PairingVar = crate::pairing::mnt6::PairingVar<Parameters>; #[test]
M r1cs-std/src/instantiated/mnt6_753/curves.rs → r1cs-std/src/instantiated/mnt6_753/curves.rs

@@ -1,10 +1,16 @@

use crate::groups::mnt6; use algebra::mnt6_753::Parameters; +/// An element of G1 in the MNT6-753 bilinear group. pub type G1Var = mnt6::G1Var<Parameters>; +/// An element of G2 in the MNT6-753 bilinear group. pub type G2Var = mnt6::G2Var<Parameters>; +/// Represents the cached precomputation that can be performed on a G1 element +/// which enables speeding up pairing computation. pub type G1PreparedVar = mnt6::G1PreparedVar<Parameters>; +/// Represents the cached precomputation that can be performed on a G2 element +/// which enables speeding up pairing computation. pub type G2PreparedVar = mnt6::G2PreparedVar<Parameters>; #[test]
M r1cs-std/src/instantiated/mnt6_753/fields.rs → r1cs-std/src/instantiated/mnt6_753/fields.rs

@@ -2,8 +2,11 @@ use algebra::mnt6_753::{Fq, Fq3Parameters, Fq6Parameters};

use crate::fields::{fp::FpVar, fp3::Fp3Var, fp6_2over3::Fp6Var}; +/// A variable that is the R1CS equivalent of `algebra::mnt4_753::Fq`. pub type FqVar = FpVar<Fq>; +/// A variable that is the R1CS equivalent of `algebra::mnt4_753::Fq3`. pub type Fq3Var = Fp3Var<Fq3Parameters>; +/// A variable that is the R1CS equivalent of `algebra::mnt4_753::Fq6`. pub type Fq6Var = Fp6Var<Fq6Parameters>; #[test]
M r1cs-std/src/instantiated/mnt6_753/pairing.rs → r1cs-std/src/instantiated/mnt6_753/pairing.rs

@@ -1,5 +1,6 @@

use algebra::mnt6_753::Parameters; +/// Specifies the constraints for computing a pairing in the MNT6-753 bilinear group. pub type PairingVar = crate::pairing::mnt6::PairingVar<Parameters>; #[test]
M r1cs-std/src/instantiated/mod.rs → r1cs-std/src/instantiated/mod.rs

@@ -1,38 +1,50 @@

+/// This module implements the R1CS equivalent of `algebra::bls12_377`. #[cfg(feature = "bls12_377")] pub mod bls12_377; +/// This module implements the R1CS equivalent of `algebra::ed_on_bls12_377`. #[cfg(feature = "ed_on_bls12_377")] pub mod ed_on_bls12_377; +/// This module implements the R1CS equivalent of `algebra::ed_on_cp6_782`. #[cfg(feature = "ed_on_cp6_782")] pub mod ed_on_cp6_782; #[cfg(all(not(feature = "ed_on_cp6_782"), feature = "ed_on_bw6_761"))] pub(crate) mod ed_on_cp6_782; +/// This module implements the R1CS equivalent of `algebra::ed_on_bw6_761`. #[cfg(feature = "ed_on_bw6_761")] pub mod ed_on_bw6_761; +/// This module implements the R1CS equivalent of `algebra::ed_on_bn254`. #[cfg(feature = "ed_on_bn254")] pub mod ed_on_bn254; +/// This module implements the R1CS equivalent of `algebra::ed_on_bls12_381`. #[cfg(feature = "ed_on_bls12_381")] pub mod ed_on_bls12_381; +/// This module implements the R1CS equivalent of `algebra::ed_on_mnt4_298`. #[cfg(feature = "ed_on_mnt4_298")] pub mod ed_on_mnt4_298; +/// This module implements the R1CS equivalent of `algebra::ed_on_mnt4_753`. #[cfg(feature = "ed_on_mnt4_753")] pub mod ed_on_mnt4_753; +/// This module implements the R1CS equivalent of `algebra::mnt4_298`. #[cfg(feature = "mnt4_298")] pub mod mnt4_298; +/// This module implements the R1CS equivalent of `algebra::mnt4_753`. #[cfg(feature = "mnt4_753")] pub mod mnt4_753; +/// This module implements the R1CS equivalent of `algebra::mnt6_298`. #[cfg(feature = "mnt6_298")] pub mod mnt6_298; +/// This module implements the R1CS equivalent of `algebra::mnt6_753`. #[cfg(feature = "mnt6_753")] pub mod mnt6_753;
M r1cs-std/src/lib.rs → r1cs-std/src/lib.rs

@@ -1,3 +1,5 @@

+//! This crate implements common "gadgets" that make +//! programming rank-1 constraint systems easier. #![cfg_attr(not(feature = "std"), no_std)] #![deny(unused_import_braces, unused_qualifications, trivial_casts)] #![deny(trivial_numeric_casts, variant_size_differences, unreachable_pub)]

@@ -5,21 +7,27 @@ #![deny(non_shorthand_field_patterns, unused_attributes, unused_imports)]

#![deny(unused_extern_crates, renamed_and_removed_lints, unused_allocation)] #![deny(unused_comparisons, bare_trait_objects, const_err, unused_must_use)] #![deny(unused_mut, unused_unsafe, private_in_public, unsafe_code)] +#![deny(missing_docs)] #![forbid(unsafe_code)] +#[doc(hidden)] #[cfg(all(test, not(feature = "std")))] #[macro_use] extern crate std; +#[doc(hidden)] #[cfg(not(feature = "std"))] extern crate alloc as ralloc; +#[doc(hidden)] #[macro_use] extern crate algebra; +#[doc(hidden)] #[macro_use] extern crate derivative; +/// Some utility macros for making downstream impls easier. #[macro_use] pub mod macros;

@@ -31,11 +39,14 @@ use std::vec::Vec;

use algebra::prelude::Field; +/// This module implements gadgets related to bit manipulation, such as `Boolean` and `UInt`s. pub mod bits; pub use self::bits::*; +/// This module implements gadgets related to field arithmetic. pub mod fields; +/// This module implements gadgets related to group arithmetic, and specifically elliptic curve arithmetic. pub mod groups; mod instantiated;

@@ -76,12 +87,17 @@

#[cfg(feature = "mnt6_753")] pub use instantiated::mnt6_753; +/// This module implements gadgets related to computing pairings in bilinear groups. pub mod pairing; +/// This module describes a trait for allocating new variables in a constraint system. pub mod alloc; +/// This module describes a trait for checking equality of variables. pub mod eq; +/// This module describes traits for conditionally selecting a variable from a list of variables. pub mod select; +#[allow(missing_docs)] pub mod prelude { pub use crate::{ alloc::*,

@@ -96,7 +112,9 @@ R1CSVar,

}; } +/// This trait describes some core functionality that is common to high-level variables, such as `Boolean`s, `FieldVar`s, `GroupVar`s, etc. pub trait R1CSVar<F: Field> { + /// The type of the "native" value that `Self` represents in the constraint system. type Value: core::fmt::Debug + Eq + Clone; /// Returns the underlying `ConstraintSystemRef`.

@@ -145,7 +163,9 @@ (*self).value()

} } +/// A utility trait to convert `Self` to `Result<T, SynthesisErrorA`.> pub trait Assignment<T> { + /// Converts `self` to `Result`. fn get(self) -> Result<T, r1cs_core::SynthesisError>; }
M r1cs-std/src/macros.rs → r1cs-std/src/macros.rs

@@ -1,5 +1,7 @@

#[allow(unused_braces)] -// Implements arithmetic operations with generic bounds. +/// Implements arithmetic traits (eg: `Add`, `Sub`, `Mul`) for the given type using the impl in `$impl`. +/// +/// Used primarily for implementing these traits for `FieldVar`s and `GroupVar`s. #[macro_export] macro_rules! impl_ops { (

@@ -17,6 +19,11 @@ impl_bounded_ops!($type, $native, $trait, $fn, $assign_trait, $assign_fn, $impl, $constant_impl, ($($args)+), );

}; } +/// Implements arithmetic traits (eg: `Add`, `Sub`, `Mul`) for the given type using the impl in `$impl`. +/// +/// Used primarily for implementing these traits for `FieldVar`s and `GroupVar`s. +/// +/// When compared to `impl_ops`, this macro allows specifying additional trait bounds. #[macro_export] macro_rules! impl_bounded_ops { (
M r1cs-std/src/pairing/bls12/mod.rs → r1cs-std/src/pairing/bls12/mod.rs

@@ -12,6 +12,7 @@ fields::BitIteratorBE,

}; use core::marker::PhantomData; +/// Specifies the constraints for computing a pairing in a BLS12 bilinear group. pub struct PairingVar<P: Bls12Parameters>(PhantomData<P>); type Fp2V<P> = Fp2Var<<P as Bls12Parameters>::Fp2Params>;
M r1cs-std/src/pairing/mnt4/mod.rs → r1cs-std/src/pairing/mnt4/mod.rs

@@ -15,10 +15,12 @@ fields::BitIteratorBE,

}; use core::marker::PhantomData; +/// Specifies the constraints for computing a pairing in a MNT4 bilinear group. pub struct PairingVar<P: MNT4Parameters>(PhantomData<P>); type Fp2G<P> = Fp2Var<<P as MNT4Parameters>::Fp2Params>; type Fp4G<P> = Fp4Var<<P as MNT4Parameters>::Fp4Params>; +/// A variable corresponding to `algebra_core::mnt4::GT`. pub type GTVar<P> = Fp4G<P>; impl<P: MNT4Parameters> PairingVar<P> {

@@ -92,7 +94,7 @@ Ok((r2, coeff))

} #[tracing::instrument(target = "r1cs", skip(p, q))] - pub fn ate_miller_loop( + pub(crate) fn ate_miller_loop( p: &G1PreparedVar<P>, q: &G2PreparedVar<P>, ) -> Result<Fp4G<P>, SynthesisError> {

@@ -142,7 +144,7 @@ Ok(f)

} #[tracing::instrument(target = "r1cs", skip(value))] - pub fn final_exponentiation(value: &Fp4G<P>) -> Result<GTVar<P>, SynthesisError> { + pub(crate) fn final_exponentiation(value: &Fp4G<P>) -> Result<GTVar<P>, SynthesisError> { let value_inv = value.inverse()?; let value_to_first_chunk = Self::final_exponentiation_first_chunk(value, &value_inv)?; let value_inv_to_first_chunk = Self::final_exponentiation_first_chunk(&value_inv, value)?;
M r1cs-std/src/pairing/mnt6/mod.rs → r1cs-std/src/pairing/mnt6/mod.rs

@@ -15,10 +15,12 @@ fields::BitIteratorBE,

}; use core::marker::PhantomData; +/// Specifies the constraints for computing a pairing in a MNT6 bilinear group. pub struct PairingVar<P: MNT6Parameters>(PhantomData<P>); type Fp3G<P> = Fp3Var<<P as MNT6Parameters>::Fp3Params>; type Fp6G<P> = Fp6Var<<P as MNT6Parameters>::Fp6Params>; +/// A variable corresponding to `algebra_core::mnt6::GT`. pub type GTVar<P> = Fp6G<P>; impl<P: MNT6Parameters> PairingVar<P> {

@@ -87,7 +89,7 @@ Ok((r2, coeff))

} #[tracing::instrument(target = "r1cs", skip(p, q))] - pub fn ate_miller_loop( + pub(crate) fn ate_miller_loop( p: &G1PreparedVar<P>, q: &G2PreparedVar<P>, ) -> Result<Fp6G<P>, SynthesisError> {

@@ -138,7 +140,7 @@ Ok(f)

} #[tracing::instrument(target = "r1cs")] - pub fn final_exponentiation(value: &Fp6G<P>) -> Result<GTVar<P>, SynthesisError> { + pub(crate) fn final_exponentiation(value: &Fp6G<P>) -> Result<GTVar<P>, SynthesisError> { let value_inv = value.inverse()?; let value_to_first_chunk = Self::final_exponentiation_first_chunk(value, &value_inv)?; let value_inv_to_first_chunk = Self::final_exponentiation_first_chunk(&value_inv, value)?;
M r1cs-std/src/pairing/mod.rs → r1cs-std/src/pairing/mod.rs

@@ -3,36 +3,55 @@ use algebra::{Field, PairingEngine};

use core::fmt::Debug; use r1cs_core::SynthesisError; +/// This module implements pairings for BLS12 bilinear groups. pub mod bls12; +/// This module implements pairings for MNT4 bilinear groups. pub mod mnt4; +/// This module implements pairings for MNT6 bilinear groups. pub mod mnt6; +/// Specifies the constraints for computing a pairing in the yybilinear group `E`. pub trait PairingVar<E: PairingEngine, ConstraintF: Field = <E as PairingEngine>::Fq> { + /// An variable representing an element of `G1`. + /// This is the R1CS equivalent of `E::G1Projective`. type G1Var: CurveVar<E::G1Projective, ConstraintF> + AllocVar<E::G1Projective, ConstraintF> + AllocVar<E::G1Affine, ConstraintF>; + + /// An variable representing an element of `G2`. + /// This is the R1CS equivalent of `E::G2Projective`. type G2Var: CurveVar<E::G2Projective, ConstraintF> + AllocVar<E::G2Projective, ConstraintF> + AllocVar<E::G2Affine, ConstraintF>; + /// An variable representing an element of `GT`. + /// This is the R1CS equivalent of `E::GT`. type GTVar: FieldVar<E::Fqk, ConstraintF>; + /// An variable representing cached precomputation that can speed up pairings computations. + /// This is the R1CS equivalent of `E::G1Prepared`. type G1PreparedVar: ToBytesGadget<ConstraintF> + AllocVar<E::G1Prepared, ConstraintF> + Clone + Debug; + /// An variable representing cached precomputation that can speed up pairings computations. + /// This is the R1CS equivalent of `E::G2Prepared`. type G2PreparedVar: ToBytesGadget<ConstraintF> + AllocVar<E::G2Prepared, ConstraintF> + Clone + Debug; + /// Computes a multi-miller loop between elements + /// of `p` and `q`. fn miller_loop( p: &[Self::G1PreparedVar], q: &[Self::G2PreparedVar], ) -> Result<Self::GTVar, SynthesisError>; + /// Computes a final exponentiation over `p`. fn final_exponentiation(p: &Self::GTVar) -> Result<Self::GTVar, SynthesisError>; + /// Computes a pairing over `p` and `q`. #[tracing::instrument(target = "r1cs")] fn pairing( p: Self::G1PreparedVar,

@@ -42,7 +61,7 @@ let tmp = Self::miller_loop(&[p], &[q])?;

Self::final_exponentiation(&tmp) } - /// Computes a product of pairings. + /// Computes a product of pairings over the elements in `p` and `q`. #[must_use] #[tracing::instrument(target = "r1cs")] fn product_of_pairings(

@@ -53,8 +72,10 @@ let miller_result = Self::miller_loop(p, q)?;

Self::final_exponentiation(&miller_result) } + /// Performs the precomputation to generate `Self::G1PreparedVar`. fn prepare_g1(q: &Self::G1Var) -> Result<Self::G1PreparedVar, SynthesisError>; + /// Performs the precomputation to generate `Self::G2PreparedVar`. fn prepare_g2(q: &Self::G2Var) -> Result<Self::G2PreparedVar, SynthesisError>; }
M r1cs-std/src/select.rs → r1cs-std/src/select.rs

@@ -2,11 +2,16 @@ use crate::prelude::*;

use algebra::Field; use r1cs_core::SynthesisError; -/// If condition is `true`, return `true_value`; else, select `false_value`. +/// Generates constraints for selecting between one of two values. pub trait CondSelectGadget<ConstraintF: Field> where Self: Sized, { + /// If `cond == &Boolean::TRUE`, then this returns `true_value`; else, returns `false_value`. + /// + /// # Note + /// `Self::conditionally_select(cond, true_value, false_value)?` can be more succinctly written as + /// `cond.select(&true_value, &false_value)?`. fn conditionally_select( cond: &Boolean<ConstraintF>, true_value: &Self,

@@ -14,12 +19,23 @@ false_value: &Self,

) -> Result<Self, SynthesisError>; } -/// Uses two bits to perform a lookup into a table +/// Performs a lookup in a 4-element table using two bits. pub trait TwoBitLookupGadget<ConstraintF: Field> where Self: Sized, { + /// The type of values being looked up. type TableConstant; + + /// Interprets the slice `bits` as a two-bit integer `b = bits[0] + (bits[1] << 1)`, + /// and then outputs `constants[b]`. + /// + /// For example, if `bits == [0, 1]`, and `constants == [0, 1, 2, 3]`, this method + /// should output a variable corresponding to `2`. + /// + /// # Panics + /// + /// This method panics if `bits.len() != 2` or `constants.len() != 4`. fn two_bit_lookup( bits: &[Boolean<ConstraintF>], constants: &[Self::TableConstant],

@@ -27,12 +43,25 @@ ) -> Result<Self, SynthesisError>;

} /// Uses three bits to perform a lookup into a table, where the last bit -/// performs negation +/// conditionally negates the looked-up value. pub trait ThreeBitCondNegLookupGadget<ConstraintF: Field> where Self: Sized, { + /// The type of values being looked up. type TableConstant; + + /// Interprets the slice `bits` as a two-bit integer `b = bits[0] + (bits[1] << 1)`, + /// and then outputs `constants[b] * c`, where `c = if bits[2] { -1 } else { 1 };`. + /// + /// That is, `bits[2]` conditionally negates the looked-up value. + /// + /// For example, if `bits == [1, 0, 1]`, and `constants == [0, 1, 2, 3]`, this method + /// should output a variable corresponding to `-1`. + /// + /// # Panics + /// + /// This method panics if `bits.len() != 3` or `constants.len() != 4`. fn three_bit_cond_neg_lookup( bits: &[Boolean<ConstraintF>], b0b1: &Boolean<ConstraintF>,