Browse Source

Add `Mul<NonNativeFieldVar> for Group` (#134)

avoid_assigned_value
Pratyush Mishra 1 year ago
committed by GitHub
parent
commit
1ff3a902bd
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 392 additions and 294 deletions
  1. +14
    -15
      .github/workflows/ci.yml
  2. +1
    -1
      src/bits/uint8.rs
  3. +17
    -22
      src/fields/nonnative/allocated_field_var.rs
  4. +11
    -14
      src/fields/nonnative/reduce.rs
  5. +100
    -103
      src/groups/curves/short_weierstrass/mod.rs
  6. +5
    -5
      src/groups/curves/short_weierstrass/non_zero_affine.rs
  7. +112
    -108
      src/groups/curves/twisted_edwards/mod.rs
  8. +10
    -7
      src/groups/mod.rs
  9. +106
    -1
      src/macros.rs
  10. +1
    -1
      src/pairing/bls12/mod.rs
  11. +1
    -1
      src/pairing/mnt4/mod.rs
  12. +1
    -1
      src/pairing/mnt6/mod.rs
  13. +11
    -15
      src/pairing/mod.rs
  14. +2
    -0
      src/poly/mod.rs

+ 14
- 15
.github/workflows/ci.yml

@ -109,14 +109,14 @@ jobs:
- 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 @@ jobs:
- 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 @@ jobs:
- 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 @@ jobs:
{
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'

+ 1
- 1
src/bits/uint8.rs

@ -342,7 +342,7 @@ impl AllocVar for UInt8 {
/// `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> {

+ 17
- 22
src/fields/nonnative/allocated_field_var.rs

@ -57,14 +57,13 @@ impl
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 @@ impl
> 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 @@ impl
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 @@ impl
&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''

+ 11
- 14
src/fields/nonnative/reduce.rs

@ -240,7 +240,7 @@ impl Reducer
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 @@ impl Reducer
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();
pad_limb_repr.muln(
(surfeit
+ (bits_per_limb - shift_per_limb)
+ shift_per_limb * num_limb_in_this_group
+ 1
+ 1) as u32,
);
let mut pad_limb_repr = BaseField::ONE.into_bigint();
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 @@ impl Reducer
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]);

+ 100
- 103
src/groups/curves/short_weierstrass/mod.rs

@ -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 @@ pub mod mnt6;
/// 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 @@ pub struct ProjectiveVar<
/// 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 struct AffineVar<
/// 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 @@ where
}
}
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 @@ where
}
}
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 @@ where
}
}
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 @@ 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<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 @@ where
&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 @@ where
}
}
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 @@ where
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 @@ where
#[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 @@ where
) -> 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 @@ where
}
}
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 @@ impl_bounded_ops!(
|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 @@ impl_bounded_ops!(
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 @@ where
}
}
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 @@ where
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 @@ where
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 @@ where
}
}
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 @@ where
}
}
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 @@ where
|| {
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 @@ fn div2(limbs: &mut [u64]) {
}
}
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 @@ where
}
#[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 @@ where
}
}
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 @@ where
}
#[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()?;

+ 5
- 5
src/groups/curves/short_weierstrass/non_zero_affine.rs

@ -8,7 +8,7 @@ use ark_std::ops::Add;
#[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 @@ pub struct NonZeroAffineVar<
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 @@ where
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 @@ where
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 @@ where
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>,
{

+ 112
- 108
src/groups/curves/twisted_edwards/mod.rs

@ -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 @@ use ark_std::{borrow::Borrow, marker::PhantomData, ops::Mul};
#[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 @@ mod montgomery_affine_impl {
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 @@ mod montgomery_affine_impl {
}
}
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 @@ mod montgomery_affine_impl {
/// 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 @@ mod montgomery_affine_impl {
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 @@ mod montgomery_affine_impl {
#[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 @@ pub struct AffineVar<
_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 @@ where
/// 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 @@ where
}
}
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 @@ where
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 @@ where
}
}
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 @@ where
}
}
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 @@ where
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 @@ where
) -> 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 @@ where
}
}
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 @@ where
|| {
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 @@ where
}
}
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 @@ where
}
}
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 @@ impl_bounded_ops!(
},
|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 @@ impl_bounded_ops!(
|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 @@ where
}
}
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 @@ where
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 @@ where
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 @@ where
}
}
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 @@ where
}
#[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 @@ where
}
}
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 @@ where
}
#[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);

+ 10
- 7
src/groups/mod.rs

@ -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 mod curves;
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 @@ pub trait CurveVar:
+ 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.

+ 106
- 1
src/macros.rs

@ -51,7 +51,7 @@ 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 {
fn $fn(self, other: &'a $type) -> Self::Output {
($impl)(self, other)
}
}
@ -165,3 +165,108 @@ macro_rules! impl_bounded_ops {
}
}
}
/// Implements arithmetic traits (eg: `Add`, `Sub`, `Mul`) for the given type
/// using the impl in `$impl`.
///
/// Used primarily for implementing these traits for `FieldVar`s and
/// `GroupVar`s.
///
/// When compared to `impl_ops`, this macro allows specifying additional trait
/// bounds.
#[macro_export]
macro_rules! impl_bounded_ops_diff {
(
$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
}
}
}
}

+ 1
- 1
src/pairing/bls12/mod.rs

@ -59,7 +59,7 @@ impl PairingVar

{

}
}
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>;

+ 1
- 1
src/pairing/mnt4/mod.rs

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

{

}
}
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>;

+ 1
- 1
src/pairing/mnt6/mod.rs

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

{

}
}
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>;

+ 11
- 15
src/pairing/mod.rs

@ -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;

+ 2
- 0
src/poly/mod.rs

@ -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;

Loading…
Cancel
Save