From 370fbcdd3b87ef46a726b0c25c78d7e50c318015 Mon Sep 17 00:00:00 2001 From: Pratyush Mishra Date: Thu, 10 Sep 2020 01:16:01 -0700 Subject: [PATCH] Document `r1cs-std` --- r1cs-std/src/alloc.rs | 19 +- r1cs-std/src/bits/boolean.rs | 51 ++-- r1cs-std/src/bits/mod.rs | 12 +- r1cs-std/src/bits/uint.rs | 48 +++- r1cs-std/src/bits/uint8.rs | 15 +- r1cs-std/src/eq.rs | 31 ++- r1cs-std/src/fields/cubic_extension.rs | 15 +- r1cs-std/src/fields/fp/cmp.rs | 2 +- r1cs-std/src/fields/fp/mod.rs | 76 +++++- r1cs-std/src/fields/fp12.rs | 10 +- r1cs-std/src/fields/fp2.rs | 2 + r1cs-std/src/fields/fp3.rs | 2 + r1cs-std/src/fields/fp4.rs | 3 + r1cs-std/src/fields/fp6_2over3.rs | 3 + r1cs-std/src/fields/fp6_3over2.rs | 6 +- r1cs-std/src/fields/mod.rs | 52 +++- r1cs-std/src/fields/quadratic_extension.rs | 13 +- r1cs-std/src/groups/curves/mod.rs | 7 + .../curves/short_weierstrass/bls12/mod.rs | 15 ++ .../curves/short_weierstrass/mnt4/mod.rs | 25 ++ .../curves/short_weierstrass/mnt6/mod.rs | 26 ++ .../groups/curves/short_weierstrass/mod.rs | 12 + .../src/groups/curves/twisted_edwards/mod.rs | 227 +++++++++--------- r1cs-std/src/groups/mod.rs | 35 ++- r1cs-std/src/instantiated/bls12_377/curves.rs | 6 + r1cs-std/src/instantiated/bls12_377/fields.rs | 4 + .../src/instantiated/bls12_377/pairing.rs | 1 + .../instantiated/ed_on_bls12_377/curves.rs | 1 + .../instantiated/ed_on_bls12_377/fields.rs | 1 + .../instantiated/ed_on_bls12_381/curves.rs | 1 + .../instantiated/ed_on_bls12_381/fields.rs | 1 + .../src/instantiated/ed_on_bn254/curves.rs | 1 + .../src/instantiated/ed_on_bn254/fields.rs | 1 + .../src/instantiated/ed_on_bw6_761/curves.rs | 11 - .../src/instantiated/ed_on_bw6_761/fields.rs | 9 - .../src/instantiated/ed_on_cp6_782/curves.rs | 1 + .../src/instantiated/ed_on_cp6_782/fields.rs | 1 + .../src/instantiated/ed_on_mnt4_298/curves.rs | 1 + .../src/instantiated/ed_on_mnt4_298/fields.rs | 1 + .../src/instantiated/ed_on_mnt4_753/curves.rs | 1 + .../src/instantiated/ed_on_mnt4_753/fields.rs | 1 + r1cs-std/src/instantiated/mnt4_298/curves.rs | 6 + r1cs-std/src/instantiated/mnt4_298/fields.rs | 3 + r1cs-std/src/instantiated/mnt4_298/pairing.rs | 1 + r1cs-std/src/instantiated/mnt4_753/curves.rs | 6 + r1cs-std/src/instantiated/mnt4_753/fields.rs | 3 + r1cs-std/src/instantiated/mnt4_753/pairing.rs | 1 + r1cs-std/src/instantiated/mnt6_298/curves.rs | 6 + r1cs-std/src/instantiated/mnt6_298/fields.rs | 3 + r1cs-std/src/instantiated/mnt6_298/pairing.rs | 1 + r1cs-std/src/instantiated/mnt6_753/curves.rs | 6 + r1cs-std/src/instantiated/mnt6_753/fields.rs | 3 + r1cs-std/src/instantiated/mnt6_753/pairing.rs | 1 + r1cs-std/src/instantiated/mod.rs | 12 + r1cs-std/src/lib.rs | 20 ++ r1cs-std/src/macros.rs | 9 +- r1cs-std/src/pairing/bls12/mod.rs | 1 + r1cs-std/src/pairing/mnt4/mod.rs | 6 +- r1cs-std/src/pairing/mnt6/mod.rs | 6 +- r1cs-std/src/pairing/mod.rs | 23 +- r1cs-std/src/select.rs | 35 ++- 61 files changed, 691 insertions(+), 211 deletions(-) delete mode 100644 r1cs-std/src/instantiated/ed_on_bw6_761/curves.rs delete mode 100644 r1cs-std/src/instantiated/ed_on_bw6_761/fields.rs diff --git a/r1cs-std/src/alloc.rs b/r1cs-std/src/alloc.rs index 1ffc6df..f07b29e 100644 --- a/r1cs-std/src/alloc.rs +++ b/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 @@ impl AllocationMode { } } +/// Specifies how variables of type `Self` should be allocated in a `ConstraintSystem`. pub trait AllocVar 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>( cs: impl Into>, f: impl FnOnce() -> Result, mode: AllocationMode, ) -> Result; + /// Allocates a new constant of type `Self` in the `ConstraintSystem`. #[tracing::instrument(target = "r1cs", skip(cs, t))] fn new_constant( cs: impl Into>, @@ -42,6 +57,7 @@ where 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>( cs: impl Into>, @@ -50,6 +66,7 @@ where 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>( cs: impl Into>, diff --git a/r1cs-std/src/bits/boolean.rs b/r1cs-std/src/bits/boolean.rs index df0e88b..f72ca36 100644 --- a/r1cs-std/src/bits/boolean.rs +++ b/r1cs-std/src/bits/boolean.rs @@ -254,6 +254,10 @@ impl Boolean { /// 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 { match self { Boolean::Constant(false) => lc!(), @@ -263,7 +267,9 @@ impl Boolean { } } - /// 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 { let mut input_bits = vec![]; for input_byte in values { @@ -274,12 +280,12 @@ impl Boolean { 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 Boolean { } impl Boolean { - /// 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 { + pub fn xor<'a>(&'a self, other: &'a Self) -> Result { 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 @@ impl Boolean { } } - /// 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 { + pub fn or<'a>(&'a self, other: &'a Self) -> Result { 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 @@ impl Boolean { } } - /// 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 { + pub fn and<'a>(&'a self, other: &'a Self) -> Result { 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 @@ impl Boolean { } } + /// Outputs `bits[0] & bits[1] & ... & bits.last().unwrap()`. #[tracing::instrument(target = "r1cs")] pub fn kary_and(bits: &[Self]) -> Result { assert!(!bits.is_empty()); @@ -354,6 +370,7 @@ impl Boolean { 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 { assert!(!bits.is_empty()); @@ -369,12 +386,15 @@ impl Boolean { 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 { 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 @@ impl Boolean { /// 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 @@ impl Boolean { 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>( &self, diff --git a/r1cs-std/src/bits/mod.rs b/r1cs-std/src/bits/mod.rs index a0d03c6..179b36a 100644 --- a/r1cs-std/src/bits/mod.rs +++ b/r1cs-std/src/bits/mod.rs @@ -5,15 +5,20 @@ use crate::{ 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 { /// Outputs the canonical little-endian bit-wise representation of `self`. /// @@ -70,6 +75,7 @@ where } } +/// Specifies constraints for conversion to a little-endian byte representation of `self`. pub trait ToBytesGadget { /// Outputs a canonical, little-endian, byte decomposition of `self`. /// diff --git a/r1cs-std/src/bits/uint.rs b/r1cs-std/src/bits/uint.rs index e4dba08..920f235 100644 --- a/r1cs-std/src/bits/uint.rs +++ b/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 @@ macro_rules! make_uint { 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 { // Least significant bit first @@ -46,7 +57,11 @@ macro_rules! make_uint { } impl $name { - /// 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 @@ macro_rules! make_uint { } } - /// 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> { 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]) -> Self { assert_eq!(bits.len(), $size); @@ -105,6 +125,7 @@ macro_rules! make_uint { 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 @@ macro_rules! make_uint { } } - /// 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 { let new_value = match (self.value, other.value) { (Some(a), Some(b)) => Some(a ^ b), @@ -147,8 +171,10 @@ macro_rules! make_uint { }) } - /// 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 where F: PrimeField, diff --git a/r1cs-std/src/bits/uint8.rs b/r1cs-std/src/bits/uint8.rs index ccc8ea4..28b22f6 100644 --- a/r1cs-std/src/bits/uint8.rs +++ b/r1cs-std/src/bits/uint8.rs @@ -64,6 +64,7 @@ impl UInt8 { } } + /// Allocates a slice of `u8`'s as private witnesses. pub fn new_witness_vec( cs: impl Into>, values: &[impl Into> + Copy], @@ -78,10 +79,13 @@ impl UInt8 { 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` 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>, values: &[u8], @@ -134,7 +138,10 @@ impl UInt8 { 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 { let new_value = match (self.value, other.value) { diff --git a/r1cs-std/src/eq.rs b/r1cs-std/src/eq.rs index 364b5e2..8c6db70 100644 --- a/r1cs-std/src/eq.rs +++ b/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 { /// Output a `Boolean` value representing whether `self.value() == other.value()`. fn is_eq(&self, other: &Self) -> Result, 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, 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 @@ pub trait EqGadget { } /// 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 @@ pub trait EqGadget { .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)) diff --git a/r1cs-std/src/fields/cubic_extension.rs b/r1cs-std/src/fields/cubic_extension.rs index a3edb4f..717c13a 100644 --- a/r1cs-std/src/fields/cubic_extension.rs +++ b/r1cs-std/src/fields/cubic_extension.rs @@ -12,6 +12,8 @@ use crate::{ 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, P: CubicEx 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

, } +/// This trait describes parameters that are used to implement arithmetic for `CubicExtVar`. pub trait CubicExtVarParams>: 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, P: CubicExtVarParams> Cu 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 @@ where } } - /// 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 { 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 @@ where 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); diff --git a/r1cs-std/src/fields/fp/cmp.rs b/r1cs-std/src/fields/fp/cmp.rs index 69aa615..5c61a11 100644 --- a/r1cs-std/src/fields/fp/cmp.rs +++ b/r1cs-std/src/fields/fp/cmp.rs @@ -95,7 +95,7 @@ impl FpVar { 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, diff --git a/r1cs-std/src/fields/fp/mod.rs b/r1cs-std/src/fields/fp/mod.rs index f11177c..cc5cfd9 100644 --- a/r1cs-std/src/fields/fp/mod.rs +++ b/r1cs-std/src/fields/fp/mod.rs @@ -6,17 +6,23 @@ use core::borrow::Borrow; 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 { pub(crate) value: Option, + /// The allocated variable corresponding to `self` in `self.cs`. pub variable: Variable, + /// The constraint system that `self` was allocated in. pub cs: ConstraintSystemRef, } impl AllocatedFp { + /// Constructs a new `AllocatedFp` from a (optional) value, a low-level Variable, + /// and a `ConstraintSystemRef`. pub fn new(value: Option, variable: Variable, cs: ConstraintSystemRef) -> Self { Self { value, @@ -26,11 +32,14 @@ impl AllocatedFp { } } -/// Represent variables corresponding to the field `F`. +/// Represent variables corresponding to a field element in `F`. #[derive(Clone, Debug)] #[must_use] pub enum FpVar { + /// 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), } @@ -79,6 +88,7 @@ impl<'a, F: PrimeField> FieldOpsBounds<'a, F, Self> for FpVar {} impl<'a, F: PrimeField> FieldOpsBounds<'a, F, FpVar> for &'a FpVar {} impl AllocatedFp { + /// Constructs `Self` from a `Boolean`: if `other` is false, this outputs `zero`, else it outputs `one`. pub fn from(other: Boolean) -> Self { if let Some(cs) = other.cs() { let variable = cs.new_lc(other.lc()).unwrap(); @@ -88,10 +98,15 @@ impl AllocatedFp { } } + /// Returns the value assigned to `self` in the underlying constraint system + /// (if a value was assigned). pub fn value(&self) -> Result { 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 @@ impl AllocatedFp { 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 @@ impl AllocatedFp { 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 @@ impl AllocatedFp { 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 @@ impl AllocatedFp { } } + /// 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 @@ impl AllocatedFp { } } + /// Output `self + self` + /// + /// This does not create any constraints. #[tracing::instrument(target = "r1cs")] pub fn double(&self) -> Result { let value = self.value.map(|val| val.double()); @@ -173,6 +206,9 @@ impl AllocatedFp { 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 @@ impl AllocatedFp { 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 @@ impl AllocatedFp { self } + /// Outputs `self * self` + /// + /// This requires *one* constraint. #[tracing::instrument(target = "r1cs")] pub fn square(&self) -> Result { Ok(self.mul(self)) } + /// Outputs `result` such that `result * self = 1`. + /// + /// This requires *one* constraint. #[tracing::instrument(target = "r1cs")] pub fn inverse(&self) -> Result { let inverse = Self::new_witness(self.cs.clone(), || { @@ -206,11 +251,15 @@ impl AllocatedFp { Ok(inverse) } + /// This is a no-op for prime fields. #[tracing::instrument(target = "r1cs")] pub fn frobenius_map(&self, _: usize) -> Result { 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 @@ impl AllocatedFp { ) } + /// 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 @@ impl AllocatedFp { /// 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, SynthesisError> { Ok(self.is_neq(other)?.not()) @@ -241,9 +291,7 @@ impl AllocatedFp { /// 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, SynthesisError> { let is_not_equal = Boolean::new_witness(self.cs.clone(), || { @@ -311,6 +359,9 @@ impl AllocatedFp { 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 @@ impl AllocatedFp { ) } + /// 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 AllocatedFp { impl ToBitsGadget for AllocatedFp { /// 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>, SynthesisError> { let bits = self.to_non_unique_bits_le()?; @@ -405,6 +462,9 @@ impl ToBitsGadget for AllocatedFp { impl ToBytesGadget for AllocatedFp { /// 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>, SynthesisError> { let num_bits = F::BigInt::NUM_LIMBS * 64; diff --git a/r1cs-std/src/fields/fp12.rs b/r1cs-std/src/fields/fp12.rs index 914553c..aa5a95f 100644 --- a/r1cs-std/src/fields/fp12.rs +++ b/r1cs-std/src/fields/fp12.rs @@ -2,6 +2,9 @@ use crate::fields::{fp2::Fp2Var, fp6_3over2::Fp6Var, quadratic_extension::*, Fie 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

`. pub type Fp12Var

= QuadExtVar::Fp6Params>, Fp12ParamsWrapper

>; type Fp2Params

= <

::Fp6Params as Fp6Parameters>::Fp2Params; @@ -15,7 +18,7 @@ impl QuadExtVarParams> for Fp12ParamsWra } impl Fp12Var

{ - /// 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 @@ impl Fp12Var

{ 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 @@ impl Fp12Var

{ Ok(Self::new(new_c0, new_c1)) } + /// Squares `self` when `self` is in the cyclotomic subgroup. pub fn cyclotomic_square(&self) -> Result { if characteristic_square_mod_6_is_one(Fp12::

::characteristic()) { let fp2_nr = ::NONRESIDUE; @@ -132,7 +136,7 @@ impl Fp12Var

{ } } - /// 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]>, diff --git a/r1cs-std/src/fields/fp2.rs b/r1cs-std/src/fields/fp2.rs index 3bf8e45..7a358ad 100644 --- a/r1cs-std/src/fields/fp2.rs +++ b/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

`. pub type Fp2Var

= QuadExtVar::Fp>, Fp2ParamsWrapper

>; impl QuadExtVarParams> for Fp2ParamsWrapper

{ diff --git a/r1cs-std/src/fields/fp3.rs b/r1cs-std/src/fields/fp3.rs index 24f14cc..b2feb39 100644 --- a/r1cs-std/src/fields/fp3.rs +++ b/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

`. pub type Fp3Var

= CubicExtVar::Fp>, Fp3ParamsWrapper

>; impl CubicExtVarParams> for Fp3ParamsWrapper

{ diff --git a/r1cs-std/src/fields/fp4.rs b/r1cs-std/src/fields/fp4.rs index 2f9da2b..e0a82be 100644 --- a/r1cs-std/src/fields/fp4.rs +++ b/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

`. pub type Fp4Var

= QuadExtVar::Fp2Params>, Fp4ParamsWrapper

>; impl QuadExtVarParams> for Fp4ParamsWrapper

{ diff --git a/r1cs-std/src/fields/fp6_2over3.rs b/r1cs-std/src/fields/fp6_2over3.rs index 147e239..8a12aa6 100644 --- a/r1cs-std/src/fields/fp6_2over3.rs +++ b/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

`. pub type Fp6Var

= QuadExtVar::Fp3Params>, Fp6ParamsWrapper

>; impl QuadExtVarParams> for Fp6ParamsWrapper

{ diff --git a/r1cs-std/src/fields/fp6_3over2.rs b/r1cs-std/src/fields/fp6_3over2.rs index 34da0bc..709e33d 100644 --- a/r1cs-std/src/fields/fp6_3over2.rs +++ b/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

`. pub type Fp6Var

= CubicExtVar::Fp2Params>, Fp6ParamsWrapper

>; impl CubicExtVarParams> for Fp6ParamsWrapper

{ @@ -17,6 +20,7 @@ impl CubicExtVarParams> for Fp6ParamsWrap } impl Fp6Var

{ + /// Multiplies `self` by a sparse element which has `c0 == c2 == zero`. pub fn mul_by_0_c1_0(&self, c1: &Fp2Var) -> Result { // Karatsuba multiplication // v0 = a0 * b0 = 0 @@ -44,7 +48,7 @@ impl Fp6Var

{ 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, diff --git a/r1cs-std/src/fields/mod.rs b/r1cs-std/src/fields/mod.rs index 71159c0..1d3d2f9 100644 --- a/r1cs-std/src/fields/mod.rs +++ b/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 @@ pub trait FieldVar: + MulAssign + Debug { + /// Returns the constant `F::zero()`. fn zero() -> Self; + /// Returns a `Boolean` representing whether `self == Self::zero()`. fn is_zero(&self) -> Result, 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, 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 { 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; + /// 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 { 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; - /// 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 { @@ -125,8 +162,10 @@ pub trait FieldVar: Ok(result) } + /// Computes the frobenius map over `self`. fn frobenius_map(&self, power: usize) -> Result; + /// 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 @@ pub trait FieldVar: 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>(&self, exp: S) -> Result { let mut res = Self::one(); for i in BitIteratorBE::without_leading_zeros(exp) { diff --git a/r1cs-std/src/fields/quadratic_extension.rs b/r1cs-std/src/fields/quadratic_extension.rs index de87f74..be29c67 100644 --- a/r1cs-std/src/fields/quadratic_extension.rs +++ b/r1cs-std/src/fields/quadratic_extension.rs @@ -12,6 +12,8 @@ use crate::{ 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, P: QuadExtV 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

, } +/// This trait describes parameters that are used to implement arithmetic for `QuadExtVar`. pub trait QuadExtVarParams>: 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, P: QuadExtVarParams> Qua 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 @@ where } } - /// 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 { 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 @@ where 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); diff --git a/r1cs-std/src/groups/curves/mod.rs b/r1cs-std/src/groups/curves/mod.rs index 11cea99..b0c12e9 100644 --- a/r1cs-std/src/groups/curves/mod.rs +++ b/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; diff --git a/r1cs-std/src/groups/curves/short_weierstrass/bls12/mod.rs b/r1cs-std/src/groups/curves/short_weierstrass/bls12/mod.rs index 0a4a848..384ac76 100644 --- a/r1cs-std/src/groups/curves/short_weierstrass/bls12/mod.rs +++ b/r1cs-std/src/groups/curves/short_weierstrass/bls12/mod.rs @@ -16,19 +16,29 @@ use crate::{ use core::fmt::Debug; +/// Represents a projective point in G1. pub type G1Var

= ProjectiveVar<

::G1Parameters, FpVar<

::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

= AffineVar<

::G1Parameters, FpVar<

::Fp>>; +/// Represents a projective point in G2. pub type G2Var

= ProjectiveVar<

::G2Parameters, Fp2G

>; +/// 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

= AffineVar<

::G2Parameters, Fp2G

>; +/// Represents the cached precomputation that can be performed on a G1 element +/// which enables speeding up pairing computation. #[derive(Derivative)] #[derivative(Clone(bound = "G1Var

: Clone"), Debug(bound = "G1Var

: Debug"))] pub struct G1PreparedVar(pub AffineVar>); impl G1PreparedVar

{ + /// Returns the value assigned to `self` in the underlying constraint system. pub fn value(&self) -> Result, SynthesisError> { let x = self.0.x.value()?; let y = self.0.y.value()?; @@ -37,6 +47,7 @@ impl G1PreparedVar

{ Ok(g.into()) } + /// Constructs `Self` from a `G1Var`. pub fn from_group_var(q: &G1Var

) -> Result { let g = q.to_affine()?; Ok(Self(g)) @@ -90,12 +101,15 @@ impl ToBytesGadget for G1PreparedVar

{ type Fp2G

= Fp2Var<

::Fp2Params>; type LCoeff

= (Fp2G

, Fp2G

); +/// Represents the cached precomputation that can be performed on a G2 element +/// which enables speeding up pairing computation. #[derive(Derivative)] #[derivative( Clone(bound = "Fp2Var: Clone"), Debug(bound = "Fp2Var: Debug") )] pub struct G2PreparedVar { + #[doc(hidden)] pub ell_coeffs: Vec>, } @@ -165,6 +179,7 @@ impl ToBytesGadget for G2PreparedVar

{ } impl G2PreparedVar

{ + /// Constructs `Self` from a `G2Var`. #[tracing::instrument(target = "r1cs")] pub fn from_group_var(q: &G2Var

) -> Result { let q = q.to_affine()?; diff --git a/r1cs-std/src/groups/curves/short_weierstrass/mnt4/mod.rs b/r1cs-std/src/groups/curves/short_weierstrass/mnt4/mod.rs index c8f2445..e78d967 100644 --- a/r1cs-std/src/groups/curves/short_weierstrass/mnt4/mod.rs +++ b/r1cs-std/src/groups/curves/short_weierstrass/mnt4/mod.rs @@ -16,17 +16,25 @@ use crate::{ }; use core::borrow::Borrow; +/// Represents a projective point in G1. pub type G1Var

= ProjectiveVar<

::G1Parameters, FpVar<

::Fp>>; +/// Represents a projective point in G2. pub type G2Var

= ProjectiveVar<

::G2Parameters, Fp2G

>; +/// 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 { + #[doc(hidden)] pub x: FpVar, + #[doc(hidden)] pub y: FpVar, + #[doc(hidden)] pub x_twist: Fp2Var, + #[doc(hidden)] pub y_twist: Fp2Var, } @@ -64,6 +72,7 @@ impl AllocVar, P::Fp> for G1PreparedVar

{ } impl G1PreparedVar

{ + /// Returns the value assigned to `self` in the underlying constraint system. pub fn value(&self) -> Result, SynthesisError> { let (x, y, x_twist, y_twist) = ( self.x.value()?, @@ -79,6 +88,7 @@ impl G1PreparedVar

{ }) } + /// Constructs `Self` from a `G1Var`. #[tracing::instrument(target = "r1cs")] pub fn from_group_var(q: &G1Var

) -> Result { let q = q.to_affine()?; @@ -124,14 +134,22 @@ impl ToBytesGadget for G1PreparedVar

{ type Fp2G

= Fp2Var<

::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 { + #[doc(hidden)] pub x: Fp2Var, + #[doc(hidden)] pub y: Fp2Var, + #[doc(hidden)] pub x_over_twist: Fp2Var, + #[doc(hidden)] pub y_over_twist: Fp2Var, + #[doc(hidden)] pub double_coefficients: Vec>, + #[doc(hidden)] pub addition_coefficients: Vec>, } @@ -225,6 +243,7 @@ impl ToBytesGadget for G2PreparedVar

{ } impl G2PreparedVar

{ + /// Returns the value assigned to `self` in the underlying constraint system. pub fn value(&self) -> Result, SynthesisError> { let x = self.x.value()?; let y = self.y.value()?; @@ -250,6 +269,7 @@ impl G2PreparedVar

{ }) } + /// Constructs `Self` from a `G2Var`. #[tracing::instrument(target = "r1cs")] pub fn from_group_var(q: &G2Var

) -> Result { let twist_inv = P::TWIST.inverse().unwrap(); @@ -320,6 +340,7 @@ impl G2PreparedVar

{ } } +#[doc(hidden)] #[derive(Derivative)] #[derivative(Clone(bound = "P: MNT4Parameters"), Debug(bound = "P: MNT4Parameters"))] pub struct AteDoubleCoefficientsVar { @@ -385,6 +406,7 @@ impl ToBytesGadget for AteDoubleCoefficientsVar

{ } impl AteDoubleCoefficientsVar

{ + /// Returns the value assigned to `self` in the underlying constraint system. pub fn value(&self) -> Result, SynthesisError> { let (c_h, c_4c, c_j, c_l) = ( self.c_l.value()?, @@ -401,6 +423,7 @@ impl AteDoubleCoefficientsVar

{ } } +#[doc(hidden)] #[derive(Derivative)] #[derivative(Clone(bound = "P: MNT4Parameters"), Debug(bound = "P: MNT4Parameters"))] pub struct AteAdditionCoefficientsVar { @@ -451,12 +474,14 @@ impl ToBytesGadget for AteAdditionCoefficientsVar

{ } impl AteAdditionCoefficientsVar

{ + /// Returns the value assigned to `self` in the underlying constraint system. pub fn value(&self) -> Result, 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 { pub x: Fp2Var, pub y: Fp2Var, diff --git a/r1cs-std/src/groups/curves/short_weierstrass/mnt6/mod.rs b/r1cs-std/src/groups/curves/short_weierstrass/mnt6/mod.rs index a0d9616..6562928 100644 --- a/r1cs-std/src/groups/curves/short_weierstrass/mnt6/mod.rs +++ b/r1cs-std/src/groups/curves/short_weierstrass/mnt6/mod.rs @@ -16,21 +16,30 @@ use crate::{ }; use core::borrow::Borrow; +/// Represents a projective point in G1. pub type G1Var

= ProjectiveVar<

::G1Parameters, FpVar<

::Fp>>; +/// Represents a projective point in G2. pub type G2Var

= ProjectiveVar<

::G2Parameters, Fp3G

>; +/// 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 { + #[doc(hidden)] pub x: FpVar, + #[doc(hidden)] pub y: FpVar, + #[doc(hidden)] pub x_twist: Fp3Var, + #[doc(hidden)] pub y_twist: Fp3Var, } impl G1PreparedVar

{ + /// Returns the value assigned to `self` in the underlying constraint system. pub fn value(&self) -> Result, SynthesisError> { let x = self.x.value()?; let y = self.y.value()?; @@ -44,6 +53,7 @@ impl G1PreparedVar

{ }) } + /// Constructs `Self` from a `G1Var`. #[tracing::instrument(target = "r1cs")] pub fn from_group_var(q: &G1Var

) -> Result { let q = q.to_affine()?; @@ -123,14 +133,23 @@ impl ToBytesGadget for G1PreparedVar

{ } type Fp3G

= Fp3Var<

::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 { + #[doc(hidden)] pub x: Fp3Var, + #[doc(hidden)] pub y: Fp3Var, + #[doc(hidden)] pub x_over_twist: Fp3Var, + #[doc(hidden)] pub y_over_twist: Fp3Var, + #[doc(hidden)] pub double_coefficients: Vec>, + #[doc(hidden)] pub addition_coefficients: Vec>, } @@ -224,6 +243,7 @@ impl ToBytesGadget for G2PreparedVar

{ } impl G2PreparedVar

{ + /// Returns the value assigned to `self` in the underlying constraint system. pub fn value(&self) -> Result, SynthesisError> { let x = self.x.value()?; let y = self.y.value()?; @@ -249,6 +269,7 @@ impl G2PreparedVar

{ }) } + /// Constructs `Self` from a `G2Var`. #[tracing::instrument(target = "r1cs")] pub fn from_group_var(q: &G2Var

) -> Result { let q = q.to_affine()?; @@ -319,6 +340,7 @@ impl G2PreparedVar

{ } } +#[doc(hidden)] #[derive(Derivative)] #[derivative(Clone(bound = "P: MNT6Parameters"), Debug(bound = "P: MNT6Parameters"))] pub struct AteDoubleCoefficientsVar { @@ -384,6 +406,7 @@ impl ToBytesGadget for AteDoubleCoefficientsVar

{ } impl AteDoubleCoefficientsVar

{ + /// Returns the value assigned to `self` in the underlying constraint system. pub fn value(&self) -> Result, SynthesisError> { let c_h = self.c_h.value()?; let c_4c = self.c_4c.value()?; @@ -398,6 +421,7 @@ impl AteDoubleCoefficientsVar

{ } } +#[doc(hidden)] #[derive(Derivative)] #[derivative(Clone(bound = "P: MNT6Parameters"), Debug(bound = "P: MNT6Parameters"))] pub struct AteAdditionCoefficientsVar { @@ -448,6 +472,7 @@ impl ToBytesGadget for AteAdditionCoefficientsVar

{ } impl AteAdditionCoefficientsVar

{ + /// Returns the value assigned to `self` in the underlying constraint system. pub fn value(&self) -> Result, SynthesisError> { let c_l1 = self.c_l1.value()?; let c_rz = self.c_rz.value()?; @@ -455,6 +480,7 @@ impl AteAdditionCoefficientsVar

{ } } +#[doc(hidden)] pub struct G2ProjectiveExtendedVar { pub x: Fp3Var, pub y: Fp3Var, diff --git a/r1cs-std/src/groups/curves/short_weierstrass/mod.rs b/r1cs-std/src/groups/curves/short_weierstrass/mod.rs index 73ad21d..46d38e4 100644 --- a/r1cs-std/src/groups/curves/short_weierstrass/mod.rs +++ b/r1cs-std/src/groups/curves/short_weierstrass/mod.rs @@ -11,8 +11,17 @@ use r1cs_core::{ConstraintSystemRef, Namespace, SynthesisError}; 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 @@ where } } + /// Returns the value assigned to `self` in the underlying + /// constraint system. pub fn value(&self) -> Result, SynthesisError> { Ok(SWAffine::new( self.x.value()?, @@ -128,6 +139,7 @@ impl::Ba 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, diff --git a/r1cs-std/src/groups/curves/twisted_edwards/mod.rs b/r1cs-std/src/groups/curves/twisted_edwards/mod.rs index e77f3c0..404af8e 100644 --- a/r1cs-std/src/groups/curves/twisted_edwards/mod.rs +++ b/r1cs-std/src/groups/curves/twisted_edwards/mod.rs @@ -13,6 +13,12 @@ use crate::{prelude::*, ToConstraintFieldGadget, Vec}; 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 @@ pub struct MontgomeryAffineVar< > 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

, @@ -59,6 +67,7 @@ mod montgomery_affine_impl { 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 @@ mod montgomery_affine_impl { } } + /// 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

, @@ -85,6 +96,8 @@ mod montgomery_affine_impl { 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<::BasePrimeField>, @@ -96,6 +109,7 @@ mod montgomery_affine_impl { Ok(Self::new(u, v)) } + /// Converts `self` into a Twisted Edwards curve point variable. #[tracing::instrument(target = "r1cs")] pub fn into_edwards(&self) -> Result, SynthesisError> { let cs = self.cs().unwrap_or(ConstraintSystemRef::None); @@ -199,6 +213,9 @@ mod montgomery_affine_impl { } } +/// 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 @@ pub struct AffineVar< > 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

, @@ -219,6 +238,7 @@ impl::Ba 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 @@ where } } +impl::BasePrimeField>> + AffineVar +where + P: TEModelParameters, + F: FieldVar::BasePrimeField> + + TwoBitLookupGadget<::BasePrimeField, TableConstant = P::BaseField> + + ThreeBitCondNegLookupGadget< + ::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( + bases: &[impl Borrow<[TEProjective

]>], + scalars: &[impl Borrow<[J]>], + ) -> Result + where + J: Borrow<[Boolean<::BasePrimeField>]>, + { + const CHUNK_SIZE: usize = 3; + let mut ed_result: Option> = None; + let mut result: Option> = None; + + let mut process_segment_result = |result: &MontgomeryAffineVar| { + 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::, _>>()?; + + let x_coeffs = coords.iter().map(|p| p.0).collect::>(); + let y_coeffs = coords.iter().map(|p| p.1).collect::>(); + + 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 R1CSVar<::BasePrimeField> for AffineVar where P: TEModelParameters, @@ -281,11 +394,7 @@ impl CurveVar, ::BasePrimeField> fo where P: TEModelParameters, F: FieldVar::BasePrimeField> - + TwoBitLookupGadget<::BasePrimeField, TableConstant = P::BaseField> - + ThreeBitCondNegLookupGadget< - ::BasePrimeField, - TableConstant = P::BaseField, - >, + + TwoBitLookupGadget<::BasePrimeField, TableConstant = P::BaseField>, for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, { fn constant(g: TEProjective

) -> Self { @@ -441,95 +550,13 @@ where 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 - where - I: Borrow<[Boolean<::BasePrimeField>]>, - J: Borrow<[I]>, - B: Borrow<[TEProjective

]>, - { - const CHUNK_SIZE: usize = 3; - let mut ed_result: Option> = None; - let mut result: Option> = None; - - let mut process_segment_result = |result: &MontgomeryAffineVar| { - 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::, _>>()?; - - let x_coeffs = coords.iter().map(|p| p.0).collect::>(); - let y_coeffs = coords.iter().map(|p| p.1).collect::>(); - - 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 AllocVar, ::BasePrimeField> for AffineVar where P: TEModelParameters, F: FieldVar::BasePrimeField> - + TwoBitLookupGadget<::BasePrimeField, TableConstant = P::BaseField> - + ThreeBitCondNegLookupGadget< - ::BasePrimeField, - TableConstant = P::BaseField, - >, + + TwoBitLookupGadget<::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 AllocVar, ::BasePrimeField> for Af where P: TEModelParameters, F: FieldVar::BasePrimeField> - + TwoBitLookupGadget<::BasePrimeField, TableConstant = P::BaseField> - + ThreeBitCondNegLookupGadget< - ::BasePrimeField, - TableConstant = P::BaseField, - >, + + TwoBitLookupGadget<::BasePrimeField, TableConstant = P::BaseField>, for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, { #[tracing::instrument(target = "r1cs", skip(cs, f))] @@ -737,8 +760,7 @@ impl_bounded_ops!( |this: &'a AffineVar, other: TEProjective

| this + AffineVar::constant(other), ( F :FieldVar::BasePrimeField> - + TwoBitLookupGadget<::BasePrimeField, TableConstant = P::BaseField> - + ThreeBitCondNegLookupGadget<::BasePrimeField, TableConstant = P::BaseField>, + + TwoBitLookupGadget<::BasePrimeField, TableConstant = P::BaseField>, P: TEModelParameters, ), for <'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>, @@ -755,8 +777,7 @@ impl_bounded_ops!( |this: &'a AffineVar, other: TEProjective

| this - AffineVar::constant(other), ( F :FieldVar::BasePrimeField> - + TwoBitLookupGadget<::BasePrimeField, TableConstant = P::BaseField> - + ThreeBitCondNegLookupGadget<::BasePrimeField, TableConstant = P::BaseField>, + + TwoBitLookupGadget<::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

, AffineVar> for AffineVa where P: TEModelParameters, F: FieldVar::BasePrimeField> - + TwoBitLookupGadget<::BasePrimeField, TableConstant = P::BaseField> - + ThreeBitCondNegLookupGadget< - ::BasePrimeField, - TableConstant = P::BaseField, - >, + + TwoBitLookupGadget<::BasePrimeField, TableConstant = P::BaseField>, for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>, { } @@ -779,11 +796,7 @@ impl<'a, P, F> GroupOpsBounds<'a, TEProjective

, AffineVar> for &'a Affi where P: TEModelParameters, F: FieldVar::BasePrimeField> - + TwoBitLookupGadget<::BasePrimeField, TableConstant = P::BaseField> - + ThreeBitCondNegLookupGadget< - ::BasePrimeField, - TableConstant = P::BaseField, - >, + + TwoBitLookupGadget<::BasePrimeField, TableConstant = P::BaseField>, for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>, { } diff --git a/r1cs-std/src/groups/mod.rs b/r1cs-std/src/groups/mod.rs index 13e81da..a2682ef 100644 --- a/r1cs-std/src/groups/mod.rs +++ b/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 @@ pub trait GroupOpsBounds<'a, F, T: 'a>: { } +/// A variable that represents a curve point for +/// the curve `C`. pub trait CurveVar: 'static + Sized @@ -43,17 +46,23 @@ pub trait CurveVar: + AddAssign + SubAssign { - 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, 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>, f: impl FnOnce() -> Result, @@ -63,6 +72,7 @@ pub trait CurveVar: /// 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 { let mut result = self.clone(); @@ -70,8 +80,10 @@ pub trait CurveVar: Ok(result) } + /// Sets `self = self + self`. fn double_in_place(&mut self) -> Result<(), SynthesisError>; + /// Coputes `-self`. fn negate(&self) -> Result; /// Computes `bits * self`, where `bits` is a little-endian @@ -113,20 +125,7 @@ pub trait CurveVar: Ok(()) } - #[tracing::instrument(target = "r1cs")] - fn precomputed_base_3_bit_signed_digit_scalar_mul<'a, I, J, B>( - _: &[B], - _: &[J], - ) -> Result - where - I: Borrow<[Boolean]>, - 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>( diff --git a/r1cs-std/src/instantiated/bls12_377/curves.rs b/r1cs-std/src/instantiated/bls12_377/curves.rs index 0cba94f..e0b86d3 100644 --- a/r1cs-std/src/instantiated/bls12_377/curves.rs +++ b/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; +/// An element of G2 in the BLS12-377 bilinear group. pub type G2Var = bls12::G2Var; +/// Represents the cached precomputation that can be performed on a G1 element +/// which enables speeding up pairing computation. pub type G1PreparedVar = bls12::G1PreparedVar; +/// Represents the cached precomputation that can be performed on a G2 element +/// which enables speeding up pairing computation. pub type G2PreparedVar = bls12::G2PreparedVar; #[test] diff --git a/r1cs-std/src/instantiated/bls12_377/fields.rs b/r1cs-std/src/instantiated/bls12_377/fields.rs index 127e362..446e77f 100644 --- a/r1cs-std/src/instantiated/bls12_377/fields.rs +++ b/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; +/// A variable that is the R1CS equivalent of `algebra::bls12_377::Fq2`. pub type Fq2Var = Fp2Var; +/// A variable that is the R1CS equivalent of `algebra::bls12_377::Fq6`. pub type Fq6Var = Fp6Var; +/// A variable that is the R1CS equivalent of `algebra::bls12_377::Fq12`. pub type Fq12Var = Fp12Var; #[test] diff --git a/r1cs-std/src/instantiated/bls12_377/pairing.rs b/r1cs-std/src/instantiated/bls12_377/pairing.rs index 1258aeb..e9a8047 100644 --- a/r1cs-std/src/instantiated/bls12_377/pairing.rs +++ b/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; #[test] diff --git a/r1cs-std/src/instantiated/ed_on_bls12_377/curves.rs b/r1cs-std/src/instantiated/ed_on_bls12_377/curves.rs index 16025d1..ed38d21 100644 --- a/r1cs-std/src/instantiated/ed_on_bls12_377/curves.rs +++ b/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; #[test] diff --git a/r1cs-std/src/instantiated/ed_on_bls12_377/fields.rs b/r1cs-std/src/instantiated/ed_on_bls12_377/fields.rs index 18e3f93..32011d1 100644 --- a/r1cs-std/src/instantiated/ed_on_bls12_377/fields.rs +++ b/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; #[test] diff --git a/r1cs-std/src/instantiated/ed_on_bls12_381/curves.rs b/r1cs-std/src/instantiated/ed_on_bls12_381/curves.rs index 9ea8758..555f4ad 100644 --- a/r1cs-std/src/instantiated/ed_on_bls12_381/curves.rs +++ b/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; #[test] diff --git a/r1cs-std/src/instantiated/ed_on_bls12_381/fields.rs b/r1cs-std/src/instantiated/ed_on_bls12_381/fields.rs index eb9b929..eaf367b 100644 --- a/r1cs-std/src/instantiated/ed_on_bls12_381/fields.rs +++ b/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; #[test] diff --git a/r1cs-std/src/instantiated/ed_on_bn254/curves.rs b/r1cs-std/src/instantiated/ed_on_bn254/curves.rs index 386acce..f3171a1 100644 --- a/r1cs-std/src/instantiated/ed_on_bn254/curves.rs +++ b/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; #[test] diff --git a/r1cs-std/src/instantiated/ed_on_bn254/fields.rs b/r1cs-std/src/instantiated/ed_on_bn254/fields.rs index 24e65be..45b30a0 100644 --- a/r1cs-std/src/instantiated/ed_on_bn254/fields.rs +++ b/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; #[test] diff --git a/r1cs-std/src/instantiated/ed_on_bw6_761/curves.rs b/r1cs-std/src/instantiated/ed_on_bw6_761/curves.rs deleted file mode 100644 index 7720aad..0000000 --- a/r1cs-std/src/instantiated/ed_on_bw6_761/curves.rs +++ /dev/null @@ -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; - -#[test] -fn test() { - crate::groups::curves::twisted_edwards::test::<_, EdwardsParameters, EdwardsGadget>(); -} diff --git a/r1cs-std/src/instantiated/ed_on_bw6_761/fields.rs b/r1cs-std/src/instantiated/ed_on_bw6_761/fields.rs deleted file mode 100644 index 37b0972..0000000 --- a/r1cs-std/src/instantiated/ed_on_bw6_761/fields.rs +++ /dev/null @@ -1,9 +0,0 @@ -use crate::fields::fp::FpGadget; -use algebra::ed_on_cp6_782::fq::Fq; - -pub type FqGadget = FpGadget; - -#[test] -fn test() { - crate::fields::tests::field_test::<_, _, Fq, FqGadget>(); -} diff --git a/r1cs-std/src/instantiated/ed_on_cp6_782/curves.rs b/r1cs-std/src/instantiated/ed_on_cp6_782/curves.rs index df5e45a..2c5d101 100644 --- a/r1cs-std/src/instantiated/ed_on_cp6_782/curves.rs +++ b/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; #[test] diff --git a/r1cs-std/src/instantiated/ed_on_cp6_782/fields.rs b/r1cs-std/src/instantiated/ed_on_cp6_782/fields.rs index 7722ff0..db4cf98 100644 --- a/r1cs-std/src/instantiated/ed_on_cp6_782/fields.rs +++ b/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; #[test] diff --git a/r1cs-std/src/instantiated/ed_on_mnt4_298/curves.rs b/r1cs-std/src/instantiated/ed_on_mnt4_298/curves.rs index 5867a0c..bc251c6 100644 --- a/r1cs-std/src/instantiated/ed_on_mnt4_298/curves.rs +++ b/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; #[test] diff --git a/r1cs-std/src/instantiated/ed_on_mnt4_298/fields.rs b/r1cs-std/src/instantiated/ed_on_mnt4_298/fields.rs index 07128a2..714bd98 100644 --- a/r1cs-std/src/instantiated/ed_on_mnt4_298/fields.rs +++ b/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; #[test] diff --git a/r1cs-std/src/instantiated/ed_on_mnt4_753/curves.rs b/r1cs-std/src/instantiated/ed_on_mnt4_753/curves.rs index aa9b9f0..c0b7677 100644 --- a/r1cs-std/src/instantiated/ed_on_mnt4_753/curves.rs +++ b/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; #[test] diff --git a/r1cs-std/src/instantiated/ed_on_mnt4_753/fields.rs b/r1cs-std/src/instantiated/ed_on_mnt4_753/fields.rs index f43a823..750b1b2 100644 --- a/r1cs-std/src/instantiated/ed_on_mnt4_753/fields.rs +++ b/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; #[test] diff --git a/r1cs-std/src/instantiated/mnt4_298/curves.rs b/r1cs-std/src/instantiated/mnt4_298/curves.rs index 359bdcc..ecb6015 100644 --- a/r1cs-std/src/instantiated/mnt4_298/curves.rs +++ b/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; +/// An element of G2 in the MNT4-298 bilinear group. pub type G2Var = mnt4::G2Var; +/// Represents the cached precomputation that can be performed on a G1 element +/// which enables speeding up pairing computation. pub type G1PreparedVar = mnt4::G1PreparedVar; +/// Represents the cached precomputation that can be performed on a G2 element +/// which enables speeding up pairing computation. pub type G2PreparedVar = mnt4::G2PreparedVar; #[test] diff --git a/r1cs-std/src/instantiated/mnt4_298/fields.rs b/r1cs-std/src/instantiated/mnt4_298/fields.rs index ad79f1e..279a5c0 100644 --- a/r1cs-std/src/instantiated/mnt4_298/fields.rs +++ b/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; +/// A variable that is the R1CS equivalent of `algebra::mnt4_298::Fq2`. pub type Fq2Var = Fp2Var; +/// A variable that is the R1CS equivalent of `algebra::mnt4_298::Fq4`. pub type Fq4Var = Fp4Var; #[test] diff --git a/r1cs-std/src/instantiated/mnt4_298/pairing.rs b/r1cs-std/src/instantiated/mnt4_298/pairing.rs index 768e73e..c1edc51 100644 --- a/r1cs-std/src/instantiated/mnt4_298/pairing.rs +++ b/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; #[test] diff --git a/r1cs-std/src/instantiated/mnt4_753/curves.rs b/r1cs-std/src/instantiated/mnt4_753/curves.rs index 4f83b8e..0f92230 100644 --- a/r1cs-std/src/instantiated/mnt4_753/curves.rs +++ b/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; +/// An element of G2 in the MNT4-753 bilinear group. pub type G2Var = mnt4::G2Var; +/// Represents the cached precomputation that can be performed on a G1 element +/// which enables speeding up pairing computation. pub type G1PreparedVar = mnt4::G1PreparedVar; +/// Represents the cached precomputation that can be performed on a G2 element +/// which enables speeding up pairing computation. pub type G2PreparedVar = mnt4::G2PreparedVar; #[test] diff --git a/r1cs-std/src/instantiated/mnt4_753/fields.rs b/r1cs-std/src/instantiated/mnt4_753/fields.rs index 5cc960e..9f79e0e 100644 --- a/r1cs-std/src/instantiated/mnt4_753/fields.rs +++ b/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; +/// A variable that is the R1CS equivalent of `algebra::mnt4_753::Fq2`. pub type Fq2Var = Fp2Var; +/// A variable that is the R1CS equivalent of `algebra::mnt4_753::Fq4`. pub type Fq4Var = Fp4Var; #[test] diff --git a/r1cs-std/src/instantiated/mnt4_753/pairing.rs b/r1cs-std/src/instantiated/mnt4_753/pairing.rs index 43e7a78..677f644 100644 --- a/r1cs-std/src/instantiated/mnt4_753/pairing.rs +++ b/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; #[test] diff --git a/r1cs-std/src/instantiated/mnt6_298/curves.rs b/r1cs-std/src/instantiated/mnt6_298/curves.rs index 4741888..0d7f245 100644 --- a/r1cs-std/src/instantiated/mnt6_298/curves.rs +++ b/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; +/// An element of G2 in the MNT6-298 bilinear group. pub type G2Var = mnt6::G2Var; +/// Represents the cached precomputation that can be performed on a G1 element +/// which enables speeding up pairing computation. pub type G1PreparedVar = mnt6::G1PreparedVar; +/// Represents the cached precomputation that can be performed on a G2 element +/// which enables speeding up pairing computation. pub type G2PreparedVar = mnt6::G2PreparedVar; #[test] diff --git a/r1cs-std/src/instantiated/mnt6_298/fields.rs b/r1cs-std/src/instantiated/mnt6_298/fields.rs index 8ef8c61..d864bb6 100644 --- a/r1cs-std/src/instantiated/mnt6_298/fields.rs +++ b/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; +/// A variable that is the R1CS equivalent of `algebra::mnt4_298::Fq3`. pub type Fq3Var = Fp3Var; +/// A variable that is the R1CS equivalent of `algebra::mnt4_298::Fq6`. pub type Fq6Var = Fp6Var; #[test] diff --git a/r1cs-std/src/instantiated/mnt6_298/pairing.rs b/r1cs-std/src/instantiated/mnt6_298/pairing.rs index 0d3af87..3d7881e 100644 --- a/r1cs-std/src/instantiated/mnt6_298/pairing.rs +++ b/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; #[test] diff --git a/r1cs-std/src/instantiated/mnt6_753/curves.rs b/r1cs-std/src/instantiated/mnt6_753/curves.rs index 3b2c273..b3b0160 100644 --- a/r1cs-std/src/instantiated/mnt6_753/curves.rs +++ b/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; +/// An element of G2 in the MNT6-753 bilinear group. pub type G2Var = mnt6::G2Var; +/// Represents the cached precomputation that can be performed on a G1 element +/// which enables speeding up pairing computation. pub type G1PreparedVar = mnt6::G1PreparedVar; +/// Represents the cached precomputation that can be performed on a G2 element +/// which enables speeding up pairing computation. pub type G2PreparedVar = mnt6::G2PreparedVar; #[test] diff --git a/r1cs-std/src/instantiated/mnt6_753/fields.rs b/r1cs-std/src/instantiated/mnt6_753/fields.rs index 3cbea4c..68d1193 100644 --- a/r1cs-std/src/instantiated/mnt6_753/fields.rs +++ b/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; +/// A variable that is the R1CS equivalent of `algebra::mnt4_753::Fq3`. pub type Fq3Var = Fp3Var; +/// A variable that is the R1CS equivalent of `algebra::mnt4_753::Fq6`. pub type Fq6Var = Fp6Var; #[test] diff --git a/r1cs-std/src/instantiated/mnt6_753/pairing.rs b/r1cs-std/src/instantiated/mnt6_753/pairing.rs index 9d39c73..c97741b 100644 --- a/r1cs-std/src/instantiated/mnt6_753/pairing.rs +++ b/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; #[test] diff --git a/r1cs-std/src/instantiated/mod.rs b/r1cs-std/src/instantiated/mod.rs index 0ca6c2c..210f268 100644 --- a/r1cs-std/src/instantiated/mod.rs +++ b/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; diff --git a/r1cs-std/src/lib.rs b/r1cs-std/src/lib.rs index ce2b89e..73bbe94 100644 --- a/r1cs-std/src/lib.rs +++ b/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(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 @@ pub use instantiated::mnt6_298; #[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 @@ pub mod prelude { }; } +/// 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 { + /// 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 @@ impl<'a, F: Field, T: 'a + R1CSVar> R1CSVar for &'a T { } } +/// A utility trait to convert `Self` to `Result pub trait Assignment { + /// Converts `self` to `Result`. fn get(self) -> Result; } diff --git a/r1cs-std/src/macros.rs b/r1cs-std/src/macros.rs index 35cccb9..c943a5d 100644 --- a/r1cs-std/src/macros.rs +++ b/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 @@ macro_rules! impl_ops { }; } +/// 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 { ( diff --git a/r1cs-std/src/pairing/bls12/mod.rs b/r1cs-std/src/pairing/bls12/mod.rs index 35c3060..25dbb49 100644 --- a/r1cs-std/src/pairing/bls12/mod.rs +++ b/r1cs-std/src/pairing/bls12/mod.rs @@ -12,6 +12,7 @@ use algebra::{ }; use core::marker::PhantomData; +/// Specifies the constraints for computing a pairing in a BLS12 bilinear group. pub struct PairingVar(PhantomData

); type Fp2V

= Fp2Var<

::Fp2Params>; diff --git a/r1cs-std/src/pairing/mnt4/mod.rs b/r1cs-std/src/pairing/mnt4/mod.rs index 9baa45a..46d75c6 100644 --- a/r1cs-std/src/pairing/mnt4/mod.rs +++ b/r1cs-std/src/pairing/mnt4/mod.rs @@ -15,10 +15,12 @@ use algebra::{ }; use core::marker::PhantomData; +/// Specifies the constraints for computing a pairing in a MNT4 bilinear group. pub struct PairingVar(PhantomData

); type Fp2G

= Fp2Var<

::Fp2Params>; type Fp4G

= Fp4Var<

::Fp4Params>; +/// A variable corresponding to `algebra_core::mnt4::GT`. pub type GTVar

= Fp4G

; impl PairingVar

{ @@ -92,7 +94,7 @@ impl PairingVar

{ } #[tracing::instrument(target = "r1cs", skip(p, q))] - pub fn ate_miller_loop( + pub(crate) fn ate_miller_loop( p: &G1PreparedVar

, q: &G2PreparedVar

, ) -> Result, SynthesisError> { @@ -142,7 +144,7 @@ impl PairingVar

{ } #[tracing::instrument(target = "r1cs", skip(value))] - pub fn final_exponentiation(value: &Fp4G

) -> Result, SynthesisError> { + pub(crate) fn final_exponentiation(value: &Fp4G

) -> Result, 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)?; diff --git a/r1cs-std/src/pairing/mnt6/mod.rs b/r1cs-std/src/pairing/mnt6/mod.rs index 832f54c..accf267 100644 --- a/r1cs-std/src/pairing/mnt6/mod.rs +++ b/r1cs-std/src/pairing/mnt6/mod.rs @@ -15,10 +15,12 @@ use algebra::{ }; use core::marker::PhantomData; +/// Specifies the constraints for computing a pairing in a MNT6 bilinear group. pub struct PairingVar(PhantomData

); type Fp3G

= Fp3Var<

::Fp3Params>; type Fp6G

= Fp6Var<

::Fp6Params>; +/// A variable corresponding to `algebra_core::mnt6::GT`. pub type GTVar

= Fp6G

; impl PairingVar

{ @@ -87,7 +89,7 @@ impl PairingVar

{ } #[tracing::instrument(target = "r1cs", skip(p, q))] - pub fn ate_miller_loop( + pub(crate) fn ate_miller_loop( p: &G1PreparedVar

, q: &G2PreparedVar

, ) -> Result, SynthesisError> { @@ -138,7 +140,7 @@ impl PairingVar

{ } #[tracing::instrument(target = "r1cs")] - pub fn final_exponentiation(value: &Fp6G

) -> Result, SynthesisError> { + pub(crate) fn final_exponentiation(value: &Fp6G

) -> Result, 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)?; diff --git a/r1cs-std/src/pairing/mod.rs b/r1cs-std/src/pairing/mod.rs index 5692237..ee2ce84 100644 --- a/r1cs-std/src/pairing/mod.rs +++ b/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::Fq> { + /// An variable representing an element of `G1`. + /// This is the R1CS equivalent of `E::G1Projective`. type G1Var: CurveVar + AllocVar + AllocVar; + + /// An variable representing an element of `G2`. + /// This is the R1CS equivalent of `E::G2Projective`. type G2Var: CurveVar + AllocVar + AllocVar; + /// An variable representing an element of `GT`. + /// This is the R1CS equivalent of `E::GT`. type GTVar: FieldVar; + /// An variable representing cached precomputation that can speed up pairings computations. + /// This is the R1CS equivalent of `E::G1Prepared`. type G1PreparedVar: ToBytesGadget + AllocVar + Clone + Debug; + /// An variable representing cached precomputation that can speed up pairings computations. + /// This is the R1CS equivalent of `E::G2Prepared`. type G2PreparedVar: ToBytesGadget + AllocVar + Clone + Debug; + /// Computes a multi-miller loop between elements + /// of `p` and `q`. fn miller_loop( p: &[Self::G1PreparedVar], q: &[Self::G2PreparedVar], ) -> Result; + /// Computes a final exponentiation over `p`. fn final_exponentiation(p: &Self::GTVar) -> Result; + /// Computes a pairing over `p` and `q`. #[tracing::instrument(target = "r1cs")] fn pairing( p: Self::G1PreparedVar, @@ -42,7 +61,7 @@ pub trait PairingVar 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 @@ pub trait PairingVar Self::final_exponentiation(&miller_result) } + /// Performs the precomputation to generate `Self::G1PreparedVar`. fn prepare_g1(q: &Self::G1Var) -> Result; + /// Performs the precomputation to generate `Self::G2PreparedVar`. fn prepare_g2(q: &Self::G2Var) -> Result; } diff --git a/r1cs-std/src/select.rs b/r1cs-std/src/select.rs index 032dcc1..0440711 100644 --- a/r1cs-std/src/select.rs +++ b/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 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, true_value: &Self, @@ -14,12 +19,23 @@ where ) -> Result; } -/// Uses two bits to perform a lookup into a table +/// Performs a lookup in a 4-element table using two bits. pub trait TwoBitLookupGadget 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], constants: &[Self::TableConstant], @@ -27,12 +43,25 @@ where } /// 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 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], b0b1: &Boolean,