Add `Mul<NonNativeFieldVar> for Group` (#134)
jump to
@@ -109,14 +109,14 @@ steps:
- name: Checkout uses: actions/checkout@v3 - - name: Install Rust (${{ matrix.rust }}) + - name: Install Rust uses: dtolnay/rust-toolchain@stable id: toolchain-thumbv6m with: target: thumbv6m-none-eabi - run: rustup override set ${{steps.toolchain-thumbv6m.outputs.name}} - - name: Install Rust ARM64 (${{ matrix.rust }}) + - name: Install Rust ARM64 uses: dtolnay/rust-toolchain@stable id: toolchain-aarch64 with:@@ -152,12 +152,12 @@ - mnt6_298
- ed_on_bls12_381 steps: - name: Checkout curves - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: - repository: arkworks-rs/curves + repository: arkworks-rs/algebra - name: Checkout r1cs-std - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: path: r1cs-std@@ -166,6 +166,7 @@ uses: dtolnay/rust-toolchain@stable
- name: Patch cargo.toml run: | + cd curves if grep -q "\[patch.crates-io\]" Cargo.toml ; then MATCH=$(awk '/\[patch.crates-io\]/{ print NR; exit }' Cargo.toml); sed -i "$MATCH,\$d" Cargo.toml@@ -173,15 +174,13 @@ fi
{ echo "[patch.crates-io]" echo "ark-std = { git = 'https://github.com/arkworks-rs/std' }" - echo "ark-ec = { git = 'https://github.com/arkworks-rs/algebra' }" - echo "ark-ff = { git = 'https://github.com/arkworks-rs/algebra' }" - echo "ark-poly = { git = 'https://github.com/arkworks-rs/algebra' }" + echo "ark-ec = { path = '../ec' }" + echo "ark-ff = { path = '../ff' }" + echo "ark-poly = { path = '../poly' }" echo "ark-relations = { git = 'https://github.com/arkworks-rs/snark' }" - echo "ark-serialize = { git = 'https://github.com/arkworks-rs/algebra' }" - echo "ark-algebra-bench-templates = { git = 'https://github.com/arkworks-rs/algebra' }" - echo "ark-algebra-test-templates = { git = 'https://github.com/arkworks-rs/algebra' }" - echo "ark-r1cs-std = { path = 'r1cs-std' }" + echo "ark-serialize = { path = '../serialize' }" + echo "ark-algebra-bench-templates = { path = '../bench-templates' }" + echo "ark-algebra-test-templates = { path = '../test-templates' }" + echo "ark-r1cs-std = { path = '../r1cs-std' }" } >> Cargo.toml - - - name: Test on ${{ matrix.curve }} - run: "cd ${{ matrix.curve }} && cargo test --features 'r1cs'" + cd ${{ matrix.curve }} && cargo test --features 'r1cs'
@@ -342,7 +342,7 @@ /// Parses the `Vec<UInt8<ConstraintF>>` in fixed-sized
/// `ConstraintF::MODULUS_BIT_SIZE - 1` chunks and converts each chunk, which is /// assumed to be little-endian, to its `FpVar<ConstraintF>` representation. /// This is the gadget counterpart to the `[u8]` implementation of -/// [ToConstraintField](ark_ff::ToConstraintField). +/// [`ToConstraintField`]. impl<ConstraintF: PrimeField> ToConstraintFieldGadget<ConstraintF> for [UInt8<ConstraintF>] { #[tracing::instrument(target = "r1cs")] fn to_constraint_field(&self) -> Result<Vec<FpVar<ConstraintF>>, SynthesisError> {
@@ -57,14 +57,13 @@ BaseField::MODULUS_BIT_SIZE as usize,
optimization_type, ); - let mut base_repr: <TargetField as PrimeField>::BigInt = TargetField::one().into_bigint(); - // Convert 2^{(params.bits_per_limb - 1)} into the TargetField and then double // the base This is because 2^{(params.bits_per_limb)} might indeed be // larger than the target field's prime. - base_repr.muln((params.bits_per_limb - 1) as u32); - let mut base: TargetField = TargetField::from_bigint(base_repr).unwrap(); - base = base + &base; + let base_repr = TargetField::ONE.into_bigint() << (params.bits_per_limb - 1) as u32; + + let mut base = TargetField::from_bigint(base_repr).unwrap(); + base.double_in_place(); let mut result = TargetField::zero(); let mut power = TargetField::one();@@ -206,25 +205,21 @@ - params.bits_per_limb * (params.num_limbs - 1))
> BaseField::MODULUS_BIT_SIZE as usize - 1) { Reducer::reduce(&mut other)?; - surfeit = overhead!(other.num_of_additions_over_normal_form + BaseField::one()) + 1; + surfeit = overhead!(other.num_of_additions_over_normal_form + BaseField::ONE) + 1; } // Step 2: construct the padding - let mut pad_non_top_limb_repr: <BaseField as PrimeField>::BigInt = - BaseField::one().into_bigint(); - let mut pad_top_limb_repr: <BaseField as PrimeField>::BigInt = pad_non_top_limb_repr; + let mut pad_non_top_limb = BaseField::ONE.into_bigint(); + let mut pad_top_limb = pad_non_top_limb; - pad_non_top_limb_repr.muln((surfeit + params.bits_per_limb) as u32); - let pad_non_top_limb = BaseField::from_bigint(pad_non_top_limb_repr).unwrap(); + pad_non_top_limb <<= (surfeit + params.bits_per_limb) as u32; + let pad_non_top_limb = BaseField::from_bigint(pad_non_top_limb).unwrap(); - pad_top_limb_repr.muln( - (surfeit - + (TargetField::MODULUS_BIT_SIZE as usize - - params.bits_per_limb * (params.num_limbs - 1))) as u32, - ); - let pad_top_limb = BaseField::from_bigint(pad_top_limb_repr).unwrap(); + pad_top_limb <<= (surfeit + TargetField::MODULUS_BIT_SIZE as usize + - params.bits_per_limb * (params.num_limbs - 1)) as u32; + let pad_top_limb = BaseField::from_bigint(pad_top_limb).unwrap(); - let mut pad_limbs = Vec::new(); + let mut pad_limbs = Vec::with_capacity(self.limbs.len()); pad_limbs.push(pad_top_limb); for _ in 0..self.limbs.len() - 1 { pad_limbs.push(pad_non_top_limb);@@ -236,12 +231,12 @@ let pad_to_kp_limbs =
Self::get_limbs_representations(&pad_to_kp_gap, self.get_optimization_type())?; // Step 4: the result is self + pad + pad_to_kp - other - let mut limbs = Vec::new(); + let mut limbs = Vec::with_capacity(self.limbs.len()); for (i, ((this_limb, other_limb), pad_to_kp_limb)) in self .limbs .iter() - .zip(other.limbs.iter()) - .zip(pad_to_kp_limbs.iter()) + .zip(&other.limbs) + .zip(&pad_to_kp_limbs) .enumerate() { if i != 0 {@@ -341,7 +336,7 @@ let cur_mod_r = <BaseField as PrimeField>::BigInt::from_bits_be(
&cur_bits[cur_bits.len() - params.bits_per_limb..], ); // therefore, the lowest `bits_per_non_top_limb` bits is what we want. limbs.push(BaseField::from_bigint(cur_mod_r).unwrap()); - cur.divn(params.bits_per_limb as u32); + cur >>= params.bits_per_limb as u32; } // then we reserve, so that the limbs are ``big limb first''
@@ -240,7 +240,7 @@ let mut array = Vec::new();
let mut cur = BaseField::one().into_bigint(); for _ in 0..num_limb_in_a_group { array.push(BaseField::from_bigint(cur).unwrap()); - cur.muln(shift_per_limb as u32); + cur <<= shift_per_limb as u32; } array@@ -280,16 +280,13 @@ let mut accumulated_extra = BigUint::zero();
for (group_id, (left_total_limb, right_total_limb, num_limb_in_this_group)) in groupped_limb_pairs.iter().enumerate() { - let mut pad_limb_repr: <BaseField as PrimeField>::BigInt = - BaseField::one().into_bigint(); + let mut pad_limb_repr = BaseField::ONE.into_bigint(); - pad_limb_repr.muln( - (surfeit - + (bits_per_limb - shift_per_limb) - + shift_per_limb * num_limb_in_this_group - + 1 - + 1) as u32, - ); + pad_limb_repr <<= (surfeit + + (bits_per_limb - shift_per_limb) + + shift_per_limb * num_limb_in_this_group + + 1 + + 1) as u32; let pad_limb = BaseField::from_bigint(pad_limb_repr).unwrap(); let left_total_limb_value = left_total_limb.value().unwrap_or_default();@@ -298,12 +295,12 @@
let mut carry_value = left_total_limb_value + carry_in_value + pad_limb - right_total_limb_value; - let mut carry_repr = carry_value.into_bigint(); - carry_repr.divn((shift_per_limb * num_limb_in_this_group) as u32); + let carry_repr = + carry_value.into_bigint() >> (shift_per_limb * num_limb_in_this_group) as u32; carry_value = BaseField::from_bigint(carry_repr).unwrap(); - let carry = FpVar::<BaseField>::new_witness(cs.clone(), || Ok(carry_value))?; + let carry = FpVar::new_witness(cs.clone(), || Ok(carry_value))?; accumulated_extra += limbs_to_bigint(bits_per_limb, &[pad_limb]);
@@ -1,14 +1,13 @@
use ark_ec::{ - short_weierstrass::{ - Affine as SWAffine, Projective as SWProjective, SWCurveConfig as SWModelParameters, - }, - AffineRepr, CurveGroup, + short_weierstrass::{Affine as SWAffine, Projective as SWProjective, SWCurveConfig}, + AffineRepr, CurveConfig, CurveGroup, }; -use ark_ff::{AdditiveGroup, BigInteger, BitIteratorBE, Field, One, PrimeField, Zero}; +use ark_ff::{AdditiveGroup, 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::nonnative::NonNativeFieldVar; use crate::{fields::fp::FpVar, prelude::*, ToConstraintFieldGadget, Vec}; /// This module provides a generic implementation of G1 and G2 for@@ -33,16 +32,17 @@ /// or underconstrained constraint systems when a represented point _is_ equal
/// to zero. The [ProjectiveVar] gadget is the recommended way of working with /// elliptic curve points. pub mod non_zero_affine; + +type BasePrimeField<P> = <<P as CurveConfig>::BaseField as Field>::BasePrimeField; + /// An implementation of arithmetic for Short Weierstrass curves that relies on /// the complete formulae derived in the paper of /// [[Renes, Costello, Batina 2015]](<https://eprint.iacr.org/2015/1060>). #[derive(Derivative)] #[derivative(Debug, Clone)] #[must_use] -pub struct ProjectiveVar< - P: SWModelParameters, - F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>, -> where +pub struct ProjectiveVar<P: SWCurveConfig, F: FieldVar<P::BaseField, BasePrimeField<P>>> +where for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, { /// The x-coordinate.@@ -57,12 +57,10 @@ }
/// An affine representation of a curve point. #[derive(Derivative)] -#[derivative(Debug, Clone)] +#[derivative(Debug(bound = "F: ark_std::fmt::Debug"), Clone(bound = "F: Clone"))] #[must_use] -pub struct AffineVar< - P: SWModelParameters, - F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>, -> where +pub struct AffineVar<P: SWCurveConfig, F: FieldVar<P::BaseField, BasePrimeField<P>>> +where for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, { /// The x-coordinate.@@ -70,18 +68,18 @@ pub x: F,
/// The y-coordinate. pub y: F, /// Is `self` the point at infinity. - pub infinity: Boolean<<P::BaseField as Field>::BasePrimeField>, + pub infinity: Boolean<BasePrimeField<P>>, #[derivative(Debug = "ignore")] _params: PhantomData<P>, } impl<P, F> AffineVar<P, F> where - P: SWModelParameters, - F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>, + P: SWCurveConfig, + F: FieldVar<P::BaseField, BasePrimeField<P>>, for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, { - fn new(x: F, y: F, infinity: Boolean<<P::BaseField as Field>::BasePrimeField>) -> Self { + fn new(x: F, y: F, infinity: Boolean<BasePrimeField<P>>) -> Self { Self { x, y,@@ -100,17 +98,15 @@ })
} } -impl<P, F> ToConstraintFieldGadget<<P::BaseField as Field>::BasePrimeField> for AffineVar<P, F> +impl<P, F> ToConstraintFieldGadget<BasePrimeField<P>> for AffineVar<P, F> where - P: SWModelParameters, - F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>, + P: SWCurveConfig, + F: FieldVar<P::BaseField, BasePrimeField<P>>, for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, - F: ToConstraintFieldGadget<<P::BaseField as Field>::BasePrimeField>, + F: ToConstraintFieldGadget<BasePrimeField<P>>, { - fn to_constraint_field( - &self, - ) -> Result<Vec<FpVar<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> { - let mut res = Vec::<FpVar<<P::BaseField as Field>::BasePrimeField>>::new(); + fn to_constraint_field(&self) -> Result<Vec<FpVar<BasePrimeField<P>>>, SynthesisError> { + let mut res = Vec::<FpVar<BasePrimeField<P>>>::new(); res.extend_from_slice(&self.x.to_constraint_field()?); res.extend_from_slice(&self.y.to_constraint_field()?);@@ -120,15 +116,15 @@ Ok(res)
} } -impl<P, F> R1CSVar<<P::BaseField as Field>::BasePrimeField> for ProjectiveVar<P, F> +impl<P, F> R1CSVar<BasePrimeField<P>> for ProjectiveVar<P, F> where - P: SWModelParameters, - F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>, + P: SWCurveConfig, + F: FieldVar<P::BaseField, BasePrimeField<P>>, for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, { type Value = SWProjective<P>; - fn cs(&self) -> ConstraintSystemRef<<P::BaseField as Field>::BasePrimeField> { + fn cs(&self) -> ConstraintSystemRef<BasePrimeField<P>> { self.x.cs().or(self.y.cs()).or(self.z.cs()) }@@ -143,8 +139,7 @@ Ok(result.into())
} } -impl<P: SWModelParameters, F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>> - ProjectiveVar<P, F> +impl<P: SWCurveConfig, F: FieldVar<P::BaseField, BasePrimeField<P>>> ProjectiveVar<P, F> where for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, {@@ -200,7 +195,7 @@ /// useful if the variable is known to be on the curve (eg., if the point
/// 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<Namespace<<P::BaseField as Field>::BasePrimeField>>, + cs: impl Into<Namespace<BasePrimeField<P>>>, f: impl FnOnce() -> Result<SWProjective<P>, SynthesisError>, mode: AllocationMode, ) -> Result<Self, SynthesisError> {@@ -288,7 +283,7 @@ fn fixed_scalar_mul_le(
&self, mul_result: &mut Self, multiple_of_power_of_two: &mut NonZeroAffineVar<P, F>, - bits: &[&Boolean<<P::BaseField as Field>::BasePrimeField>], + bits: &[&Boolean<BasePrimeField<P>>], ) -> Result<(), SynthesisError> { let scalar_modulus_bits = <P::ScalarField as PrimeField>::MODULUS_BIT_SIZE as usize;@@ -371,11 +366,10 @@ Ok(())
} } -impl<P, F> CurveVar<SWProjective<P>, <P::BaseField as Field>::BasePrimeField> - for ProjectiveVar<P, F> +impl<P, F> CurveVar<SWProjective<P>, BasePrimeField<P>> for ProjectiveVar<P, F> where - P: SWModelParameters, - F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>, + P: SWCurveConfig, + F: FieldVar<P::BaseField, BasePrimeField<P>>, for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, { fn constant(g: SWProjective<P>) -> Self {@@ -387,13 +381,13 @@ fn zero() -> Self {
Self::new(F::zero(), F::one(), F::zero()) } - fn is_zero(&self) -> Result<Boolean<<P::BaseField as Field>::BasePrimeField>, SynthesisError> { + fn is_zero(&self) -> Result<Boolean<BasePrimeField<P>>, SynthesisError> { self.z.is_zero() } #[tracing::instrument(target = "r1cs", skip(cs, f))] fn new_variable_omit_prime_order_check( - cs: impl Into<Namespace<<P::BaseField as Field>::BasePrimeField>>, + cs: impl Into<Namespace<BasePrimeField<P>>>, f: impl FnOnce() -> Result<SWProjective<P>, SynthesisError>, mode: AllocationMode, ) -> Result<Self, SynthesisError> {@@ -503,7 +497,7 @@ /// `Boolean` representation of a scalar.
#[tracing::instrument(target = "r1cs", skip(bits))] fn scalar_mul_le<'a>( &self, - bits: impl Iterator<Item = &'a Boolean<<P::BaseField as Field>::BasePrimeField>>, + bits: impl Iterator<Item = &'a Boolean<BasePrimeField<P>>>, ) -> Result<Self, SynthesisError> { if self.is_constant() { if self.value().unwrap().is_zero() {@@ -565,7 +559,7 @@ scalar_bits_with_bases: I,
) -> Result<(), SynthesisError> where I: Iterator<Item = (B, &'a SWProjective<P>)>, - B: Borrow<Boolean<<P::BaseField as Field>::BasePrimeField>>, + B: Borrow<Boolean<BasePrimeField<P>>>, { // We just ignore the provided bases and use the faster scalar multiplication. let (bits, bases): (Vec<_>, Vec<_>) = scalar_bits_with_bases@@ -577,26 +571,19 @@ Ok(())
} } -impl<P, F> ToConstraintFieldGadget<<P::BaseField as Field>::BasePrimeField> for ProjectiveVar<P, F> +impl<P, F> ToConstraintFieldGadget<BasePrimeField<P>> for ProjectiveVar<P, F> where - P: SWModelParameters, - F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>, + P: SWCurveConfig, + F: FieldVar<P::BaseField, BasePrimeField<P>>, for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, - F: ToConstraintFieldGadget<<P::BaseField as Field>::BasePrimeField>, + F: ToConstraintFieldGadget<BasePrimeField<P>>, { - fn to_constraint_field( - &self, - ) -> Result<Vec<FpVar<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> { + fn to_constraint_field(&self) -> Result<Vec<FpVar<BasePrimeField<P>>>, SynthesisError> { self.to_affine()?.to_constraint_field() } } -fn mul_by_coeff_a< - P: SWModelParameters, - F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>, ->( - f: &F, -) -> F +fn mul_by_coeff_a<P: SWCurveConfig, F: FieldVar<P::BaseField, BasePrimeField<P>>>(f: &F) -> F where for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, {@@ -681,7 +668,7 @@ },
|this: &'a ProjectiveVar<P, F>, other: SWProjective<P>| { this + ProjectiveVar::constant(other) }, - (F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>, P: SWModelParameters), + (F: FieldVar<P::BaseField, BasePrimeField<P>>, P: SWCurveConfig), for <'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>, );@@ -694,36 +681,59 @@ SubAssign,
sub_assign, |this: &'a ProjectiveVar<P, F>, other: &'a ProjectiveVar<P, F>| this + other.negate().unwrap(), |this: &'a ProjectiveVar<P, F>, other: SWProjective<P>| this - ProjectiveVar::constant(other), - (F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>, P: SWModelParameters), + (F: FieldVar<P::BaseField, BasePrimeField<P>>, P: SWCurveConfig), for <'b> &'b F: FieldOpsBounds<'b, P::BaseField, F> ); +impl_bounded_ops_diff!( + ProjectiveVar<P, F>, + SWProjective<P>, + NonNativeFieldVar<P::ScalarField, BasePrimeField<P>>, + P::ScalarField, + Mul, + mul, + MulAssign, + mul_assign, + |this: &'a ProjectiveVar<P, F>, other: &'a NonNativeFieldVar<P::ScalarField, BasePrimeField<P>>| { + if this.is_constant() && other.is_constant() { + assert!(this.is_constant() && other.is_constant()); + ProjectiveVar::constant(this.value().unwrap() * &other.value().unwrap()) + } else { + let bits = other.to_bits_le().unwrap(); + this.scalar_mul_le(bits.iter()).unwrap() + } + }, + |this: &'a ProjectiveVar<P, F>, other: P::ScalarField| this * NonNativeFieldVar::constant(other), + (F: FieldVar<P::BaseField, BasePrimeField<P>>, P: SWCurveConfig), + for <'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>, +); + impl<'a, P, F> GroupOpsBounds<'a, SWProjective<P>, ProjectiveVar<P, F>> for ProjectiveVar<P, F> where - P: SWModelParameters, - F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>, + P: SWCurveConfig, + F: FieldVar<P::BaseField, BasePrimeField<P>>, for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>, { } impl<'a, P, F> GroupOpsBounds<'a, SWProjective<P>, ProjectiveVar<P, F>> for &'a ProjectiveVar<P, F> where - P: SWModelParameters, - F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>, + P: SWCurveConfig, + F: FieldVar<P::BaseField, BasePrimeField<P>>, for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>, { } -impl<P, F> CondSelectGadget<<P::BaseField as Field>::BasePrimeField> for ProjectiveVar<P, F> +impl<P, F> CondSelectGadget<BasePrimeField<P>> for ProjectiveVar<P, F> where - P: SWModelParameters, - F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>, + P: SWCurveConfig, + F: FieldVar<P::BaseField, BasePrimeField<P>>, for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, { #[inline] #[tracing::instrument(target = "r1cs")] fn conditionally_select( - cond: &Boolean<<P::BaseField as Field>::BasePrimeField>, + cond: &Boolean<BasePrimeField<P>>, true_value: &Self, false_value: &Self, ) -> Result<Self, SynthesisError> {@@ -735,17 +745,14 @@ Ok(Self::new(x, y, z))
} } -impl<P, F> EqGadget<<P::BaseField as Field>::BasePrimeField> for ProjectiveVar<P, F> +impl<P, F> EqGadget<BasePrimeField<P>> for ProjectiveVar<P, F> where - P: SWModelParameters, - F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>, + P: SWCurveConfig, + F: FieldVar<P::BaseField, BasePrimeField<P>>, for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, { #[tracing::instrument(target = "r1cs")] - fn is_eq( - &self, - other: &Self, - ) -> Result<Boolean<<P::BaseField as Field>::BasePrimeField>, SynthesisError> { + fn is_eq(&self, other: &Self) -> Result<Boolean<BasePrimeField<P>>, 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)?;@@ -758,7 +765,7 @@ #[tracing::instrument(target = "r1cs")]
fn conditional_enforce_equal( &self, other: &Self, - condition: &Boolean<<P::BaseField as Field>::BasePrimeField>, + condition: &Boolean<BasePrimeField<P>>, ) -> 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))?;@@ -775,7 +782,7 @@ #[tracing::instrument(target = "r1cs")]
fn conditional_enforce_not_equal( &self, other: &Self, - condition: &Boolean<<P::BaseField as Field>::BasePrimeField>, + condition: &Boolean<BasePrimeField<P>>, ) -> Result<(), SynthesisError> { let is_equal = self.is_eq(other)?; is_equal@@ -784,14 +791,14 @@ .enforce_equal(&Boolean::Constant(false))
} } -impl<P, F> AllocVar<SWAffine<P>, <P::BaseField as Field>::BasePrimeField> for ProjectiveVar<P, F> +impl<P, F> AllocVar<SWAffine<P>, BasePrimeField<P>> for ProjectiveVar<P, F> where - P: SWModelParameters, - F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>, + P: SWCurveConfig, + F: FieldVar<P::BaseField, BasePrimeField<P>>, for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, { fn new_variable<T: Borrow<SWAffine<P>>>( - cs: impl Into<Namespace<<P::BaseField as Field>::BasePrimeField>>, + cs: impl Into<Namespace<BasePrimeField<P>>>, f: impl FnOnce() -> Result<T, SynthesisError>, mode: AllocationMode, ) -> Result<Self, SynthesisError> {@@ -803,15 +810,14 @@ )
} } -impl<P, F> AllocVar<SWProjective<P>, <P::BaseField as Field>::BasePrimeField> - for ProjectiveVar<P, F> +impl<P, F> AllocVar<SWProjective<P>, BasePrimeField<P>> for ProjectiveVar<P, F> where - P: SWModelParameters, - F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>, + P: SWCurveConfig, + F: FieldVar<P::BaseField, BasePrimeField<P>>, for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, { fn new_variable<T: Borrow<SWProjective<P>>>( - cs: impl Into<Namespace<<P::BaseField as Field>::BasePrimeField>>, + cs: impl Into<Namespace<BasePrimeField<P>>>, f: impl FnOnce() -> Result<T, SynthesisError>, mode: AllocationMode, ) -> Result<Self, SynthesisError> {@@ -864,8 +870,7 @@ ark_relations::ns!(cs, "Witness without subgroup check with `r` check"),
|| { f().map(|g| { let g = g.into_affine(); - let mut power_of_two = P::ScalarField::one().into_bigint(); - power_of_two.muln(power_of_2); + let power_of_two = P::ScalarField::ONE.into_bigint() << power_of_2; let power_of_two_inv = P::ScalarField::from_bigint(power_of_two) .and_then(|n| n.inverse()) .unwrap();@@ -915,16 +920,14 @@ t = t2;
} } -impl<P, F> ToBitsGadget<<P::BaseField as Field>::BasePrimeField> for ProjectiveVar<P, F> +impl<P, F> ToBitsGadget<BasePrimeField<P>> for ProjectiveVar<P, F> where - P: SWModelParameters, - F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>, + P: SWCurveConfig, + F: FieldVar<P::BaseField, BasePrimeField<P>>, for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, { #[tracing::instrument(target = "r1cs")] - fn to_bits_le( - &self, - ) -> Result<Vec<Boolean<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> { + fn to_bits_le(&self) -> Result<Vec<Boolean<BasePrimeField<P>>>, SynthesisError> { let g = self.to_affine()?; let mut bits = g.x.to_bits_le()?; let y_bits = g.y.to_bits_le()?;@@ -934,9 +937,7 @@ Ok(bits)
} #[tracing::instrument(target = "r1cs")] - fn to_non_unique_bits_le( - &self, - ) -> Result<Vec<Boolean<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> { + fn to_non_unique_bits_le(&self) -> Result<Vec<Boolean<BasePrimeField<P>>>, 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()?;@@ -946,16 +947,14 @@ Ok(bits)
} } -impl<P, F> ToBytesGadget<<P::BaseField as Field>::BasePrimeField> for ProjectiveVar<P, F> +impl<P, F> ToBytesGadget<BasePrimeField<P>> for ProjectiveVar<P, F> where - P: SWModelParameters, - F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>, + P: SWCurveConfig, + F: FieldVar<P::BaseField, BasePrimeField<P>>, for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, { #[tracing::instrument(target = "r1cs")] - fn to_bytes( - &self, - ) -> Result<Vec<UInt8<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> { + fn to_bytes(&self) -> Result<Vec<UInt8<BasePrimeField<P>>>, SynthesisError> { let g = self.to_affine()?; let mut bytes = g.x.to_bytes()?; let y_bytes = g.y.to_bytes()?;@@ -966,9 +965,7 @@ Ok(bytes)
} #[tracing::instrument(target = "r1cs")] - fn to_non_unique_bytes( - &self, - ) -> Result<Vec<UInt8<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> { + fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<BasePrimeField<P>>>, SynthesisError> { let g = self.to_affine()?; let mut bytes = g.x.to_non_unique_bytes()?; let y_bytes = g.y.to_non_unique_bytes()?;
@@ -8,7 +8,7 @@ #[derive(Derivative)]
#[derivative(Debug, Clone)] #[must_use] pub struct NonZeroAffineVar< - P: SWModelParameters, + P: SWCurveConfig, F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>, > where for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,@@ -23,7 +23,7 @@ }
impl<P, F> NonZeroAffineVar<P, F> where - P: SWModelParameters, + P: SWCurveConfig, F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>, for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, {@@ -140,7 +140,7 @@ }
impl<P, F> R1CSVar<<P::BaseField as Field>::BasePrimeField> for NonZeroAffineVar<P, F> where - P: SWModelParameters, + P: SWCurveConfig, F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>, for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, {@@ -157,7 +157,7 @@ }
impl<P, F> CondSelectGadget<<P::BaseField as Field>::BasePrimeField> for NonZeroAffineVar<P, F> where - P: SWModelParameters, + P: SWCurveConfig, F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>, for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, {@@ -177,7 +177,7 @@ }
impl<P, F> EqGadget<<P::BaseField as Field>::BasePrimeField> for NonZeroAffineVar<P, F> where - P: SWModelParameters, + P: SWCurveConfig, F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>, for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, {
@@ -1,18 +1,21 @@
use ark_ec::{ + models::CurveConfig, twisted_edwards::{ - Affine as TEAffine, MontCurveConfig as MontgomeryModelParameter, - Projective as TEProjective, TECurveConfig as TEModelParameters, + Affine as TEAffine, MontCurveConfig, Projective as TEProjective, TECurveConfig, }, AdditiveGroup, AffineRepr, CurveGroup, }; -use ark_ff::{BigInteger, BitIteratorBE, Field, One, PrimeField, Zero}; +use ark_ff::{BitIteratorBE, Field, One, PrimeField, Zero}; use ark_relations::r1cs::{ConstraintSystemRef, Namespace, SynthesisError}; +use crate::fields::nonnative::NonNativeFieldVar; use crate::{prelude::*, ToConstraintFieldGadget, Vec}; use crate::fields::fp::FpVar; use ark_std::{borrow::Borrow, marker::PhantomData, ops::Mul}; +type BasePrimeField<P> = <<P as CurveConfig>::BaseField as Field>::BasePrimeField; + /// 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).@@ -22,10 +25,8 @@ /// multi-scalar-multiplication in the Bowe-Hopwood-Pedersen hash.
#[derive(Derivative)] #[derivative(Debug, Clone)] #[must_use] -pub struct MontgomeryAffineVar< - P: TEModelParameters, - F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>, -> where +pub struct MontgomeryAffineVar<P: TECurveConfig, F: FieldVar<P::BaseField, BasePrimeField<P>>> +where for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, { /// The x-coordinate.@@ -42,15 +43,15 @@ use ark_ec::twisted_edwards::MontgomeryAffine as GroupAffine;
use ark_ff::Field; use core::ops::Add; - impl<P, F> R1CSVar<<P::BaseField as Field>::BasePrimeField> for MontgomeryAffineVar<P, F> + impl<P, F> R1CSVar<BasePrimeField<P>> for MontgomeryAffineVar<P, F> where - P: TEModelParameters, - F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>, + P: TECurveConfig, + F: FieldVar<P::BaseField, BasePrimeField<P>>, for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, { type Value = (P::BaseField, P::BaseField); - fn cs(&self) -> ConstraintSystemRef<<P::BaseField as Field>::BasePrimeField> { + fn cs(&self) -> ConstraintSystemRef<BasePrimeField<P>> { self.x.cs().or(self.y.cs()) }@@ -61,10 +62,7 @@ Ok((x, y))
} } - impl< - P: TEModelParameters, - F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>, - > MontgomeryAffineVar<P, F> + impl<P: TECurveConfig, F: FieldVar<P::BaseField, BasePrimeField<P>>> MontgomeryAffineVar<P, F> where for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, {@@ -101,7 +99,7 @@ /// Converts a Twisted Edwards curve point to coordinates for the
/// corresponding affine Montgomery curve point. #[tracing::instrument(target = "r1cs")] pub fn new_witness_from_edwards( - cs: ConstraintSystemRef<<P::BaseField as Field>::BasePrimeField>, + cs: ConstraintSystemRef<BasePrimeField<P>>, p: &TEAffine<P>, ) -> Result<Self, SynthesisError> { let montgomery_coords = Self::from_edwards_to_coords(p)?;@@ -160,8 +158,8 @@ }
impl<'a, P, F> Add<&'a MontgomeryAffineVar<P, F>> for MontgomeryAffineVar<P, F> where - P: TEModelParameters, - F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>, + P: TECurveConfig, + F: FieldVar<P::BaseField, BasePrimeField<P>>, for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>, { type Output = MontgomeryAffineVar<P, F>;@@ -234,10 +232,8 @@ /// [EFD](https://www.hyperelliptic.org/EFD/g1p/auto-twisted.html).
#[derive(Derivative)] #[derivative(Debug, Clone)] #[must_use] -pub struct AffineVar< - P: TEModelParameters, - F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>, -> where +pub struct AffineVar<P: TECurveConfig, F: FieldVar<P::BaseField, BasePrimeField<P>>> +where for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, { /// The x-coordinate.@@ -248,8 +244,7 @@ #[derivative(Debug = "ignore")]
_params: PhantomData<P>, } -impl<P: TEModelParameters, F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>> - AffineVar<P, F> +impl<P: TECurveConfig, F: FieldVar<P::BaseField, BasePrimeField<P>>> AffineVar<P, F> where for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, {@@ -267,7 +262,7 @@ /// useful if the variable is known to be on the curve (eg., if the point
/// is a constant or is a public input). #[tracing::instrument(target = "r1cs", skip(cs, f))] pub fn new_variable_omit_on_curve_check<T: Into<TEAffine<P>>>( - cs: impl Into<Namespace<<P::BaseField as Field>::BasePrimeField>>, + cs: impl Into<Namespace<BasePrimeField<P>>>, f: impl FnOnce() -> Result<T, SynthesisError>, mode: AllocationMode, ) -> Result<Self, SynthesisError> {@@ -292,16 +287,12 @@ Ok(Self::new(x, y))
} } -impl<P: TEModelParameters, F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>> - AffineVar<P, F> +impl<P: TECurveConfig, F: FieldVar<P::BaseField, BasePrimeField<P>>> AffineVar<P, F> where - P: TEModelParameters, - F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField> - + TwoBitLookupGadget<<P::BaseField as Field>::BasePrimeField, TableConstant = P::BaseField> - + ThreeBitCondNegLookupGadget< - <P::BaseField as Field>::BasePrimeField, - TableConstant = P::BaseField, - >, + P: TECurveConfig, + F: FieldVar<P::BaseField, BasePrimeField<P>> + + TwoBitLookupGadget<BasePrimeField<P>, TableConstant = P::BaseField> + + ThreeBitCondNegLookupGadget<BasePrimeField<P>, TableConstant = P::BaseField>, for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, { /// Compute a scalar multiplication of `bases` with respect to `scalars`,@@ -315,7 +306,7 @@ bases: &[impl Borrow<[TEProjective<P>]>],
scalars: &[impl Borrow<[J]>], ) -> Result<Self, SynthesisError> where - J: Borrow<[Boolean<<P::BaseField as Field>::BasePrimeField>]>, + J: Borrow<[Boolean<BasePrimeField<P>>]>, { const CHUNK_SIZE: usize = 3; let mut ed_result: Option<AffineVar<P, F>> = None;@@ -385,15 +376,15 @@ Ok(ed_result.unwrap())
} } -impl<P, F> R1CSVar<<P::BaseField as Field>::BasePrimeField> for AffineVar<P, F> +impl<P, F> R1CSVar<BasePrimeField<P>> for AffineVar<P, F> where - P: TEModelParameters, - F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>, + P: TECurveConfig, + F: FieldVar<P::BaseField, BasePrimeField<P>>, for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, { type Value = TEProjective<P>; - fn cs(&self) -> ConstraintSystemRef<<P::BaseField as Field>::BasePrimeField> { + fn cs(&self) -> ConstraintSystemRef<BasePrimeField<P>> { self.x.cs().or(self.y.cs()) }@@ -405,11 +396,11 @@ Ok(result.into())
} } -impl<P, F> CurveVar<TEProjective<P>, <P::BaseField as Field>::BasePrimeField> for AffineVar<P, F> +impl<P, F> CurveVar<TEProjective<P>, BasePrimeField<P>> for AffineVar<P, F> where - P: TEModelParameters, - F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField> - + TwoBitLookupGadget<<P::BaseField as Field>::BasePrimeField, TableConstant = P::BaseField>, + P: TECurveConfig, + F: FieldVar<P::BaseField, BasePrimeField<P>> + + TwoBitLookupGadget<BasePrimeField<P>, TableConstant = P::BaseField>, for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, { fn constant(g: TEProjective<P>) -> Self {@@ -421,13 +412,13 @@ fn zero() -> Self {
Self::new(F::zero(), F::one()) } - fn is_zero(&self) -> Result<Boolean<<P::BaseField as Field>::BasePrimeField>, SynthesisError> { + fn is_zero(&self) -> Result<Boolean<BasePrimeField<P>>, SynthesisError> { self.x.is_zero()?.and(&self.y.is_one()?) } #[tracing::instrument(target = "r1cs", skip(cs, f))] fn new_variable_omit_prime_order_check( - cs: impl Into<Namespace<<P::BaseField as Field>::BasePrimeField>>, + cs: impl Into<Namespace<BasePrimeField<P>>>, f: impl FnOnce() -> Result<TEProjective<P>, SynthesisError>, mode: AllocationMode, ) -> Result<Self, SynthesisError> {@@ -531,7 +522,7 @@ scalar_bits_with_base_multiples: I,
) -> Result<(), SynthesisError> where I: Iterator<Item = (B, &'a TEProjective<P>)>, - B: Borrow<Boolean<<P::BaseField as Field>::BasePrimeField>>, + B: Borrow<Boolean<BasePrimeField<P>>>, { let (bits, multiples): (Vec<_>, Vec<_>) = scalar_bits_with_base_multiples .map(|(bit, base)| (bit.borrow().clone(), *base))@@ -559,16 +550,16 @@ Ok(())
} } -impl<P, F> AllocVar<TEProjective<P>, <P::BaseField as Field>::BasePrimeField> for AffineVar<P, F> +impl<P, F> AllocVar<TEProjective<P>, BasePrimeField<P>> for AffineVar<P, F> where - P: TEModelParameters, - F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField> - + TwoBitLookupGadget<<P::BaseField as Field>::BasePrimeField, TableConstant = P::BaseField>, + P: TECurveConfig, + F: FieldVar<P::BaseField, BasePrimeField<P>> + + TwoBitLookupGadget<BasePrimeField<P>, TableConstant = P::BaseField>, for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, { #[tracing::instrument(target = "r1cs", skip(cs, f))] fn new_variable<Point: Borrow<TEProjective<P>>>( - cs: impl Into<Namespace<<P::BaseField as Field>::BasePrimeField>>, + cs: impl Into<Namespace<BasePrimeField<P>>>, f: impl FnOnce() -> Result<Point, SynthesisError>, mode: AllocationMode, ) -> Result<Self, SynthesisError> {@@ -621,8 +612,7 @@ ark_relations::ns!(cs, "Witness without subgroup check with `r` check"),
|| { f().map(|g| { let g = g.into_affine(); - let mut power_of_two = P::ScalarField::one().into_bigint(); - power_of_two.muln(power_of_2); + let power_of_two = P::ScalarField::ONE.into_bigint() << power_of_2; let power_of_two_inv = P::ScalarField::from_bigint(power_of_two) .and_then(|n| n.inverse()) .unwrap();@@ -660,16 +650,16 @@ }
} } -impl<P, F> AllocVar<TEAffine<P>, <P::BaseField as Field>::BasePrimeField> for AffineVar<P, F> +impl<P, F> AllocVar<TEAffine<P>, BasePrimeField<P>> for AffineVar<P, F> where - P: TEModelParameters, - F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField> - + TwoBitLookupGadget<<P::BaseField as Field>::BasePrimeField, TableConstant = P::BaseField>, + P: TECurveConfig, + F: FieldVar<P::BaseField, BasePrimeField<P>> + + TwoBitLookupGadget<BasePrimeField<P>, TableConstant = P::BaseField>, for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, { #[tracing::instrument(target = "r1cs", skip(cs, f))] fn new_variable<Point: Borrow<TEAffine<P>>>( - cs: impl Into<Namespace<<P::BaseField as Field>::BasePrimeField>>, + cs: impl Into<Namespace<BasePrimeField<P>>>, f: impl FnOnce() -> Result<Point, SynthesisError>, mode: AllocationMode, ) -> Result<Self, SynthesisError> {@@ -681,16 +671,14 @@ )
} } -impl<P, F> ToConstraintFieldGadget<<P::BaseField as Field>::BasePrimeField> for AffineVar<P, F> +impl<P, F> ToConstraintFieldGadget<BasePrimeField<P>> for AffineVar<P, F> where - P: TEModelParameters, - F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>, + P: TECurveConfig, + F: FieldVar<P::BaseField, BasePrimeField<P>>, for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>, - F: ToConstraintFieldGadget<<P::BaseField as Field>::BasePrimeField>, + F: ToConstraintFieldGadget<BasePrimeField<P>>, { - fn to_constraint_field( - &self, - ) -> Result<Vec<FpVar<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> { + fn to_constraint_field(&self) -> Result<Vec<FpVar<BasePrimeField<P>>>, SynthesisError> { let mut res = Vec::new(); res.extend_from_slice(&self.x.to_constraint_field()?);@@ -772,9 +760,9 @@ }
}, |this: &'a AffineVar<P, F>, other: TEProjective<P>| this + AffineVar::constant(other), ( - F :FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField> - + TwoBitLookupGadget<<P::BaseField as Field>::BasePrimeField, TableConstant = P::BaseField>, - P: TEModelParameters, + F :FieldVar<P::BaseField, BasePrimeField<P>> + + TwoBitLookupGadget<BasePrimeField<P>, TableConstant = P::BaseField>, + P: TECurveConfig, ), for <'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>, );@@ -789,41 +777,68 @@ sub_assign,
|this: &'a AffineVar<P, F>, other: &'a AffineVar<P, F>| this + other.negate().unwrap(), |this: &'a AffineVar<P, F>, other: TEProjective<P>| this - AffineVar::constant(other), ( - F :FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField> - + TwoBitLookupGadget<<P::BaseField as Field>::BasePrimeField, TableConstant = P::BaseField>, - P: TEModelParameters, + F :FieldVar<P::BaseField, BasePrimeField<P>> + + TwoBitLookupGadget<BasePrimeField<P>, TableConstant = P::BaseField>, + P: TECurveConfig, ), for <'b> &'b F: FieldOpsBounds<'b, P::BaseField, F> ); +impl_bounded_ops_diff!( + AffineVar<P, F>, + TEProjective<P>, + NonNativeFieldVar<P::ScalarField, BasePrimeField<P>>, + P::ScalarField, + Mul, + mul, + MulAssign, + mul_assign, + |this: &'a AffineVar<P, F>, other: &'a NonNativeFieldVar<P::ScalarField, BasePrimeField<P>>| { + if this.is_constant() && other.is_constant() { + assert!(this.is_constant() && other.is_constant()); + AffineVar::constant(this.value().unwrap() * &other.value().unwrap()) + } else { + let bits = other.to_bits_le().unwrap(); + this.scalar_mul_le(bits.iter()).unwrap() + } + }, + |this: &'a AffineVar<P, F>, other: P::ScalarField| this * NonNativeFieldVar::constant(other), + ( + F :FieldVar<P::BaseField, BasePrimeField<P>> + + TwoBitLookupGadget<BasePrimeField<P>, TableConstant = P::BaseField>, + P: TECurveConfig, + ), + for <'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>, +); + impl<'a, P, F> GroupOpsBounds<'a, TEProjective<P>, AffineVar<P, F>> for AffineVar<P, F> where - P: TEModelParameters, - F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField> - + TwoBitLookupGadget<<P::BaseField as Field>::BasePrimeField, TableConstant = P::BaseField>, + P: TECurveConfig, + F: FieldVar<P::BaseField, BasePrimeField<P>> + + TwoBitLookupGadget<BasePrimeField<P>, TableConstant = P::BaseField>, for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>, { } impl<'a, P, F> GroupOpsBounds<'a, TEProjective<P>, AffineVar<P, F>> for &'a AffineVar<P, F> where - P: TEModelParameters, - F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField> - + TwoBitLookupGadget<<P::BaseField as Field>::BasePrimeField, TableConstant = P::BaseField>, + P: TECurveConfig, + F: FieldVar<P::BaseField, BasePrimeField<P>> + + TwoBitLookupGadget<BasePrimeField<P>, TableConstant = P::BaseField>, for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>, { } -impl<P, F> CondSelectGadget<<P::BaseField as Field>::BasePrimeField> for AffineVar<P, F> +impl<P, F> CondSelectGadget<BasePrimeField<P>> for AffineVar<P, F> where - P: TEModelParameters, - F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>, + P: TECurveConfig, + F: FieldVar<P::BaseField, BasePrimeField<P>>, for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>, { #[inline] #[tracing::instrument(target = "r1cs")] fn conditionally_select( - cond: &Boolean<<P::BaseField as Field>::BasePrimeField>, + cond: &Boolean<BasePrimeField<P>>, true_value: &Self, false_value: &Self, ) -> Result<Self, SynthesisError> {@@ -834,17 +849,14 @@ Ok(Self::new(x, y))
} } -impl<P, F> EqGadget<<P::BaseField as Field>::BasePrimeField> for AffineVar<P, F> +impl<P, F> EqGadget<BasePrimeField<P>> for AffineVar<P, F> where - P: TEModelParameters, - F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>, + P: TECurveConfig, + F: FieldVar<P::BaseField, BasePrimeField<P>>, for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>, { #[tracing::instrument(target = "r1cs")] - fn is_eq( - &self, - other: &Self, - ) -> Result<Boolean<<P::BaseField as Field>::BasePrimeField>, SynthesisError> { + fn is_eq(&self, other: &Self) -> Result<Boolean<BasePrimeField<P>>, SynthesisError> { let x_equal = self.x.is_eq(&other.x)?; let y_equal = self.y.is_eq(&other.y)?; x_equal.and(&y_equal)@@ -855,7 +867,7 @@ #[tracing::instrument(target = "r1cs")]
fn conditional_enforce_equal( &self, other: &Self, - condition: &Boolean<<P::BaseField as Field>::BasePrimeField>, + condition: &Boolean<BasePrimeField<P>>, ) -> Result<(), SynthesisError> { self.x.conditional_enforce_equal(&other.x, condition)?; self.y.conditional_enforce_equal(&other.y, condition)?;@@ -867,7 +879,7 @@ #[tracing::instrument(target = "r1cs")]
fn conditional_enforce_not_equal( &self, other: &Self, - condition: &Boolean<<P::BaseField as Field>::BasePrimeField>, + condition: &Boolean<BasePrimeField<P>>, ) -> Result<(), SynthesisError> { self.is_eq(other)? .and(condition)?@@ -875,16 +887,14 @@ .enforce_equal(&Boolean::Constant(false))
} } -impl<P, F> ToBitsGadget<<P::BaseField as Field>::BasePrimeField> for AffineVar<P, F> +impl<P, F> ToBitsGadget<BasePrimeField<P>> for AffineVar<P, F> where - P: TEModelParameters, - F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>, + P: TECurveConfig, + F: FieldVar<P::BaseField, BasePrimeField<P>>, for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>, { #[tracing::instrument(target = "r1cs")] - fn to_bits_le( - &self, - ) -> Result<Vec<Boolean<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> { + fn to_bits_le(&self) -> Result<Vec<Boolean<BasePrimeField<P>>>, 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);@@ -892,9 +902,7 @@ Ok(x_bits)
} #[tracing::instrument(target = "r1cs")] - fn to_non_unique_bits_le( - &self, - ) -> Result<Vec<Boolean<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> { + fn to_non_unique_bits_le(&self) -> Result<Vec<Boolean<BasePrimeField<P>>>, 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);@@ -903,16 +911,14 @@ Ok(x_bits)
} } -impl<P, F> ToBytesGadget<<P::BaseField as Field>::BasePrimeField> for AffineVar<P, F> +impl<P, F> ToBytesGadget<BasePrimeField<P>> for AffineVar<P, F> where - P: TEModelParameters, - F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>, + P: TECurveConfig, + F: FieldVar<P::BaseField, BasePrimeField<P>>, for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>, { #[tracing::instrument(target = "r1cs")] - fn to_bytes( - &self, - ) -> Result<Vec<UInt8<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> { + fn to_bytes(&self) -> Result<Vec<UInt8<BasePrimeField<P>>>, SynthesisError> { let mut x_bytes = self.x.to_bytes()?; let y_bytes = self.y.to_bytes()?; x_bytes.extend_from_slice(&y_bytes);@@ -920,9 +926,7 @@ Ok(x_bytes)
} #[tracing::instrument(target = "r1cs")] - fn to_non_unique_bytes( - &self, - ) -> Result<Vec<UInt8<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> { + fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<BasePrimeField<P>>>, 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);
@@ -1,7 +1,7 @@
-use crate::prelude::*; -use ark_ff::Field; +use crate::{fields::nonnative::NonNativeFieldVar, prelude::*}; +use ark_ff::PrimeField; use ark_relations::r1cs::{Namespace, SynthesisError}; -use core::ops::{Add, AddAssign, Sub, SubAssign}; +use core::ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign}; use ark_ec::CurveGroup; use core::{borrow::Borrow, fmt::Debug};@@ -12,20 +12,20 @@
pub use self::curves::short_weierstrass::{bls12, mnt4, mnt6}; /// A hack used to work around the lack of implied bounds. -pub trait GroupOpsBounds<'a, F, T: 'a>: +pub trait GroupOpsBounds<'a, G, T: 'a>: Sized + Add<&'a T, Output = T> + Sub<&'a T, Output = T> + Add<T, Output = T> + Sub<T, Output = T> - + Add<F, Output = T> - + Sub<F, Output = T> + + Add<G, Output = T> + + Sub<G, Output = T> { } /// A variable that represents a curve point for /// the curve `C`. -pub trait CurveVar<C: CurveGroup, ConstraintF: Field>: +pub trait CurveVar<C: CurveGroup, ConstraintF: PrimeField>: 'static + Sized + Clone@@ -44,6 +44,9 @@ + AddAssign<C>
+ SubAssign<C> + AddAssign<Self> + SubAssign<Self> + + Mul<NonNativeFieldVar<C::ScalarField, ConstraintF>, Output = Self> + + for<'a> Mul<&'a NonNativeFieldVar<C::ScalarField, ConstraintF>, Output = Self> + + MulAssign<NonNativeFieldVar<C::ScalarField, ConstraintF>> { /// Returns the constant `F::zero()`. This is the identity /// of the group.
@@ -51,7 +51,7 @@ type Output = $type;
#[tracing::instrument(target = "r1cs", skip(self))] #[allow(unused_braces, clippy::redundant_closure_call)] - fn $fn(self, other: Self) -> Self::Output { + fn $fn(self, other: &'a $type) -> Self::Output { ($impl)(self, other) } }@@ -165,3 +165,108 @@ }
} } } + +/// Implements arithmetic traits (eg: `Add`, `Sub`, `Mul`) for the given type +/// using the impl in `$impl`. +/// +/// Used primarily for implementing these traits for `FieldVar`s and +/// `GroupVar`s. +/// +/// When compared to `impl_ops`, this macro allows specifying additional trait +/// bounds. +#[macro_export] +macro_rules! impl_bounded_ops_diff { + ( + $type: ty, + $native: ty, + $other_type: ty, + $other_native: ty, + $trait: ident, + $fn: ident, + $assign_trait: ident, + $assign_fn: ident, + $impl: expr, + $constant_impl: expr, + ($($params:tt)+), + $($bounds:tt)* + ) => { + impl<'a, $($params)+> core::ops::$trait<&'a $other_type> for &'a $type + where + $($bounds)* + { + type Output = $type; + + #[tracing::instrument(target = "r1cs", skip(self))] + #[allow(unused_braces, clippy::redundant_closure_call)] + fn $fn(self, other: &'a $other_type) -> Self::Output { + ($impl)(self, other) + } + } + + impl<'a, $($params)+> core::ops::$trait<$other_type> for &'a $type + where + $($bounds)* + { + type Output = $type; + + #[tracing::instrument(target = "r1cs", skip(self))] + #[allow(unused_braces)] + fn $fn(self, other: $other_type) -> Self::Output { + core::ops::$trait::$fn(self, &other) + } + } + + impl<'a, $($params)+> core::ops::$trait<&'a $other_type> for $type + where + $($bounds)* + { + type Output = $type; + + #[tracing::instrument(target = "r1cs", skip(self))] + #[allow(unused_braces)] + fn $fn(self, other: &'a $other_type) -> Self::Output { + core::ops::$trait::$fn(&self, other) + } + } + + impl<$($params)+> core::ops::$trait<$other_type> for $type + where + + $($bounds)* + { + type Output = $type; + + #[tracing::instrument(target = "r1cs", skip(self))] + #[allow(unused_braces)] + fn $fn(self, other: $other_type) -> Self::Output { + core::ops::$trait::$fn(&self, &other) + } + } + + impl<$($params)+> core::ops::$assign_trait<$other_type> for $type + where + + $($bounds)* + { + #[tracing::instrument(target = "r1cs", skip(self))] + #[allow(unused_braces)] + fn $assign_fn(&mut self, other: $other_type) { + let result = core::ops::$trait::$fn(&*self, &other); + *self = result + } + } + + impl<'a, $($params)+> core::ops::$assign_trait<&'a $other_type> for $type + where + + $($bounds)* + { + #[tracing::instrument(target = "r1cs", skip(self))] + #[allow(unused_braces)] + fn $assign_fn(&mut self, other: &'a $other_type) { + let result = core::ops::$trait::$fn(&*self, other); + *self = result + } + } + } +}
@@ -59,7 +59,7 @@ Ok(result)
} } -impl<P: Bls12Config> PG<Bls12<P>, P::Fp> for PairingVar<P> { +impl<P: Bls12Config> PG<Bls12<P>> for PairingVar<P> { type G1Var = G1Var<P>; type G2Var = G2Var<P>; type G1PreparedVar = G1PreparedVar<P>;
@@ -196,7 +196,7 @@ Ok(w1_part * &w0_part)
} } -impl<P: MNT4Config> PG<MNT4<P>, P::Fp> for PairingVar<P> { +impl<P: MNT4Config> PG<MNT4<P>> for PairingVar<P> { type G1Var = G1Var<P>; type G2Var = G2Var<P>; type G1PreparedVar = G1PreparedVar<P>;
@@ -191,7 +191,7 @@ Ok(w1_part * &w0_part)
} } -impl<P: MNT6Config> PG<MNT6<P>, P::Fp> for PairingVar<P> { +impl<P: MNT6Config> PG<MNT6<P>> for PairingVar<P> { type G1Var = G1Var<P>; type G2Var = G2Var<P>; type G1PreparedVar = G1PreparedVar<P>;
@@ -1,6 +1,5 @@
use crate::prelude::*; -use ark_ec::{pairing::Pairing, CurveGroup}; -use ark_ff::Field; +use ark_ec::pairing::Pairing; use ark_relations::r1cs::SynthesisError; use core::fmt::Debug;@@ -11,38 +10,35 @@ pub mod mnt4;
/// This module implements pairings for MNT6 bilinear groups. pub mod mnt6; +type BasePrimeField<E> = <<E as Pairing>::BaseField as ark_ff::Field>::BasePrimeField; + /// Specifies the constraints for computing a pairing in the yybilinear group /// `E`. -pub trait PairingVar<E: Pairing, ConstraintF: Field = <<E as Pairing>::G1 as CurveGroup>::BaseField> -{ +pub trait PairingVar<E: Pairing> { /// An variable representing an element of `G1`. /// This is the R1CS equivalent of `E::G1Projective`. - type G1Var: CurveVar<E::G1, ConstraintF> - + AllocVar<E::G1, ConstraintF> - + AllocVar<E::G1Affine, ConstraintF>; + type G1Var: CurveVar<E::G1, BasePrimeField<E>>; /// An variable representing an element of `G2`. /// This is the R1CS equivalent of `E::G2Projective`. - type G2Var: CurveVar<E::G2, ConstraintF> - + AllocVar<E::G2, ConstraintF> - + AllocVar<E::G2Affine, ConstraintF>; + type G2Var: CurveVar<E::G2, BasePrimeField<E>>; /// An variable representing an element of `GT`. /// This is the R1CS equivalent of `E::GT`. - type GTVar: FieldVar<E::TargetField, ConstraintF>; + type GTVar: FieldVar<E::TargetField, BasePrimeField<E>>; /// An variable representing cached precomputation that can speed up /// pairings computations. This is the R1CS equivalent of /// `E::G1Prepared`. - type G1PreparedVar: ToBytesGadget<ConstraintF> - + AllocVar<E::G1Prepared, ConstraintF> + type G1PreparedVar: ToBytesGadget<BasePrimeField<E>> + + AllocVar<E::G1Prepared, BasePrimeField<E>> + Clone + Debug; /// An variable representing cached precomputation that can speed up /// pairings computations. This is the R1CS equivalent of /// `E::G2Prepared`. - type G2PreparedVar: ToBytesGadget<ConstraintF> - + AllocVar<E::G2Prepared, ConstraintF> + type G2PreparedVar: ToBytesGadget<BasePrimeField<E>> + + AllocVar<E::G2Prepared, BasePrimeField<E>> + Clone + Debug;
@@ -1,4 +1,6 @@
+/// Evaluation domains for polynomials. pub mod domain; +/// Evaluations of polynomials over domains. pub mod evaluations; /// Modules for working with polynomials in coefficient forms. pub mod polynomial;