arnaucube
arnaucube/ark-r1cs-stdPublic Self-hosted repository
ark-r1cs-std/src/groups/curves/short_weierstrass/mod.rs
src/groups/curves/short_weierstrass/mod.rsRaw
  1use ark_ec::{
  2    short_weierstrass::{
  3        Affine as SWAffine, Projective as SWProjective, SWCurveConfig as SWModelParameters,
  4    },
  5    AffineRepr, CurveGroup,
  6};
  7use ark_ff::{BigInteger, BitIteratorBE, Field, One, PrimeField, Zero};
  8use ark_relations::r1cs::{ConstraintSystemRef, Namespace, SynthesisError};
  9use ark_std::{borrow::Borrow, marker::PhantomData, ops::Mul};
 10use non_zero_affine::NonZeroAffineVar;
 11
 12use crate::{fields::fp::FpVar, prelude::*, ToConstraintFieldGadget, Vec};
 13
 14/// This module provides a generic implementation of G1 and G2 for
 15/// the [\[BLS12]\](<https://eprint.iacr.org/2002/088.pdf>) family of bilinear groups.
 16pub mod bls12;
 17
 18/// This module provides a generic implementation of G1 and G2 for
 19/// the [\[MNT4]\](<https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.20.8113&rep=rep1&type=pdf>)
 20///  family of bilinear groups.
 21pub mod mnt4;
 22/// This module provides a generic implementation of G1 and G2 for
 23/// the [\[MNT6]\](<https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.20.8113&rep=rep1&type=pdf>)
 24///  family of bilinear groups.
 25pub mod mnt6;
 26
 27/// This module provides a generic implementation of elliptic curve operations
 28/// for points on short-weierstrass curves in affine coordinates that **are
 29/// not** equal to zero.
 30///
 31/// Note: this module is **unsafe** in general: it can synthesize unsatisfiable
 32/// or underconstrained constraint systems when a represented point _is_ equal
 33/// to zero. The [ProjectiveVar] gadget is the recommended way of working with
 34/// elliptic curve points.
 35pub mod non_zero_affine;
 36/// An implementation of arithmetic for Short Weierstrass curves that relies on
 37/// the complete formulae derived in the paper of
 38/// [[Renes, Costello, Batina 2015]](<https://eprint.iacr.org/2015/1060>).
 39#[derive(Derivative)]
 40#[derivative(Debug, Clone)]
 41#[must_use]
 42pub struct ProjectiveVar<
 43    P: SWModelParameters,
 44    F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
 45> where
 46    for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
 47{
 48    /// The x-coordinate.
 49    pub x: F,
 50    /// The y-coordinate.
 51    pub y: F,
 52    /// The z-coordinate.
 53    pub z: F,
 54    #[derivative(Debug = "ignore")]
 55    _params: PhantomData<P>,
 56}
 57
 58/// An affine representation of a curve point.
 59#[derive(Derivative)]
 60#[derivative(Debug, Clone)]
 61#[must_use]
 62pub struct AffineVar<
 63    P: SWModelParameters,
 64    F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
 65> where
 66    for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
 67{
 68    /// The x-coordinate.
 69    pub x: F,
 70    /// The y-coordinate.
 71    pub y: F,
 72    /// Is `self` the point at infinity.
 73    pub infinity: Boolean<<P::BaseField as Field>::BasePrimeField>,
 74    #[derivative(Debug = "ignore")]
 75    _params: PhantomData<P>,
 76}
 77
 78impl<P, F> AffineVar<P, F>
 79where
 80    P: SWModelParameters,
 81    F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
 82    for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
 83{
 84    fn new(x: F, y: F, infinity: Boolean<<P::BaseField as Field>::BasePrimeField>) -> Self {
 85        Self {
 86            x,
 87            y,
 88            infinity,
 89            _params: PhantomData,
 90        }
 91    }
 92
 93    /// Returns the value assigned to `self` in the underlying
 94    /// constraint system.
 95    pub fn value(&self) -> Result<SWAffine<P>, SynthesisError> {
 96        Ok(match self.infinity.value()? {
 97            true => SWAffine::identity(),
 98            false => SWAffine::new(self.x.value()?, self.y.value()?),
 99        })
100    }
101}
102
103impl<P, F> ToConstraintFieldGadget<<P::BaseField as Field>::BasePrimeField> for AffineVar<P, F>
104where
105    P: SWModelParameters,
106    F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
107    for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
108    F: ToConstraintFieldGadget<<P::BaseField as Field>::BasePrimeField>,
109{
110    fn to_constraint_field(
111        &self,
112    ) -> Result<Vec<FpVar<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> {
113        let mut res = Vec::<FpVar<<P::BaseField as Field>::BasePrimeField>>::new();
114
115        res.extend_from_slice(&self.x.to_constraint_field()?);
116        res.extend_from_slice(&self.y.to_constraint_field()?);
117        res.extend_from_slice(&self.infinity.to_constraint_field()?);
118
119        Ok(res)
120    }
121}
122
123impl<P, F> R1CSVar<<P::BaseField as Field>::BasePrimeField> for ProjectiveVar<P, F>
124where
125    P: SWModelParameters,
126    F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
127    for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
128{
129    type Value = SWProjective<P>;
130
131    fn cs(&self) -> ConstraintSystemRef<<P::BaseField as Field>::BasePrimeField> {
132        self.x.cs().or(self.y.cs()).or(self.z.cs())
133    }
134
135    fn value(&self) -> Result<Self::Value, SynthesisError> {
136        let (x, y, z) = (self.x.value()?, self.y.value()?, self.z.value()?);
137        let result = if let Some(z_inv) = z.inverse() {
138            SWAffine::new(x * &z_inv, y * &z_inv)
139        } else {
140            SWAffine::identity()
141        };
142        Ok(result.into())
143    }
144}
145
146impl<P: SWModelParameters, F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>>
147    ProjectiveVar<P, F>
148where
149    for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
150{
151    /// Constructs `Self` from an `(x, y, z)` coordinate triple.
152    pub fn new(x: F, y: F, z: F) -> Self {
153        Self {
154            x,
155            y,
156            z,
157            _params: PhantomData,
158        }
159    }
160
161    /// Convert this point into affine form.
162    #[tracing::instrument(target = "r1cs")]
163    pub fn to_affine(&self) -> Result<AffineVar<P, F>, SynthesisError> {
164        if self.is_constant() {
165            let point = self.value()?.into_affine();
166            let x = F::new_constant(ConstraintSystemRef::None, point.x)?;
167            let y = F::new_constant(ConstraintSystemRef::None, point.y)?;
168            let infinity = Boolean::constant(point.infinity);
169            Ok(AffineVar::new(x, y, infinity))
170        } else {
171            let cs = self.cs();
172            let infinity = self.is_zero()?;
173            let zero_x = F::zero();
174            let zero_y = F::one();
175            // Allocate a variable whose value is either `self.z.inverse()` if the inverse
176            // exists, and is zero otherwise.
177            let z_inv = F::new_witness(ark_relations::ns!(cs, "z_inverse"), || {
178                Ok(self.z.value()?.inverse().unwrap_or_else(P::BaseField::zero))
179            })?;
180            // The inverse exists if `!self.is_zero()`.
181            // This means that `z_inv * self.z = 1` if `self.is_not_zero()`, and
182            //                 `z_inv * self.z = 0` if `self.is_zero()`.
183            //
184            // Thus, `z_inv * self.z = !self.is_zero()`.
185            z_inv.mul_equals(&self.z, &F::from(infinity.not()))?;
186
187            let non_zero_x = &self.x * &z_inv;
188            let non_zero_y = &self.y * &z_inv;
189
190            let x = infinity.select(&zero_x, &non_zero_x)?;
191            let y = infinity.select(&zero_y, &non_zero_y)?;
192
193            Ok(AffineVar::new(x, y, infinity))
194        }
195    }
196
197    /// Allocates a new variable without performing an on-curve check, which is
198    /// useful if the variable is known to be on the curve (eg., if the point
199    /// is a constant or is a public input).
200    #[tracing::instrument(target = "r1cs", skip(cs, f))]
201    pub fn new_variable_omit_on_curve_check(
202        cs: impl Into<Namespace<<P::BaseField as Field>::BasePrimeField>>,
203        f: impl FnOnce() -> Result<SWProjective<P>, SynthesisError>,
204        mode: AllocationMode,
205    ) -> Result<Self, SynthesisError> {
206        let ns = cs.into();
207        let cs = ns.cs();
208
209        let (x, y, z) = match f() {
210            Ok(ge) => {
211                let ge = ge.into_affine();
212                if ge.is_zero() {
213                    (
214                        Ok(P::BaseField::zero()),
215                        Ok(P::BaseField::one()),
216                        Ok(P::BaseField::zero()),
217                    )
218                } else {
219                    (Ok(ge.x), Ok(ge.y), Ok(P::BaseField::one()))
220                }
221            },
222            _ => (
223                Err(SynthesisError::AssignmentMissing),
224                Err(SynthesisError::AssignmentMissing),
225                Err(SynthesisError::AssignmentMissing),
226            ),
227        };
228
229        let x = F::new_variable(ark_relations::ns!(cs, "x"), || x, mode)?;
230        let y = F::new_variable(ark_relations::ns!(cs, "y"), || y, mode)?;
231        let z = F::new_variable(ark_relations::ns!(cs, "z"), || z, mode)?;
232
233        Ok(Self::new(x, y, z))
234    }
235
236    /// Mixed addition, which is useful when `other = (x2, y2)` is known to have
237    /// z = 1.
238    #[tracing::instrument(target = "r1cs", skip(self, other))]
239    pub(crate) fn add_mixed(&self, other: &NonZeroAffineVar<P, F>) -> Result<Self, SynthesisError> {
240        // Complete mixed addition formula from Renes-Costello-Batina 2015
241        // Algorithm 2
242        // (https://eprint.iacr.org/2015/1060).
243        // Below, comments at the end of a line denote the corresponding
244        // step(s) of the algorithm
245        //
246        // Adapted from code in
247        // https://github.com/RustCrypto/elliptic-curves/blob/master/p256/src/arithmetic/projective.rs
248        let three_b = P::COEFF_B.double() + &P::COEFF_B;
249        let (x1, y1, z1) = (&self.x, &self.y, &self.z);
250        let (x2, y2) = (&other.x, &other.y);
251
252        let xx = x1 * x2; // 1
253        let yy = y1 * y2; // 2
254        let xy_pairs = ((x1 + y1) * &(x2 + y2)) - (&xx + &yy); // 4, 5, 6, 7, 8
255        let xz_pairs = (x2 * z1) + x1; // 8, 9
256        let yz_pairs = (y2 * z1) + y1; // 10, 11
257
258        let axz = mul_by_coeff_a::<P, F>(&xz_pairs); // 12
259
260        let bz3_part = &axz + z1 * three_b; // 13, 14
261
262        let yy_m_bz3 = &yy - &bz3_part; // 15
263        let yy_p_bz3 = &yy + &bz3_part; // 16
264
265        let azz = mul_by_coeff_a::<P, F>(z1); // 20
266        let xx3_p_azz = xx.double().unwrap() + &xx + &azz; // 18, 19, 22
267
268        let bxz3 = &xz_pairs * three_b; // 21
269        let b3_xz_pairs = mul_by_coeff_a::<P, F>(&(&xx - &azz)) + &bxz3; // 23, 24, 25
270
271        let x = (&yy_m_bz3 * &xy_pairs) - &yz_pairs * &b3_xz_pairs; // 28,29, 30
272        let y = (&yy_p_bz3 * &yy_m_bz3) + &xx3_p_azz * b3_xz_pairs; // 17, 26, 27
273        let z = (&yy_p_bz3 * &yz_pairs) + xy_pairs * xx3_p_azz; // 31, 32, 33
274
275        Ok(ProjectiveVar::new(x, y, z))
276    }
277
278    /// Computes a scalar multiplication with a little-endian scalar of size
279    /// `P::ScalarField::MODULUS_BITS`.
280    #[tracing::instrument(
281        target = "r1cs",
282        skip(self, mul_result, multiple_of_power_of_two, bits)
283    )]
284    fn fixed_scalar_mul_le(
285        &self,
286        mul_result: &mut Self,
287        multiple_of_power_of_two: &mut NonZeroAffineVar<P, F>,
288        bits: &[&Boolean<<P::BaseField as Field>::BasePrimeField>],
289    ) -> Result<(), SynthesisError> {
290        let scalar_modulus_bits = <P::ScalarField as PrimeField>::MODULUS_BIT_SIZE as usize;
291
292        assert!(scalar_modulus_bits >= bits.len());
293        let split_len = ark_std::cmp::min(scalar_modulus_bits - 2, bits.len());
294        let (affine_bits, proj_bits) = bits.split_at(split_len);
295        // Computes the standard little-endian double-and-add algorithm
296        // (Algorithm 3.26, Guide to Elliptic Curve Cryptography)
297        //
298        // We rely on *incomplete* affine formulae for partially computing this.
299        // However, we avoid exceptional edge cases because we partition the scalar
300        // into two chunks: one guaranteed to be less than p - 2, and the rest.
301        // We only use incomplete formulae for the first chunk, which means we avoid
302        // exceptions:
303        //
304        // `add_unchecked(a, b)` is incomplete when either `b.is_zero()`, or when
305        // `b = ±a`. During scalar multiplication, we don't hit either case:
306        // * `b = ±a`: `b = accumulator = k * a`, where `2 <= k < p - 1`. This implies
307        //   that `k != p ± 1`, and so `b != (p ± 1) * a`. Because the group is finite,
308        //   this in turn means that `b != ±a`, as required.
309        // * `a` or `b` is zero: for `a`, we handle the zero case after the loop; for
310        //   `b`, notice that it is monotonically increasing, and furthermore, equals `k
311        //   * a`, where `k != p = 0 mod p`.
312
313        // Unlike normal double-and-add, here we start off with a non-zero
314        // `accumulator`, because `NonZeroAffineVar::add_unchecked` doesn't
315        // support addition with `zero`. In more detail, we initialize
316        // `accumulator` to be the initial value of `multiple_of_power_of_two`.
317        // This ensures that all unchecked additions of `accumulator` with later
318        // values of `multiple_of_power_of_two` are safe. However, to do this
319        // correctly, we need to perform two steps:
320        // * We must skip the LSB, and instead proceed assuming that it was 1. Later, we
321        //   will conditionally subtract the initial value of `accumulator`: if LSB ==
322        //   0: subtract initial_acc_value; else, subtract 0.
323        // * Because we are assuming the first bit, we must double
324        //   `multiple_of_power_of_two`.
325
326        let mut accumulator = multiple_of_power_of_two.clone();
327        let initial_acc_value = accumulator.into_projective();
328
329        // The powers start at 2 (instead of 1) because we're skipping the first bit.
330        multiple_of_power_of_two.double_in_place()?;
331
332        // As mentioned, we will skip the LSB, and will later handle it via a
333        // conditional subtraction.
334        for bit in affine_bits.iter().skip(1) {
335            if bit.is_constant() {
336                if *bit == &Boolean::TRUE {
337                    accumulator = accumulator.add_unchecked(&multiple_of_power_of_two)?;
338                }
339            } else {
340                let temp = accumulator.add_unchecked(&multiple_of_power_of_two)?;
341                accumulator = bit.select(&temp, &accumulator)?;
342            }
343            multiple_of_power_of_two.double_in_place()?;
344        }
345        // Perform conditional subtraction:
346
347        // We can convert to projective safely because the result is guaranteed to be
348        // non-zero by the condition on `affine_bits.len()`, and by the fact
349        // that `accumulator` is non-zero
350        let result = accumulator.into_projective();
351        // If bits[0] is 0, then we have to subtract `self`; else, we subtract zero.
352        let subtrahend = bits[0].select(&Self::zero(), &initial_acc_value)?;
353        *mul_result += result - subtrahend;
354
355        // Now, let's finish off the rest of the bits using our complete formulae
356        for bit in proj_bits {
357            if bit.is_constant() {
358                if *bit == &Boolean::TRUE {
359                    *mul_result += &multiple_of_power_of_two.into_projective();
360                }
361            } else {
362                let temp = &*mul_result + &multiple_of_power_of_two.into_projective();
363                *mul_result = bit.select(&temp, &mul_result)?;
364            }
365            multiple_of_power_of_two.double_in_place()?;
366        }
367        Ok(())
368    }
369}
370
371impl<P, F> CurveVar<SWProjective<P>, <P::BaseField as Field>::BasePrimeField>
372    for ProjectiveVar<P, F>
373where
374    P: SWModelParameters,
375    F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
376    for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
377{
378    fn constant(g: SWProjective<P>) -> Self {
379        let cs = ConstraintSystemRef::None;
380        Self::new_variable_omit_on_curve_check(cs, || Ok(g), AllocationMode::Constant).unwrap()
381    }
382
383    fn zero() -> Self {
384        Self::new(F::zero(), F::one(), F::zero())
385    }
386
387    fn is_zero(&self) -> Result<Boolean<<P::BaseField as Field>::BasePrimeField>, SynthesisError> {
388        self.z.is_zero()
389    }
390
391    #[tracing::instrument(target = "r1cs", skip(cs, f))]
392    fn new_variable_omit_prime_order_check(
393        cs: impl Into<Namespace<<P::BaseField as Field>::BasePrimeField>>,
394        f: impl FnOnce() -> Result<SWProjective<P>, SynthesisError>,
395        mode: AllocationMode,
396    ) -> Result<Self, SynthesisError> {
397        let ns = cs.into();
398        let cs = ns.cs();
399        // Curve equation in projective form:
400        // E: Y² * Z = X³ + aX * Z² + bZ³
401        //
402        // This can be re-written as
403        // E: Y² * Z - bZ³ = X³ + aX * Z²
404        // E: Z * (Y² - bZ²) = X * (X² + aZ²)
405        // so, compute X², Y², Z²,
406        //     compute temp = X * (X² + aZ²)
407        //     check Z.mul_equals((Y² - bZ²), temp)
408        //
409        //     A total of 5 multiplications
410
411        let g = Self::new_variable_omit_on_curve_check(cs, f, mode)?;
412
413        if mode != AllocationMode::Constant {
414            // Perform on-curve check.
415            let b = P::COEFF_B;
416            let a = P::COEFF_A;
417
418            let x2 = g.x.square()?;
419            let y2 = g.y.square()?;
420            let z2 = g.z.square()?;
421            let t = &g.x * (x2 + &z2 * a);
422
423            g.z.mul_equals(&(y2 - z2 * b), &t)?;
424        }
425        Ok(g)
426    }
427
428    /// Enforce that `self` is in the prime-order subgroup.
429    ///
430    /// Does so by multiplying by the prime order, and checking that the result
431    /// is unchanged.
432    // TODO: at the moment this doesn't work, because the addition and doubling
433    // formulae are incomplete for even-order points.
434    #[tracing::instrument(target = "r1cs")]
435    fn enforce_prime_order(&self) -> Result<(), SynthesisError> {
436        unimplemented!("cannot enforce prime order");
437        // let r_minus_1 = (-P::ScalarField::one()).into_bigint();
438
439        // let mut result = Self::zero();
440        // for b in BitIteratorBE::without_leading_zeros(r_minus_1) {
441        //     result.double_in_place()?;
442
443        //     if b {
444        //         result += self;
445        //     }
446        // }
447        // self.negate()?.enforce_equal(&result)?;
448        // Ok(())
449    }
450
451    #[inline]
452    #[tracing::instrument(target = "r1cs")]
453    fn double_in_place(&mut self) -> Result<(), SynthesisError> {
454        // Complete doubling formula from Renes-Costello-Batina 2015
455        // Algorithm 3
456        // (https://eprint.iacr.org/2015/1060).
457        // Below, comments at the end of a line denote the corresponding
458        // step(s) of the algorithm
459        //
460        // Adapted from code in
461        // https://github.com/RustCrypto/elliptic-curves/blob/master/p256/src/arithmetic/projective.rs
462        let three_b = P::COEFF_B.double() + &P::COEFF_B;
463
464        let xx = self.x.square()?; // 1
465        let yy = self.y.square()?; // 2
466        let zz = self.z.square()?; // 3
467        let xy2 = (&self.x * &self.y).double()?; // 4, 5
468        let xz2 = (&self.x * &self.z).double()?; // 6, 7
469
470        let axz2 = mul_by_coeff_a::<P, F>(&xz2); // 8
471
472        let bzz3_part = &axz2 + &zz * three_b; // 9, 10
473        let yy_m_bzz3 = &yy - &bzz3_part; // 11
474        let yy_p_bzz3 = &yy + &bzz3_part; // 12
475        let y_frag = yy_p_bzz3 * &yy_m_bzz3; // 13
476        let x_frag = yy_m_bzz3 * &xy2; // 14
477
478        let bxz3 = xz2 * three_b; // 15
479        let azz = mul_by_coeff_a::<P, F>(&zz); // 16
480        let b3_xz_pairs = mul_by_coeff_a::<P, F>(&(&xx - &azz)) + &bxz3; // 15, 16, 17, 18, 19
481        let xx3_p_azz = (xx.double()? + &xx + &azz) * &b3_xz_pairs; // 23, 24, 25
482
483        let y = y_frag + &xx3_p_azz; // 26, 27
484        let yz2 = (&self.y * &self.z).double()?; // 28, 29
485        let x = x_frag - &(b3_xz_pairs * &yz2); // 30, 31
486        let z = (yz2 * &yy).double()?.double()?; // 32, 33, 34
487        self.x = x;
488        self.y = y;
489        self.z = z;
490        Ok(())
491    }
492
493    #[tracing::instrument(target = "r1cs")]
494    fn negate(&self) -> Result<Self, SynthesisError> {
495        Ok(Self::new(self.x.clone(), self.y.negate()?, self.z.clone()))
496    }
497
498    /// Computes `bits * self`, where `bits` is a little-endian
499    /// `Boolean` representation of a scalar.
500    #[tracing::instrument(target = "r1cs", skip(bits))]
501    fn scalar_mul_le<'a>(
502        &self,
503        bits: impl Iterator<Item = &'a Boolean<<P::BaseField as Field>::BasePrimeField>>,
504    ) -> Result<Self, SynthesisError> {
505        if self.is_constant() {
506            if self.value().unwrap().is_zero() {
507                return Ok(self.clone());
508            }
509        }
510        let self_affine = self.to_affine()?;
511        let (x, y, infinity) = (self_affine.x, self_affine.y, self_affine.infinity);
512        // We first handle the non-zero case, and then later
513        // will conditionally select zero if `self` was zero.
514        let non_zero_self = NonZeroAffineVar::new(x, y);
515
516        let mut bits = bits.collect::<Vec<_>>();
517        if bits.len() == 0 {
518            return Ok(Self::zero());
519        }
520        // Remove unnecessary constant zeros in the most-significant positions.
521        bits = bits
522            .into_iter()
523            // We iterate from the MSB down.
524            .rev()
525            // Skip leading zeros, if they are constants.
526            .skip_while(|b| b.is_constant() && (b.value().unwrap() == false))
527            .collect();
528        // After collecting we are in big-endian form; we have to reverse to get back to
529        // little-endian.
530        bits.reverse();
531
532        let scalar_modulus_bits = <P::ScalarField as PrimeField>::MODULUS_BIT_SIZE;
533        let mut mul_result = Self::zero();
534        let mut power_of_two_times_self = non_zero_self;
535        // We chunk up `bits` into `p`-sized chunks.
536        for bits in bits.chunks(scalar_modulus_bits as usize) {
537            self.fixed_scalar_mul_le(&mut mul_result, &mut power_of_two_times_self, bits)?;
538        }
539
540        // The foregoing algorithm relies on incomplete addition, and so does not
541        // work when the input (`self`) is zero. We hence have to perform
542        // a check to ensure that if the input is zero, then so is the output.
543        // The cost of this check should be less than the benefit of using
544        // mixed addition in almost all cases.
545        infinity.select(&Self::zero(), &mul_result)
546    }
547
548    #[tracing::instrument(target = "r1cs", skip(scalar_bits_with_bases))]
549    fn precomputed_base_scalar_mul_le<'a, I, B>(
550        &mut self,
551        scalar_bits_with_bases: I,
552    ) -> Result<(), SynthesisError>
553    where
554        I: Iterator<Item = (B, &'a SWProjective<P>)>,
555        B: Borrow<Boolean<<P::BaseField as Field>::BasePrimeField>>,
556    {
557        // We just ignore the provided bases and use the faster scalar multiplication.
558        let (bits, bases): (Vec<_>, Vec<_>) = scalar_bits_with_bases
559            .map(|(b, c)| (b.borrow().clone(), *c))
560            .unzip();
561        let base = bases[0];
562        *self += Self::constant(base).scalar_mul_le(bits.iter())?;
563        Ok(())
564    }
565}
566
567impl<P, F> ToConstraintFieldGadget<<P::BaseField as Field>::BasePrimeField> for ProjectiveVar<P, F>
568where
569    P: SWModelParameters,
570    F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
571    for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
572    F: ToConstraintFieldGadget<<P::BaseField as Field>::BasePrimeField>,
573{
574    fn to_constraint_field(
575        &self,
576    ) -> Result<Vec<FpVar<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> {
577        self.to_affine()?.to_constraint_field()
578    }
579}
580
581fn mul_by_coeff_a<
582    P: SWModelParameters,
583    F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
584>(
585    f: &F,
586) -> F
587where
588    for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
589{
590    if !P::COEFF_A.is_zero() {
591        f * P::COEFF_A
592    } else {
593        F::zero()
594    }
595}
596
597impl_bounded_ops!(
598    ProjectiveVar<P, F>,
599    SWProjective<P>,
600    Add,
601    add,
602    AddAssign,
603    add_assign,
604    |mut this: &'a ProjectiveVar<P, F>, mut other: &'a ProjectiveVar<P, F>| {
605        // Implement complete addition for Short Weierstrass curves, following
606        // the complete addition formula from Renes-Costello-Batina 2015
607        // (https://eprint.iacr.org/2015/1060).
608        //
609        // We special case handling of constants to get better constraint weight.
610        if this.is_constant() {
611            // we'll just act like `other` is constant.
612            core::mem::swap(&mut this, &mut other);
613        }
614
615        if other.is_constant() {
616            // The value should exist because `other` is a constant.
617            let other = other.value().unwrap();
618            if other.is_zero() {
619                // this + 0 = this
620                this.clone()
621            } else {
622                // We'll use mixed addition to add non-zero constants.
623                let x = F::constant(other.x);
624                let y = F::constant(other.y);
625                this.add_mixed(&NonZeroAffineVar::new(x, y)).unwrap()
626            }
627        } else {
628            // Complete addition formula from Renes-Costello-Batina 2015
629            // Algorithm 1
630            // (https://eprint.iacr.org/2015/1060).
631            // Below, comments at the end of a line denote the corresponding
632            // step(s) of the algorithm
633            //
634            // Adapted from code in
635            // https://github.com/RustCrypto/elliptic-curves/blob/master/p256/src/arithmetic/projective.rs
636            let three_b = P::COEFF_B.double() + &P::COEFF_B;
637            let (x1, y1, z1) = (&this.x, &this.y, &this.z);
638            let (x2, y2, z2) = (&other.x, &other.y, &other.z);
639
640            let xx = x1 * x2; // 1
641            let yy = y1 * y2; // 2
642            let zz = z1 * z2; // 3
643            let xy_pairs = ((x1 + y1) * &(x2 + y2)) - (&xx + &yy); // 4, 5, 6, 7, 8
644            let xz_pairs = ((x1 + z1) * &(x2 + z2)) - (&xx + &zz); // 9, 10, 11, 12, 13
645            let yz_pairs = ((y1 + z1) * &(y2 + z2)) - (&yy + &zz); // 14, 15, 16, 17, 18
646
647            let axz = mul_by_coeff_a::<P, F>(&xz_pairs); // 19
648
649            let bzz3_part = &axz + &zz * three_b; // 20, 21
650
651            let yy_m_bzz3 = &yy - &bzz3_part; // 22
652            let yy_p_bzz3 = &yy + &bzz3_part; // 23
653
654            let azz = mul_by_coeff_a::<P, F>(&zz);
655            let xx3_p_azz = xx.double().unwrap() + &xx + &azz; // 25, 26, 27, 29
656
657            let bxz3 = &xz_pairs * three_b; // 28
658            let b3_xz_pairs = mul_by_coeff_a::<P, F>(&(&xx - &azz)) + &bxz3; // 30, 31, 32
659
660            let x = (&yy_m_bzz3 * &xy_pairs) - &yz_pairs * &b3_xz_pairs; // 35, 39, 40
661            let y = (&yy_p_bzz3 * &yy_m_bzz3) + &xx3_p_azz * b3_xz_pairs; // 24, 36, 37, 38
662            let z = (&yy_p_bzz3 * &yz_pairs) + xy_pairs * xx3_p_azz; // 41, 42, 43
663
664            ProjectiveVar::new(x, y, z)
665        }
666
667    },
668    |this: &'a ProjectiveVar<P, F>, other: SWProjective<P>| {
669        this + ProjectiveVar::constant(other)
670    },
671    (F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>, P: SWModelParameters),
672    for <'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>,
673);
674
675impl_bounded_ops!(
676    ProjectiveVar<P, F>,
677    SWProjective<P>,
678    Sub,
679    sub,
680    SubAssign,
681    sub_assign,
682    |this: &'a ProjectiveVar<P, F>, other: &'a ProjectiveVar<P, F>| this + other.negate().unwrap(),
683    |this: &'a ProjectiveVar<P, F>, other: SWProjective<P>| this - ProjectiveVar::constant(other),
684    (F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>, P: SWModelParameters),
685    for <'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>
686);
687
688impl<'a, P, F> GroupOpsBounds<'a, SWProjective<P>, ProjectiveVar<P, F>> for ProjectiveVar<P, F>
689where
690    P: SWModelParameters,
691    F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
692    for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>,
693{
694}
695
696impl<'a, P, F> GroupOpsBounds<'a, SWProjective<P>, ProjectiveVar<P, F>> for &'a ProjectiveVar<P, F>
697where
698    P: SWModelParameters,
699    F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
700    for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>,
701{
702}
703
704impl<P, F> CondSelectGadget<<P::BaseField as Field>::BasePrimeField> for ProjectiveVar<P, F>
705where
706    P: SWModelParameters,
707    F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
708    for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
709{
710    #[inline]
711    #[tracing::instrument(target = "r1cs")]
712    fn conditionally_select(
713        cond: &Boolean<<P::BaseField as Field>::BasePrimeField>,
714        true_value: &Self,
715        false_value: &Self,
716    ) -> Result<Self, SynthesisError> {
717        let x = cond.select(&true_value.x, &false_value.x)?;
718        let y = cond.select(&true_value.y, &false_value.y)?;
719        let z = cond.select(&true_value.z, &false_value.z)?;
720
721        Ok(Self::new(x, y, z))
722    }
723}
724
725impl<P, F> EqGadget<<P::BaseField as Field>::BasePrimeField> for ProjectiveVar<P, F>
726where
727    P: SWModelParameters,
728    F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
729    for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
730{
731    #[tracing::instrument(target = "r1cs")]
732    fn is_eq(
733        &self,
734        other: &Self,
735    ) -> Result<Boolean<<P::BaseField as Field>::BasePrimeField>, SynthesisError> {
736        let x_equal = (&self.x * &other.z).is_eq(&(&other.x * &self.z))?;
737        let y_equal = (&self.y * &other.z).is_eq(&(&other.y * &self.z))?;
738        let coordinates_equal = x_equal.and(&y_equal)?;
739        let both_are_zero = self.is_zero()?.and(&other.is_zero()?)?;
740        both_are_zero.or(&coordinates_equal)
741    }
742
743    #[inline]
744    #[tracing::instrument(target = "r1cs")]
745    fn conditional_enforce_equal(
746        &self,
747        other: &Self,
748        condition: &Boolean<<P::BaseField as Field>::BasePrimeField>,
749    ) -> Result<(), SynthesisError> {
750        let x_equal = (&self.x * &other.z).is_eq(&(&other.x * &self.z))?;
751        let y_equal = (&self.y * &other.z).is_eq(&(&other.y * &self.z))?;
752        let coordinates_equal = x_equal.and(&y_equal)?;
753        let both_are_zero = self.is_zero()?.and(&other.is_zero()?)?;
754        both_are_zero
755            .or(&coordinates_equal)?
756            .conditional_enforce_equal(&Boolean::Constant(true), condition)?;
757        Ok(())
758    }
759
760    #[inline]
761    #[tracing::instrument(target = "r1cs")]
762    fn conditional_enforce_not_equal(
763        &self,
764        other: &Self,
765        condition: &Boolean<<P::BaseField as Field>::BasePrimeField>,
766    ) -> Result<(), SynthesisError> {
767        let is_equal = self.is_eq(other)?;
768        is_equal
769            .and(condition)?
770            .enforce_equal(&Boolean::Constant(false))
771    }
772}
773
774impl<P, F> AllocVar<SWAffine<P>, <P::BaseField as Field>::BasePrimeField> for ProjectiveVar<P, F>
775where
776    P: SWModelParameters,
777    F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
778    for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
779{
780    fn new_variable<T: Borrow<SWAffine<P>>>(
781        cs: impl Into<Namespace<<P::BaseField as Field>::BasePrimeField>>,
782        f: impl FnOnce() -> Result<T, SynthesisError>,
783        mode: AllocationMode,
784    ) -> Result<Self, SynthesisError> {
785        Self::new_variable(
786            cs,
787            || f().map(|b| SWProjective::from((*b.borrow()).clone())),
788            mode,
789        )
790    }
791}
792
793impl<P, F> AllocVar<SWProjective<P>, <P::BaseField as Field>::BasePrimeField>
794    for ProjectiveVar<P, F>
795where
796    P: SWModelParameters,
797    F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
798    for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
799{
800    fn new_variable<T: Borrow<SWProjective<P>>>(
801        cs: impl Into<Namespace<<P::BaseField as Field>::BasePrimeField>>,
802        f: impl FnOnce() -> Result<T, SynthesisError>,
803        mode: AllocationMode,
804    ) -> Result<Self, SynthesisError> {
805        let ns = cs.into();
806        let cs = ns.cs();
807        let f = || Ok(*f()?.borrow());
808        match mode {
809            AllocationMode::Constant => Self::new_variable_omit_prime_order_check(cs, f, mode),
810            AllocationMode::Input => Self::new_variable_omit_prime_order_check(cs, f, mode),
811            AllocationMode::Witness => {
812                // if cofactor.is_even():
813                //   divide until you've removed all even factors
814                // else:
815                //   just directly use double and add.
816                let mut power_of_2: u32 = 0;
817                let mut cofactor = P::COFACTOR.to_vec();
818                while cofactor[0] % 2 == 0 {
819                    div2(&mut cofactor);
820                    power_of_2 += 1;
821                }
822
823                let cofactor_weight = BitIteratorBE::new(cofactor.as_slice())
824                    .filter(|b| *b)
825                    .count();
826                let modulus_minus_1 = (-P::ScalarField::one()).into_bigint(); // r - 1
827                let modulus_minus_1_weight =
828                    BitIteratorBE::new(modulus_minus_1).filter(|b| *b).count();
829
830                // We pick the most efficient method of performing the prime order check:
831                // If the cofactor has lower hamming weight than the scalar field's modulus,
832                // we first multiply by the inverse of the cofactor, and then, after allocating,
833                // multiply by the cofactor. This ensures the resulting point has no cofactors
834                //
835                // Else, we multiply by the scalar field's modulus and ensure that the result
836                // equals the identity.
837
838                let (mut ge, iter) = if cofactor_weight < modulus_minus_1_weight {
839                    let ge = Self::new_variable_omit_prime_order_check(
840                        ark_relations::ns!(cs, "Witness without subgroup check with cofactor mul"),
841                        || f().map(|g| g.borrow().into_affine().mul_by_cofactor_inv().into()),
842                        mode,
843                    )?;
844                    (
845                        ge,
846                        BitIteratorBE::without_leading_zeros(cofactor.as_slice()),
847                    )
848                } else {
849                    let ge = Self::new_variable_omit_prime_order_check(
850                        ark_relations::ns!(cs, "Witness without subgroup check with `r` check"),
851                        || {
852                            f().map(|g| {
853                                let g = g.into_affine();
854                                let mut power_of_two = P::ScalarField::one().into_bigint();
855                                power_of_two.muln(power_of_2);
856                                let power_of_two_inv = P::ScalarField::from_bigint(power_of_two)
857                                    .and_then(|n| n.inverse())
858                                    .unwrap();
859                                g.mul(power_of_two_inv)
860                            })
861                        },
862                        mode,
863                    )?;
864
865                    (
866                        ge,
867                        BitIteratorBE::without_leading_zeros(modulus_minus_1.as_ref()),
868                    )
869                };
870                // Remove the even part of the cofactor
871                for _ in 0..power_of_2 {
872                    ge.double_in_place()?;
873                }
874
875                let mut result = Self::zero();
876                for b in iter {
877                    result.double_in_place()?;
878
879                    if b {
880                        result += &ge
881                    }
882                }
883                if cofactor_weight < modulus_minus_1_weight {
884                    Ok(result)
885                } else {
886                    ge.enforce_equal(&ge)?;
887                    Ok(ge)
888                }
889            },
890        }
891    }
892}
893
894#[inline]
895fn div2(limbs: &mut [u64]) {
896    let mut t = 0;
897    for i in limbs.iter_mut().rev() {
898        let t2 = *i << 63;
899        *i >>= 1;
900        *i |= t;
901        t = t2;
902    }
903}
904
905impl<P, F> ToBitsGadget<<P::BaseField as Field>::BasePrimeField> for ProjectiveVar<P, F>
906where
907    P: SWModelParameters,
908    F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
909    for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
910{
911    #[tracing::instrument(target = "r1cs")]
912    fn to_bits_le(
913        &self,
914    ) -> Result<Vec<Boolean<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> {
915        let g = self.to_affine()?;
916        let mut bits = g.x.to_bits_le()?;
917        let y_bits = g.y.to_bits_le()?;
918        bits.extend_from_slice(&y_bits);
919        bits.push(g.infinity);
920        Ok(bits)
921    }
922
923    #[tracing::instrument(target = "r1cs")]
924    fn to_non_unique_bits_le(
925        &self,
926    ) -> Result<Vec<Boolean<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> {
927        let g = self.to_affine()?;
928        let mut bits = g.x.to_non_unique_bits_le()?;
929        let y_bits = g.y.to_non_unique_bits_le()?;
930        bits.extend_from_slice(&y_bits);
931        bits.push(g.infinity);
932        Ok(bits)
933    }
934}
935
936impl<P, F> ToBytesGadget<<P::BaseField as Field>::BasePrimeField> for ProjectiveVar<P, F>
937where
938    P: SWModelParameters,
939    F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
940    for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
941{
942    #[tracing::instrument(target = "r1cs")]
943    fn to_bytes(
944        &self,
945    ) -> Result<Vec<UInt8<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> {
946        let g = self.to_affine()?;
947        let mut bytes = g.x.to_bytes()?;
948        let y_bytes = g.y.to_bytes()?;
949        let inf_bytes = g.infinity.to_bytes()?;
950        bytes.extend_from_slice(&y_bytes);
951        bytes.extend_from_slice(&inf_bytes);
952        Ok(bytes)
953    }
954
955    #[tracing::instrument(target = "r1cs")]
956    fn to_non_unique_bytes(
957        &self,
958    ) -> Result<Vec<UInt8<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> {
959        let g = self.to_affine()?;
960        let mut bytes = g.x.to_non_unique_bytes()?;
961        let y_bytes = g.y.to_non_unique_bytes()?;
962        let inf_bytes = g.infinity.to_non_unique_bytes()?;
963        bytes.extend_from_slice(&y_bytes);
964        bytes.extend_from_slice(&inf_bytes);
965        Ok(bytes)
966    }
967}