diff --git a/Cargo.toml b/Cargo.toml index 8f0668a7..cf563445 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ark-r1cs-std" -version = "0.3.1" +version = "0.4.0-alpha.1" authors = [ "arkworks contributors" ] description = "A standard library for constraint system gadgets" homepage = "https://arkworks.rs" @@ -13,10 +13,10 @@ license = "MIT/Apache-2.0" edition = "2018" [dependencies] -ark-ff = { version = "^0.3.0", default-features = false } -ark-ec = { version = "^0.3.0", default-features = false } -ark-std = { version = "^0.3.0", default-features = false } -ark-relations = { version = "^0.3.0", default-features = false } +ark-ff = { version = "0.4.0-alpha", default-features = false } +ark-ec = { version = "0.4.0-alpha", default-features = false } +ark-std = { version = "0.4.0-alpha", default-features = false } +ark-relations = { version = "0.4.0-alpha", default-features = false } derivative = { version = "2", features = ["use_core"] } tracing = { version = "0.1", default-features = false, features = [ "attributes" ] } @@ -25,16 +25,16 @@ num-traits = {version = "0.2", default-features = false } num-integer = { version = "0.1.44", default-features = false } [dev-dependencies] -ark-test-curves = { version = "^0.3.0", default-features = false, features = ["bls12_381_scalar_field", "bls12_381_curve", "mnt4_753_scalar_field"] } -ark-poly = { version = "^0.3.0", default-features = false } +ark-test-curves = { version = "0.4.0-alpha", default-features = false, features = ["bls12_381_scalar_field", "bls12_381_curve", "mnt4_753_scalar_field"] } +ark-poly = { version = "0.4.0-alpha", default-features = false } paste = "1.0" -ark-bls12-377 = { version = "^0.3.0", features = ["curve"], default-features = false } -ark-bls12-381 = { version = "^0.3.0", features = ["curve"], default-features = false } -ark-mnt4-298 = { version = "^0.3.0", features = ["curve"], default-features = false } -ark-mnt4-753 = { version = "^0.3.0", features = ["curve"], default-features = false } -ark-mnt6-298 = { version = "^0.3.0", default-features = false } -ark-mnt6-753 = { version = "^0.3.0", default-features = false } -ark-pallas = { version = "^0.3.0", features = ["curve"], default-features = false } +ark-bls12-377 = { version = "0.4.0-alpha", features = ["curve"], default-features = false } +ark-bls12-381 = { version = "0.4.0-alpha", features = ["curve"], default-features = false } +ark-mnt4-298 = { version = "0.4.0-alpha", features = ["curve"], default-features = false } +ark-mnt4-753 = { version = "0.4.0-alpha", features = ["curve"], default-features = false } +ark-mnt6-298 = { version = "0.4.0-alpha", default-features = false } +ark-mnt6-753 = { version = "0.4.0-alpha", default-features = false } +ark-pallas = { version = "0.4.0-alpha", features = ["curve"], default-features = false } [features] default = ["std"] @@ -70,19 +70,3 @@ lto = "thin" incremental = true debug-assertions = true debug = true - -# To be removed in the new release. -[patch.crates-io] -ark-std = { git = "https://github.com/arkworks-rs/std" } -ark-ec = { git = "https://github.com/arkworks-rs/algebra" } -ark-ff = { git = "https://github.com/arkworks-rs/algebra" } -ark-poly = { git = "https://github.com/arkworks-rs/algebra" } -ark-serialize = { git = "https://github.com/arkworks-rs/algebra" } -ark-test-curves = { git = "https://github.com/arkworks-rs/algebra" } -ark-bls12-381 = { git = "https://github.com/arkworks-rs/curves" } -ark-bls12-377 = { git = "https://github.com/arkworks-rs/curves" } -ark-mnt4-298 = { git = "https://github.com/arkworks-rs/curves" } -ark-mnt4-753 = { git = "https://github.com/arkworks-rs/curves" } -ark-mnt6-298 = { git = "https://github.com/arkworks-rs/curves" } -ark-mnt6-753 = { git = "https://github.com/arkworks-rs/curves" } -ark-pallas = { git = "https://github.com/arkworks-rs/curves" } diff --git a/src/bits/boolean.rs b/src/bits/boolean.rs index ff9e79ad..7ea02b27 100644 --- a/src/bits/boolean.rs +++ b/src/bits/boolean.rs @@ -1,6 +1,6 @@ -use ark_ff::{BitIteratorBE, Field, PrimeField}; - use crate::{fields::fp::FpVar, prelude::*, Assignment, ToConstraintFieldGadget, Vec}; + +use ark_ff::{BitIteratorBE, Field, PrimeField}; use ark_relations::r1cs::{ ConstraintSystemRef, LinearCombination, Namespace, SynthesisError, Variable, }; diff --git a/src/bits/uint8.rs b/src/bits/uint8.rs index f1612719..f203a436 100644 --- a/src/bits/uint8.rs +++ b/src/bits/uint8.rs @@ -1,5 +1,4 @@ use ark_ff::{Field, PrimeField, ToConstraintField}; - use ark_relations::r1cs::{ConstraintSystemRef, Namespace, SynthesisError}; use crate::{ @@ -363,14 +362,9 @@ impl ToConstraintFieldGadget for Vec, P: CubicExtVarConfig> +pub struct CubicExtVar where - for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>, + P::BaseField: FieldWithVar, { /// The zero-th coefficient of this field element. - pub c0: BF, + pub c0: BFVar

, /// The first coefficient of this field element. - pub c1: BF, + pub c1: BFVar

, /// The second coefficient of this field element. - pub c2: BF, + pub c2: BFVar

, #[derivative(Debug = "ignore")] _params: PhantomData

, } +type BFVar

= <

::BaseField as FieldWithVar>::Var; + +impl FieldWithVar for CubicExtField

+where + P::BaseField: FieldWithVar, +{ + type Var = CubicExtVar

; +} + /// This trait describes parameters that are used to implement arithmetic for /// `CubicExtVar`. -pub trait CubicExtVarConfig>: - CubicExtConfig +pub trait CubicExtVarConfig: CubicExtConfig where - for<'a> &'a BF: FieldOpsBounds<'a, Self::BaseField, BF>, + Self::BaseField: FieldWithVar, { /// 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); + fn mul_base_field_vars_by_frob_coeff(c1: &mut BFVar, c2: &mut BFVar, power: usize); } -impl, P: CubicExtVarConfig> CubicExtVar +impl CubicExtVar

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

, c1: BFVar

, c2: BFVar

) -> Self { let _params = PhantomData; Self { c0, @@ -62,17 +74,18 @@ where /// 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) + pub fn mul_base_field_by_nonresidue(fe: &BFVar

) -> Result, SynthesisError> { + Ok(fe.clone() * 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 * fe; - let c1 = &self.c1 * fe; - let c2 = &self.c2 * fe; - Self::new(c0, c1, c2) + let mut result = self.clone(); + result.c0 *= fe; + result.c1 *= fe; + result.c2 *= fe; + result } /// Sets `self = self.mul_by_base_field_constant(fe)`. @@ -82,11 +95,10 @@ where } } -impl R1CSVar for CubicExtVar +impl

R1CSVar for CubicExtVar

where - BF: FieldVar, - for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>, - P: CubicExtVarConfig, + P: CubicExtVarConfig, + P::BaseField: FieldWithVar, { type Value = CubicExtField

; @@ -103,79 +115,74 @@ where } } -impl From> for CubicExtVar +impl

From> for CubicExtVar

where - BF: FieldVar, - for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>, - P: CubicExtVarConfig, + P: CubicExtVarConfig, + P::BaseField: FieldWithVar, { fn from(other: Boolean) -> Self { - let c0 = BF::from(other); - let c1 = BF::zero(); - let c2 = BF::zero(); + let c0 = BFVar::

::from(other); + let c1 = BFVar::

::zero(); + let c2 = BFVar::

::zero(); Self::new(c0, c1, c2) } } -impl<'a, BF, P> FieldOpsBounds<'a, CubicExtField

, CubicExtVar> for CubicExtVar +impl<'a, P> FieldOpsBounds, &'a Self> for CubicExtVar

where - BF: FieldVar, - for<'b> &'b BF: FieldOpsBounds<'b, P::BaseField, BF>, - P: CubicExtVarConfig, + P: CubicExtVarConfig, + P::BaseField: FieldWithVar, { } -impl<'a, BF, P> FieldOpsBounds<'a, CubicExtField

, CubicExtVar> for &'a CubicExtVar +impl<'a, P> FieldRefOpsBounds, CubicExtVar

> for &'a CubicExtVar

where - BF: FieldVar, - for<'b> &'b BF: FieldOpsBounds<'b, P::BaseField, BF>, - P: CubicExtVarConfig, + P: CubicExtVarConfig, + P::BaseField: FieldWithVar, { } -impl FieldVar, P::BasePrimeField> for CubicExtVar +impl

FieldVar, P::BasePrimeField> for CubicExtVar

where - BF: FieldVar, - for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>, - P: CubicExtVarConfig, + P: CubicExtVarConfig, + P::BaseField: FieldWithVar, { fn constant(other: CubicExtField

) -> Self { - let c0 = BF::constant(other.c0); - let c1 = BF::constant(other.c1); - let c2 = BF::constant(other.c2); + let c0 = BFVar::

::constant(other.c0); + let c1 = BFVar::

::constant(other.c1); + let c2 = BFVar::

::constant(other.c2); Self::new(c0, c1, c2) } fn zero() -> Self { - let c0 = BF::zero(); - let c1 = BF::zero(); - let c2 = BF::zero(); + let c0 = BFVar::

::zero(); + let c1 = BFVar::

::zero(); + let c2 = BFVar::

::zero(); Self::new(c0, c1, c2) } fn one() -> Self { - let c0 = BF::one(); - let c1 = BF::zero(); - let c2 = BF::zero(); + let c0 = BFVar::

::one(); + let c1 = BFVar::

::zero(); + let c2 = BFVar::

::zero(); Self::new(c0, c1, c2) } #[inline] #[tracing::instrument(target = "r1cs")] - fn double(&self) -> Result { - let c0 = self.c0.double()?; - let c1 = self.c1.double()?; - let c2 = self.c2.double()?; - Ok(Self::new(c0, c1, c2)) + fn double_in_place(&mut self) -> Result<&mut Self, SynthesisError> { + self.c0.double_in_place()?; + self.c1.double_in_place()?; + self.c2.double_in_place()?; + Ok(self) } #[inline] #[tracing::instrument(target = "r1cs")] - fn negate(&self) -> Result { - let mut result = self.clone(); - result.c0.negate_in_place()?; - result.c1.negate_in_place()?; - result.c2.negate_in_place()?; - Ok(result) + fn negate_in_place(&mut self) -> Result<&mut Self, SynthesisError> { + self.c0.negate_in_place()?; + self.c1.negate_in_place()?; + self.c2.negate_in_place()?; + Ok(self) } /// Use the Chung-Hasan asymmetric squaring formula. @@ -185,23 +192,23 @@ where /// Fields.pdf; Section 4 (CH-SQR2)) #[inline] #[tracing::instrument(target = "r1cs")] - fn square(&self) -> Result { + fn square_in_place(&mut self) -> Result<&mut Self, SynthesisError> { let a = self.c0.clone(); let b = self.c1.clone(); let c = self.c2.clone(); let s0 = a.square()?; - let ab = &a * &b; + let ab = a.clone() * &b; let s1 = ab.double()?; - let s2 = (&a - &b + &c).square()?; - let s3 = (&b * &c).double()?; + let s2 = (a - &b + &c).square()?; + let s3 = (b * &c).double()?; let s4 = c.square()?; - let c0 = Self::mul_base_field_by_nonresidue(&s3)? + &s0; - let c1 = Self::mul_base_field_by_nonresidue(&s4)? + &s1; - let c2 = s1 + &s2 + &s3 - &s0 - &s4; + self.c0 = Self::mul_base_field_by_nonresidue(&s3)? + &s0; + self.c1 = Self::mul_base_field_by_nonresidue(&s4)? + &s1; + self.c2 = s1 + &s2 + &s3 - &s0 - &s4; - Ok(Self::new(c0, c1, c2)) + Ok(self) } #[tracing::instrument(target = "r1cs")] @@ -228,28 +235,28 @@ where // // This implementation adapted from // https://github.com/ZencashOfficial/ginger-lib/blob/development/r1cs/gadgets/std/src/fields/fp3.rs - let v0 = &self.c0 * &other.c0; - let v1 = &self.c1 * &other.c1; - let v2 = &self.c2 * &other.c2; + let v0 = self.c0.clone() * &other.c0; + let v1 = self.c1.clone() * &other.c1; + let v2 = self.c2.clone() * &other.c2; // Check c0 - let nr_a1_plus_a2 = (&self.c1 + &self.c2) * P::NONRESIDUE; - let b1_plus_b2 = &other.c1 + &other.c2; - let nr_v1 = &v1 * P::NONRESIDUE; - let nr_v2 = &v2 * P::NONRESIDUE; - let to_check = &result.c0 - &v0 + &nr_v1 + &nr_v2; + let nr_a1_plus_a2 = (self.c1.clone() + &self.c2) * P::NONRESIDUE; + let b1_plus_b2 = other.c1.clone() + &other.c2; + let nr_v1 = v1.clone() * P::NONRESIDUE; + let nr_v2 = v2.clone() * P::NONRESIDUE; + let to_check = result.c0.clone() - &v0 + &nr_v1 + &nr_v2; nr_a1_plus_a2.mul_equals(&b1_plus_b2, &to_check)?; // Check c1 - let a0_plus_a1 = &self.c0 + &self.c1; - let b0_plus_b1 = &other.c0 + &other.c1; - let to_check = &result.c1 - &nr_v2 + &v0 + &v1; + let a0_plus_a1 = self.c0.clone() + &self.c1; + let b0_plus_b1 = other.c0.clone() + &other.c1; + let to_check = result.c1.clone() - &nr_v2 + &v0 + &v1; a0_plus_a1.mul_equals(&b0_plus_b1, &to_check)?; // Check c2 - let a0_plus_a2 = &self.c0 + &self.c2; - let b0_plus_b2 = &other.c0 + &other.c2; - let to_check = &result.c2 + &v0 - &v1 + &v2; + let a0_plus_a2 = self.c0.clone() + &self.c2; + let b0_plus_b2 = other.c0.clone() + &other.c2; + let to_check = result.c2.clone() + &v0 - &v1 + &v2; a0_plus_a2.mul_equals(&b0_plus_b2, &to_check)?; Ok(()) } @@ -286,51 +293,49 @@ where } impl_bounded_ops!( - CubicExtVar, + CubicExtVar

, CubicExtField

, Add, add, AddAssign, add_assign, - |this: &'a CubicExtVar, other: &'a CubicExtVar| { - let c0 = &this.c0 + &other.c0; - let c1 = &this.c1 + &other.c1; - let c2 = &this.c2 + &other.c2; - CubicExtVar::new(c0, c1, c2) + |this: &mut CubicExtVar

, other: &'a CubicExtVar

| { + this.c0 += &other.c0; + this.c1 += &other.c1; + this.c2 += &other.c2; }, - |this: &'a CubicExtVar, other: CubicExtField

| { - this + CubicExtVar::constant(other) + |this: &mut CubicExtVar

, other: CubicExtField

| { + *this = &*this + CubicExtVar::constant(other) }, - (BF: FieldVar, P: CubicExtVarConfig), - for<'b> &'b BF: FieldOpsBounds<'b, P::BaseField, BF>, + (P: CubicExtVarConfig), + P::BaseField: FieldWithVar, ); impl_bounded_ops!( - CubicExtVar, + CubicExtVar

, CubicExtField

, Sub, sub, SubAssign, sub_assign, - |this: &'a CubicExtVar, other: &'a CubicExtVar| { - let c0 = &this.c0 - &other.c0; - let c1 = &this.c1 - &other.c1; - let c2 = &this.c2 - &other.c2; - CubicExtVar::new(c0, c1, c2) + |this: &mut CubicExtVar

, other: &'a CubicExtVar

| { + this.c0 -= &other.c0; + this.c1 -= &other.c1; + this.c2 -= &other.c2; }, - |this: &'a CubicExtVar, other: CubicExtField

| { - this - CubicExtVar::constant(other) + |this: &mut CubicExtVar

, other: CubicExtField

| { + *this = &*this - CubicExtVar::constant(other) }, - (BF: FieldVar, P: CubicExtVarConfig), - for<'b> &'b BF: FieldOpsBounds<'b, P::BaseField, BF>, + (P: CubicExtVarConfig), + P::BaseField: FieldWithVar, ); impl_bounded_ops!( - CubicExtVar, + CubicExtVar

, CubicExtField

, Mul, mul, MulAssign, mul_assign, - |this: &'a CubicExtVar, other: &'a CubicExtVar| { + |this: &mut CubicExtVar

, other: &'a CubicExtVar

| { // Karatsuba multiplication for cubic extensions: // v0 = A.c0 * B.c0 // v1 = A.c1 * B.c1 @@ -342,30 +347,31 @@ impl_bounded_ops!( // Reference: // "Multiplication and Squaring on Pairing-Friendly Fields" // Devegili, OhEigeartaigh, Scott, Dahab - let v0 = &this.c0 * &other.c0; - let v1 = &this.c1 * &other.c1; - let v2 = &this.c2 * &other.c2; - let c0 = - (((&this.c1 + &this.c2) * (&other.c1 + &other.c2) - &v1 - &v2) * P::NONRESIDUE) + &v0 ; - let c1 = - (&this.c0 + &this.c1) * (&other.c0 + &other.c1) - &v0 - &v1 + (&v2 * P::NONRESIDUE); - let c2 = - (&this.c0 + &this.c2) * (&other.c0 + &other.c2) - &v0 + &v1 - &v2; - - CubicExtVar::new(c0, c1, c2) + let this_copy = this.clone(); + let v0 = this_copy.c0 * &other.c0; + let v1 = this_copy.c1 * &other.c1; + let v2 = this_copy.c2 * &other.c2; + let c0 = (((this.c1.clone() + &this.c2) * (other.c1.clone() + &other.c2) - &v1 - &v2) + * P::NONRESIDUE) + + &v0; + let c1 = (this.c0.clone() + &this.c1) * (other.c0.clone() + &other.c1) - &v0 - &v1 + + (v2.clone() * P::NONRESIDUE); + let c2 = (this.c0.clone() + &this.c2) * (other.c0.clone() + &other.c2) - &v0 + &v1 - &v2; + this.c0 = c0; + this.c1 = c1; + this.c2 = c2; }, - |this: &'a CubicExtVar, other: CubicExtField

| { - this * CubicExtVar::constant(other) + |this: &mut CubicExtVar

, other: CubicExtField

| { + *this = CubicExtVar::constant(other) * &*this; }, - (BF: FieldVar, P: CubicExtVarConfig), - for<'b> &'b BF: FieldOpsBounds<'b, P::BaseField, BF>, + (P: CubicExtVarConfig), + P::BaseField: FieldWithVar, ); -impl EqGadget for CubicExtVar +impl

EqGadget for CubicExtVar

where - BF: FieldVar, - for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>, - P: CubicExtVarConfig, + P: CubicExtVarConfig, + P::BaseField: FieldWithVar, { #[tracing::instrument(target = "r1cs")] fn is_eq(&self, other: &Self) -> Result, SynthesisError> { @@ -402,11 +408,10 @@ where } } -impl ToBitsGadget for CubicExtVar +impl

ToBitsGadget for CubicExtVar

where - BF: FieldVar, - for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>, - P: CubicExtVarConfig, + P::BaseField: FieldWithVar, + P: CubicExtVarConfig, { #[tracing::instrument(target = "r1cs")] fn to_bits_le(&self) -> Result>, SynthesisError> { @@ -429,11 +434,10 @@ where } } -impl ToBytesGadget for CubicExtVar +impl

ToBytesGadget for CubicExtVar

where - BF: FieldVar, - for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>, - P: CubicExtVarConfig, + P: CubicExtVarConfig, + P::BaseField: FieldWithVar, { #[tracing::instrument(target = "r1cs")] fn to_bytes(&self) -> Result>, SynthesisError> { @@ -459,12 +463,11 @@ where } } -impl ToConstraintFieldGadget for CubicExtVar +impl

ToConstraintFieldGadget for CubicExtVar

where - BF: FieldVar, - for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>, - P: CubicExtVarConfig, - BF: ToConstraintFieldGadget, + P: CubicExtVarConfig, + P::BaseField: FieldWithVar, + BFVar

: ToConstraintFieldGadget, { #[tracing::instrument(target = "r1cs")] fn to_constraint_field(&self) -> Result>, SynthesisError> { @@ -478,11 +481,10 @@ where } } -impl CondSelectGadget for CubicExtVar +impl

CondSelectGadget for CubicExtVar

where - BF: FieldVar, - for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>, - P: CubicExtVarConfig, + P: CubicExtVarConfig, + P::BaseField: FieldWithVar, { #[inline] #[tracing::instrument(target = "r1cs")] @@ -491,19 +493,18 @@ where true_value: &Self, false_value: &Self, ) -> Result { - let c0 = BF::conditionally_select(cond, &true_value.c0, &false_value.c0)?; - let c1 = BF::conditionally_select(cond, &true_value.c1, &false_value.c1)?; - let c2 = BF::conditionally_select(cond, &true_value.c2, &false_value.c2)?; + let c0 = BFVar::

::conditionally_select(cond, &true_value.c0, &false_value.c0)?; + let c1 = BFVar::

::conditionally_select(cond, &true_value.c1, &false_value.c1)?; + let c2 = BFVar::

::conditionally_select(cond, &true_value.c2, &false_value.c2)?; Ok(Self::new(c0, c1, c2)) } } -impl TwoBitLookupGadget for CubicExtVar +impl

TwoBitLookupGadget for CubicExtVar

where - BF: FieldVar - + TwoBitLookupGadget, - for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>, - P: CubicExtVarConfig, + BFVar

: TwoBitLookupGadget, + P: CubicExtVarConfig, + P::BaseField: FieldWithVar, { type TableConstant = CubicExtField

; @@ -515,19 +516,18 @@ where let c0s = c.iter().map(|f| f.c0).collect::>(); let c1s = c.iter().map(|f| f.c1).collect::>(); let c2s = c.iter().map(|f| f.c2).collect::>(); - let c0 = BF::two_bit_lookup(b, &c0s)?; - let c1 = BF::two_bit_lookup(b, &c1s)?; - let c2 = BF::two_bit_lookup(b, &c2s)?; + let c0 = BFVar::

::two_bit_lookup(b, &c0s)?; + let c1 = BFVar::

::two_bit_lookup(b, &c1s)?; + let c2 = BFVar::

::two_bit_lookup(b, &c2s)?; Ok(Self::new(c0, c1, c2)) } } -impl ThreeBitCondNegLookupGadget for CubicExtVar +impl

ThreeBitCondNegLookupGadget for CubicExtVar

where - BF: FieldVar - + ThreeBitCondNegLookupGadget, - for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>, - P: CubicExtVarConfig, + BFVar

: ThreeBitCondNegLookupGadget, + P: CubicExtVarConfig, + P::BaseField: FieldWithVar, { type TableConstant = CubicExtField

; @@ -540,18 +540,17 @@ where let c0s = c.iter().map(|f| f.c0).collect::>(); let c1s = c.iter().map(|f| f.c1).collect::>(); let c2s = c.iter().map(|f| f.c2).collect::>(); - let c0 = BF::three_bit_cond_neg_lookup(b, b0b1, &c0s)?; - let c1 = BF::three_bit_cond_neg_lookup(b, b0b1, &c1s)?; - let c2 = BF::three_bit_cond_neg_lookup(b, b0b1, &c2s)?; + let c0 = BFVar::

::three_bit_cond_neg_lookup(b, b0b1, &c0s)?; + let c1 = BFVar::

::three_bit_cond_neg_lookup(b, b0b1, &c1s)?; + let c2 = BFVar::

::three_bit_cond_neg_lookup(b, b0b1, &c2s)?; Ok(Self::new(c0, c1, c2)) } } -impl AllocVar, P::BasePrimeField> for CubicExtVar +impl

AllocVar, P::BasePrimeField> for CubicExtVar

where - BF: FieldVar, - for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>, - P: CubicExtVarConfig, + P: CubicExtVarConfig, + P::BaseField: FieldWithVar, { fn new_variable>>( cs: impl Into>, @@ -571,9 +570,35 @@ where ), }; - let c0 = BF::new_variable(ark_relations::ns!(cs, "c0"), || c0, mode)?; - let c1 = BF::new_variable(ark_relations::ns!(cs, "c1"), || c1, mode)?; - let c2 = BF::new_variable(ark_relations::ns!(cs, "c2"), || c2, mode)?; + let c0 = BFVar::

::new_variable(ark_relations::ns!(cs, "c0"), || c0, mode)?; + let c1 = BFVar::

::new_variable(ark_relations::ns!(cs, "c1"), || c1, mode)?; + let c2 = BFVar::

::new_variable(ark_relations::ns!(cs, "c2"), || c2, mode)?; Ok(Self::new(c0, c1, c2)) } } + +impl<'a, P: CubicExtVarConfig> Sum<&'a CubicExtVar

> for CubicExtVar

+where + P::BaseField: FieldWithVar, +{ + fn sum>(iter: I) -> Self { + let elements = iter.collect::>(); + let c0 = elements.iter().map(|v| &v.c0).sum::>(); + let c1 = elements.iter().map(|v| &v.c1).sum::>(); + let c2 = elements.iter().map(|v| &v.c2).sum::>(); + Self::new(c0, c1, c2) + } +} + +impl<'a, P: CubicExtVarConfig> Sum> for CubicExtVar

+where + P::BaseField: FieldWithVar, +{ + fn sum>(iter: I) -> Self { + let elements = iter.collect::>(); + let c0 = elements.iter().map(|v| &v.c0).sum::>(); + let c1 = elements.iter().map(|v| &v.c1).sum::>(); + let c2 = elements.iter().map(|v| &v.c2).sum::>(); + Self::new(c0, c1, c2) + } +} diff --git a/src/fields/fp/mod.rs b/src/fields/fp/mod.rs index 2486309d..792c10ae 100644 --- a/src/fields/fp/mod.rs +++ b/src/fields/fp/mod.rs @@ -6,7 +6,7 @@ use ark_relations::r1cs::{ use core::borrow::Borrow; use crate::{ - fields::{FieldOpsBounds, FieldVar}, + fields::{FieldOpsBounds, FieldRefOpsBounds, FieldVar, FieldWithVar}, prelude::*, Assignment, ToConstraintFieldGadget, Vec, }; @@ -49,6 +49,10 @@ pub enum FpVar { Var(AllocatedFp), } +impl, const N: usize> FieldWithVar for ark_ff::models::Fp { + type Var = FpVar; +} + impl R1CSVar for FpVar { type Value = F; @@ -90,8 +94,8 @@ impl From> for FpVar { } } -impl<'a, F: PrimeField> FieldOpsBounds<'a, F, Self> for FpVar {} -impl<'a, F: PrimeField> FieldOpsBounds<'a, F, FpVar> for &'a FpVar {} +impl<'a, F: PrimeField> FieldOpsBounds for FpVar {} +impl<'a, F: PrimeField> FieldRefOpsBounds> for &'a FpVar {} impl AllocatedFp { /// Constructs `Self` from a `Boolean`: if `other` is false, this outputs @@ -127,9 +131,8 @@ impl AllocatedFp { /// Add many allocated Fp elements together. /// - /// This does not create any constraints and only creates one linear - /// combination. - pub fn addmany<'a, I: Iterator>(iter: I) -> Self { + /// This does not create any constraints and only creates one linear combination. + pub fn add_many<'a, I: Iterator>(iter: I) -> Self { let mut cs = ConstraintSystemRef::None; let mut has_value = true; let mut value = F::zero(); @@ -687,27 +690,30 @@ impl FieldVar for FpVar { } #[tracing::instrument(target = "r1cs")] - fn double(&self) -> Result { - match self { - Self::Constant(c) => Ok(Self::Constant(c.double())), - Self::Var(v) => Ok(Self::Var(v.double()?)), - } + fn double_in_place(&mut self) -> Result<&mut Self, SynthesisError> { + *self = match self { + Self::Constant(c) => Self::Constant(c.double()), + Self::Var(v) => Self::Var(v.double()?), + }; + Ok(self) } #[tracing::instrument(target = "r1cs")] - fn negate(&self) -> Result { - match self { - Self::Constant(c) => Ok(Self::Constant(-*c)), - Self::Var(v) => Ok(Self::Var(v.negate())), - } + fn negate_in_place(&mut self) -> Result<&mut Self, SynthesisError> { + *self = match self { + Self::Constant(c) => Self::Constant(-*c), + Self::Var(v) => Self::Var(v.negate()), + }; + Ok(self) } #[tracing::instrument(target = "r1cs")] - fn square(&self) -> Result { - match self { - Self::Constant(c) => Ok(Self::Constant(c.square())), - Self::Var(v) => Ok(Self::Var(v.square()?)), - } + fn square_in_place(&mut self) -> Result<&mut Self, SynthesisError> { + *self = match self { + Self::Constant(c) => Self::Constant(c.square()), + Self::Var(v) => Self::Var(v.square()?), + }; + Ok(self) } /// Enforce that `self * other == result`. @@ -782,15 +788,15 @@ impl_ops!( add, AddAssign, add_assign, - |this: &'a FpVar, other: &'a FpVar| { + |this: &mut FpVar, other: &'a FpVar| { use FpVar::*; - match (this, other) { + *this = match (&*this, other) { (Constant(c1), Constant(c2)) => Constant(*c1 + *c2), (Constant(c), Var(v)) | (Var(v), Constant(c)) => Var(v.add_constant(*c)), (Var(v1), Var(v2)) => Var(v1.add(v2)), - } + }; }, - |this: &'a FpVar, other: F| { this + &FpVar::Constant(other) }, + |this: &mut FpVar, other: F| { *this = &*this + &FpVar::Constant(other) }, F: PrimeField, ); @@ -801,16 +807,16 @@ impl_ops!( sub, SubAssign, sub_assign, - |this: &'a FpVar, other: &'a FpVar| { + |this: &mut FpVar, other: &'a FpVar| { use FpVar::*; - match (this, other) { + *this = match (&*this, other) { (Constant(c1), Constant(c2)) => Constant(*c1 - *c2), (Var(v), Constant(c)) => Var(v.sub_constant(*c)), (Constant(c), Var(v)) => Var(v.sub_constant(*c).negate()), (Var(v1), Var(v2)) => Var(v1.sub(v2)), - } + }; }, - |this: &'a FpVar, other: F| { this - &FpVar::Constant(other) }, + |this: &mut FpVar, other: F| { *this = &*this - &FpVar::Constant(other) }, F: PrimeField ); @@ -821,20 +827,20 @@ impl_ops!( mul, MulAssign, mul_assign, - |this: &'a FpVar, other: &'a FpVar| { + |this: &mut FpVar, other: &'a FpVar| { use FpVar::*; - match (this, other) { + *this = match (&*this, other) { (Constant(c1), Constant(c2)) => Constant(*c1 * *c2), (Constant(c), Var(v)) | (Var(v), Constant(c)) => Var(v.mul_constant(*c)), (Var(v1), Var(v2)) => Var(v1.mul(v2)), - } + }; }, - |this: &'a FpVar, other: F| { - if other.is_zero() { + |this: &mut FpVar, other: F| { + *this = if other.is_zero() { FpVar::zero() } else { - this * &FpVar::Constant(other) - } + &*this * FpVar::Constant(other) + }; }, F: PrimeField ); @@ -1050,7 +1056,7 @@ impl AllocVar for FpVar { impl<'a, F: PrimeField> Sum<&'a FpVar> for FpVar { fn sum>>(iter: I) -> FpVar { let mut sum_constants = F::zero(); - let sum_variables = FpVar::Var(AllocatedFp::::addmany(iter.filter_map(|x| match x { + let sum_variables = FpVar::Var(AllocatedFp::::add_many(iter.filter_map(|x| match x { FpVar::Constant(c) => { sum_constants += c; None @@ -1063,6 +1069,25 @@ impl<'a, F: PrimeField> Sum<&'a FpVar> for FpVar { } } +impl Sum> for FpVar { + fn sum>>(iter: I) -> FpVar { + let mut sum_constants = F::zero(); + let vars = iter + .filter_map(|x| match x { + FpVar::Constant(c) => { + sum_constants += c; + None + }, + FpVar::Var(v) => Some(v), + }) + .collect::>(); + let sum_variables = FpVar::Var(AllocatedFp::::add_many(vars.iter())); + + let sum = sum_variables + sum_constants; + sum + } +} + #[cfg(test)] mod test { use crate::{ diff --git a/src/fields/fp12.rs b/src/fields/fp12.rs index 12bdc8c1..db99df05 100644 --- a/src/fields/fp12.rs +++ b/src/fields/fp12.rs @@ -1,19 +1,20 @@ -use crate::fields::{fp2::Fp2Var, fp6_3over2::Fp6Var, quadratic_extension::*, FieldVar}; -use ark_ff::{ - fields::{fp12_2over3over2::*, Field}, - fp6_3over2::Fp6Config, - QuadExtConfig, +use crate::fields::{ + fp2::Fp2Var, fp6_3over2::Fp6Var, quadratic_extension::*, FieldVar, FieldWithVar, }; +use ark_ff::fields::{fp12_2over3over2::*, fp6_3over2::Fp6Config, Field, QuadExtConfig}; use ark_relations::r1cs::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 `ark_ff::fp12_2over3over2::Fp12

`. -pub type Fp12Var

= QuadExtVar::Fp6Config>, Fp12ConfigWrapper

>; +pub type Fp12Var

= QuadExtVar>; type Fp2Config

= <

::Fp6Config as Fp6Config>::Fp2Config; -impl QuadExtVarConfig> for Fp12ConfigWrapper

{ +impl QuadExtVarConfig for Fp12ConfigWrapper

+where + Self::BasePrimeField: FieldWithVar, +{ fn mul_base_field_var_by_frob_coeff(fe: &mut Fp6Var, power: usize) { fe.c0 *= Self::FROBENIUS_COEFF_C1[power % Self::DEGREE_OVER_BASE_PRIME_FIELD]; fe.c1 *= Self::FROBENIUS_COEFF_C1[power % Self::DEGREE_OVER_BASE_PRIME_FIELD]; @@ -21,7 +22,10 @@ impl QuadExtVarConfig> for Fp12ConfigWrapper } } -impl Fp12Var

{ +impl Fp12Var

+where + as Field>::BasePrimeField: FieldWithVar, +{ /// Multiplies by a sparse element of the form `(c0 = (c0, c1, 0), c1 = (0, /// d1, 0))`. #[inline] diff --git a/src/fields/fp2.rs b/src/fields/fp2.rs index 13d88688..fca20cda 100644 --- a/src/fields/fp2.rs +++ b/src/fields/fp2.rs @@ -1,12 +1,17 @@ -use crate::fields::{fp::FpVar, quadratic_extension::*}; +use crate::fields::{quadratic_extension::*, FieldWithVar}; use ark_ff::fields::{Fp2Config, Fp2ConfigWrapper, QuadExtConfig}; +type FpVar

= < as QuadExtConfig>::BasePrimeField as FieldWithVar>::Var; + /// A quadratic extension field constructed over a prime field. /// This is the R1CS equivalent of `ark_ff::Fp2

`. -pub type Fp2Var

= QuadExtVar::Fp>, Fp2ConfigWrapper

>; +pub type Fp2Var

= QuadExtVar>; -impl QuadExtVarConfig> for Fp2ConfigWrapper

{ - fn mul_base_field_var_by_frob_coeff(fe: &mut FpVar, power: usize) { +impl QuadExtVarConfig for Fp2ConfigWrapper

+where + Self::BaseField: FieldWithVar, +{ + fn mul_base_field_var_by_frob_coeff(fe: &mut FpVar

, power: usize) { *fe *= Self::FROBENIUS_COEFF_C1[power % Self::DEGREE_OVER_BASE_PRIME_FIELD]; } } diff --git a/src/fields/fp3.rs b/src/fields/fp3.rs index a93922c6..3819250c 100644 --- a/src/fields/fp3.rs +++ b/src/fields/fp3.rs @@ -1,19 +1,17 @@ -use crate::fields::{cubic_extension::*, fp::FpVar}; -use ark_ff::{ - fields::{CubicExtConfig, Fp3ConfigWrapper}, - Fp3Config, -}; +use crate::fields::{cubic_extension::*, FieldWithVar}; +use ark_ff::fields::{CubicExtConfig, Fp3Config, Fp3ConfigWrapper}; + +type FpVar

= < as CubicExtConfig>::BasePrimeField as FieldWithVar>::Var; /// A cubic extension field constructed over a prime field. /// This is the R1CS equivalent of `ark_ff::Fp3

`. -pub type Fp3Var

= CubicExtVar::Fp>, Fp3ConfigWrapper

>; +pub type Fp3Var

= CubicExtVar>; -impl CubicExtVarConfig> for Fp3ConfigWrapper

{ - fn mul_base_field_vars_by_frob_coeff( - c1: &mut FpVar, - c2: &mut FpVar, - power: usize, - ) { +impl CubicExtVarConfig for Fp3ConfigWrapper

+where + Self::BasePrimeField: FieldWithVar, +{ + fn mul_base_field_vars_by_frob_coeff(c1: &mut FpVar

, c2: &mut FpVar

, power: usize) { *c1 *= Self::FROBENIUS_COEFF_C1[power % Self::DEGREE_OVER_BASE_PRIME_FIELD]; *c2 *= Self::FROBENIUS_COEFF_C2[power % Self::DEGREE_OVER_BASE_PRIME_FIELD]; } diff --git a/src/fields/fp4.rs b/src/fields/fp4.rs index 6340d862..0373e339 100644 --- a/src/fields/fp4.rs +++ b/src/fields/fp4.rs @@ -1,15 +1,15 @@ -use crate::fields::{fp2::Fp2Var, quadratic_extension::*}; -use ark_ff::{ - fields::{Fp4ConfigWrapper, QuadExtConfig}, - Fp4Config, -}; +use crate::fields::{fp2::Fp2Var, quadratic_extension::*, FieldWithVar}; +use ark_ff::fields::{Fp4Config, Fp4ConfigWrapper, QuadExtConfig}; /// A quartic extension field constructed as the tower of a /// quadratic extension over a quadratic extension field. /// This is the R1CS equivalent of `ark_ff::Fp4

`. -pub type Fp4Var

= QuadExtVar::Fp2Config>, Fp4ConfigWrapper

>; +pub type Fp4Var

= QuadExtVar>; -impl QuadExtVarConfig> for Fp4ConfigWrapper

{ +impl QuadExtVarConfig for Fp4ConfigWrapper

+where + Self::BasePrimeField: FieldWithVar, +{ fn mul_base_field_var_by_frob_coeff(fe: &mut Fp2Var, power: usize) { fe.c0 *= Self::FROBENIUS_COEFF_C1[power % Self::DEGREE_OVER_BASE_PRIME_FIELD]; fe.c1 *= Self::FROBENIUS_COEFF_C1[power % Self::DEGREE_OVER_BASE_PRIME_FIELD]; diff --git a/src/fields/fp6_2over3.rs b/src/fields/fp6_2over3.rs index c3262c1a..a5f144f8 100644 --- a/src/fields/fp6_2over3.rs +++ b/src/fields/fp6_2over3.rs @@ -1,12 +1,15 @@ -use crate::fields::{fp3::Fp3Var, quadratic_extension::*}; -use ark_ff::{fields::fp6_2over3::*, QuadExtConfig}; +use crate::fields::{fp3::Fp3Var, quadratic_extension::*, FieldWithVar}; +use ark_ff::fields::{fp6_2over3::*, QuadExtConfig}; /// A sextic extension field constructed as the tower of a /// quadratic extension over a cubic extension field. /// This is the R1CS equivalent of `ark_ff::fp6_2over3::Fp6

`. -pub type Fp6Var

= QuadExtVar::Fp3Config>, Fp6ConfigWrapper

>; +pub type Fp6Var

= QuadExtVar>; -impl QuadExtVarConfig> for Fp6ConfigWrapper

{ +impl QuadExtVarConfig for Fp6ConfigWrapper

+where + Self::BasePrimeField: FieldWithVar, +{ fn mul_base_field_var_by_frob_coeff(fe: &mut Fp3Var, power: usize) { fe.c0 *= Self::FROBENIUS_COEFF_C1[power % Self::DEGREE_OVER_BASE_PRIME_FIELD]; fe.c1 *= Self::FROBENIUS_COEFF_C1[power % Self::DEGREE_OVER_BASE_PRIME_FIELD]; diff --git a/src/fields/fp6_3over2.rs b/src/fields/fp6_3over2.rs index 19c9648b..c8ae1fca 100644 --- a/src/fields/fp6_3over2.rs +++ b/src/fields/fp6_3over2.rs @@ -1,17 +1,19 @@ -use crate::fields::{cubic_extension::*, fp2::*}; -use ark_ff::{ - fields::{fp6_3over2::*, Fp2}, - CubicExtConfig, -}; +use crate::fields::{cubic_extension::*, fp2::*, FieldWithVar}; +use ark_ff::fields::{fp6_3over2::*, CubicExtConfig, Fp2}; use ark_relations::r1cs::SynthesisError; use ark_std::ops::MulAssign; /// A sextic extension field constructed as the tower of a /// cubic extension over a quadratic extension field. /// This is the R1CS equivalent of `ark_ff::fp6_3over3::Fp6

`. -pub type Fp6Var

= CubicExtVar::Fp2Config>, Fp6ConfigWrapper

>; +pub type Fp6Var

= CubicExtVar>; -impl CubicExtVarConfig> for Fp6ConfigWrapper

{ +type Fp

= as CubicExtConfig>::BasePrimeField; + +impl CubicExtVarConfig for Fp6ConfigWrapper

+where + Fp

: FieldWithVar, +{ fn mul_base_field_vars_by_frob_coeff( c1: &mut Fp2Var, c2: &mut Fp2Var, @@ -22,7 +24,10 @@ impl CubicExtVarConfig> for Fp6ConfigWrapper< } } -impl Fp6Var

{ +impl Fp6Var

+where + Fp

: FieldWithVar, +{ /// Multiplies `self` by a sparse element which has `c0 == c2 == zero`. pub fn mul_by_0_c1_0(&self, c1: &Fp2Var) -> Result { // Karatsuba multiplication @@ -79,7 +84,10 @@ impl Fp6Var

{ } } -impl MulAssign> for Fp6Var

{ +impl MulAssign> for Fp6Var

+where + Fp

: FieldWithVar, +{ fn mul_assign(&mut self, other: Fp2) { self.c0 *= other; self.c1 *= other; diff --git a/src/fields/mod.rs b/src/fields/mod.rs index 0c342998..772fb026 100644 --- a/src/fields/mod.rs +++ b/src/fields/mod.rs @@ -2,6 +2,7 @@ use ark_ff::{prelude::*, BitIteratorBE}; use ark_relations::r1cs::{ConstraintSystemRef, SynthesisError}; use core::{ fmt::Debug, + iter::Sum, ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign}, }; @@ -49,12 +50,15 @@ pub mod fp6_2over3; /// `ark_ff::fp6_3over2::Fp6` pub mod fp6_3over2; -/// This trait is a hack used to work around the lack of implied bounds. -pub trait FieldOpsBounds<'a, F, T: 'a>: +pub trait FieldWithVar: Field { + type Var: FieldVar + for<'a> FieldOpsBounds; +} + +pub trait FieldRefOpsBounds: Sized - + Add<&'a T, Output = T> - + Sub<&'a T, Output = T> - + Mul<&'a T, Output = T> + + for<'a> Add<&'a T, Output = T> + + for<'a> Sub<&'a T, Output = T> + + for<'a> Mul<&'a T, Output = T> + Add + Sub + Mul @@ -64,6 +68,22 @@ pub trait FieldOpsBounds<'a, F, T: 'a>: { } +/// This trait is a hack used to work around the lack of implied bounds. +pub trait FieldOpsBounds>: + 'static + + Sized + + for<'a> Add<&'a Self, Output = Self> + + for<'a> Sub<&'a Self, Output = Self> + + for<'a> Mul<&'a Self, Output = Self> + + Add + + Sub + + Mul + + Add + + Sub + + Mul +{ +} + /// A variable representing a field. Corresponds to the native type `F`. pub trait FieldVar: 'static @@ -75,7 +95,7 @@ pub trait FieldVar: + AllocVar + ToBytesGadget + CondSelectGadget - + for<'a> FieldOpsBounds<'a, F, Self> + + for<'a> FieldOpsBounds + for<'a> AddAssign<&'a Self> + for<'a> SubAssign<&'a Self> + for<'a> MulAssign<&'a Self> @@ -86,6 +106,8 @@ pub trait FieldVar: + SubAssign + MulAssign + Debug + + for<'a> Sum<&'a Self> + + Sum { /// Returns the constant `F::zero()`. fn zero() -> Self; @@ -110,41 +132,36 @@ pub trait FieldVar: /// Computes `self + self`. fn double(&self) -> Result { - Ok(self.clone() + self) + let mut result = self.clone(); + result.double_in_place()?; + Ok(result) } /// Sets `self = self + self`. - fn double_in_place(&mut self) -> Result<&mut Self, SynthesisError> { - *self += self.double()?; - Ok(self) - } + fn double_in_place(&mut self) -> Result<&mut Self, SynthesisError>; - /// Coputes `-self`. - fn negate(&self) -> Result; + /// Computes `-self`. + fn negate(&self) -> Result { + let mut result = self.clone(); + result.negate_in_place()?; + Ok(result) + } /// Sets `self = -self`. - #[inline] - fn negate_in_place(&mut self) -> Result<&mut Self, SynthesisError> { - *self = self.negate()?; - Ok(self) - } + fn negate_in_place(&mut self) -> Result<&mut Self, SynthesisError>; /// 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) + let mut result = self.clone(); + result.square_in_place()?; + Ok(result) } - /// Sets `self = self.square()`. - fn square_in_place(&mut self) -> Result<&mut Self, SynthesisError> { - *self = self.square()?; - Ok(self) - } + /// Sets `self = self * self`. + fn square_in_place(&mut self) -> Result<&mut Self, SynthesisError>; /// Enforces that `self * other == result`. + /// Provides a default implementation in terms of `mul` and `self.enforce_equal`. fn mul_equals(&self, other: &Self, result: &Self) -> Result<(), SynthesisError> { let actual_result = self.clone() * other; result.enforce_equal(&actual_result) @@ -194,7 +211,7 @@ pub trait FieldVar: } } - /// Computes the frobenius map over `self`. + /// Computes the Frobenius map over `self`. fn frobenius_map(&self, power: usize) -> Result; /// Sets `self = self.frobenius_map()`. diff --git a/src/fields/nonnative/allocated_field_var.rs b/src/fields/nonnative/allocated_field_var.rs index aadbe1a3..d2e2e3f8 100644 --- a/src/fields/nonnative/allocated_field_var.rs +++ b/src/fields/nonnative/allocated_field_var.rs @@ -185,6 +185,67 @@ impl Ok(res) } + /// Add many allocated elements together. + /// + /// This does not create any constraints and only creates #limbs linear combinations. + /// + /// If there are 0 items in the iterator, then this returns `Ok(None)`. + pub fn add_many<'a, I: Iterator>( + mut iter: I, + ) -> Result, SynthesisError> { + let mut intermediate_results = Vec::new(); + let cs; + let mut num_of_additions_over_normal_form; + let is_in_the_normal_form = false; + if let Some(first) = iter.next() { + let mut limbs_iter = Vec::new(); + cs = first.cs(); + let optimization_type = first.get_optimization_type(); + for limb in &first.limbs { + limbs_iter.push(vec![limb]); + } + num_of_additions_over_normal_form = first.num_of_additions_over_normal_form; + for elem in iter { + for (cur_limb, limbs) in elem.limbs.iter().zip(&mut limbs_iter) { + limbs.push(cur_limb); + } + num_of_additions_over_normal_form += + elem.num_of_additions_over_normal_form + BaseField::one(); + + // Reduce the result if we're past the budget. + if Reducer::::should_reduce_post_addition( + num_of_additions_over_normal_form, + optimization_type, + ) { + let limbs = limbs_iter + .into_iter() + .map(|limbs| limbs.into_iter().sum::>()) + .collect::>(); + + let mut result = Self { + cs: cs.clone(), + limbs, + num_of_additions_over_normal_form, + is_in_the_normal_form, + target_phantom: PhantomData, + }; + Reducer::::post_add_reduce(&mut result)?; + intermediate_results.push(result); + limbs_iter = Vec::new(); + } + } + let result = intermediate_results + .into_iter() + .fold(Self::zero(cs.clone()).unwrap(), |sum, new| { + sum.add(&new).unwrap() + }); + + Ok(Some(result)) + } else { + Ok(None) + } + } + /// Subtract a nonnative field element, without the final reduction step #[tracing::instrument(target = "r1cs")] pub fn sub_without_reduce(&self, other: &Self) -> R1CSResult { diff --git a/src/fields/nonnative/allocated_mul_result.rs b/src/fields/nonnative/allocated_mul_result.rs index 07c74daf..50a15e13 100644 --- a/src/fields/nonnative/allocated_mul_result.rs +++ b/src/fields/nonnative/allocated_mul_result.rs @@ -13,7 +13,7 @@ use ark_std::{marker::PhantomData, vec::Vec}; use num_bigint::BigUint; /// The allocated form of `NonNativeFieldMulResultVar` (introduced below) -#[derive(Debug)] +#[derive(Debug, Clone)] #[must_use] pub struct AllocatedNonNativeFieldMulResultVar { /// Constraint system reference diff --git a/src/fields/nonnative/field_var.rs b/src/fields/nonnative/field_var.rs index 4a08dd16..8b558c68 100644 --- a/src/fields/nonnative/field_var.rs +++ b/src/fields/nonnative/field_var.rs @@ -1,7 +1,7 @@ use super::{params::OptimizationType, AllocatedNonNativeFieldVar, NonNativeFieldMulResultVar}; use crate::{ boolean::Boolean, - fields::{fp::FpVar, FieldVar}, + fields::{fp::FpVar, FieldVar, FieldRefOpsBounds}, prelude::*, R1CSVar, ToConstraintFieldGadget, }; @@ -10,6 +10,7 @@ use ark_relations::r1cs::{ConstraintSystemRef, Namespace, Result as R1CSResult, use ark_std::{ borrow::Borrow, hash::{Hash, Hasher}, + iter::Sum, vec::Vec, }; @@ -91,13 +92,13 @@ impl } } -impl<'a, TargetField: PrimeField, BaseField: PrimeField> FieldOpsBounds<'a, TargetField, Self> +impl<'a, TargetField: PrimeField, BaseField: PrimeField> FieldOpsBounds for NonNativeFieldVar { } impl<'a, TargetField: PrimeField, BaseField: PrimeField> - FieldOpsBounds<'a, TargetField, NonNativeFieldVar> + FieldRefOpsBounds> for &'a NonNativeFieldVar { } @@ -118,11 +119,30 @@ impl FieldVar R1CSResult { - match self { - Self::Constant(c) => Ok(Self::Constant(-*c)), - Self::Var(v) => Ok(Self::Var(v.negate()?)), - } + fn negate_in_place(&mut self) -> R1CSResult<&mut Self> { + *self = match self { + Self::Constant(c) => Self::Constant(-*c), + Self::Var(v) => Self::Var(v.negate()?), + }; + Ok(self) + } + + #[tracing::instrument(target = "r1cs")] + fn double_in_place(&mut self) -> R1CSResult<&mut Self> { + *self = match self { + Self::Constant(c) => Self::Constant(c.double()), + Self::Var(v) => Self::Var(v.add(&*v)?), + }; + Ok(self) + } + + #[tracing::instrument(target = "r1cs")] + fn square_in_place(&mut self) -> R1CSResult<&mut Self> { + *self = match self { + Self::Constant(c) => Self::Constant(c.square()), + Self::Var(v) => Self::Var(v.mul(&*v)?), + }; + Ok(self) } #[tracing::instrument(target = "r1cs")] @@ -153,15 +173,15 @@ impl_bounded_ops!( add, AddAssign, add_assign, - |this: &'a NonNativeFieldVar, other: &'a NonNativeFieldVar| { + |this: &mut NonNativeFieldVar, other: &'a NonNativeFieldVar| { use NonNativeFieldVar::*; - match (this, other) { + *this = match (&*this, other) { (Constant(c1), Constant(c2)) => Constant(*c1 + c2), (Constant(c), Var(v)) | (Var(v), Constant(c)) => Var(v.add_constant(c).unwrap()), (Var(v1), Var(v2)) => Var(v1.add(v2).unwrap()), - } + }; }, - |this: &'a NonNativeFieldVar, other: TargetField| { this + &NonNativeFieldVar::Constant(other) }, + |this: &mut NonNativeFieldVar, other: TargetField| { *this = &*this + &NonNativeFieldVar::Constant(other) }, (TargetField: PrimeField, BaseField: PrimeField), ); @@ -172,17 +192,17 @@ impl_bounded_ops!( sub, SubAssign, sub_assign, - |this: &'a NonNativeFieldVar, other: &'a NonNativeFieldVar| { + |this: &mut NonNativeFieldVar, other: &'a NonNativeFieldVar| { use NonNativeFieldVar::*; - match (this, other) { + *this = match (&*this, other) { (Constant(c1), Constant(c2)) => Constant(*c1 - c2), (Var(v), Constant(c)) => Var(v.sub_constant(c).unwrap()), (Constant(c), Var(v)) => Var(v.sub_constant(c).unwrap().negate().unwrap()), (Var(v1), Var(v2)) => Var(v1.sub(v2).unwrap()), - } + }; }, - |this: &'a NonNativeFieldVar, other: TargetField| { - this - &NonNativeFieldVar::Constant(other) + |this: &mut NonNativeFieldVar, other: TargetField| { + *this = &*this - &NonNativeFieldVar::Constant(other) }, (TargetField: PrimeField, BaseField: PrimeField), ); @@ -194,20 +214,20 @@ impl_bounded_ops!( mul, MulAssign, mul_assign, - |this: &'a NonNativeFieldVar, other: &'a NonNativeFieldVar| { + |this: &mut NonNativeFieldVar, other: &'a NonNativeFieldVar| { use NonNativeFieldVar::*; - match (this, other) { + *this = match (&*this, other) { (Constant(c1), Constant(c2)) => Constant(*c1 * c2), (Constant(c), Var(v)) | (Var(v), Constant(c)) => Var(v.mul_constant(c).unwrap()), (Var(v1), Var(v2)) => Var(v1.mul(v2).unwrap()), } }, - |this: &'a NonNativeFieldVar, other: TargetField| { - if other.is_zero() { + |this: &mut NonNativeFieldVar, other: TargetField| { + *this = if other.is_zero() { NonNativeFieldVar::zero() } else { - this * &NonNativeFieldVar::Constant(other) - } + &*this * &NonNativeFieldVar::Constant(other) + }; }, (TargetField: PrimeField, BaseField: PrimeField), ); @@ -459,6 +479,54 @@ impl ToConstraintFieldGadget Sum<&'a Self> + for NonNativeFieldVar +{ + fn sum>(iter: I) -> Self { + let mut sum_constants = TargetField::zero(); + let vars = iter + .filter_map(|x| match x { + Self::Constant(c) => { + sum_constants += c; + None + }, + Self::Var(v) => Some(v), + }) + .collect::>(); + let sum_variables = AllocatedNonNativeFieldVar::add_many(vars.into_iter()) + .unwrap() + .map(Self::Var) + .unwrap_or(Self::zero()); + + let sum = sum_variables + sum_constants; + sum + } +} + +impl Sum + for NonNativeFieldVar +{ + fn sum>(iter: I) -> Self { + let mut sum_constants = TargetField::zero(); + let vars = iter + .filter_map(|x| match x { + Self::Constant(c) => { + sum_constants += c; + None + }, + Self::Var(v) => Some(v), + }) + .collect::>(); + let sum_variables = AllocatedNonNativeFieldVar::add_many(vars.iter()) + .unwrap() + .map(Self::Var) + .unwrap_or(Self::zero()); + + let sum = sum_variables + sum_constants; + sum + } +} + impl NonNativeFieldVar { /// The `mul_without_reduce` for `NonNativeFieldVar` #[tracing::instrument(target = "r1cs")] diff --git a/src/fields/nonnative/mod.rs b/src/fields/nonnative/mod.rs index 548a40f2..31a23d26 100644 --- a/src/fields/nonnative/mod.rs +++ b/src/fields/nonnative/mod.rs @@ -178,7 +178,7 @@ macro_rules! overhead { pub(crate) use overhead; -/// Parameters for a specific `NonNativeFieldVar` instantiation +/// Config for a specific `NonNativeFieldVar` instantiation #[derive(Clone, Debug)] pub struct NonNativeFieldConfig { /// The number of limbs (`BaseField` elements) used to represent a diff --git a/src/fields/nonnative/mul_result.rs b/src/fields/nonnative/mul_result.rs index a04e8d6e..a141dcac 100644 --- a/src/fields/nonnative/mul_result.rs +++ b/src/fields/nonnative/mul_result.rs @@ -10,7 +10,7 @@ use ark_relations::r1cs::Result as R1CSResult; /// obtain this intermediate representation, which can still be added. /// Then, one can call `reduce` to reduce it back to `NonNativeFieldVar`. /// This may help cut the number of reduce operations. -#[derive(Debug)] +#[derive(Debug, Clone)] #[must_use] pub enum NonNativeFieldMulResultVar { /// as a constant @@ -66,14 +66,14 @@ impl_bounded_ops!( add, AddAssign, add_assign, - |this: &'a NonNativeFieldMulResultVar, other: &'a NonNativeFieldMulResultVar| { + |this: &mut NonNativeFieldMulResultVar, other: &'a NonNativeFieldMulResultVar| { use NonNativeFieldMulResultVar::*; - match (this, other) { + *this = match (&*this, other) { (Constant(c1), Constant(c2)) => Constant(*c1 + c2), (Constant(c), Var(v)) | (Var(v), Constant(c)) => Var(v.add_constant(c).unwrap()), (Var(v1), Var(v2)) => Var(v1.add(v2).unwrap()), - } + }; }, - |this: &'a NonNativeFieldMulResultVar, other: TargetField| { this + &NonNativeFieldMulResultVar::Constant(other) }, + |this: &mut NonNativeFieldMulResultVar, other: TargetField| { *this = &*this + &NonNativeFieldMulResultVar::Constant(other) }, (TargetField: PrimeField, BaseField: PrimeField), ); diff --git a/src/fields/nonnative/reduce.rs b/src/fields/nonnative/reduce.rs index 31e5fe7a..7f29ea06 100644 --- a/src/fields/nonnative/reduce.rs +++ b/src/fields/nonnative/reduce.rs @@ -1,4 +1,8 @@ -use super::{overhead, params::get_params, AllocatedNonNativeFieldVar}; +use super::{ + overhead, + params::{get_params, OptimizationType}, + AllocatedNonNativeFieldVar, +}; use crate::{ alloc::AllocVar, boolean::Boolean, @@ -130,6 +134,17 @@ impl Reducer bool { + let target_size = TargetField::MODULUS_BIT_SIZE as usize; + let base_size = BaseField::MODULUS_BIT_SIZE as usize; + let params = get_params(target_size, base_size, optimization_type); + let surfeit = overhead!(num_of_additions_over_normal_form + BaseField::one()) + 1; + base_size <= (2 * params.bits_per_limb + surfeit + 1) + } + /// Reduction to be enforced after additions #[tracing::instrument(target = "r1cs")] pub fn post_add_reduce( diff --git a/src/fields/quadratic_extension.rs b/src/fields/quadratic_extension.rs index 5e665bb4..ae3602a4 100644 --- a/src/fields/quadratic_extension.rs +++ b/src/fields/quadratic_extension.rs @@ -10,43 +10,57 @@ use crate::{ prelude::*, ToConstraintFieldGadget, Vec, }; +use ark_std::iter::Sum; + +use super::{FieldWithVar, FieldRefOpsBounds}; /// This struct is the `R1CS` equivalent of the quadratic extension field type /// in `ark-ff`, i.e. `ark_ff::QuadExtField`. #[derive(Derivative)] -#[derivative(Debug(bound = "BF: core::fmt::Debug"), Clone(bound = "BF: Clone"))] +#[derivative( + Debug(bound = "P::BaseField: FieldWithVar"), + Clone(bound = "P::BaseField: FieldWithVar") +)] #[must_use] -pub struct QuadExtVar, P: QuadExtVarConfig> +pub struct QuadExtVar where - for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>, + P::BaseField: FieldWithVar, { /// The zero-th coefficient of this field element. - pub c0: BF, + pub c0: BFVar

, /// The first coefficient of this field element. - pub c1: BF, + pub c1: BFVar

, #[derivative(Debug = "ignore")] _params: PhantomData

, } +type BFVar

= <

::BaseField as FieldWithVar>::Var; + +impl FieldWithVar for QuadExtField

+where + P::BaseField: FieldWithVar, +{ + type Var = QuadExtVar

; +} + /// This trait describes parameters that are used to implement arithmetic for /// `QuadExtVar`. -pub trait QuadExtVarConfig>: - QuadExtConfig +pub trait QuadExtVarConfig: QuadExtConfig where - for<'a> &'a BF: FieldOpsBounds<'a, Self::BaseField, BF>, + Self::BaseField: FieldWithVar, { /// 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); + fn mul_base_field_var_by_frob_coeff(fe: &mut BFVar, power: usize); } -impl, P: QuadExtVarConfig> QuadExtVar +impl QuadExtVar

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

, c1: BFVar

) -> Self { Self { c0, c1, @@ -57,8 +71,8 @@ where /// 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) + pub fn mul_base_field_by_nonresidue(fe: &BFVar

) -> Result, SynthesisError> { + Ok(fe.clone() * P::NONRESIDUE) } /// Multiplies `self` by a constant from the base field. @@ -116,11 +130,9 @@ where } } -impl R1CSVar for QuadExtVar +impl R1CSVar for QuadExtVar

where - BF: FieldVar, - for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>, - P: QuadExtVarConfig, + P::BaseField: FieldWithVar, { type Value = QuadExtField

; @@ -137,98 +149,91 @@ where } } -impl From> for QuadExtVar +impl From> for QuadExtVar

where - BF: FieldVar, - for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>, - P: QuadExtVarConfig, + P::BaseField: FieldWithVar, { fn from(other: Boolean) -> Self { - let c0 = BF::from(other); - let c1 = BF::zero(); + let c0 = BFVar::

::from(other); + let c1 = BFVar::

::zero(); Self::new(c0, c1) } } -impl<'a, BF, P> FieldOpsBounds<'a, QuadExtField

, QuadExtVar> for QuadExtVar -where - BF: FieldVar, - for<'b> &'b BF: FieldOpsBounds<'b, P::BaseField, BF>, - P: QuadExtVarConfig, +impl<'a, P: QuadExtVarConfig> FieldOpsBounds, &'a Self> for QuadExtVar

where + P::BaseField: FieldWithVar { } -impl<'a, BF, P> FieldOpsBounds<'a, QuadExtField

, QuadExtVar> for &'a QuadExtVar + +impl<'a, P: QuadExtVarConfig> FieldRefOpsBounds, QuadExtVar

> + for &'a QuadExtVar

where - BF: FieldVar, - for<'b> &'b BF: FieldOpsBounds<'b, P::BaseField, BF>, - P: QuadExtVarConfig, + P::BaseField: FieldWithVar, { } -impl FieldVar, P::BasePrimeField> for QuadExtVar +impl FieldVar, P::BasePrimeField> for QuadExtVar

where - BF: FieldVar, - for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>, - P: QuadExtVarConfig, + P::BaseField: FieldWithVar, { fn constant(other: QuadExtField

) -> Self { - let c0 = BF::constant(other.c0); - let c1 = BF::constant(other.c1); + let c0 = BFVar::

::constant(other.c0); + let c1 = BFVar::

::constant(other.c1); Self::new(c0, c1) } fn zero() -> Self { - let c0 = BF::zero(); - let c1 = BF::zero(); + let c0 = BFVar::

::zero(); + let c1 = BFVar::

::zero(); Self::new(c0, c1) } fn one() -> Self { - let c0 = BF::one(); - let c1 = BF::zero(); + let c0 = BFVar::

::one(); + let c1 = BFVar::

::zero(); Self::new(c0, c1) } #[inline] #[tracing::instrument(target = "r1cs")] - fn double(&self) -> Result { - let c0 = self.c0.double()?; - let c1 = self.c1.double()?; - Ok(Self::new(c0, c1)) + fn double_in_place(&mut self) -> Result<&mut Self, SynthesisError> { + self.c0.double_in_place()?; + self.c1.double_in_place()?; + Ok(self) } #[inline] #[tracing::instrument(target = "r1cs")] - fn negate(&self) -> Result { - let mut result = self.clone(); - result.c0.negate_in_place()?; - result.c1.negate_in_place()?; - Ok(result) + fn negate_in_place(&mut self) -> Result<&mut Self, SynthesisError> { + self.c0.negate_in_place()?; + self.c1.negate_in_place()?; + Ok(self) } #[inline] #[tracing::instrument(target = "r1cs")] - fn square(&self) -> Result { + fn square_in_place(&mut self) -> Result<&mut Self, SynthesisError> { // From Libsnark/fp2_gadget.tcc // Complex multiplication for Fp2: // "Multiplication and Squaring on Pairing-Friendly Fields" // Devegili, OhEigeartaigh, Scott, Dahab // v0 = c0 - c1 - let mut v0 = &self.c0 - &self.c1; + let self_c0 = self.c0.clone(); + let mut v0 = self_c0.clone() - &self.c1; // v3 = c0 - beta * c1 - let v3 = &self.c0 - &Self::mul_base_field_by_nonresidue(&self.c1)?; + let v3 = self_c0.clone() - &Self::mul_base_field_by_nonresidue(&self.c1)?; // v2 = c0 * c1 - let v2 = &self.c0 * &self.c1; + let v2 = self_c0 * &self.c1; // v0 = (v0 * v3) + v2 v0 *= &v3; v0 += &v2; - let c0 = &v0 + &Self::mul_base_field_by_nonresidue(&v2)?; - let c1 = v2.double()?; + self.c0 = v0 + &Self::mul_base_field_by_nonresidue(&v2)?; + self.c1 = v2.double()?; - Ok(Self::new(c0, c1)) + Ok(self) } #[tracing::instrument(target = "r1cs")] @@ -246,19 +251,19 @@ where // "Multiplication and Squaring on Pairing-Friendly Fields" // Devegili, OhEigeartaigh, Scott, Dahab // Compute v1 - let v1 = &self.c1 * &other.c1; + let v1 = self.c1.clone() * &other.c1; // Perform second check let non_residue_times_v1 = Self::mul_base_field_by_nonresidue(&v1)?; - let rhs = &result.c0 - &non_residue_times_v1; + let rhs = result.c0.clone() - &non_residue_times_v1; self.c0.mul_equals(&other.c0, &rhs)?; // Last check - let a0_plus_a1 = &self.c0 + &self.c1; - let b0_plus_b1 = &other.c0 + &other.c1; - let one_minus_non_residue_v1 = &v1 - &non_residue_times_v1; + let a0_plus_a1 = self.c0.clone() + &self.c1; + let b0_plus_b1 = other.c0.clone() + &other.c1; + let one_minus_non_residue_v1 = v1 - non_residue_times_v1; - let tmp = &(&result.c1 + &result.c0) + &one_minus_non_residue_v1; + let tmp = one_minus_non_residue_v1 + &result.c1 + &result.c0; a0_plus_a1.mul_equals(&b0_plus_b1, &tmp)?; Ok(()) @@ -294,49 +299,47 @@ where } impl_bounded_ops!( - QuadExtVar, + QuadExtVar

, QuadExtField

, Add, add, AddAssign, add_assign, - |this: &'a QuadExtVar, other: &'a QuadExtVar| { - let c0 = &this.c0 + &other.c0; - let c1 = &this.c1 + &other.c1; - QuadExtVar::new(c0, c1) + |this: &mut QuadExtVar

, other: &'a QuadExtVar

| { + this.c0 += &other.c0; + this.c1 += &other.c1; }, - |this: &'a QuadExtVar, other: QuadExtField

| { - this + QuadExtVar::constant(other) + |this: &mut QuadExtVar

, other: QuadExtField

| { + *this = &*this + QuadExtVar::constant(other); }, - (BF: FieldVar, P: QuadExtVarConfig), - for <'b> &'b BF: FieldOpsBounds<'b, P::BaseField, BF> + (P: QuadExtVarConfig), + P::BaseField: FieldWithVar, ); impl_bounded_ops!( - QuadExtVar, + QuadExtVar

, QuadExtField

, Sub, sub, SubAssign, sub_assign, - |this: &'a QuadExtVar, other: &'a QuadExtVar| { - let c0 = &this.c0 - &other.c0; - let c1 = &this.c1 - &other.c1; - QuadExtVar::new(c0, c1) + |this: &mut QuadExtVar

, other: &'a QuadExtVar

| { + this.c0 -= &other.c0; + this.c1 -= &other.c1; }, - |this: &'a QuadExtVar, other: QuadExtField

| { - this - QuadExtVar::constant(other) + |this: &mut QuadExtVar

, other: QuadExtField

| { + *this = &*this - QuadExtVar::constant(other); }, - (BF: FieldVar, P: QuadExtVarConfig), - for <'b> &'b BF: FieldOpsBounds<'b, P::BaseField, BF> + (P: QuadExtVarConfig), + P::BaseField: FieldWithVar, ); impl_bounded_ops!( - QuadExtVar, + QuadExtVar

, QuadExtField

, Mul, mul, MulAssign, mul_assign, - |this: &'a QuadExtVar, other: &'a QuadExtVar| { + |this: &mut QuadExtVar

, other: &'a QuadExtVar

| { // Karatsuba multiplication for Fp2: // v0 = A.c0 * B.c0 // v1 = A.c1 * B.c1 @@ -349,29 +352,27 @@ impl_bounded_ops!( // Reference: // "Multiplication and Squaring on Pairing-Friendly Fields" // Devegili, OhEigeartaigh, Scott, Dahab - let mut result = this.clone(); - let v0 = &this.c0 * &other.c0; - let v1 = &this.c1 * &other.c1; - - result.c1 += &this.c0; - result.c1 *= &other.c0 + &other.c1; - result.c1 -= &v0; - result.c1 -= &v1; - result.c0 = v0 + &QuadExtVar::::mul_base_field_by_nonresidue(&v1).unwrap(); - result + let this_copy = this.clone(); + let v0 = this_copy.c0 * &other.c0; + let v1 = this_copy.c1 * &other.c1; + + this.c1 += &this.c0; + this.c1 *= &(other.c0.clone() + &other.c1); + this.c1 -= &v0; + this.c1 -= &v1; + this.c0 = v0 + &QuadExtVar::

::mul_base_field_by_nonresidue(&v1).unwrap(); }, - |this: &'a QuadExtVar, other: QuadExtField

| { - this * QuadExtVar::constant(other) + |this: &mut QuadExtVar

, other: QuadExtField

| { + *this = QuadExtVar::constant(other) * &*this; }, - (BF: FieldVar, P: QuadExtVarConfig), - for <'b> &'b BF: FieldOpsBounds<'b, P::BaseField, BF> + (P: QuadExtVarConfig), + P::BaseField: FieldWithVar, ); -impl EqGadget for QuadExtVar +impl

EqGadget for QuadExtVar

where - BF: FieldVar, - for<'b> &'b BF: FieldOpsBounds<'b, P::BaseField, BF>, - P: QuadExtVarConfig, + P::BaseField: FieldWithVar, + P: QuadExtVarConfig, { #[tracing::instrument(target = "r1cs")] fn is_eq(&self, other: &Self) -> Result, SynthesisError> { @@ -406,11 +407,9 @@ where } } -impl ToBitsGadget for QuadExtVar +impl ToBitsGadget for QuadExtVar

where - BF: FieldVar, - for<'b> &'b BF: FieldOpsBounds<'b, P::BaseField, BF>, - P: QuadExtVarConfig, + P::BaseField: FieldWithVar, { #[tracing::instrument(target = "r1cs")] fn to_bits_le(&self) -> Result>, SynthesisError> { @@ -429,11 +428,9 @@ where } } -impl ToBytesGadget for QuadExtVar +impl ToBytesGadget for QuadExtVar

where - BF: FieldVar, - for<'b> &'b BF: FieldOpsBounds<'b, P::BaseField, BF>, - P: QuadExtVarConfig, + P::BaseField: FieldWithVar, { #[tracing::instrument(target = "r1cs")] fn to_bytes(&self) -> Result>, SynthesisError> { @@ -452,12 +449,10 @@ where } } -impl ToConstraintFieldGadget for QuadExtVar +impl ToConstraintFieldGadget for QuadExtVar

where - BF: FieldVar, - for<'a> &'a BF: FieldOpsBounds<'a, P::BaseField, BF>, - P: QuadExtVarConfig, - BF: ToConstraintFieldGadget, + P::BaseField: FieldWithVar, + BFVar

: ToConstraintFieldGadget, { #[tracing::instrument(target = "r1cs")] fn to_constraint_field(&self) -> Result>, SynthesisError> { @@ -470,11 +465,9 @@ where } } -impl CondSelectGadget for QuadExtVar +impl CondSelectGadget for QuadExtVar

where - BF: FieldVar, - for<'b> &'b BF: FieldOpsBounds<'b, P::BaseField, BF>, - P: QuadExtVarConfig, + P::BaseField: FieldWithVar, { #[inline] fn conditionally_select( @@ -482,18 +475,16 @@ where true_value: &Self, false_value: &Self, ) -> Result { - let c0 = BF::conditionally_select(cond, &true_value.c0, &false_value.c0)?; - let c1 = BF::conditionally_select(cond, &true_value.c1, &false_value.c1)?; + let c0 = BFVar::

::conditionally_select(cond, &true_value.c0, &false_value.c0)?; + let c1 = BFVar::

::conditionally_select(cond, &true_value.c1, &false_value.c1)?; Ok(Self::new(c0, c1)) } } -impl TwoBitLookupGadget for QuadExtVar +impl TwoBitLookupGadget for QuadExtVar

where - BF: FieldVar - + TwoBitLookupGadget, - for<'b> &'b BF: FieldOpsBounds<'b, P::BaseField, BF>, - P: QuadExtVarConfig, + P::BaseField: FieldWithVar, + BFVar

: TwoBitLookupGadget, { type TableConstant = QuadExtField

; @@ -504,18 +495,16 @@ where ) -> Result { let c0s = c.iter().map(|f| f.c0).collect::>(); let c1s = c.iter().map(|f| f.c1).collect::>(); - let c0 = BF::two_bit_lookup(b, &c0s)?; - let c1 = BF::two_bit_lookup(b, &c1s)?; + let c0 = BFVar::

::two_bit_lookup(b, &c0s)?; + let c1 = BFVar::

::two_bit_lookup(b, &c1s)?; Ok(Self::new(c0, c1)) } } -impl ThreeBitCondNegLookupGadget for QuadExtVar +impl ThreeBitCondNegLookupGadget for QuadExtVar

where - BF: FieldVar - + ThreeBitCondNegLookupGadget, - for<'b> &'b BF: FieldOpsBounds<'b, P::BaseField, BF>, - P: QuadExtVarConfig, + P::BaseField: FieldWithVar, + BFVar

: ThreeBitCondNegLookupGadget, { type TableConstant = QuadExtField

; @@ -527,17 +516,15 @@ where ) -> Result { let c0s = c.iter().map(|f| f.c0).collect::>(); let c1s = c.iter().map(|f| f.c1).collect::>(); - let c0 = BF::three_bit_cond_neg_lookup(b, b0b1, &c0s)?; - let c1 = BF::three_bit_cond_neg_lookup(b, b0b1, &c1s)?; + let c0 = BFVar::

::three_bit_cond_neg_lookup(b, b0b1, &c0s)?; + let c1 = BFVar::

::three_bit_cond_neg_lookup(b, b0b1, &c1s)?; Ok(Self::new(c0, c1)) } } -impl AllocVar, P::BasePrimeField> for QuadExtVar +impl AllocVar, P::BasePrimeField> for QuadExtVar

where - BF: FieldVar, - for<'b> &'b BF: FieldOpsBounds<'b, P::BaseField, BF>, - P: QuadExtVarConfig, + P::BaseField: FieldWithVar, { fn new_variable>>( cs: impl Into>, @@ -554,8 +541,32 @@ where ), }; - let c0 = BF::new_variable(ark_relations::ns!(cs, "c0"), || c0, mode)?; - let c1 = BF::new_variable(ark_relations::ns!(cs, "c1"), || c1, mode)?; + let c0 = BFVar::

::new_variable(ark_relations::ns!(cs, "c0"), || c0, mode)?; + let c1 = BFVar::

::new_variable(ark_relations::ns!(cs, "c1"), || c1, mode)?; Ok(Self::new(c0, c1)) } } + +impl<'a, P: QuadExtVarConfig> Sum<&'a QuadExtVar

> for QuadExtVar

+where + P::BaseField: FieldWithVar, +{ + fn sum>(iter: I) -> Self { + let (c0_s, c1_s): (Vec<_>, Vec<_>) = iter.map(|v| (&v.c0, &v.c1)).unzip(); + let c0 = c0_s.into_iter().sum::>(); + let c1 = c1_s.into_iter().sum::>(); + Self::new(c0, c1) + } +} + +impl<'a, P: QuadExtVarConfig> Sum> for QuadExtVar

+where + P::BaseField: FieldWithVar, +{ + fn sum>(iter: I) -> Self { + let (c0_s, c1_s): (Vec<_>, Vec<_>) = iter.map(|v| (v.c0, v.c1)).unzip(); + let c0 = c0_s.iter().sum::>(); + let c1 = c1_s.iter().sum::>(); + Self::new(c0, c1) + } +} diff --git a/src/groups/curves/short_weierstrass/bls12/mod.rs b/src/groups/curves/short_weierstrass/bls12/mod.rs index 99dcd116..c20ca1f6 100644 --- a/src/groups/curves/short_weierstrass/bls12/mod.rs +++ b/src/groups/curves/short_weierstrass/bls12/mod.rs @@ -1,41 +1,48 @@ use ark_ec::{ - bls12::{Bls12Parameters, G1Prepared, G2Prepared, TwistType}, + bls12::{Bls12Config, G1Prepared, G2Prepared, TwistType}, short_weierstrass::Affine as GroupAffine, }; use ark_ff::{BitIteratorBE, Field, One}; use ark_relations::r1cs::{Namespace, SynthesisError}; use crate::{ - fields::{fp::FpVar, fp2::Fp2Var, FieldVar}, + fields::{fp2::Fp2Var, FieldVar}, groups::curves::short_weierstrass::*, Vec, }; -use core::fmt::Debug; + +type FpVar

= <

::Fp as FieldWithVar>::Var; /// Represents a projective point in G1. -pub type G1Var

= - ProjectiveVar<

::G1Parameters, FpVar<

::Fp>>; +pub type G1Var

= ProjectiveVar<

::G1Config>; /// 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>>; +pub type G1AffineVar

= AffineVar<

::G1Config>; /// Represents a projective point in G2. -pub type G2Var

= ProjectiveVar<

::G2Parameters, Fp2G

>; +pub type G2Var

= ProjectiveVar<

::G2Config>; /// 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

>; +pub type G2AffineVar

= AffineVar<

::G2Config>; /// 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>); +#[derivative( + Clone(bound = "P: Bls12Config, P::Fp: FieldWithVar"), + Debug(bound = "P: Bls12Config, P::Fp: FieldWithVar") +)] +pub struct G1PreparedVar(pub G1AffineVar

) +where + P::Fp: FieldWithVar; -impl G1PreparedVar

{ +impl G1PreparedVar

+where + P::Fp: FieldWithVar, +{ /// Returns the value assigned to `self` in the underlying constraint /// system. pub fn value(&self) -> Result, SynthesisError> { @@ -56,7 +63,10 @@ impl G1PreparedVar

{ } } -impl AllocVar, P::Fp> for G1PreparedVar

{ +impl AllocVar, P::Fp> for G1PreparedVar

+where + P::Fp: FieldWithVar, +{ fn new_variable>>( cs: impl Into>, f: impl FnOnce() -> Result, @@ -66,19 +76,24 @@ impl AllocVar, P::Fp> for G1PreparedVar

{ let cs = ns.cs(); let g1_prep = f().map(|b| b.borrow().0); - let x = FpVar::new_variable(ark_relations::ns!(cs, "x"), || g1_prep.map(|g| g.x), mode)?; - let y = FpVar::new_variable(ark_relations::ns!(cs, "y"), || g1_prep.map(|g| g.y), mode)?; + let x = + FpVar::

::new_variable(ark_relations::ns!(cs, "x"), || g1_prep.map(|g| g.x), mode)?; + let y = + FpVar::

::new_variable(ark_relations::ns!(cs, "y"), || g1_prep.map(|g| g.y), mode)?; let infinity = Boolean::new_variable( ark_relations::ns!(cs, "inf"), || g1_prep.map(|g| g.infinity), mode, )?; - let g = AffineVar::new(x, y, infinity); + let g = G1AffineVar::

::new(x, y, infinity); Ok(Self(g)) } } -impl ToBytesGadget for G1PreparedVar

{ +impl ToBytesGadget for G1PreparedVar

+where + P::Fp: FieldWithVar, +{ #[inline] #[tracing::instrument(target = "r1cs")] fn to_bytes(&self) -> Result>, SynthesisError> { @@ -101,21 +116,27 @@ impl ToBytesGadget for G1PreparedVar

{ } } -type Fp2G

= Fp2Var<

::Fp2Config>; +type Fp2G

= Fp2Var<

::Fp2Config>; 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") + Clone(bound = "P::Fp: FieldWithVar"), + Debug(bound = "P::Fp: FieldWithVar") )] -pub struct G2PreparedVar { +pub struct G2PreparedVar +where + P::Fp: FieldWithVar, +{ #[doc(hidden)] pub ell_coeffs: Vec>, } -impl AllocVar, P::Fp> for G2PreparedVar

{ +impl AllocVar, P::Fp> for G2PreparedVar

+where + P::Fp: FieldWithVar, +{ #[tracing::instrument(target = "r1cs", skip(cs, f, mode))] fn new_variable>>( cs: impl Into>, @@ -173,7 +194,10 @@ impl AllocVar, P::Fp> for G2PreparedVar

{ } } -impl ToBytesGadget for G2PreparedVar

{ +impl ToBytesGadget for G2PreparedVar

+where + P::Fp: FieldWithVar, +{ #[inline] #[tracing::instrument(target = "r1cs")] fn to_bytes(&self) -> Result>, SynthesisError> { @@ -196,7 +220,10 @@ impl ToBytesGadget for G2PreparedVar

{ } } -impl G2PreparedVar

{ +impl G2PreparedVar

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

) -> Result { diff --git a/src/groups/curves/short_weierstrass/mnt4/mod.rs b/src/groups/curves/short_weierstrass/mnt4/mod.rs index 51e98c56..a37d7941 100644 --- a/src/groups/curves/short_weierstrass/mnt4/mod.rs +++ b/src/groups/curves/short_weierstrass/mnt4/mod.rs @@ -1,31 +1,36 @@ use ark_ec::mnt4::{ g2::{AteAdditionCoefficients, AteDoubleCoefficients}, - G1Prepared, G2Prepared, MNT4Parameters, + G1Prepared, G2Prepared, MNT4Config, }; use ark_ff::Field; use ark_relations::r1cs::{Namespace, SynthesisError}; use crate::{ - fields::{fp::FpVar, fp2::Fp2Var, FieldVar}, + fields::{fp::FpVar, fp2::Fp2Var, FieldVar, FieldWithVar}, groups::curves::short_weierstrass::ProjectiveVar, - pairing::mnt4::PairingVar, + pairing::mnt4::MNT4Gadget, prelude::*, Vec, }; use core::borrow::Borrow; /// Represents a projective point in G1. -pub type G1Var

= - ProjectiveVar<

::G1Parameters, FpVar<

::Fp>>; +pub type G1Var

= ProjectiveVar<

::G1Config>; /// Represents a projective point in G2. -pub type G2Var

= ProjectiveVar<

::G2Parameters, Fp2G

>; +pub type G2Var

= ProjectiveVar<

::G2Config>; /// 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 { +#[derivative( + Clone(bound = "P: MNT4Config, P::Fp: FieldWithVar>"), + Debug(bound = "P: MNT4Config, P::Fp: FieldWithVar>") +)] +pub struct G1PreparedVar +where + P::Fp: FieldWithVar>, +{ #[doc(hidden)] pub x: FpVar, #[doc(hidden)] @@ -36,7 +41,10 @@ pub struct G1PreparedVar { pub y_twist: Fp2Var, } -impl AllocVar, P::Fp> for G1PreparedVar

{ +impl AllocVar, P::Fp> for G1PreparedVar

+where + P::Fp: FieldWithVar>, +{ #[tracing::instrument(target = "r1cs", skip(cs, f))] fn new_variable>>( cs: impl Into>, @@ -48,8 +56,16 @@ impl AllocVar, P::Fp> for G1PreparedVar

{ let g1_prep = f().map(|b| *b.borrow()); - let x = FpVar::new_variable(ark_relations::ns!(cs, "x"), || g1_prep.map(|g| g.x), mode)?; - let y = FpVar::new_variable(ark_relations::ns!(cs, "y"), || g1_prep.map(|g| g.y), mode)?; + let x = FpVar::::new_variable( + ark_relations::ns!(cs, "x"), + || g1_prep.map(|g| g.x), + mode, + )?; + let y = FpVar::::new_variable( + ark_relations::ns!(cs, "y"), + || g1_prep.map(|g| g.y), + mode, + )?; let x_twist = Fp2Var::new_variable( ark_relations::ns!(cs, "x_twist"), || g1_prep.map(|g| g.x_twist), @@ -69,7 +85,10 @@ impl AllocVar, P::Fp> for G1PreparedVar

{ } } -impl G1PreparedVar

{ +impl G1PreparedVar

+where + P::Fp: FieldWithVar>, +{ /// Returns the value assigned to `self` in the underlying constraint /// system. pub fn value(&self) -> Result, SynthesisError> { @@ -91,8 +110,8 @@ impl G1PreparedVar

{ #[tracing::instrument(target = "r1cs")] pub fn from_group_var(q: &G1Var

) -> Result { let q = q.to_affine()?; - let x_twist = Fp2Var::new(&q.x * P::TWIST.c0, &q.x * P::TWIST.c1); - let y_twist = Fp2Var::new(&q.y * P::TWIST.c0, &q.y * P::TWIST.c1); + let x_twist = Fp2Var::new(q.x.clone() * P::TWIST.c0, q.x.clone() * P::TWIST.c1); + let y_twist = Fp2Var::new(q.y.clone() * P::TWIST.c0, q.y.clone() * P::TWIST.c1); Ok(G1PreparedVar { x: q.x, y: q.y, @@ -102,7 +121,10 @@ impl G1PreparedVar

{ } } -impl ToBytesGadget for G1PreparedVar

{ +impl ToBytesGadget for G1PreparedVar

+where + P::Fp: FieldWithVar>, +{ #[inline] #[tracing::instrument(target = "r1cs")] fn to_bytes(&self) -> Result>, SynthesisError> { @@ -131,13 +153,19 @@ impl ToBytesGadget for G1PreparedVar

{ } } -type Fp2G

= Fp2Var<

::Fp2Config>; +type Fp2G

= Fp2Var<

::Fp2Config>; /// 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 { +#[derivative( + Clone(bound = "P: MNT4Config, P::Fp: FieldWithVar>"), + Debug(bound = "P: MNT4Config, P::Fp: FieldWithVar>") +)] +pub struct G2PreparedVar +where + P::Fp: FieldWithVar>, +{ #[doc(hidden)] pub x: Fp2Var, #[doc(hidden)] @@ -152,7 +180,10 @@ pub struct G2PreparedVar { pub addition_coefficients: Vec>, } -impl AllocVar, P::Fp> for G2PreparedVar

{ +impl AllocVar, P::Fp> for G2PreparedVar

+where + P::Fp: FieldWithVar>, +{ #[tracing::instrument(target = "r1cs", skip(cs, f))] fn new_variable>>( cs: impl Into>, @@ -198,7 +229,10 @@ impl AllocVar, P::Fp> for G2PreparedVar

{ } } -impl ToBytesGadget for G2PreparedVar

{ +impl ToBytesGadget for G2PreparedVar

+where + P::Fp: FieldWithVar>, +{ #[inline] #[tracing::instrument(target = "r1cs")] fn to_bytes(&self) -> Result>, SynthesisError> { @@ -241,7 +275,10 @@ impl ToBytesGadget for G2PreparedVar

{ } } -impl G2PreparedVar

{ +impl G2PreparedVar

+where + P::Fp: FieldWithVar>, +{ /// Returns the value assigned to `self` in the underlying constraint /// system. pub fn value(&self) -> Result, SynthesisError> { @@ -292,7 +329,7 @@ impl G2PreparedVar

{ }; for bit in P::ATE_LOOP_COUNT.iter().skip(1) { - let (r2, coeff) = PairingVar::

::doubling_step_for_flipped_miller_loop(&r)?; + let (r2, coeff) = MNT4Gadget::

::doubling_step_for_flipped_miller_loop(&r)?; g2p.double_coefficients.push(coeff); r = r2; @@ -301,13 +338,13 @@ impl G2PreparedVar

{ match bit { 1 => { (r_temp, add_coeff) = - PairingVar::

::mixed_addition_step_for_flipped_miller_loop( + MNT4Gadget::

::mixed_addition_step_for_flipped_miller_loop( &q.x, &q.y, &r, )?; }, -1 => { (r_temp, add_coeff) = - PairingVar::

::mixed_addition_step_for_flipped_miller_loop( + MNT4Gadget::

::mixed_addition_step_for_flipped_miller_loop( &q.x, &q.y.negate()?, &r, @@ -327,7 +364,7 @@ impl G2PreparedVar

{ let minus_r_affine_x = &r.x * &rz2_inv; let minus_r_affine_y = r.y.negate()? * &rz3_inv; - let add_result = PairingVar::

::mixed_addition_step_for_flipped_miller_loop( + let add_result = MNT4Gadget::

::mixed_addition_step_for_flipped_miller_loop( &minus_r_affine_x, &minus_r_affine_y, &r, @@ -341,15 +378,24 @@ impl G2PreparedVar

{ #[doc(hidden)] #[derive(Derivative)] -#[derivative(Clone(bound = "P: MNT4Parameters"), Debug(bound = "P: MNT4Parameters"))] -pub struct AteDoubleCoefficientsVar { +#[derivative( + Clone(bound = "P: MNT4Config, P::Fp: FieldWithVar>"), + Debug(bound = "P: MNT4Config, P::Fp: FieldWithVar>") +)] +pub struct AteDoubleCoefficientsVar +where + P::Fp: FieldWithVar>, +{ pub c_h: Fp2Var, pub c_4c: Fp2Var, pub c_j: Fp2Var, pub c_l: Fp2Var, } -impl AllocVar, P::Fp> for AteDoubleCoefficientsVar

{ +impl AllocVar, P::Fp> for AteDoubleCoefficientsVar

+where + P::Fp: FieldWithVar>, +{ #[tracing::instrument(target = "r1cs", skip(cs, f))] fn new_variable>>( cs: impl Into>, @@ -376,7 +422,10 @@ impl AllocVar, P::Fp> for AteDoubleC } } -impl ToBytesGadget for AteDoubleCoefficientsVar

{ +impl ToBytesGadget for AteDoubleCoefficientsVar

+where + P::Fp: FieldWithVar>, +{ #[inline] #[tracing::instrument(target = "r1cs")] fn to_bytes(&self) -> Result>, SynthesisError> { @@ -405,7 +454,10 @@ impl ToBytesGadget for AteDoubleCoefficientsVar

{ } } -impl AteDoubleCoefficientsVar

{ +impl AteDoubleCoefficientsVar

+where + P::Fp: FieldWithVar>, +{ /// Returns the value assigned to `self` in the underlying constraint /// system. pub fn value(&self) -> Result, SynthesisError> { @@ -426,14 +478,21 @@ impl AteDoubleCoefficientsVar

{ #[doc(hidden)] #[derive(Derivative)] -#[derivative(Clone(bound = "P: MNT4Parameters"), Debug(bound = "P: MNT4Parameters"))] -pub struct AteAdditionCoefficientsVar { +#[derivative( + Clone(bound = "P: MNT4Config, P::Fp: FieldWithVar>"), + Debug(bound = "P: MNT4Config, P::Fp: FieldWithVar>") +)] +pub struct AteAdditionCoefficientsVar +where + P::Fp: FieldWithVar>, +{ pub c_l1: Fp2Var, pub c_rz: Fp2Var, } -impl AllocVar, P::Fp> - for AteAdditionCoefficientsVar

+impl AllocVar, P::Fp> for AteAdditionCoefficientsVar

+where + P::Fp: FieldWithVar>, { #[tracing::instrument(target = "r1cs", skip(cs, f))] fn new_variable>>( @@ -455,7 +514,10 @@ impl AllocVar, P::Fp> } } -impl ToBytesGadget for AteAdditionCoefficientsVar

{ +impl ToBytesGadget for AteAdditionCoefficientsVar

+where + P::Fp: FieldWithVar>, +{ #[inline] #[tracing::instrument(target = "r1cs")] fn to_bytes(&self) -> Result>, SynthesisError> { @@ -476,7 +538,10 @@ impl ToBytesGadget for AteAdditionCoefficientsVar

{ } } -impl AteAdditionCoefficientsVar

{ +impl AteAdditionCoefficientsVar

+where + P::Fp: FieldWithVar>, +{ /// Returns the value assigned to `self` in the underlying constraint /// system. pub fn value(&self) -> Result, SynthesisError> { @@ -486,7 +551,10 @@ impl AteAdditionCoefficientsVar

{ } #[doc(hidden)] -pub struct G2ProjectiveExtendedVar { +pub struct G2ProjectiveExtendedVar +where + P::Fp: FieldWithVar>, +{ pub x: Fp2Var, pub y: Fp2Var, pub z: Fp2Var, diff --git a/src/groups/curves/short_weierstrass/mnt6/mod.rs b/src/groups/curves/short_weierstrass/mnt6/mod.rs index b3ab838e..8521fcc0 100644 --- a/src/groups/curves/short_weierstrass/mnt6/mod.rs +++ b/src/groups/curves/short_weierstrass/mnt6/mod.rs @@ -1,31 +1,36 @@ use ark_ec::mnt6::{ g2::{AteAdditionCoefficients, AteDoubleCoefficients}, - G1Prepared, G2Prepared, MNT6Parameters, + G1Prepared, G2Prepared, MNT6Config, }; use ark_ff::Field; use ark_relations::r1cs::{Namespace, SynthesisError}; use crate::{ - fields::{fp::FpVar, fp3::Fp3Var, FieldVar}, + fields::{fp::FpVar, fp3::Fp3Var, FieldVar, FieldWithVar}, groups::curves::short_weierstrass::ProjectiveVar, - pairing::mnt6::PairingVar, + pairing::mnt6::MNT6Gadget, prelude::*, Vec, }; use core::borrow::Borrow; /// Represents a projective point in G1. -pub type G1Var

= - ProjectiveVar<

::G1Parameters, FpVar<

::Fp>>; +pub type G1Var

= ProjectiveVar<

::G1Config>; /// Represents a projective point in G2. -pub type G2Var

= ProjectiveVar<

::G2Parameters, Fp3G

>; +pub type G2Var

= ProjectiveVar<

::G2Config>; /// 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 { +#[derivative( + Clone(bound = "P: MNT6Config, P::Fp: FieldWithVar>"), + Debug(bound = "P: MNT6Config, P::Fp: FieldWithVar>") +)] +pub struct G1PreparedVar +where + P::Fp: FieldWithVar>, +{ #[doc(hidden)] pub x: FpVar, #[doc(hidden)] @@ -36,7 +41,10 @@ pub struct G1PreparedVar { pub y_twist: Fp3Var, } -impl G1PreparedVar

{ +impl G1PreparedVar

+where + P::Fp: FieldWithVar>, +{ /// Returns the value assigned to `self` in the underlying constraint /// system. pub fn value(&self) -> Result, SynthesisError> { @@ -69,7 +77,10 @@ impl G1PreparedVar

{ } } -impl AllocVar, P::Fp> for G1PreparedVar

{ +impl AllocVar, P::Fp> for G1PreparedVar

+where + P::Fp: FieldWithVar>, +{ #[tracing::instrument(target = "r1cs", skip(cs, f))] fn new_variable>>( cs: impl Into>, @@ -81,8 +92,16 @@ impl AllocVar, P::Fp> for G1PreparedVar

{ let g1_prep = f().map(|b| *b.borrow()); - let x = FpVar::new_variable(ark_relations::ns!(cs, "x"), || g1_prep.map(|g| g.x), mode)?; - let y = FpVar::new_variable(ark_relations::ns!(cs, "y"), || g1_prep.map(|g| g.y), mode)?; + let x = FpVar::::new_variable( + ark_relations::ns!(cs, "x"), + || g1_prep.map(|g| g.x), + mode, + )?; + let y = FpVar::::new_variable( + ark_relations::ns!(cs, "y"), + || g1_prep.map(|g| g.y), + mode, + )?; let x_twist = Fp3Var::new_variable( ark_relations::ns!(cs, "x_twist"), || g1_prep.map(|g| g.x_twist), @@ -102,7 +121,10 @@ impl AllocVar, P::Fp> for G1PreparedVar

{ } } -impl ToBytesGadget for G1PreparedVar

{ +impl ToBytesGadget for G1PreparedVar

+where + P::Fp: FieldWithVar>, +{ #[inline] #[tracing::instrument(target = "r1cs")] fn to_bytes(&self) -> Result>, SynthesisError> { @@ -131,13 +153,19 @@ impl ToBytesGadget for G1PreparedVar

{ } } -type Fp3G

= Fp3Var<

::Fp3Config>; +type Fp3G

= Fp3Var<

::Fp3Config>; /// 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 { +#[derivative( + Clone(bound = "P: MNT6Config, P::Fp: FieldWithVar>"), + Debug(bound = "P: MNT6Config, P::Fp: FieldWithVar>") +)] +pub struct G2PreparedVar +where + P::Fp: FieldWithVar>, +{ #[doc(hidden)] pub x: Fp3Var, #[doc(hidden)] @@ -152,7 +180,10 @@ pub struct G2PreparedVar { pub addition_coefficients: Vec>, } -impl AllocVar, P::Fp> for G2PreparedVar

{ +impl AllocVar, P::Fp> for G2PreparedVar

+where + P::Fp: FieldWithVar>, +{ #[tracing::instrument(target = "r1cs", skip(cs, f))] fn new_variable>>( cs: impl Into>, @@ -198,7 +229,10 @@ impl AllocVar, P::Fp> for G2PreparedVar

{ } } -impl ToBytesGadget for G2PreparedVar

{ +impl ToBytesGadget for G2PreparedVar

+where + P::Fp: FieldWithVar>, +{ #[inline] #[tracing::instrument(target = "r1cs")] fn to_bytes(&self) -> Result>, SynthesisError> { @@ -241,7 +275,10 @@ impl ToBytesGadget for G2PreparedVar

{ } } -impl G2PreparedVar

{ +impl G2PreparedVar

+where + P::Fp: FieldWithVar>, +{ /// Returns the value assigned to `self` in the underlying constraint /// system. pub fn value(&self) -> Result, SynthesisError> { @@ -292,7 +329,7 @@ impl G2PreparedVar

{ }; for bit in P::ATE_LOOP_COUNT.iter().skip(1) { - let (r2, coeff) = PairingVar::

::doubling_step_for_flipped_miller_loop(&r)?; + let (r2, coeff) = MNT6Gadget::

::doubling_step_for_flipped_miller_loop(&r)?; g2p.double_coefficients.push(coeff); r = r2; @@ -301,13 +338,13 @@ impl G2PreparedVar

{ match bit { 1 => { (r_temp, add_coeff) = - PairingVar::

::mixed_addition_step_for_flipped_miller_loop( + MNT6Gadget::

::mixed_addition_step_for_flipped_miller_loop( &q.x, &q.y, &r, )?; }, -1 => { (r_temp, add_coeff) = - PairingVar::

::mixed_addition_step_for_flipped_miller_loop( + MNT6Gadget::

::mixed_addition_step_for_flipped_miller_loop( &q.x, &q.y.negate()?, &r, @@ -327,7 +364,7 @@ impl G2PreparedVar

{ let minus_r_affine_x = &r.x * &rz2_inv; let minus_r_affine_y = r.y.negate()? * &rz3_inv; - let add_result = PairingVar::

::mixed_addition_step_for_flipped_miller_loop( + let add_result = MNT6Gadget::

::mixed_addition_step_for_flipped_miller_loop( &minus_r_affine_x, &minus_r_affine_y, &r, @@ -341,15 +378,24 @@ impl G2PreparedVar

{ #[doc(hidden)] #[derive(Derivative)] -#[derivative(Clone(bound = "P: MNT6Parameters"), Debug(bound = "P: MNT6Parameters"))] -pub struct AteDoubleCoefficientsVar { +#[derivative( + Clone(bound = "P: MNT6Config, P::Fp: FieldWithVar>"), + Debug(bound = "P: MNT6Config, P::Fp: FieldWithVar>") +)] +pub struct AteDoubleCoefficientsVar +where + P::Fp: FieldWithVar>, +{ pub c_h: Fp3Var, pub c_4c: Fp3Var, pub c_j: Fp3Var, pub c_l: Fp3Var, } -impl AllocVar, P::Fp> for AteDoubleCoefficientsVar

{ +impl AllocVar, P::Fp> for AteDoubleCoefficientsVar

+where + P::Fp: FieldWithVar>, +{ #[tracing::instrument(target = "r1cs", skip(cs, f))] fn new_variable>>( cs: impl Into>, @@ -376,7 +422,10 @@ impl AllocVar, P::Fp> for AteDoubleC } } -impl ToBytesGadget for AteDoubleCoefficientsVar

{ +impl ToBytesGadget for AteDoubleCoefficientsVar

+where + P::Fp: FieldWithVar>, +{ #[inline] #[tracing::instrument(target = "r1cs")] fn to_bytes(&self) -> Result>, SynthesisError> { @@ -405,7 +454,10 @@ impl ToBytesGadget for AteDoubleCoefficientsVar

{ } } -impl AteDoubleCoefficientsVar

{ +impl AteDoubleCoefficientsVar

+where + P::Fp: FieldWithVar>, +{ /// Returns the value assigned to `self` in the underlying constraint /// system. pub fn value(&self) -> Result, SynthesisError> { @@ -424,14 +476,18 @@ impl AteDoubleCoefficientsVar

{ #[doc(hidden)] #[derive(Derivative)] -#[derivative(Clone(bound = "P: MNT6Parameters"), Debug(bound = "P: MNT6Parameters"))] -pub struct AteAdditionCoefficientsVar { +#[derivative(Clone(bound = "P: MNT6Config"), Debug(bound = "P: MNT6Config"))] +pub struct AteAdditionCoefficientsVar +where + P::Fp: FieldWithVar>, +{ pub c_l1: Fp3Var, pub c_rz: Fp3Var, } -impl AllocVar, P::Fp> - for AteAdditionCoefficientsVar

+impl AllocVar, P::Fp> for AteAdditionCoefficientsVar

+where + P::Fp: FieldWithVar>, { #[tracing::instrument(target = "r1cs", skip(cs, f))] fn new_variable>>( @@ -453,7 +509,10 @@ impl AllocVar, P::Fp> } } -impl ToBytesGadget for AteAdditionCoefficientsVar

{ +impl ToBytesGadget for AteAdditionCoefficientsVar

+where + P::Fp: FieldWithVar>, +{ #[inline] #[tracing::instrument(target = "r1cs")] fn to_bytes(&self) -> Result>, SynthesisError> { @@ -474,7 +533,10 @@ impl ToBytesGadget for AteAdditionCoefficientsVar

{ } } -impl AteAdditionCoefficientsVar

{ +impl AteAdditionCoefficientsVar

+where + P::Fp: FieldWithVar>, +{ /// Returns the value assigned to `self` in the underlying constraint /// system. pub fn value(&self) -> Result, SynthesisError> { @@ -485,7 +547,10 @@ impl AteAdditionCoefficientsVar

{ } #[doc(hidden)] -pub struct G2ProjectiveExtendedVar { +pub struct G2ProjectiveExtendedVar +where + P::Fp: FieldWithVar>, +{ pub x: Fp3Var, pub y: Fp3Var, pub z: Fp3Var, diff --git a/src/groups/curves/short_weierstrass/mod.rs b/src/groups/curves/short_weierstrass/mod.rs index 91eae941..9044170a 100644 --- a/src/groups/curves/short_weierstrass/mod.rs +++ b/src/groups/curves/short_weierstrass/mod.rs @@ -1,15 +1,17 @@ use ark_ec::{ - short_weierstrass::{ - Affine as SWAffine, Projective as SWProjective, SWCurveConfig as SWModelParameters, - }, - AffineRepr, CurveGroup, + short_weierstrass::{Affine, Projective, SWCurveConfig}, + AffineRepr, CurveConfig, CurveGroup, }; use ark_ff::{BigInteger, BitIteratorBE, Field, One, PrimeField, Zero}; use ark_relations::r1cs::{ConstraintSystemRef, Namespace, SynthesisError}; use ark_std::{borrow::Borrow, marker::PhantomData, ops::Mul}; use non_zero_affine::NonZeroAffineVar; -use crate::{fields::fp::FpVar, prelude::*, ToConstraintFieldGadget, Vec}; +use crate::{ + fields::{fp::FpVar, FieldWithVar}, + prelude::*, + ToConstraintFieldGadget, Vec, +}; /// This module provides a generic implementation of G1 and G2 for /// the [\[BLS12]\]() family of bilinear groups. @@ -19,6 +21,7 @@ pub mod bls12; /// the [\[MNT4]\]() /// family of bilinear groups. pub mod mnt4; + /// This module provides a generic implementation of G1 and G2 for /// the [\[MNT6]\]() /// family of bilinear groups. @@ -33,55 +36,57 @@ pub mod mnt6; /// to zero. The [ProjectiveVar] gadget is the recommended way of working with /// elliptic curve points. pub mod non_zero_affine; + +type BF

=

::BaseField; +type CF

= as Field>::BasePrimeField; +type BFVar

= as FieldWithVar>::Var; + /// An implementation of arithmetic for Short Weierstrass curves that relies on /// the complete formulae derived in the paper of /// [[Renes, Costello, Batina 2015]](). #[derive(Derivative)] -#[derivative(Debug, Clone)] +#[derivative(Debug(bound = "P: SWCurveConfig"), Clone(bound = "P: SWCurveConfig"))] #[must_use] -pub struct ProjectiveVar< - P: SWModelParameters, - F: FieldVar::BasePrimeField>, -> where - for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, +pub struct ProjectiveVar +where + BF

: FieldWithVar, { /// The x-coordinate. - pub x: F, + pub x: BFVar

, /// The y-coordinate. - pub y: F, + pub y: BFVar

, /// The z-coordinate. - pub z: F, + pub z: BFVar

, #[derivative(Debug = "ignore")] _params: PhantomData

, } /// An affine representation of a curve point. #[derive(Derivative)] -#[derivative(Debug, Clone)] +#[derivative( + Debug(bound = "P: SWCurveConfig, BF

: FieldWithVar"), + Clone(bound = "P: SWCurveConfig, BF

: FieldWithVar") +)] #[must_use] -pub struct AffineVar< - P: SWModelParameters, - F: FieldVar::BasePrimeField>, -> where - for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, +pub struct AffineVar +where + BF

: FieldWithVar, { /// The x-coordinate. - pub x: F, + pub x: BFVar

, /// The y-coordinate. - pub y: F, + pub y: BFVar

, /// Is `self` the point at infinity. - pub infinity: Boolean<::BasePrimeField>, + pub infinity: Boolean>, #[derivative(Debug = "ignore")] _params: PhantomData

, } -impl AffineVar +impl AffineVar

where - P: SWModelParameters, - F: FieldVar::BasePrimeField>, - for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, + BF

: FieldWithVar, { - fn new(x: F, y: F, infinity: Boolean<::BasePrimeField>) -> Self { + fn new(x: BFVar

, y: BFVar

, infinity: Boolean>) -> Self { Self { x, y, @@ -92,25 +97,22 @@ where /// Returns the value assigned to `self` in the underlying /// constraint system. - pub fn value(&self) -> Result, SynthesisError> { + pub fn value(&self) -> Result, SynthesisError> { Ok(match self.infinity.value()? { - true => SWAffine::identity(), - false => SWAffine::new(self.x.value()?, self.y.value()?), + true => Affine::identity(), + false => Affine::new(self.x.value()?, self.y.value()?), }) } } -impl ToConstraintFieldGadget<::BasePrimeField> for AffineVar +impl

ToConstraintFieldGadget> for AffineVar

where - P: SWModelParameters, - F: FieldVar::BasePrimeField>, - for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, - F: ToConstraintFieldGadget<::BasePrimeField>, + BF

: FieldWithVar, + P: SWCurveConfig, + BFVar

: ToConstraintFieldGadget>, { - fn to_constraint_field( - &self, - ) -> Result::BasePrimeField>>, SynthesisError> { - let mut res = Vec::::BasePrimeField>>::new(); + fn to_constraint_field(&self) -> Result>>, SynthesisError> { + let mut res = Vec::>>::new(); res.extend_from_slice(&self.x.to_constraint_field()?); res.extend_from_slice(&self.y.to_constraint_field()?); @@ -120,36 +122,34 @@ where } } -impl R1CSVar<::BasePrimeField> for ProjectiveVar +impl

R1CSVar> for ProjectiveVar

where - P: SWModelParameters, - F: FieldVar::BasePrimeField>, - for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, + P: SWCurveConfig, + BF

: FieldWithVar, { - type Value = SWProjective

; + type Value = Projective

; - fn cs(&self) -> ConstraintSystemRef<::BasePrimeField> { + fn cs(&self) -> ConstraintSystemRef> { self.x.cs().or(self.y.cs()).or(self.z.cs()) } fn value(&self) -> Result { let (x, y, z) = (self.x.value()?, self.y.value()?, self.z.value()?); let result = if let Some(z_inv) = z.inverse() { - SWAffine::new(x * &z_inv, y * &z_inv) + Affine::new(x * &z_inv, y * &z_inv) } else { - SWAffine::identity() + Affine::identity() }; Ok(result.into()) } } -impl::BasePrimeField>> - ProjectiveVar +impl ProjectiveVar

where - for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, + BF

: FieldWithVar, { /// Constructs `Self` from an `(x, y, z)` coordinate triple. - pub fn new(x: F, y: F, z: F) -> Self { + pub fn new(x: BFVar

, y: BFVar

, z: BFVar

) -> Self { Self { x, y, @@ -158,23 +158,27 @@ where } } + fn is_zero(&self) -> Result>, SynthesisError> { + self.z.is_zero() + } + /// Convert this point into affine form. #[tracing::instrument(target = "r1cs")] - pub fn to_affine(&self) -> Result, SynthesisError> { + pub fn to_affine(&self) -> Result, SynthesisError> { if self.is_constant() { let point = self.value()?.into_affine(); - let x = F::new_constant(ConstraintSystemRef::None, point.x)?; - let y = F::new_constant(ConstraintSystemRef::None, point.y)?; + let x = BFVar::

::new_constant(ConstraintSystemRef::None, point.x)?; + let y = BFVar::

::new_constant(ConstraintSystemRef::None, point.y)?; let infinity = Boolean::constant(point.infinity); Ok(AffineVar::new(x, y, infinity)) } else { let cs = self.cs(); let infinity = self.is_zero()?; - let zero_x = F::zero(); - let zero_y = F::one(); + let zero_x = BFVar::

::zero(); + let zero_y = BFVar::

::one(); // Allocate a variable whose value is either `self.z.inverse()` if the inverse // exists, and is zero otherwise. - let z_inv = F::new_witness(ark_relations::ns!(cs, "z_inverse"), || { + let z_inv = BFVar::

::new_witness(ark_relations::ns!(cs, "z_inverse"), || { Ok(self.z.value()?.inverse().unwrap_or_else(P::BaseField::zero)) })?; // The inverse exists if `!self.is_zero()`. @@ -182,10 +186,10 @@ where // `z_inv * self.z = 0` if `self.is_zero()`. // // Thus, `z_inv * self.z = !self.is_zero()`. - z_inv.mul_equals(&self.z, &F::from(infinity.not()))?; + z_inv.mul_equals(&self.z, &BFVar::

::from(infinity.not()))?; - let non_zero_x = &self.x * &z_inv; - let non_zero_y = &self.y * &z_inv; + let non_zero_x = z_inv.clone() * &self.x; + let non_zero_y = z_inv * &self.y; let x = infinity.select(&zero_x, &non_zero_x)?; let y = infinity.select(&zero_y, &non_zero_y)?; @@ -199,8 +203,8 @@ where /// is a constant or is a public input). #[tracing::instrument(target = "r1cs", skip(cs, f))] pub fn new_variable_omit_on_curve_check( - cs: impl Into::BasePrimeField>>, - f: impl FnOnce() -> Result, SynthesisError>, + cs: impl Into>>, + f: impl FnOnce() -> Result, SynthesisError>, mode: AllocationMode, ) -> Result { let ns = cs.into(); @@ -226,17 +230,22 @@ where ), }; - let x = F::new_variable(ark_relations::ns!(cs, "x"), || x, mode)?; - let y = F::new_variable(ark_relations::ns!(cs, "y"), || y, mode)?; - let z = F::new_variable(ark_relations::ns!(cs, "z"), || z, mode)?; + let x = BFVar::

::new_variable(ark_relations::ns!(cs, "x"), || x, mode)?; + let y = BFVar::

::new_variable(ark_relations::ns!(cs, "y"), || y, mode)?; + let z = BFVar::

::new_variable(ark_relations::ns!(cs, "z"), || z, mode)?; Ok(Self::new(x, y, z)) } +} +impl ProjectiveVar

+where + BF

: FieldWithVar, +{ /// Mixed addition, which is useful when `other = (x2, y2)` is known to have /// z = 1. #[tracing::instrument(target = "r1cs", skip(self, other))] - pub(crate) fn add_mixed(&self, other: &NonZeroAffineVar) -> Result { + pub(crate) fn add_mixed(&self, other: &NonZeroAffineVar

) -> Result { // Complete mixed addition formula from Renes-Costello-Batina 2015 // Algorithm 2 // (https://eprint.iacr.org/2015/1060). @@ -251,22 +260,22 @@ where let xx = x1 * x2; // 1 let yy = y1 * y2; // 2 - let xy_pairs = ((x1 + y1) * &(x2 + y2)) - (&xx + &yy); // 4, 5, 6, 7, 8 + let xy_pairs = ((x1 + y1) * (x2 + y2)) - (&xx + &yy); // 4, 5, 6, 7, 8 let xz_pairs = (x2 * z1) + x1; // 8, 9 let yz_pairs = (y2 * z1) + y1; // 10, 11 - let axz = mul_by_coeff_a::(&xz_pairs); // 12 + let axz = mul_by_coeff_a::

(&xz_pairs); // 12 let bz3_part = &axz + z1 * three_b; // 13, 14 let yy_m_bz3 = &yy - &bz3_part; // 15 let yy_p_bz3 = &yy + &bz3_part; // 16 - let azz = mul_by_coeff_a::(z1); // 20 + let azz = mul_by_coeff_a::

(z1); // 20 let xx3_p_azz = xx.double().unwrap() + &xx + &azz; // 18, 19, 22 let bxz3 = &xz_pairs * three_b; // 21 - let b3_xz_pairs = mul_by_coeff_a::(&(&xx - &azz)) + &bxz3; // 23, 24, 25 + let b3_xz_pairs = mul_by_coeff_a::

(&(&xx - &azz)) + &bxz3; // 23, 24, 25 let x = (&yy_m_bz3 * &xy_pairs) - &yz_pairs * &b3_xz_pairs; // 28,29, 30 let y = (&yy_p_bz3 * &yy_m_bz3) + &xx3_p_azz * b3_xz_pairs; // 17, 26, 27 @@ -284,8 +293,8 @@ where fn fixed_scalar_mul_le( &self, mul_result: &mut Self, - multiple_of_power_of_two: &mut NonZeroAffineVar, - bits: &[&Boolean<::BasePrimeField>], + multiple_of_power_of_two: &mut NonZeroAffineVar

, + bits: &[&Boolean>], ) -> Result<(), SynthesisError> { let scalar_modulus_bits = ::MODULUS_BIT_SIZE as usize; @@ -368,30 +377,35 @@ where } } -impl CurveVar, ::BasePrimeField> - for ProjectiveVar +impl CurveWithVar> for Projective

+where + BF

: FieldWithVar, +{ + type Var = ProjectiveVar

; +} + +impl

CurveVar, CF

> for ProjectiveVar

where - P: SWModelParameters, - F: FieldVar::BasePrimeField>, - for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, + P: SWCurveConfig, + BF

: FieldWithVar, { - fn constant(g: SWProjective

) -> Self { + fn constant(g: Projective

) -> Self { let cs = ConstraintSystemRef::None; Self::new_variable_omit_on_curve_check(cs, || Ok(g), AllocationMode::Constant).unwrap() } fn zero() -> Self { - Self::new(F::zero(), F::one(), F::zero()) + Self::new(BFVar::

::zero(), BFVar::

::one(), BFVar::

::zero()) } - fn is_zero(&self) -> Result::BasePrimeField>, SynthesisError> { + fn is_zero(&self) -> Result>, SynthesisError> { self.z.is_zero() } #[tracing::instrument(target = "r1cs", skip(cs, f))] fn new_variable_omit_prime_order_check( - cs: impl Into::BasePrimeField>>, - f: impl FnOnce() -> Result, SynthesisError>, + cs: impl Into>>, + f: impl FnOnce() -> Result, SynthesisError>, mode: AllocationMode, ) -> Result { let ns = cs.into(); @@ -467,7 +481,7 @@ where let xy2 = (&self.x * &self.y).double()?; // 4, 5 let xz2 = (&self.x * &self.z).double()?; // 6, 7 - let axz2 = mul_by_coeff_a::(&xz2); // 8 + let axz2 = mul_by_coeff_a::

(&xz2); // 8 let bzz3_part = &axz2 + &zz * three_b; // 9, 10 let yy_m_bzz3 = &yy - &bzz3_part; // 11 @@ -476,8 +490,8 @@ where let x_frag = yy_m_bzz3 * &xy2; // 14 let bxz3 = xz2 * three_b; // 15 - let azz = mul_by_coeff_a::(&zz); // 16 - let b3_xz_pairs = mul_by_coeff_a::(&(&xx - &azz)) + &bxz3; // 15, 16, 17, 18, 19 + let azz = mul_by_coeff_a::

(&zz); // 16 + let b3_xz_pairs = mul_by_coeff_a::

(&(&xx - &azz)) + &bxz3; // 15, 16, 17, 18, 19 let xx3_p_azz = (xx.double()? + &xx + &azz) * &b3_xz_pairs; // 23, 24, 25 let y = y_frag + &xx3_p_azz; // 26, 27 @@ -500,7 +514,7 @@ where #[tracing::instrument(target = "r1cs", skip(bits))] fn scalar_mul_le<'a>( &self, - bits: impl Iterator::BasePrimeField>>, + bits: impl Iterator>>, ) -> Result { if self.is_constant() { if self.value().unwrap().is_zero() { @@ -551,8 +565,8 @@ where scalar_bits_with_bases: I, ) -> Result<(), SynthesisError> where - I: Iterator)>, - B: Borrow::BasePrimeField>>, + I: Iterator)>, + B: Borrow>>, { // We just ignore the provided bases and use the faster scalar multiplication. let (bits, bases): (Vec<_>, Vec<_>) = scalar_bits_with_bases @@ -564,65 +578,60 @@ where } } -impl ToConstraintFieldGadget<::BasePrimeField> for ProjectiveVar +impl

ToConstraintFieldGadget> for ProjectiveVar

where - P: SWModelParameters, - F: FieldVar::BasePrimeField>, - for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, - F: ToConstraintFieldGadget<::BasePrimeField>, + P: SWCurveConfig, + BF

: FieldWithVar, + BFVar

: ToConstraintFieldGadget>, { - fn to_constraint_field( - &self, - ) -> Result::BasePrimeField>>, SynthesisError> { + fn to_constraint_field(&self) -> Result>>, SynthesisError> { self.to_affine()?.to_constraint_field() } } -fn mul_by_coeff_a< - P: SWModelParameters, - F: FieldVar::BasePrimeField>, ->( - f: &F, -) -> F +fn mul_by_coeff_a(f: &BFVar

) -> BFVar

where - for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, + BF

: FieldWithVar, { if !P::COEFF_A.is_zero() { f * P::COEFF_A } else { - F::zero() + BFVar::

::zero() } } impl_bounded_ops!( - ProjectiveVar, - SWProjective

, + ProjectiveVar

, + Projective

, Add, add, AddAssign, add_assign, - |mut this: &'a ProjectiveVar, mut other: &'a ProjectiveVar| { + |this: &mut ProjectiveVar

, other: &'a ProjectiveVar

| { // Implement complete addition for Short Weierstrass curves, following // the complete addition formula from Renes-Costello-Batina 2015 // (https://eprint.iacr.org/2015/1060). // // We special case handling of constants to get better constraint weight. if this.is_constant() { - // we'll just act like `other` is constant. - core::mem::swap(&mut this, &mut other); - } - - if other.is_constant() { + // The value should exist because `this` is a constant. + let this_val = this.value().unwrap(); + if this_val.is_zero() { + *this = other.clone(); + } else { + // We'll use mixed addition to add non-zero constants. + let x = BFVar::

::constant(this_val.x); + let y = BFVar::

::constant(this_val.y); + *this = other.add_mixed(&NonZeroAffineVar::new(x, y)).unwrap() + } + } else if other.is_constant() { // The value should exist because `other` is a constant. let other = other.value().unwrap(); - if other.is_zero() { - // this + 0 = this - this.clone() - } else { + if !other.is_zero() { // We'll use mixed addition to add non-zero constants. - let x = F::constant(other.x); - let y = F::constant(other.y); - this.add_mixed(&NonZeroAffineVar::new(x, y)).unwrap() + let x = BFVar::

::constant(other.x); + let y = BFVar::

::constant(other.y); + *this = this.add_mixed(&NonZeroAffineVar::new(x, y)).unwrap() } } else { // Complete addition formula from Renes-Costello-Batina 2015 @@ -644,73 +653,68 @@ impl_bounded_ops!( let xz_pairs = ((x1 + z1) * &(x2 + z2)) - (&xx + &zz); // 9, 10, 11, 12, 13 let yz_pairs = ((y1 + z1) * &(y2 + z2)) - (&yy + &zz); // 14, 15, 16, 17, 18 - let axz = mul_by_coeff_a::(&xz_pairs); // 19 + let axz = mul_by_coeff_a::

(&xz_pairs); // 19 let bzz3_part = &axz + &zz * three_b; // 20, 21 let yy_m_bzz3 = &yy - &bzz3_part; // 22 let yy_p_bzz3 = &yy + &bzz3_part; // 23 - let azz = mul_by_coeff_a::(&zz); + let azz = mul_by_coeff_a::

(&zz); let xx3_p_azz = xx.double().unwrap() + &xx + &azz; // 25, 26, 27, 29 let bxz3 = &xz_pairs * three_b; // 28 - let b3_xz_pairs = mul_by_coeff_a::(&(&xx - &azz)) + &bxz3; // 30, 31, 32 - - let x = (&yy_m_bzz3 * &xy_pairs) - &yz_pairs * &b3_xz_pairs; // 35, 39, 40 - let y = (&yy_p_bzz3 * &yy_m_bzz3) + &xx3_p_azz * b3_xz_pairs; // 24, 36, 37, 38 - let z = (&yy_p_bzz3 * &yz_pairs) + xy_pairs * xx3_p_azz; // 41, 42, 43 + let b3_xz_pairs = mul_by_coeff_a::

(&(&xx - &azz)) + &bxz3; // 30, 31, 32 - ProjectiveVar::new(x, y, z) + this.x = (&yy_m_bzz3 * &xy_pairs) - &yz_pairs * &b3_xz_pairs; // 35, 39, 40 + this.y = (&yy_p_bzz3 * &yy_m_bzz3) + &xx3_p_azz * b3_xz_pairs; // 24, 36, 37, 38 + this.z = (yy_p_bzz3 * &yz_pairs) + xy_pairs * xx3_p_azz; // 41, 42, 43 } }, - |this: &'a ProjectiveVar, other: SWProjective

| { - this + ProjectiveVar::constant(other) + |this: &mut ProjectiveVar

, other: Projective

| { + *this = &*this + ProjectiveVar::constant(other) }, - (F: FieldVar::BasePrimeField>, P: SWModelParameters), - for <'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>, + (P: SWCurveConfig), + BF

: FieldWithVar, ); impl_bounded_ops!( - ProjectiveVar, - SWProjective

, + ProjectiveVar

, + Projective

, Sub, sub, SubAssign, sub_assign, - |this: &'a ProjectiveVar, other: &'a ProjectiveVar| this + other.negate().unwrap(), - |this: &'a ProjectiveVar, other: SWProjective

| this - ProjectiveVar::constant(other), - (F: FieldVar::BasePrimeField>, P: SWModelParameters), - for <'b> &'b F: FieldOpsBounds<'b, P::BaseField, F> + |this: &mut ProjectiveVar

, other: &'a ProjectiveVar

| *this += other.negate().unwrap(), + |this: &mut ProjectiveVar

, other: Projective

| *this = &*this - ProjectiveVar::constant(other), + (P: SWCurveConfig), + BF

: FieldWithVar, ); -impl<'a, P, F> GroupOpsBounds<'a, SWProjective

, ProjectiveVar> for ProjectiveVar +impl<'a, P> GroupOpsBounds<'a, Projective

, ProjectiveVar

> for ProjectiveVar

where - P: SWModelParameters, - F: FieldVar::BasePrimeField>, - for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>, + P: SWCurveConfig, + BF

: FieldWithVar, { } -impl<'a, P, F> GroupOpsBounds<'a, SWProjective

, ProjectiveVar> for &'a ProjectiveVar +impl<'a, P> GroupOpsBounds<'a, Projective

, ProjectiveVar

> for &'a ProjectiveVar

where - P: SWModelParameters, - F: FieldVar::BasePrimeField>, - for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>, + P: SWCurveConfig, + BF

: FieldWithVar, { } -impl CondSelectGadget<::BasePrimeField> for ProjectiveVar +impl

CondSelectGadget> for ProjectiveVar

where - P: SWModelParameters, - F: FieldVar::BasePrimeField>, - for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, + P: SWCurveConfig, + BF

: FieldWithVar, { #[inline] #[tracing::instrument(target = "r1cs")] fn conditionally_select( - cond: &Boolean<::BasePrimeField>, + cond: &Boolean>, true_value: &Self, false_value: &Self, ) -> Result { @@ -722,17 +726,13 @@ where } } -impl EqGadget<::BasePrimeField> for ProjectiveVar +impl

EqGadget> for ProjectiveVar

where - P: SWModelParameters, - F: FieldVar::BasePrimeField>, - for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, + P: SWCurveConfig, + BF

: FieldWithVar, { #[tracing::instrument(target = "r1cs")] - fn is_eq( - &self, - other: &Self, - ) -> Result::BasePrimeField>, SynthesisError> { + fn is_eq(&self, other: &Self) -> Result>, SynthesisError> { let x_equal = (&self.x * &other.z).is_eq(&(&other.x * &self.z))?; let y_equal = (&self.y * &other.z).is_eq(&(&other.y * &self.z))?; let coordinates_equal = x_equal.and(&y_equal)?; @@ -745,7 +745,7 @@ where fn conditional_enforce_equal( &self, other: &Self, - condition: &Boolean<::BasePrimeField>, + condition: &Boolean>, ) -> Result<(), SynthesisError> { let x_equal = (&self.x * &other.z).is_eq(&(&other.x * &self.z))?; let y_equal = (&self.y * &other.z).is_eq(&(&other.y * &self.z))?; @@ -762,7 +762,7 @@ where fn conditional_enforce_not_equal( &self, other: &Self, - condition: &Boolean<::BasePrimeField>, + condition: &Boolean>, ) -> Result<(), SynthesisError> { let is_equal = self.is_eq(other)?; is_equal @@ -771,34 +771,31 @@ where } } -impl AllocVar, ::BasePrimeField> for ProjectiveVar +impl

AllocVar, CF

> for ProjectiveVar

where - P: SWModelParameters, - F: FieldVar::BasePrimeField>, - for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, + P: SWCurveConfig, + BF

: FieldWithVar, { - fn new_variable>>( - cs: impl Into::BasePrimeField>>, + fn new_variable>>( + cs: impl Into>>, f: impl FnOnce() -> Result, mode: AllocationMode, ) -> Result { Self::new_variable( cs, - || f().map(|b| SWProjective::from((*b.borrow()).clone())), + || f().map(|b| Projective::from((*b.borrow()).clone())), mode, ) } } -impl AllocVar, ::BasePrimeField> - for ProjectiveVar +impl

AllocVar, CF

> for ProjectiveVar

where - P: SWModelParameters, - F: FieldVar::BasePrimeField>, - for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, + P: SWCurveConfig, + BF

: FieldWithVar, { - fn new_variable>>( - cs: impl Into::BasePrimeField>>, + fn new_variable>>( + cs: impl Into>>, f: impl FnOnce() -> Result, mode: AllocationMode, ) -> Result { @@ -902,16 +899,13 @@ fn div2(limbs: &mut [u64]) { } } -impl ToBitsGadget<::BasePrimeField> for ProjectiveVar +impl

ToBitsGadget> for ProjectiveVar

where - P: SWModelParameters, - F: FieldVar::BasePrimeField>, - for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, + P: SWCurveConfig, + BF

: FieldWithVar, { #[tracing::instrument(target = "r1cs")] - fn to_bits_le( - &self, - ) -> Result::BasePrimeField>>, SynthesisError> { + fn to_bits_le(&self) -> Result>>, SynthesisError> { let g = self.to_affine()?; let mut bits = g.x.to_bits_le()?; let y_bits = g.y.to_bits_le()?; @@ -921,9 +915,7 @@ where } #[tracing::instrument(target = "r1cs")] - fn to_non_unique_bits_le( - &self, - ) -> Result::BasePrimeField>>, SynthesisError> { + fn to_non_unique_bits_le(&self) -> Result>>, SynthesisError> { let g = self.to_affine()?; let mut bits = g.x.to_non_unique_bits_le()?; let y_bits = g.y.to_non_unique_bits_le()?; @@ -933,16 +925,13 @@ where } } -impl ToBytesGadget<::BasePrimeField> for ProjectiveVar +impl

ToBytesGadget> for ProjectiveVar

where - P: SWModelParameters, - F: FieldVar::BasePrimeField>, - for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, + P: SWCurveConfig, + BF

: FieldWithVar, { #[tracing::instrument(target = "r1cs")] - fn to_bytes( - &self, - ) -> Result::BasePrimeField>>, SynthesisError> { + fn to_bytes(&self) -> Result>>, SynthesisError> { let g = self.to_affine()?; let mut bytes = g.x.to_bytes()?; let y_bytes = g.y.to_bytes()?; @@ -953,9 +942,7 @@ where } #[tracing::instrument(target = "r1cs")] - fn to_non_unique_bytes( - &self, - ) -> Result::BasePrimeField>>, SynthesisError> { + fn to_non_unique_bytes(&self) -> Result>>, SynthesisError> { let g = self.to_affine()?; let mut bytes = g.x.to_non_unique_bytes()?; let y_bytes = g.y.to_non_unique_bytes()?; diff --git a/src/groups/curves/short_weierstrass/non_zero_affine.rs b/src/groups/curves/short_weierstrass/non_zero_affine.rs index 8578702e..a3ffc434 100644 --- a/src/groups/curves/short_weierstrass/non_zero_affine.rs +++ b/src/groups/curves/short_weierstrass/non_zero_affine.rs @@ -1,33 +1,30 @@ use super::*; -use ark_ec::Group; +use ark_ec::{models::short_weierstrass::SWCurveConfig, Group}; use ark_std::ops::Add; /// An affine representation of a prime order curve point that is guaranteed /// to *not* be the point at infinity. #[derive(Derivative)] -#[derivative(Debug, Clone)] +#[derivative(Debug(bound = "P: SWCurveConfig"), Clone(bound = "P: SWCurveConfig"))] #[must_use] -pub struct NonZeroAffineVar< - P: SWModelParameters, - F: FieldVar::BasePrimeField>, -> where - for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, +pub struct NonZeroAffineVar +where + BF

: FieldWithVar, { /// The x-coordinate. - pub x: F, + pub x: BFVar

, /// The y-coordinate. - pub y: F, + pub y: BFVar

, #[derivative(Debug = "ignore")] _params: PhantomData

, } -impl NonZeroAffineVar +impl

NonZeroAffineVar

where - P: SWModelParameters, - F: FieldVar::BasePrimeField>, - for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, + P: SWCurveConfig, + BF

: FieldWithVar, { - pub fn new(x: F, y: F) -> Self { + pub fn new(x: BFVar

, y: BFVar

) -> Self { Self { x, y, @@ -37,16 +34,26 @@ where /// Converts self into a non-zero projective point. #[tracing::instrument(target = "r1cs", skip(self))] - pub fn into_projective(&self) -> ProjectiveVar { - ProjectiveVar::new(self.x.clone(), self.y.clone(), F::one()) + pub fn into_projective(&self) -> ProjectiveVar

{ + ProjectiveVar::new(self.x.clone(), self.y.clone(), BFVar::

::one()) } +} +impl

NonZeroAffineVar

+where + P: SWCurveConfig, + BF

: FieldWithVar, + BFVar

: FieldVar>, +{ /// Performs an addition without checking that other != ±self. #[tracing::instrument(target = "r1cs", skip(self, other))] pub fn add_unchecked(&self, other: &Self) -> Result { if [self, other].is_constant() { let result = self.value()?.add(other.value()?).into_affine(); - Ok(Self::new(F::constant(result.x), F::constant(result.y))) + Ok(Self::new( + BFVar::

::constant(result.x), + BFVar::

::constant(result.y), + )) } else { let (x1, y1) = (&self.x, &self.y); let (x2, y2) = (&other.x, &other.y); @@ -71,12 +78,13 @@ where #[tracing::instrument(target = "r1cs", skip(self))] pub fn double(&self) -> Result { if [self].is_constant() { - let result = SWProjective::

::from(self.value()?) - .double() - .into_affine(); + let result = Projective::

::from(self.value()?).double().into_affine(); // Panic if the result is zero. assert!(!result.is_zero()); - Ok(Self::new(F::constant(result.x), F::constant(result.y))) + Ok(Self::new( + BFVar::

::constant(result.x), + BFVar::

::constant(result.y), + )) } else { let (x1, y1) = (&self.x, &self.y); let x1_sqr = x1.square()?; @@ -138,33 +146,31 @@ where } } -impl R1CSVar<::BasePrimeField> for NonZeroAffineVar +impl

R1CSVar> for NonZeroAffineVar

where - P: SWModelParameters, - F: FieldVar::BasePrimeField>, - for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, + P: SWCurveConfig, + BF

: FieldWithVar, { - type Value = SWAffine

; + type Value = Affine

; - fn cs(&self) -> ConstraintSystemRef<::BasePrimeField> { + fn cs(&self) -> ConstraintSystemRef> { self.x.cs().or(self.y.cs()) } - fn value(&self) -> Result, SynthesisError> { - Ok(SWAffine::new(self.x.value()?, self.y.value()?)) + fn value(&self) -> Result, SynthesisError> { + Ok(Affine::new(self.x.value()?, self.y.value()?)) } } -impl CondSelectGadget<::BasePrimeField> for NonZeroAffineVar +impl

CondSelectGadget> for NonZeroAffineVar

where - P: SWModelParameters, - F: FieldVar::BasePrimeField>, - for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, + P: SWCurveConfig, + BF

: FieldWithVar, { #[inline] #[tracing::instrument(target = "r1cs")] fn conditionally_select( - cond: &Boolean<::BasePrimeField>, + cond: &Boolean>, true_value: &Self, false_value: &Self, ) -> Result { @@ -175,11 +181,10 @@ where } } -impl EqGadget<::BasePrimeField> for NonZeroAffineVar +impl

EqGadget<::BasePrimeField> for NonZeroAffineVar

where - P: SWModelParameters, - F: FieldVar::BasePrimeField>, - for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, + P: SWCurveConfig, + BF

: FieldWithVar, { #[tracing::instrument(target = "r1cs")] fn is_eq( @@ -242,7 +247,7 @@ mod test_non_zero_affine { use ark_ec::{models::short_weierstrass::SWCurveConfig, CurveGroup}; use ark_relations::r1cs::ConstraintSystem; use ark_std::{vec::Vec, One}; - use ark_test_curves::bls12_381::{g1::Parameters as G1Parameters, Fq}; + use ark_test_curves::bls12_381::{g1::Config as G1Config, Fq}; #[test] fn correctness_test_1() { @@ -259,11 +264,8 @@ mod test_non_zero_affine { // (1 + 2 + ... + 2^9) G let sum_a = { - let mut a = ProjectiveVar::>::new( - x.clone(), - y.clone(), - FpVar::Constant(Fq::one()), - ); + let mut a = + ProjectiveVar::::new(x.clone(), y.clone(), FpVar::Constant(Fq::one())); let mut double_sequence = Vec::new(); double_sequence.push(a.clone()); @@ -283,7 +285,7 @@ mod test_non_zero_affine { }; let sum_b = { - let mut a = NonZeroAffineVar::>::new(x, y); + let mut a = NonZeroAffineVar::::new(x, y); let mut double_sequence = Vec::new(); double_sequence.push(a.clone()); @@ -318,11 +320,8 @@ mod test_non_zero_affine { // The following code tests `double_and_add`. let sum_a = { - let a = ProjectiveVar::>::new( - x.clone(), - y.clone(), - FpVar::Constant(Fq::one()), - ); + let a = + ProjectiveVar::::new(x.clone(), y.clone(), FpVar::Constant(Fq::one())); let mut cur = a.clone(); cur.double_in_place().unwrap(); @@ -336,7 +335,7 @@ mod test_non_zero_affine { }; let sum_b = { - let a = NonZeroAffineVar::>::new(x, y); + let a = NonZeroAffineVar::::new(x, y); let mut cur = a.double().unwrap(); for _ in 1..10 { diff --git a/src/groups/curves/twisted_edwards/mod.rs b/src/groups/curves/twisted_edwards/mod.rs index 789cb594..ef21910c 100644 --- a/src/groups/curves/twisted_edwards/mod.rs +++ b/src/groups/curves/twisted_edwards/mod.rs @@ -1,18 +1,19 @@ use ark_ec::{ twisted_edwards::{ - Affine as TEAffine, MontCurveConfig as MontgomeryModelParameter, - Projective as TEProjective, TECurveConfig as TEModelParameters, + Affine as TEAffine, MontCurveConfig, Projective as TEProjective, TECurveConfig, }, - AffineRepr, CurveGroup, Group, + AffineRepr, CurveConfig, CurveGroup, Group, }; use ark_ff::{BigInteger, BitIteratorBE, Field, One, PrimeField, Zero}; use ark_relations::r1cs::{ConstraintSystemRef, Namespace, SynthesisError}; -use crate::{prelude::*, ToConstraintFieldGadget, Vec}; +use crate::{fields::FieldWithVar, prelude::*, ToConstraintFieldGadget, Vec}; use crate::fields::fp::FpVar; use ark_std::{borrow::Borrow, marker::PhantomData, ops::Mul}; +type BFVar

= <

::BaseField as FieldWithVar>::Var; + /// 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). @@ -20,18 +21,19 @@ use ark_std::{borrow::Borrow, marker::PhantomData, ops::Mul}; /// This is intended for use primarily for implementing efficient /// multi-scalar-multiplication in the Bowe-Hopwood-Pedersen hash. #[derive(Derivative)] -#[derivative(Debug, Clone)] +#[derivative( + Debug(bound = "P: TECurveConfig, P::BaseField: FieldWithVar"), + Clone(bound = "P: TECurveConfig, P::BaseField: FieldWithVar") +)] #[must_use] -pub struct MontgomeryAffineVar< - P: TEModelParameters, - F: FieldVar::BasePrimeField>, -> where - for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, +pub struct MontgomeryAffineVar +where + P::BaseField: FieldWithVar, { /// The x-coordinate. - pub x: F, + pub x: BFVar

, /// The y-coordinate. - pub y: F, + pub y: BFVar

, #[derivative(Debug = "ignore")] _params: PhantomData

, } @@ -42,15 +44,14 @@ mod montgomery_affine_impl { use ark_ff::Field; use core::ops::Add; - impl R1CSVar<::BasePrimeField> for MontgomeryAffineVar + impl

R1CSVar> for MontgomeryAffineVar

where - P: TEModelParameters, - F: FieldVar::BasePrimeField>, - for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, + P::BaseField: FieldWithVar, + P: TECurveConfig, { type Value = (P::BaseField, P::BaseField); - fn cs(&self) -> ConstraintSystemRef<::BasePrimeField> { + fn cs(&self) -> ConstraintSystemRef> { self.x.cs().or(self.y.cs()) } @@ -61,15 +62,12 @@ mod montgomery_affine_impl { } } - impl< - P: TEModelParameters, - F: FieldVar::BasePrimeField>, - > MontgomeryAffineVar + impl MontgomeryAffineVar

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

, y: BFVar

) -> Self { Self { x, y, @@ -101,18 +99,25 @@ mod montgomery_affine_impl { /// corresponding affine Montgomery curve point. #[tracing::instrument(target = "r1cs")] pub fn new_witness_from_edwards( - cs: ConstraintSystemRef<::BasePrimeField>, + cs: ConstraintSystemRef>, p: &TEAffine

, ) -> Result { let montgomery_coords = Self::from_edwards_to_coords(p)?; - let u = F::new_witness(ark_relations::ns!(cs, "u"), || Ok(montgomery_coords.0))?; - let v = F::new_witness(ark_relations::ns!(cs, "v"), || Ok(montgomery_coords.1))?; + let u = + BFVar::

::new_witness(ark_relations::ns!(cs, "u"), || Ok(montgomery_coords.0))?; + let v = + BFVar::

::new_witness(ark_relations::ns!(cs, "v"), || Ok(montgomery_coords.1))?; Ok(Self::new(u, v)) } + } + impl MontgomeryAffineVar

+ where + P::BaseField: FieldWithVar, + { /// Converts `self` into a Twisted Edwards curve point variable. #[tracing::instrument(target = "r1cs")] - pub fn into_edwards(&self) -> Result, SynthesisError> { + pub fn into_edwards(&self) -> Result, SynthesisError> { let cs = self.cs(); let mode = if cs.is_none() { @@ -122,7 +127,7 @@ mod montgomery_affine_impl { }; // Compute u = x / y - let u = F::new_variable( + let u = BFVar::

::new_variable( ark_relations::ns!(cs, "u"), || { let y_inv = self @@ -137,7 +142,7 @@ mod montgomery_affine_impl { u.mul_equals(&self.y, &self.x)?; - let v = F::new_variable( + let v = BFVar::

::new_variable( ark_relations::ns!(cs, "v"), || { let mut t0 = self.x.value()?; @@ -158,13 +163,12 @@ mod montgomery_affine_impl { } } - impl<'a, P, F> Add<&'a MontgomeryAffineVar> for MontgomeryAffineVar + impl<'a, P> Add<&'a MontgomeryAffineVar

> for MontgomeryAffineVar

where - P: TEModelParameters, - F: FieldVar::BasePrimeField>, - for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>, + P: TECurveConfig, + P::BaseField: FieldWithVar, { - type Output = MontgomeryAffineVar; + type Output = MontgomeryAffineVar

; #[tracing::instrument(target = "r1cs")] fn add(self, other: &'a Self) -> Self::Output { @@ -178,7 +182,7 @@ mod montgomery_affine_impl { let coeff_b = P::MontCurveConfig::COEFF_B; let coeff_a = P::MontCurveConfig::COEFF_A; - let lambda = F::new_variable( + let lambda = BFVar::

::new_variable( ark_relations::ns!(cs, "lambda"), || { let n = other.y.value()? - &self.y.value()?; @@ -193,7 +197,7 @@ mod montgomery_affine_impl { lambda_d.mul_equals(&lambda, &lambda_n).unwrap(); // Compute x'' = B*lambda^2 - A - x - x' - let xprime = F::new_variable( + let xprime = BFVar::

::new_variable( ark_relations::ns!(cs, "xprime"), || { Ok(lambda.value()?.square() * &coeff_b @@ -210,7 +214,7 @@ mod montgomery_affine_impl { let lambda_b = &lambda * coeff_b; lambda_b.mul_equals(&lambda, &xprime_lc).unwrap(); - let yprime = F::new_variable( + let yprime = BFVar::

::new_variable( ark_relations::ns!(cs, "yprime"), || { Ok(-(self.y.value()? @@ -232,29 +236,29 @@ mod montgomery_affine_impl { /// 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)] +#[derivative( + Debug(bound = "P: TECurveConfig, P::BaseField: FieldWithVar"), + Clone(bound = "P: TECurveConfig, P::BaseField: FieldWithVar") +)] #[must_use] -pub struct AffineVar< - P: TEModelParameters, - F: FieldVar::BasePrimeField>, -> where - for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, +pub struct AffineVar +where + P::BaseField: FieldWithVar, { /// The x-coordinate. - pub x: F, + pub x: BFVar

, /// The y-coordinate. - pub y: F, + pub y: BFVar

, #[derivative(Debug = "ignore")] _params: PhantomData

, } -impl::BasePrimeField>> - AffineVar +impl AffineVar

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

, y: BFVar

) -> Self { Self { x, y, @@ -267,7 +271,7 @@ where /// is a constant or is a public input). #[tracing::instrument(target = "r1cs", skip(cs, f))] pub fn new_variable_omit_on_curve_check>>( - cs: impl Into::BasePrimeField>>, + cs: impl Into>>, f: impl FnOnce() -> Result, mode: AllocationMode, ) -> Result { @@ -285,24 +289,19 @@ where ), }; - let x = F::new_variable(ark_relations::ns!(cs, "x"), || x, mode)?; - let y = F::new_variable(ark_relations::ns!(cs, "y"), || y, mode)?; + let x = BFVar::

::new_variable(ark_relations::ns!(cs, "x"), || x, mode)?; + let y = BFVar::

::new_variable(ark_relations::ns!(cs, "y"), || y, mode)?; Ok(Self::new(x, y)) } } -impl::BasePrimeField>> - AffineVar +impl 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>, + P: TECurveConfig, + P::BaseField: FieldWithVar, + BFVar

: TwoBitLookupGadget, TableConstant = P::BaseField> + + ThreeBitCondNegLookupGadget, TableConstant = P::BaseField>, { /// Compute a scalar multiplication of `bases` with respect to `scalars`, /// where the elements of `scalars` are length-three slices of bits, and @@ -315,13 +314,13 @@ where scalars: &[impl Borrow<[J]>], ) -> Result where - J: Borrow<[Boolean<::BasePrimeField>]>, + J: Borrow<[Boolean>]>, { const CHUNK_SIZE: usize = 3; - let mut ed_result: Option> = None; - let mut result: Option> = None; + let mut ed_result: Option> = None; + let mut result: Option> = None; - let mut process_segment_result = |result: &MontgomeryAffineVar| { + let mut process_segment_result = |result: &MontgomeryAffineVar

| { let sgmt_result = result.into_edwards()?; ed_result = match ed_result.as_ref() { None => Some(sgmt_result), @@ -360,14 +359,14 @@ where let precomp = bits[0].and(&bits[1])?; - let x = F::zero() + let x = BFVar::

::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()) + + BFVar::

::from(bits[0].clone()) * (x_coeffs[1] - &x_coeffs[0]) + + BFVar::

::from(bits[1].clone()) * (x_coeffs[2] - &x_coeffs[0]) + + BFVar::

::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 y = BFVar::

::three_bit_cond_neg_lookup(&bits, &precomp, &y_coeffs)?; let tmp = MontgomeryAffineVar::new(x, y); result = match result.as_ref() { @@ -386,15 +385,14 @@ where } } -impl R1CSVar<::BasePrimeField> for AffineVar +impl

R1CSVar> for AffineVar

where - P: TEModelParameters, - F: FieldVar::BasePrimeField>, - for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, + P: TECurveConfig, + P::BaseField: FieldWithVar, { type Value = TEProjective

; - fn cs(&self) -> ConstraintSystemRef<::BasePrimeField> { + fn cs(&self) -> ConstraintSystemRef> { self.x.cs().or(self.y.cs()) } @@ -406,12 +404,21 @@ where } } -impl CurveVar, ::BasePrimeField> for AffineVar +type CF

= <

::BaseField as Field>::BasePrimeField; + +impl CurveWithVar> for TEProjective

+where + P::BaseField: FieldWithVar, + BFVar

: TwoBitLookupGadget, TableConstant = P::BaseField>, +{ + type Var = AffineVar

; +} + +impl

CurveVar, CF

> for AffineVar

where - P: TEModelParameters, - F: FieldVar::BasePrimeField> - + TwoBitLookupGadget<::BasePrimeField, TableConstant = P::BaseField>, - for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, + P: TECurveConfig, + P::BaseField: FieldWithVar, + BFVar

: TwoBitLookupGadget, TableConstant = P::BaseField>, { fn constant(g: TEProjective

) -> Self { let cs = ConstraintSystemRef::None; @@ -419,16 +426,16 @@ where } fn zero() -> Self { - Self::new(F::zero(), F::one()) + Self::new(BFVar::

::zero(), BFVar::

::one()) } - fn is_zero(&self) -> Result::BasePrimeField>, SynthesisError> { - self.x.is_zero()?.and(&self.y.is_one()?) + fn is_zero(&self) -> Result>, SynthesisError> { + self.x.is_zero()?.and(&self.x.is_one()?) } #[tracing::instrument(target = "r1cs", skip(cs, f))] fn new_variable_omit_prime_order_check( - cs: impl Into::BasePrimeField>>, + cs: impl Into>>, f: impl FnOnce() -> Result, SynthesisError>, mode: AllocationMode, ) -> Result { @@ -492,7 +499,7 @@ where let a_x2 = &x2 * a; // Compute x3 = (2xy) / (ax^2 + y^2) - let x3 = F::new_witness(ark_relations::ns!(cs, "x3"), || { + let x3 = BFVar::

::new_witness(ark_relations::ns!(cs, "x3"), || { let t0 = xy.value()?.double(); let t1 = a * &x2.value()? + &y2.value()?; Ok(t0 * &t1.inverse().ok_or(SynthesisError::DivisionByZero)?) @@ -504,7 +511,7 @@ where // Compute y3 = (y^2 - ax^2) / (2 - ax^2 - y^2) let two = P::BaseField::one().double(); - let y3 = F::new_witness(ark_relations::ns!(cs, "y3"), || { + let y3 = BFVar::

::new_witness(ark_relations::ns!(cs, "y3"), || { let a_x2 = a * &x2.value()?; let t0 = y2.value()? - &a_x2; let t1 = two - &a_x2 - &y2.value()?; @@ -532,7 +539,7 @@ where ) -> Result<(), SynthesisError> where I: Iterator)>, - B: Borrow::BasePrimeField>>, + B: Borrow>>, { let (bits, multiples): (Vec<_>, Vec<_>) = scalar_bits_with_base_multiples .map(|(bit, base)| (bit.borrow().clone(), *base)) @@ -546,8 +553,8 @@ where let x_s = [zero.x, table[0].x, table[1].x, table[2].x]; let y_s = [zero.y, table[0].y, table[1].y, table[2].y]; - let x = F::two_bit_lookup(&bits, &x_s)?; - let y = F::two_bit_lookup(&bits, &y_s)?; + let x = BFVar::

::two_bit_lookup(&bits, &x_s)?; + let y = BFVar::

::two_bit_lookup(&bits, &y_s)?; *self += Self::new(x, y); } else if bits.len() == 1 { let bit = &bits[0]; @@ -560,16 +567,15 @@ where } } -impl AllocVar, ::BasePrimeField> for AffineVar +impl

AllocVar, CF

> for AffineVar

where - P: TEModelParameters, - F: FieldVar::BasePrimeField> - + TwoBitLookupGadget<::BasePrimeField, TableConstant = P::BaseField>, - for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, + P: TECurveConfig, + P::BaseField: FieldWithVar, + BFVar

: TwoBitLookupGadget, TableConstant = P::BaseField>, { #[tracing::instrument(target = "r1cs", skip(cs, f))] fn new_variable>>( - cs: impl Into::BasePrimeField>>, + cs: impl Into>>, f: impl FnOnce() -> Result, mode: AllocationMode, ) -> Result { @@ -661,16 +667,15 @@ where } } -impl AllocVar, ::BasePrimeField> for AffineVar +impl

AllocVar, CF

> for AffineVar

where - P: TEModelParameters, - F: FieldVar::BasePrimeField> - + TwoBitLookupGadget<::BasePrimeField, TableConstant = P::BaseField>, - for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, + P: TECurveConfig, + P::BaseField: FieldWithVar, + BFVar

: TwoBitLookupGadget, TableConstant = P::BaseField>, { #[tracing::instrument(target = "r1cs", skip(cs, f))] fn new_variable>>( - cs: impl Into::BasePrimeField>>, + cs: impl Into>>, f: impl FnOnce() -> Result, mode: AllocationMode, ) -> Result { @@ -682,16 +687,13 @@ where } } -impl ToConstraintFieldGadget<::BasePrimeField> for AffineVar +impl

ToConstraintFieldGadget> for AffineVar

where - P: TEModelParameters, - F: FieldVar::BasePrimeField>, - for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, - F: ToConstraintFieldGadget<::BasePrimeField>, + P: TECurveConfig, + P::BaseField: FieldWithVar, + BFVar

: ToConstraintFieldGadget>, { - fn to_constraint_field( - &self, - ) -> Result::BasePrimeField>>, SynthesisError> { + fn to_constraint_field(&self) -> Result>>, SynthesisError> { let mut res = Vec::new(); res.extend_from_slice(&self.x.to_constraint_field()?); @@ -713,15 +715,14 @@ fn div2(limbs: &mut [u64]) { } impl_bounded_ops!( - AffineVar, + AffineVar

, TEProjective

, Add, add, AddAssign, add_assign, - |this: &'a AffineVar, other: &'a AffineVar| { - - if [this, other].is_constant() { + |this: &mut AffineVar

, other: &'a AffineVar

| { + *this = if [this, other].is_constant() { assert!(this.is_constant() && other.is_constant()); AffineVar::constant(this.value().unwrap() + &other.value().unwrap()) } else { @@ -745,7 +746,7 @@ impl_bounded_ops!( let v2 = &v0 * &v1 * d; // Compute x3 = (v0 + v1) / (1 + v2) - let x3 = F::new_witness(ark_relations::ns!(cs, "x3"), || { + let x3 = BFVar::

::new_witness(ark_relations::ns!(cs, "x3"), || { let t0 = v0.value()? + &v1.value()?; let t1 = P::BaseField::one() + &v2.value()?; Ok(t0 * &t1.inverse().ok_or(SynthesisError::DivisionByZero)?) @@ -756,7 +757,7 @@ impl_bounded_ops!( x3.mul_equals(&v2_plus_one, &v0_plus_v1).unwrap(); // Compute y3 = (U + a * v0 - v1) / (1 - v2) - let y3 = F::new_witness(ark_relations::ns!(cs, "y3"), || { + let y3 = BFVar::

::new_witness(ark_relations::ns!(cs, "y3"), || { let t0 = u.value()? + &(a * &v0.value()?) - &v1.value()?; let t1 = P::BaseField::one() - &v2.value()?; Ok(t0 * &t1.inverse().ok_or(SynthesisError::DivisionByZero)?) @@ -769,62 +770,57 @@ impl_bounded_ops!( y3.mul_equals(&one_minus_v2, &u_plus_a_v0_minus_v1).unwrap(); AffineVar::new(x3, y3) - } + }; }, - |this: &'a AffineVar, other: TEProjective

| this + AffineVar::constant(other), + |this: &mut AffineVar

, other: TEProjective

| *this = &*this + AffineVar::constant(other), ( - F :FieldVar::BasePrimeField> - + TwoBitLookupGadget<::BasePrimeField, TableConstant = P::BaseField>, - P: TEModelParameters, + P: TECurveConfig, ), - for <'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>, + P::BaseField: FieldWithVar, + BFVar

: TwoBitLookupGadget, TableConstant = P::BaseField>, ); impl_bounded_ops!( - AffineVar, + AffineVar

, TEProjective

, Sub, sub, SubAssign, sub_assign, - |this: &'a AffineVar, other: &'a AffineVar| this + other.negate().unwrap(), - |this: &'a AffineVar, other: TEProjective

| this - AffineVar::constant(other), + |this: &mut AffineVar

, other: &'a AffineVar

| *this += other.negate().unwrap(), + |this: &mut AffineVar

, other: TEProjective

| *this = &*this - AffineVar::constant(other), ( - F :FieldVar::BasePrimeField> - + TwoBitLookupGadget<::BasePrimeField, TableConstant = P::BaseField>, - P: TEModelParameters, + P: TECurveConfig, ), - for <'b> &'b F: FieldOpsBounds<'b, P::BaseField, F> + P::BaseField: FieldWithVar, + BFVar

: TwoBitLookupGadget, TableConstant = P::BaseField>, ); -impl<'a, P, F> GroupOpsBounds<'a, TEProjective

, AffineVar> for AffineVar +impl<'a, P> GroupOpsBounds<'a, TEProjective

, AffineVar

> for AffineVar

where - P: TEModelParameters, - F: FieldVar::BasePrimeField> - + TwoBitLookupGadget<::BasePrimeField, TableConstant = P::BaseField>, - for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>, + P: TECurveConfig, + P::BaseField: FieldWithVar, + BFVar

: TwoBitLookupGadget, TableConstant = P::BaseField>, { } -impl<'a, P, F> GroupOpsBounds<'a, TEProjective

, AffineVar> for &'a AffineVar +impl<'a, P> GroupOpsBounds<'a, TEProjective

, AffineVar

> for &'a AffineVar

where - P: TEModelParameters, - F: FieldVar::BasePrimeField> - + TwoBitLookupGadget<::BasePrimeField, TableConstant = P::BaseField>, - for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>, + P: TECurveConfig, + P::BaseField: FieldWithVar, + BFVar

: TwoBitLookupGadget, TableConstant = P::BaseField>, { } -impl CondSelectGadget<::BasePrimeField> for AffineVar +impl

CondSelectGadget> for AffineVar

where - P: TEModelParameters, - F: FieldVar::BasePrimeField>, - for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>, + P: TECurveConfig, + P::BaseField: FieldWithVar, { #[inline] #[tracing::instrument(target = "r1cs")] fn conditionally_select( - cond: &Boolean<::BasePrimeField>, + cond: &Boolean>, true_value: &Self, false_value: &Self, ) -> Result { @@ -835,17 +831,13 @@ where } } -impl EqGadget<::BasePrimeField> for AffineVar +impl

EqGadget> for AffineVar

where - P: TEModelParameters, - F: FieldVar::BasePrimeField>, - for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>, + P: TECurveConfig, + P::BaseField: FieldWithVar, { #[tracing::instrument(target = "r1cs")] - fn is_eq( - &self, - other: &Self, - ) -> Result::BasePrimeField>, SynthesisError> { + fn is_eq(&self, other: &Self) -> Result>, SynthesisError> { let x_equal = self.x.is_eq(&other.x)?; let y_equal = self.y.is_eq(&other.y)?; x_equal.and(&y_equal) @@ -856,7 +848,7 @@ where fn conditional_enforce_equal( &self, other: &Self, - condition: &Boolean<::BasePrimeField>, + condition: &Boolean>, ) -> Result<(), SynthesisError> { self.x.conditional_enforce_equal(&other.x, condition)?; self.y.conditional_enforce_equal(&other.y, condition)?; @@ -868,7 +860,7 @@ where fn conditional_enforce_not_equal( &self, other: &Self, - condition: &Boolean<::BasePrimeField>, + condition: &Boolean>, ) -> Result<(), SynthesisError> { self.is_eq(other)? .and(condition)? @@ -876,16 +868,13 @@ where } } -impl ToBitsGadget<::BasePrimeField> for AffineVar +impl

ToBitsGadget> for AffineVar

where - P: TEModelParameters, - F: FieldVar::BasePrimeField>, - for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>, + P: TECurveConfig, + P::BaseField: FieldWithVar, { #[tracing::instrument(target = "r1cs")] - fn to_bits_le( - &self, - ) -> Result::BasePrimeField>>, SynthesisError> { + fn to_bits_le(&self) -> Result>>, SynthesisError> { let mut x_bits = self.x.to_bits_le()?; let y_bits = self.y.to_bits_le()?; x_bits.extend_from_slice(&y_bits); @@ -893,9 +882,7 @@ where } #[tracing::instrument(target = "r1cs")] - fn to_non_unique_bits_le( - &self, - ) -> Result::BasePrimeField>>, SynthesisError> { + fn to_non_unique_bits_le(&self) -> Result>>, SynthesisError> { let mut x_bits = self.x.to_non_unique_bits_le()?; let y_bits = self.y.to_non_unique_bits_le()?; x_bits.extend_from_slice(&y_bits); @@ -904,16 +891,13 @@ where } } -impl ToBytesGadget<::BasePrimeField> for AffineVar +impl

ToBytesGadget> for AffineVar

where - P: TEModelParameters, - F: FieldVar::BasePrimeField>, - for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>, + P: TECurveConfig, + P::BaseField: FieldWithVar, { #[tracing::instrument(target = "r1cs")] - fn to_bytes( - &self, - ) -> Result::BasePrimeField>>, SynthesisError> { + fn to_bytes(&self) -> Result>>, SynthesisError> { let mut x_bytes = self.x.to_bytes()?; let y_bytes = self.y.to_bytes()?; x_bytes.extend_from_slice(&y_bytes); @@ -921,9 +905,7 @@ where } #[tracing::instrument(target = "r1cs")] - fn to_non_unique_bytes( - &self, - ) -> Result::BasePrimeField>>, SynthesisError> { + fn to_non_unique_bytes(&self) -> Result>>, SynthesisError> { let mut x_bytes = self.x.to_non_unique_bytes()?; let y_bytes = self.y.to_non_unique_bytes()?; x_bytes.extend_from_slice(&y_bytes); diff --git a/src/groups/mod.rs b/src/groups/mod.rs index a02e303a..61378aab 100644 --- a/src/groups/mod.rs +++ b/src/groups/mod.rs @@ -23,6 +23,10 @@ pub trait GroupOpsBounds<'a, F, T: 'a>: { } +pub trait CurveWithVar: CurveGroup { + type Var: CurveVar; +} + /// A variable that represents a curve point for /// the curve `C`. pub trait CurveVar: diff --git a/src/lib.rs b/src/lib.rs index 9c6b7019..4d183305 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,7 @@ #![cfg_attr(not(feature = "std"), no_std)] //! This crate implements common "gadgets" that make //! programming rank-1 constraint systems easier. -#![deny( +#![warn( warnings, unused, future_incompatible, @@ -65,9 +65,9 @@ pub mod prelude { alloc::*, bits::{boolean::Boolean, uint32::UInt32, uint8::UInt8, ToBitsGadget, ToBytesGadget}, eq::*, - fields::{FieldOpsBounds, FieldVar}, - groups::{CurveVar, GroupOpsBounds}, - pairing::PairingVar, + fields::{FieldOpsBounds, FieldVar, FieldWithVar}, + groups::{CurveVar, CurveWithVar, GroupOpsBounds}, + pairing::PairingGadget, select::*, R1CSVar, }; diff --git a/src/macros.rs b/src/macros.rs index 2770a7e3..0fc62baf 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -52,7 +52,9 @@ macro_rules! impl_bounded_ops { #[tracing::instrument(target = "r1cs", skip(self))] #[allow(unused_braces, clippy::redundant_closure_call)] fn $fn(self, other: Self) -> Self::Output { - ($impl)(self, other) + let mut result = self.clone(); + core::ops::$assign_trait::$assign_fn(&mut result, other); + result } } @@ -77,8 +79,9 @@ macro_rules! impl_bounded_ops { #[tracing::instrument(target = "r1cs", skip(self))] #[allow(unused_braces)] - fn $fn(self, other: &'a $type) -> Self::Output { - core::ops::$trait::$fn(&self, other) + fn $fn(mut self, other: &'a $type) -> Self::Output { + core::ops::$assign_trait::$assign_fn(&mut self, other); + self } } @@ -91,8 +94,9 @@ macro_rules! impl_bounded_ops { #[tracing::instrument(target = "r1cs", skip(self))] #[allow(unused_braces)] - fn $fn(self, other: $type) -> Self::Output { - core::ops::$trait::$fn(&self, &other) + fn $fn(mut self, other: $type) -> Self::Output { + core::ops::$assign_trait::$assign_fn(&mut self, &other); + self } } @@ -104,8 +108,7 @@ macro_rules! impl_bounded_ops { #[tracing::instrument(target = "r1cs", skip(self))] #[allow(unused_braces)] fn $assign_fn(&mut self, other: $type) { - let result = core::ops::$trait::$fn(&*self, &other); - *self = result + core::ops::$assign_trait::$assign_fn(self, &other); } } @@ -117,8 +120,7 @@ macro_rules! impl_bounded_ops { #[tracing::instrument(target = "r1cs", skip(self))] #[allow(unused_braces)] fn $assign_fn(&mut self, other: &'a $type) { - let result = core::ops::$trait::$fn(&*self, other); - *self = result + ($impl)(self, other) } } @@ -132,7 +134,9 @@ macro_rules! impl_bounded_ops { #[tracing::instrument(target = "r1cs", skip(self))] #[allow(unused_braces, clippy::redundant_closure_call)] fn $fn(self, other: $native) -> Self::Output { - ($constant_impl)(self, other) + let mut result = self.clone(); + core::ops::$assign_trait::$assign_fn(&mut result, other); + result } } @@ -145,8 +149,9 @@ macro_rules! impl_bounded_ops { #[tracing::instrument(target = "r1cs", skip(self))] #[allow(unused_braces)] - fn $fn(self, other: $native) -> Self::Output { - core::ops::$trait::$fn(&self, other) + fn $fn(mut self, other: $native) -> Self::Output { + core::ops::$assign_trait::$assign_fn(&mut self, other); + self } } @@ -155,12 +160,10 @@ macro_rules! impl_bounded_ops { $($bounds)* { - #[tracing::instrument(target = "r1cs", skip(self))] #[allow(unused_braces)] fn $assign_fn(&mut self, other: $native) { - let result = core::ops::$trait::$fn(&*self, other); - *self = result + ($constant_impl)(self, other) } } } diff --git a/src/pairing/bls12/mod.rs b/src/pairing/bls12/mod.rs index 91adbb78..624645db 100644 --- a/src/pairing/bls12/mod.rs +++ b/src/pairing/bls12/mod.rs @@ -1,21 +1,24 @@ use ark_relations::r1cs::SynthesisError; -use super::PairingVar as PG; +use super::PairingGadget as PG; use crate::{ - fields::{fp::FpVar, fp12::Fp12Var, fp2::Fp2Var, FieldVar}, + fields::{fp::FpVar, fp12::Fp12Var, fp2::Fp2Var, FieldVar, FieldWithVar}, groups::bls12::{G1AffineVar, G1PreparedVar, G1Var, G2PreparedVar, G2Var}, }; -use ark_ec::bls12::{Bls12, Bls12Parameters, TwistType}; +use ark_ec::bls12::{Bls12, Bls12Config, TwistType}; use ark_ff::BitIteratorBE; use ark_std::marker::PhantomData; /// Specifies the constraints for computing a pairing in a BLS12 bilinear group. -pub struct PairingVar(PhantomData

); +pub struct Bls12Gadget(PhantomData

); -type Fp2V

= Fp2Var<

::Fp2Config>; +type Fp2V

= Fp2Var<

::Fp2Config>; -impl PairingVar

{ +impl Bls12Gadget

+where + P::Fp: FieldWithVar>, +{ // Evaluate the line function at point p. #[tracing::instrument(target = "r1cs")] fn ell( @@ -59,7 +62,10 @@ impl PairingVar

{ } } -impl PG, P::Fp> for PairingVar

{ +impl PG for Bls12

+where + P::Fp: FieldWithVar>, +{ type G1Var = G1Var

; type G2Var = G2Var

; type G1PreparedVar = G1PreparedVar

; @@ -67,7 +73,7 @@ impl PG, P::Fp> for PairingVar

{ type GTVar = Fp12Var; #[tracing::instrument(target = "r1cs")] - fn miller_loop( + fn miller_loop_gadget( ps: &[Self::G1PreparedVar], qs: &[Self::G2PreparedVar], ) -> Result { @@ -81,12 +87,12 @@ impl PG, P::Fp> for PairingVar

{ f.square_in_place()?; for &mut (p, ref mut coeffs) in pairs.iter_mut() { - Self::ell(&mut f, coeffs.next().unwrap(), &p.0)?; + Bls12Gadget::

::ell(&mut f, coeffs.next().unwrap(), &p.0)?; } if i { for &mut (p, ref mut coeffs) in pairs.iter_mut() { - Self::ell(&mut f, &coeffs.next().unwrap(), &p.0)?; + Bls12Gadget::

::ell(&mut f, &coeffs.next().unwrap(), &p.0)?; } } } @@ -99,7 +105,7 @@ impl PG, P::Fp> for PairingVar

{ } #[tracing::instrument(target = "r1cs")] - fn final_exponentiation(f: &Self::GTVar) -> Result { + fn final_exponentiation_gadget(f: &Self::GTVar) -> Result { // Computing the final exponentation following // https://eprint.iacr.org/2016/130.pdf. // We don't use their "faster" formula because it is difficult to make @@ -128,15 +134,15 @@ impl PG, P::Fp> for PairingVar

{ let mut y0 = r.cyclotomic_square()?; y0 = y0.unitary_inverse()?; - let mut y5 = Self::exp_by_x(&r)?; + let mut y5 = Bls12Gadget::

::exp_by_x(&r)?; let mut y1 = y5.cyclotomic_square()?; let mut y3 = y0 * &y5; - y0 = Self::exp_by_x(&y3)?; - let y2 = Self::exp_by_x(&y0)?; - let mut y4 = Self::exp_by_x(&y2)?; + y0 = Bls12Gadget::

::exp_by_x(&y3)?; + let y2 = Bls12Gadget::

::exp_by_x(&y0)?; + let mut y4 = Bls12Gadget::

::exp_by_x(&y2)?; y4 *= &y1; - y1 = Self::exp_by_x(&y4)?; + y1 = Bls12Gadget::

::exp_by_x(&y4)?; y3 = y3.unitary_inverse()?; y1 *= &y3; y1 *= &r; diff --git a/src/pairing/mnt4/mod.rs b/src/pairing/mnt4/mod.rs index b7ce0b35..a02cd159 100644 --- a/src/pairing/mnt4/mod.rs +++ b/src/pairing/mnt4/mod.rs @@ -1,27 +1,30 @@ use ark_relations::r1cs::SynthesisError; -use super::PairingVar as PG; +use super::PairingGadget as PG; use crate::{ - fields::{fp::FpVar, fp2::Fp2Var, fp4::Fp4Var, FieldVar}, + fields::{fp::FpVar, fp2::Fp2Var, fp4::Fp4Var, FieldVar, FieldWithVar}, groups::mnt4::{ AteAdditionCoefficientsVar, AteDoubleCoefficientsVar, G1PreparedVar, G1Var, G2PreparedVar, G2ProjectiveExtendedVar, G2Var, }, }; -use ark_ec::mnt4::{MNT4Parameters, MNT4}; +use ark_ec::mnt4::{MNT4Config, MNT4}; use core::marker::PhantomData; /// Specifies the constraints for computing a pairing in a MNT4 bilinear group. -pub struct PairingVar(PhantomData

); +pub struct MNT4Gadget(PhantomData

); -type Fp2G

= Fp2Var<

::Fp2Config>; -type Fp4G

= Fp4Var<

::Fp4Config>; +type Fp2G

= Fp2Var<

::Fp2Config>; +type Fp4G

= Fp4Var<

::Fp4Config>; /// A variable corresponding to `ark_ec::mnt4::GT`. pub type GTVar

= Fp4G

; -impl PairingVar

{ +impl MNT4Gadget

+where + P::Fp: FieldWithVar>, +{ #[tracing::instrument(target = "r1cs", skip(r))] pub(crate) fn doubling_step_for_flipped_miller_loop( r: &G2ProjectiveExtendedVar

, @@ -196,7 +199,10 @@ impl PairingVar

{ } } -impl PG, P::Fp> for PairingVar

{ +impl PG for MNT4

+where + P::Fp: FieldWithVar>, +{ type G1Var = G1Var

; type G2Var = G2Var

; type G1PreparedVar = G1PreparedVar

; @@ -204,21 +210,21 @@ impl PG, P::Fp> for PairingVar

{ type GTVar = GTVar

; #[tracing::instrument(target = "r1cs")] - fn miller_loop( + fn miller_loop_gadget( ps: &[Self::G1PreparedVar], qs: &[Self::G2PreparedVar], ) -> Result { let mut result = Fp4G::

::one(); for (p, q) in ps.iter().zip(qs) { - result *= Self::ate_miller_loop(p, q)?; + result *= MNT4Gadget::ate_miller_loop(p, q)?; } Ok(result) } #[tracing::instrument(target = "r1cs")] - fn final_exponentiation(r: &Self::GTVar) -> Result { - Self::final_exponentiation(r) + fn final_exponentiation_gadget(r: &Self::GTVar) -> Result { + MNT4Gadget::

::final_exponentiation(r) } #[tracing::instrument(target = "r1cs")] diff --git a/src/pairing/mnt6/mod.rs b/src/pairing/mnt6/mod.rs index 350eb620..aaec7d79 100644 --- a/src/pairing/mnt6/mod.rs +++ b/src/pairing/mnt6/mod.rs @@ -1,26 +1,29 @@ use ark_relations::r1cs::SynthesisError; -use super::PairingVar as PG; +use super::PairingGadget as PG; use crate::{ - fields::{fp::FpVar, fp3::Fp3Var, fp6_2over3::Fp6Var, FieldVar}, + fields::{fp::FpVar, fp3::Fp3Var, fp6_2over3::Fp6Var, FieldVar, FieldWithVar}, groups::mnt6::{ AteAdditionCoefficientsVar, AteDoubleCoefficientsVar, G1PreparedVar, G1Var, G2PreparedVar, G2ProjectiveExtendedVar, G2Var, }, }; -use ark_ec::mnt6::{MNT6Parameters, MNT6}; +use ark_ec::mnt6::{MNT6Config, MNT6}; use core::marker::PhantomData; /// Specifies the constraints for computing a pairing in a MNT6 bilinear group. -pub struct PairingVar(PhantomData

); +pub struct MNT6Gadget(PhantomData

); -type Fp3G

= Fp3Var<

::Fp3Config>; -type Fp6G

= Fp6Var<

::Fp6Config>; +type Fp3G

= Fp3Var<

::Fp3Config>; +type Fp6G

= Fp6Var<

::Fp6Config>; /// A variable corresponding to `ark_ec::mnt6::GT`. pub type GTVar

= Fp6G

; -impl PairingVar

{ +impl MNT6Gadget

+where + P::Fp: FieldWithVar>, +{ #[tracing::instrument(target = "r1cs", skip(r))] pub(crate) fn doubling_step_for_flipped_miller_loop( r: &G2ProjectiveExtendedVar

, @@ -191,7 +194,10 @@ impl PairingVar

{ } } -impl PG, P::Fp> for PairingVar

{ +impl PG for MNT6

+where + P::Fp: FieldWithVar>, +{ type G1Var = G1Var

; type G2Var = G2Var

; type G1PreparedVar = G1PreparedVar

; @@ -199,21 +205,21 @@ impl PG, P::Fp> for PairingVar

{ type GTVar = GTVar

; #[tracing::instrument(target = "r1cs")] - fn miller_loop( + fn miller_loop_gadget( ps: &[Self::G1PreparedVar], qs: &[Self::G2PreparedVar], ) -> Result { let mut result = Fp6G::

::one(); for (p, q) in ps.iter().zip(qs) { - result *= Self::ate_miller_loop(p, q)?; + result *= MNT6Gadget::ate_miller_loop(p, q)?; } Ok(result) } #[tracing::instrument(target = "r1cs")] - fn final_exponentiation(r: &Self::GTVar) -> Result { - Self::final_exponentiation(r) + fn final_exponentiation_gadget(r: &Self::GTVar) -> Result { + MNT6Gadget::

::final_exponentiation(r) } #[tracing::instrument(target = "r1cs")] diff --git a/src/pairing/mod.rs b/src/pairing/mod.rs index 958134e1..1220dbb6 100644 --- a/src/pairing/mod.rs +++ b/src/pairing/mod.rs @@ -1,7 +1,5 @@ -use crate::prelude::*; +use crate::{fields::fp::FpVar, prelude::*}; use ark_ec::pairing::Pairing; -use ark_ec::CurveGroup; -use ark_ff::Field; use ark_relations::r1cs::SynthesisError; use core::fmt::Debug; @@ -14,68 +12,73 @@ pub mod mnt6; /// Specifies the constraints for computing a pairing in the yybilinear group /// `E`. -pub trait PairingVar::G1 as CurveGroup>::BaseField> +pub trait PairingGadget: Pairing +where + Self::BaseField: FieldWithVar>, + Self::TargetField: FieldWithVar, + Self::G1: CurveWithVar, + Self::G2: CurveWithVar, { /// An variable representing an element of `G1`. /// This is the R1CS equivalent of `E::G1Projective`. - type G1Var: CurveVar - + AllocVar - + AllocVar; + 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; + type G2Var: CurveVar + + AllocVar + + AllocVar; /// An variable representing an element of `GT`. /// This is the R1CS equivalent of `E::GT`. - type GTVar: FieldVar; + 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 + 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 + type G2PreparedVar: ToBytesGadget + + AllocVar + Clone + Debug; /// Computes a multi-miller loop between elements /// of `p` and `q`. - fn miller_loop( + fn miller_loop_gadget( p: &[Self::G1PreparedVar], q: &[Self::G2PreparedVar], ) -> Result; /// Computes a final exponentiation over `p`. - fn final_exponentiation(p: &Self::GTVar) -> Result; + fn final_exponentiation_gadget(p: &Self::GTVar) -> Result; /// Computes a pairing over `p` and `q`. #[tracing::instrument(target = "r1cs")] - fn pairing( + fn pairing_gadget( p: Self::G1PreparedVar, q: Self::G2PreparedVar, ) -> Result { - let tmp = Self::miller_loop(&[p], &[q])?; - Self::final_exponentiation(&tmp) + let tmp = ::miller_loop_gadget(&[p], &[q])?; + ::final_exponentiation_gadget(&tmp) } /// Computes a product of pairings over the elements in `p` and `q`. #[must_use] #[tracing::instrument(target = "r1cs")] - fn product_of_pairings( + fn product_of_pairings_gadget( p: &[Self::G1PreparedVar], q: &[Self::G2PreparedVar], ) -> Result { - let miller_result = Self::miller_loop(p, q)?; - Self::final_exponentiation(&miller_result) + let miller_result = ::miller_loop_gadget(p, q)?; + ::final_exponentiation_gadget(&miller_result) } /// Performs the precomputation to generate `Self::G1PreparedVar`.