1use ark_ec::{
2 short_weierstrass::{Affine as SWAffine, Projective as SWProjective, SWCurveConfig},
3 AffineRepr, CurveConfig, CurveGroup,
4};
5use ark_ff::{AdditiveGroup, BitIteratorBE, Field, One, PrimeField, Zero};
6use ark_relations::r1cs::{ConstraintSystemRef, Namespace, SynthesisError};
7use ark_std::{borrow::Borrow, marker::PhantomData, ops::Mul};
8use educe::Educe;
9use non_zero_affine::NonZeroAffineVar;
10
11use crate::{
12 convert::{ToBitsGadget, ToBytesGadget, ToConstraintFieldGadget},
13 fields::{emulated_fp::EmulatedFpVar, fp::FpVar},
14 prelude::*,
15 Vec,
16};
17
18pub mod bls12;
21
22pub mod mnt4;
26pub mod mnt6;
30
31pub mod non_zero_affine;
40
41type BasePrimeField<P> = <<P as CurveConfig>::BaseField as Field>::BasePrimeField;
42
43#[derive(Educe)]
47#[educe(Debug, Clone)]
48#[must_use]
49pub struct ProjectiveVar<P: SWCurveConfig, F: FieldVar<P::BaseField, BasePrimeField<P>>>
50where
51 for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
52{
53 pub x: F,
55 pub y: F,
57 pub z: F,
59 #[educe(Debug(ignore))]
60 _params: PhantomData<P>,
61}
62
63#[derive(Educe)]
65#[educe(Debug, Clone)]
66#[must_use]
67pub struct AffineVar<P: SWCurveConfig, F: FieldVar<P::BaseField, BasePrimeField<P>>>
68where
69 for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
70{
71 pub x: F,
73 pub y: F,
75 pub infinity: Boolean<BasePrimeField<P>>,
77 #[educe(Debug(ignore))]
78 _params: PhantomData<P>,
79}
80
81impl<P, F> AffineVar<P, F>
82where
83 P: SWCurveConfig,
84 F: FieldVar<P::BaseField, BasePrimeField<P>>,
85 for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
86{
87 fn new(x: F, y: F, infinity: Boolean<BasePrimeField<P>>) -> Self {
88 Self {
89 x,
90 y,
91 infinity,
92 _params: PhantomData,
93 }
94 }
95
96 pub fn value(&self) -> Result<SWAffine<P>, SynthesisError> {
99 Ok(match self.infinity.value()? {
100 true => SWAffine::identity(),
101 false => SWAffine::new(self.x.value()?, self.y.value()?),
102 })
103 }
104}
105
106impl<P, F> ToConstraintFieldGadget<BasePrimeField<P>> for AffineVar<P, F>
107where
108 P: SWCurveConfig,
109 F: FieldVar<P::BaseField, BasePrimeField<P>>,
110 for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
111 F: ToConstraintFieldGadget<BasePrimeField<P>>,
112{
113 fn to_constraint_field(&self) -> Result<Vec<FpVar<BasePrimeField<P>>>, SynthesisError> {
114 let mut res = Vec::<FpVar<BasePrimeField<P>>>::new();
115
116 res.extend_from_slice(&self.x.to_constraint_field()?);
117 res.extend_from_slice(&self.y.to_constraint_field()?);
118 res.extend_from_slice(&self.infinity.to_constraint_field()?);
119
120 Ok(res)
121 }
122}
123
124impl<P, F> R1CSVar<BasePrimeField<P>> for ProjectiveVar<P, F>
125where
126 P: SWCurveConfig,
127 F: FieldVar<P::BaseField, BasePrimeField<P>>,
128 for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
129{
130 type Value = SWProjective<P>;
131
132 fn cs(&self) -> ConstraintSystemRef<BasePrimeField<P>> {
133 self.x.cs().or(self.y.cs()).or(self.z.cs())
134 }
135
136 fn value(&self) -> Result<Self::Value, SynthesisError> {
137 let (x, y, z) = (self.x.value()?, self.y.value()?, self.z.value()?);
138 let result = if let Some(z_inv) = z.inverse() {
139 SWAffine::new(x * &z_inv, y * &z_inv)
140 } else {
141 SWAffine::identity()
142 };
143 Ok(result.into())
144 }
145}
146
147impl<P: SWCurveConfig, F: FieldVar<P::BaseField, BasePrimeField<P>>> ProjectiveVar<P, F>
148where
149 for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
150{
151 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 #[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_affine = SWAffine::<P>::zero();
174 let zero_x = F::new_constant(cs.clone(), &zero_affine.x)?;
175 let zero_y = F::new_constant(cs.clone(), &zero_affine.y)?;
176 let z_inv = F::new_witness(ark_relations::ns!(cs, "z_inverse"), || {
179 Ok(self.z.value()?.inverse().unwrap_or_else(P::BaseField::zero))
180 })?;
181 z_inv.mul_equals(&self.z, &F::from(!&infinity))?;
187
188 let non_zero_x = &self.x * &z_inv;
189 let non_zero_y = &self.y * &z_inv;
190
191 let x = infinity.select(&zero_x, &non_zero_x)?;
192 let y = infinity.select(&zero_y, &non_zero_y)?;
193
194 Ok(AffineVar::new(x, y, infinity))
195 }
196 }
197
198 #[tracing::instrument(target = "r1cs", skip(cs, f))]
202 pub fn new_variable_omit_on_curve_check(
203 cs: impl Into<Namespace<BasePrimeField<P>>>,
204 f: impl FnOnce() -> Result<SWProjective<P>, SynthesisError>,
205 mode: AllocationMode,
206 ) -> Result<Self, SynthesisError> {
207 let ns = cs.into();
208 let cs = ns.cs();
209
210 let (x, y, z) = match f() {
211 Ok(ge) => {
212 let ge = ge.into_affine();
213 if ge.is_zero() {
214 (
217 Ok(P::BaseField::zero()),
218 Ok(P::BaseField::one()),
219 Ok(P::BaseField::zero()),
220 )
221 } else {
222 (Ok(ge.x), Ok(ge.y), Ok(P::BaseField::one()))
223 }
224 },
225 _ => (
226 Err(SynthesisError::AssignmentMissing),
227 Err(SynthesisError::AssignmentMissing),
228 Err(SynthesisError::AssignmentMissing),
229 ),
230 };
231
232 let x = F::new_variable(ark_relations::ns!(cs, "x"), || x, mode)?;
233 let y = F::new_variable(ark_relations::ns!(cs, "y"), || y, mode)?;
234 let z = F::new_variable(ark_relations::ns!(cs, "z"), || z, mode)?;
235
236 Ok(Self::new(x, y, z))
237 }
238
239 #[tracing::instrument(target = "r1cs", skip(self, other))]
242 pub(crate) fn add_mixed(&self, other: &NonZeroAffineVar<P, F>) -> Result<Self, SynthesisError> {
243 let three_b = P::COEFF_B.double() + &P::COEFF_B;
252 let (x1, y1, z1) = (&self.x, &self.y, &self.z);
253 let (x2, y2) = (&other.x, &other.y);
254
255 let xx = x1 * x2; let yy = y1 * y2; let xy_pairs = ((x1 + y1) * &(x2 + y2)) - (&xx + &yy); let xz_pairs = (x2 * z1) + x1; let yz_pairs = (y2 * z1) + y1; let axz = mul_by_coeff_a::<P, F>(&xz_pairs); let bz3_part = &axz + z1 * three_b; let yy_m_bz3 = &yy - &bz3_part; let yy_p_bz3 = &yy + &bz3_part; let azz = mul_by_coeff_a::<P, F>(z1); let xx3_p_azz = xx.double().unwrap() + &xx + &azz; let bxz3 = &xz_pairs * three_b; let b3_xz_pairs = mul_by_coeff_a::<P, F>(&(&xx - &azz)) + &bxz3; let x = (&yy_m_bz3 * &xy_pairs) - &yz_pairs * &b3_xz_pairs; let y = (&yy_p_bz3 * &yy_m_bz3) + &xx3_p_azz * b3_xz_pairs; let z = (&yy_p_bz3 * &yz_pairs) + xy_pairs * xx3_p_azz; Ok(ProjectiveVar::new(x, y, z))
279 }
280
281 #[tracing::instrument(
284 target = "r1cs",
285 skip(self, mul_result, multiple_of_power_of_two, bits)
286 )]
287 fn fixed_scalar_mul_le(
288 &self,
289 mul_result: &mut Self,
290 multiple_of_power_of_two: &mut NonZeroAffineVar<P, F>,
291 bits: &[&Boolean<BasePrimeField<P>>],
292 ) -> Result<(), SynthesisError> {
293 let scalar_modulus_bits = <P::ScalarField as PrimeField>::MODULUS_BIT_SIZE as usize;
294
295 assert!(scalar_modulus_bits >= bits.len());
296 let split_len = ark_std::cmp::min(scalar_modulus_bits - 2, bits.len());
297 let (affine_bits, proj_bits) = bits.split_at(split_len);
298 let mut accumulator = multiple_of_power_of_two.clone();
330 let initial_acc_value = accumulator.into_projective();
331
332 multiple_of_power_of_two.double_in_place()?;
334
335 for bit in affine_bits.iter().skip(1) {
338 if bit.is_constant() {
339 if *bit == &Boolean::TRUE {
340 accumulator = accumulator.add_unchecked(multiple_of_power_of_two)?;
341 }
342 } else {
343 let temp = accumulator.add_unchecked(multiple_of_power_of_two)?;
344 accumulator = bit.select(&temp, &accumulator)?;
345 }
346 multiple_of_power_of_two.double_in_place()?;
347 }
348 let result = accumulator.into_projective();
354 let subtrahend = bits[0].select(&Self::zero(), &initial_acc_value)?;
356 *mul_result += result - subtrahend;
357
358 for bit in proj_bits {
360 if bit.is_constant() {
361 if *bit == &Boolean::TRUE {
362 *mul_result += &multiple_of_power_of_two.into_projective();
363 }
364 } else {
365 let temp = &*mul_result + &multiple_of_power_of_two.into_projective();
366 *mul_result = bit.select(&temp, &mul_result)?;
367 }
368 multiple_of_power_of_two.double_in_place()?;
369 }
370 Ok(())
371 }
372}
373
374impl<P, F> CurveVar<SWProjective<P>, BasePrimeField<P>> for ProjectiveVar<P, F>
375where
376 P: SWCurveConfig,
377 F: FieldVar<P::BaseField, BasePrimeField<P>>,
378 for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
379{
380 fn constant(g: SWProjective<P>) -> Self {
381 let cs = ConstraintSystemRef::None;
382 Self::new_variable_omit_on_curve_check(cs, || Ok(g), AllocationMode::Constant).unwrap()
383 }
384
385 fn zero() -> Self {
386 Self::new(F::zero(), F::one(), F::zero())
387 }
388
389 fn is_zero(&self) -> Result<Boolean<BasePrimeField<P>>, SynthesisError> {
390 self.z.is_zero()
391 }
392
393 #[tracing::instrument(target = "r1cs", skip(cs, f))]
394 fn new_variable_omit_prime_order_check(
395 cs: impl Into<Namespace<BasePrimeField<P>>>,
396 f: impl FnOnce() -> Result<SWProjective<P>, SynthesisError>,
397 mode: AllocationMode,
398 ) -> Result<Self, SynthesisError> {
399 let ns = cs.into();
400 let cs = ns.cs();
401 let g = Self::new_variable_omit_on_curve_check(cs, f, mode)?;
414
415 if mode != AllocationMode::Constant {
416 let b = P::COEFF_B;
418 let a = P::COEFF_A;
419
420 let x2 = g.x.square()?;
421 let y2 = g.y.square()?;
422 let z2 = g.z.square()?;
423 let t = &g.x * (x2 + &z2 * a);
424
425 g.z.mul_equals(&(y2 - z2 * b), &t)?;
426 }
427 Ok(g)
428 }
429
430 #[tracing::instrument(target = "r1cs")]
437 fn enforce_prime_order(&self) -> Result<(), SynthesisError> {
438 unimplemented!("cannot enforce prime order");
439 }
452
453 #[inline]
454 #[tracing::instrument(target = "r1cs")]
455 fn double_in_place(&mut self) -> Result<(), SynthesisError> {
456 let three_b = P::COEFF_B.double() + &P::COEFF_B;
465
466 let xx = self.x.square()?; let yy = self.y.square()?; let zz = self.z.square()?; let xy2 = (&self.x * &self.y).double()?; let xz2 = (&self.x * &self.z).double()?; let axz2 = mul_by_coeff_a::<P, F>(&xz2); let bzz3_part = &axz2 + &zz * three_b; let yy_m_bzz3 = &yy - &bzz3_part; let yy_p_bzz3 = &yy + &bzz3_part; let y_frag = yy_p_bzz3 * &yy_m_bzz3; let x_frag = yy_m_bzz3 * &xy2; let bxz3 = xz2 * three_b; let azz = mul_by_coeff_a::<P, F>(&zz); let b3_xz_pairs = mul_by_coeff_a::<P, F>(&(&xx - &azz)) + &bxz3; let xx3_p_azz = (xx.double()? + &xx + &azz) * &b3_xz_pairs; let y = y_frag + &xx3_p_azz; let yz2 = (&self.y * &self.z).double()?; let x = x_frag - &(b3_xz_pairs * &yz2); let z = (yz2 * &yy).double()?.double()?; self.x = x;
490 self.y = y;
491 self.z = z;
492 Ok(())
493 }
494
495 #[tracing::instrument(target = "r1cs")]
496 fn negate(&self) -> Result<Self, SynthesisError> {
497 Ok(Self::new(self.x.clone(), self.y.negate()?, self.z.clone()))
498 }
499
500 #[tracing::instrument(target = "r1cs", skip(bits))]
503 fn scalar_mul_le<'a>(
504 &self,
505 bits: impl Iterator<Item = &'a Boolean<BasePrimeField<P>>>,
506 ) -> Result<Self, SynthesisError> {
507 if self.is_constant() {
508 if self.value().unwrap().is_zero() {
509 return Ok(self.clone());
510 }
511 }
512 let self_affine = self.to_affine()?;
513 let (x, y, infinity) = (self_affine.x, self_affine.y, self_affine.infinity);
514 let x = infinity.select(&F::constant(P::GENERATOR.x), &x)?;
525 let y = infinity.select(&F::constant(P::GENERATOR.y), &y)?;
526 let non_zero_self = NonZeroAffineVar::new(x, y);
527
528 let mut bits = bits.collect::<Vec<_>>();
529 if bits.len() == 0 {
530 return Ok(Self::zero());
531 }
532 bits = bits
534 .into_iter()
535 .rev()
537 .skip_while(|b| b.is_constant() && (b.value().unwrap() == false))
539 .collect();
540 bits.reverse();
543
544 let scalar_modulus_bits = <P::ScalarField as PrimeField>::MODULUS_BIT_SIZE;
545 let mut mul_result = Self::zero();
546 let mut power_of_two_times_self = non_zero_self;
547 for bits in bits.chunks(scalar_modulus_bits as usize) {
549 self.fixed_scalar_mul_le(&mut mul_result, &mut power_of_two_times_self, bits)?;
550 }
551
552 infinity.select(&Self::zero(), &mul_result)
558 }
559
560 #[tracing::instrument(target = "r1cs", skip(scalar_bits_with_bases))]
561 fn precomputed_base_scalar_mul_le<'a, I, B>(
562 &mut self,
563 scalar_bits_with_bases: I,
564 ) -> Result<(), SynthesisError>
565 where
566 I: Iterator<Item = (B, &'a SWProjective<P>)>,
567 B: Borrow<Boolean<BasePrimeField<P>>>,
568 {
569 let (bits, bases): (Vec<_>, Vec<_>) = scalar_bits_with_bases
571 .map(|(b, c)| (b.borrow().clone(), *c))
572 .unzip();
573 let base = bases[0];
574 *self += Self::constant(base).scalar_mul_le(bits.iter())?;
575 Ok(())
576 }
577}
578
579impl<P, F> ToConstraintFieldGadget<BasePrimeField<P>> for ProjectiveVar<P, F>
580where
581 P: SWCurveConfig,
582 F: FieldVar<P::BaseField, BasePrimeField<P>>,
583 for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
584 F: ToConstraintFieldGadget<BasePrimeField<P>>,
585{
586 fn to_constraint_field(&self) -> Result<Vec<FpVar<BasePrimeField<P>>>, SynthesisError> {
587 self.to_affine()?.to_constraint_field()
588 }
589}
590
591fn mul_by_coeff_a<P: SWCurveConfig, F: FieldVar<P::BaseField, BasePrimeField<P>>>(f: &F) -> F
592where
593 for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
594{
595 if !P::COEFF_A.is_zero() {
596 f * P::COEFF_A
597 } else {
598 F::zero()
599 }
600}
601
602impl_bounded_ops!(
603 ProjectiveVar<P, F>,
604 SWProjective<P>,
605 Add,
606 add,
607 AddAssign,
608 add_assign,
609 |mut this: &'a ProjectiveVar<P, F>, mut other: &'a ProjectiveVar<P, F>| {
610 if this.is_constant() {
616 core::mem::swap(&mut this, &mut other);
618 }
619
620 if other.is_constant() {
621 let other = other.value().unwrap();
623 if other.is_zero() {
624 this.clone()
626 } else {
627 let x = F::constant(other.x);
629 let y = F::constant(other.y);
630 this.add_mixed(&NonZeroAffineVar::new(x, y)).unwrap()
631 }
632 } else {
633 let three_b = P::COEFF_B.double() + &P::COEFF_B;
642 let (x1, y1, z1) = (&this.x, &this.y, &this.z);
643 let (x2, y2, z2) = (&other.x, &other.y, &other.z);
644
645 let xx = x1 * x2; let yy = y1 * y2; let zz = z1 * z2; let xy_pairs = ((x1 + y1) * &(x2 + y2)) - (&xx + &yy); let xz_pairs = ((x1 + z1) * &(x2 + z2)) - (&xx + &zz); let yz_pairs = ((y1 + z1) * &(y2 + z2)) - (&yy + &zz); let axz = mul_by_coeff_a::<P, F>(&xz_pairs); let bzz3_part = &axz + &zz * three_b; let yy_m_bzz3 = &yy - &bzz3_part; let yy_p_bzz3 = &yy + &bzz3_part; let azz = mul_by_coeff_a::<P, F>(&zz);
660 let xx3_p_azz = xx.double().unwrap() + &xx + &azz; let bxz3 = &xz_pairs * three_b; let b3_xz_pairs = mul_by_coeff_a::<P, F>(&(&xx - &azz)) + &bxz3; let x = (&yy_m_bzz3 * &xy_pairs) - &yz_pairs * &b3_xz_pairs; let y = (&yy_p_bzz3 * &yy_m_bzz3) + &xx3_p_azz * b3_xz_pairs; let z = (&yy_p_bzz3 * &yz_pairs) + xy_pairs * xx3_p_azz; ProjectiveVar::new(x, y, z)
670 }
671
672 },
673 |this: &'a ProjectiveVar<P, F>, other: SWProjective<P>| {
674 this + ProjectiveVar::constant(other)
675 },
676 (F: FieldVar<P::BaseField, BasePrimeField<P>>, P: SWCurveConfig),
677 for <'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>,
678);
679
680impl_bounded_ops!(
681 ProjectiveVar<P, F>,
682 SWProjective<P>,
683 Sub,
684 sub,
685 SubAssign,
686 sub_assign,
687 |this: &'a ProjectiveVar<P, F>, other: &'a ProjectiveVar<P, F>| this + other.negate().unwrap(),
688 |this: &'a ProjectiveVar<P, F>, other: SWProjective<P>| this - ProjectiveVar::constant(other),
689 (F: FieldVar<P::BaseField, BasePrimeField<P>>, P: SWCurveConfig),
690 for <'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>
691);
692
693impl_bounded_ops_diff!(
694 ProjectiveVar<P, F>,
695 SWProjective<P>,
696 EmulatedFpVar<P::ScalarField, BasePrimeField<P>>,
697 P::ScalarField,
698 Mul,
699 mul,
700 MulAssign,
701 mul_assign,
702 |this: &'a ProjectiveVar<P, F>, other: &'a EmulatedFpVar<P::ScalarField, BasePrimeField<P>>| {
703 if this.is_constant() && other.is_constant() {
704 assert!(this.is_constant() && other.is_constant());
705 ProjectiveVar::constant(this.value().unwrap() * &other.value().unwrap())
706 } else {
707 let bits = other.to_bits_le().unwrap();
708 this.scalar_mul_le(bits.iter()).unwrap()
709 }
710 },
711 |this: &'a ProjectiveVar<P, F>, other: P::ScalarField| this * EmulatedFpVar::constant(other),
712 (F: FieldVar<P::BaseField, BasePrimeField<P>>, P: SWCurveConfig),
713 for <'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>,
714);
715
716impl<'a, P, F> GroupOpsBounds<'a, SWProjective<P>, ProjectiveVar<P, F>> for ProjectiveVar<P, F>
717where
718 P: SWCurveConfig,
719 F: FieldVar<P::BaseField, BasePrimeField<P>>,
720 for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>,
721{
722}
723
724impl<'a, P, F> GroupOpsBounds<'a, SWProjective<P>, ProjectiveVar<P, F>> for &'a ProjectiveVar<P, F>
725where
726 P: SWCurveConfig,
727 F: FieldVar<P::BaseField, BasePrimeField<P>>,
728 for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>,
729{
730}
731
732impl<P, F> CondSelectGadget<BasePrimeField<P>> for ProjectiveVar<P, F>
733where
734 P: SWCurveConfig,
735 F: FieldVar<P::BaseField, BasePrimeField<P>>,
736 for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
737{
738 #[inline]
739 #[tracing::instrument(target = "r1cs")]
740 fn conditionally_select(
741 cond: &Boolean<BasePrimeField<P>>,
742 true_value: &Self,
743 false_value: &Self,
744 ) -> Result<Self, SynthesisError> {
745 let x = cond.select(&true_value.x, &false_value.x)?;
746 let y = cond.select(&true_value.y, &false_value.y)?;
747 let z = cond.select(&true_value.z, &false_value.z)?;
748
749 Ok(Self::new(x, y, z))
750 }
751}
752
753impl<P, F> EqGadget<BasePrimeField<P>> for ProjectiveVar<P, F>
754where
755 P: SWCurveConfig,
756 F: FieldVar<P::BaseField, BasePrimeField<P>>,
757 for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
758{
759 #[tracing::instrument(target = "r1cs")]
760 fn is_eq(&self, other: &Self) -> Result<Boolean<BasePrimeField<P>>, SynthesisError> {
761 let x_equal = (&self.x * &other.z).is_eq(&(&other.x * &self.z))?;
762 let y_equal = (&self.y * &other.z).is_eq(&(&other.y * &self.z))?;
763 let coordinates_equal = x_equal & y_equal;
764 let both_are_zero = self.is_zero()? & other.is_zero()?;
765 Ok(both_are_zero | coordinates_equal)
766 }
767
768 #[inline]
769 #[tracing::instrument(target = "r1cs")]
770 fn conditional_enforce_equal(
771 &self,
772 other: &Self,
773 condition: &Boolean<BasePrimeField<P>>,
774 ) -> Result<(), SynthesisError> {
775 let x_equal = (&self.x * &other.z).is_eq(&(&other.x * &self.z))?;
776 let y_equal = (&self.y * &other.z).is_eq(&(&other.y * &self.z))?;
777 let coordinates_equal = x_equal & y_equal;
778 let both_are_zero = self.is_zero()? & other.is_zero()?;
779 (both_are_zero | coordinates_equal).conditional_enforce_equal(&Boolean::TRUE, condition)
780 }
781
782 #[inline]
783 #[tracing::instrument(target = "r1cs")]
784 fn conditional_enforce_not_equal(
785 &self,
786 other: &Self,
787 condition: &Boolean<BasePrimeField<P>>,
788 ) -> Result<(), SynthesisError> {
789 let is_equal = self.is_eq(other)?;
790 (is_equal & condition).enforce_equal(&Boolean::FALSE)
791 }
792}
793
794impl<P, F> AllocVar<SWAffine<P>, BasePrimeField<P>> for ProjectiveVar<P, F>
795where
796 P: SWCurveConfig,
797 F: FieldVar<P::BaseField, BasePrimeField<P>>,
798 for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
799{
800 fn new_variable<T: Borrow<SWAffine<P>>>(
801 cs: impl Into<Namespace<BasePrimeField<P>>>,
802 f: impl FnOnce() -> Result<T, SynthesisError>,
803 mode: AllocationMode,
804 ) -> Result<Self, SynthesisError> {
805 Self::new_variable(
806 cs,
807 || f().map(|b| SWProjective::from((*b.borrow()).clone())),
808 mode,
809 )
810 }
811}
812
813impl<P, F> AllocVar<SWProjective<P>, BasePrimeField<P>> for ProjectiveVar<P, F>
814where
815 P: SWCurveConfig,
816 F: FieldVar<P::BaseField, BasePrimeField<P>>,
817 for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
818{
819 fn new_variable<T: Borrow<SWProjective<P>>>(
820 cs: impl Into<Namespace<BasePrimeField<P>>>,
821 f: impl FnOnce() -> Result<T, SynthesisError>,
822 mode: AllocationMode,
823 ) -> Result<Self, SynthesisError> {
824 let ns = cs.into();
825 let cs = ns.cs();
826 let f = || Ok(*f()?.borrow());
827 match mode {
828 AllocationMode::Constant => Self::new_variable_omit_prime_order_check(cs, f, mode),
829 AllocationMode::Input => Self::new_variable_omit_prime_order_check(cs, f, mode),
830 AllocationMode::Witness => {
831 let mut power_of_2: u32 = 0;
836 let mut cofactor = P::COFACTOR.to_vec();
837 while cofactor[0] % 2 == 0 {
838 div2(&mut cofactor);
839 power_of_2 += 1;
840 }
841
842 let cofactor_weight = BitIteratorBE::new(cofactor.as_slice())
843 .filter(|b| *b)
844 .count();
845 let modulus_minus_1 = (-P::ScalarField::one()).into_bigint(); let modulus_minus_1_weight =
847 BitIteratorBE::new(modulus_minus_1).filter(|b| *b).count();
848
849 let (mut ge, iter) = if cofactor_weight < modulus_minus_1_weight {
858 let ge = Self::new_variable_omit_prime_order_check(
859 ark_relations::ns!(cs, "Witness without subgroup check with cofactor mul"),
860 || f().map(|g| g.into_affine().mul_by_cofactor_inv().into()),
861 mode,
862 )?;
863 (
864 ge,
865 BitIteratorBE::without_leading_zeros(cofactor.as_slice()),
866 )
867 } else {
868 let ge = Self::new_variable_omit_prime_order_check(
869 ark_relations::ns!(cs, "Witness without subgroup check with `r` check"),
870 || {
871 f().map(|g| {
872 let g = g.into_affine();
873 let power_of_two = P::ScalarField::ONE.into_bigint() << power_of_2;
874 let power_of_two_inv = P::ScalarField::from_bigint(power_of_two)
875 .and_then(|n| n.inverse())
876 .unwrap();
877 g.mul(power_of_two_inv)
878 })
879 },
880 mode,
881 )?;
882
883 (
884 ge,
885 BitIteratorBE::without_leading_zeros(modulus_minus_1.as_ref()),
886 )
887 };
888 for _ in 0..power_of_2 {
890 ge.double_in_place()?;
891 }
892
893 let mut result = Self::zero();
894 for b in iter {
895 result.double_in_place()?;
896
897 if b {
898 result += &ge
899 }
900 }
901 if cofactor_weight < modulus_minus_1_weight {
902 Ok(result)
903 } else {
904 ge.enforce_equal(&ge)?;
905 Ok(ge)
906 }
907 },
908 }
909 }
910}
911
912#[inline]
913fn div2(limbs: &mut [u64]) {
914 let mut t = 0;
915 for i in limbs.iter_mut().rev() {
916 let t2 = *i << 63;
917 *i >>= 1;
918 *i |= t;
919 t = t2;
920 }
921}
922
923impl<P, F> ToBitsGadget<BasePrimeField<P>> for ProjectiveVar<P, F>
924where
925 P: SWCurveConfig,
926 F: FieldVar<P::BaseField, BasePrimeField<P>>,
927 for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
928{
929 #[tracing::instrument(target = "r1cs")]
930 fn to_bits_le(&self) -> Result<Vec<Boolean<BasePrimeField<P>>>, SynthesisError> {
931 let g = self.to_affine()?;
932 let mut bits = g.x.to_bits_le()?;
933 let y_bits = g.y.to_bits_le()?;
934 bits.extend_from_slice(&y_bits);
935 bits.push(g.infinity);
936 Ok(bits)
937 }
938
939 #[tracing::instrument(target = "r1cs")]
940 fn to_non_unique_bits_le(&self) -> Result<Vec<Boolean<BasePrimeField<P>>>, SynthesisError> {
941 let g = self.to_affine()?;
942 let mut bits = g.x.to_non_unique_bits_le()?;
943 let y_bits = g.y.to_non_unique_bits_le()?;
944 bits.extend_from_slice(&y_bits);
945 bits.push(g.infinity);
946 Ok(bits)
947 }
948}
949
950impl<P, F> ToBytesGadget<BasePrimeField<P>> for ProjectiveVar<P, F>
951where
952 P: SWCurveConfig,
953 F: FieldVar<P::BaseField, BasePrimeField<P>>,
954 for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
955{
956 #[tracing::instrument(target = "r1cs")]
957 fn to_bytes_le(&self) -> Result<Vec<UInt8<BasePrimeField<P>>>, SynthesisError> {
958 let g = self.to_affine()?;
959 let mut bytes = g.x.to_bytes_le()?;
960 let y_bytes = g.y.to_bytes_le()?;
961 let inf_bytes = g.infinity.to_bytes_le()?;
962 bytes.extend_from_slice(&y_bytes);
963 bytes.extend_from_slice(&inf_bytes);
964 Ok(bytes)
965 }
966
967 #[tracing::instrument(target = "r1cs")]
968 fn to_non_unique_bytes_le(&self) -> Result<Vec<UInt8<BasePrimeField<P>>>, SynthesisError> {
969 let g = self.to_affine()?;
970 let mut bytes = g.x.to_non_unique_bytes_le()?;
971 let y_bytes = g.y.to_non_unique_bytes_le()?;
972 let inf_bytes = g.infinity.to_non_unique_bytes_le()?;
973 bytes.extend_from_slice(&y_bytes);
974 bytes.extend_from_slice(&inf_bytes);
975 Ok(bytes)
976 }
977}
978
979#[cfg(test)]
980mod test_sw_curve {
981 use crate::{
982 alloc::AllocVar,
983 convert::ToBitsGadget,
984 eq::EqGadget,
985 fields::{emulated_fp::EmulatedFpVar, fp::FpVar},
986 groups::{curves::short_weierstrass::ProjectiveVar, CurveVar},
987 };
988 use ark_ec::{
989 short_weierstrass::{Projective, SWCurveConfig},
990 CurveGroup,
991 };
992 use ark_ff::PrimeField;
993 use ark_relations::r1cs::{ConstraintSystem, Result};
994 use ark_std::UniformRand;
995 use num_traits::Zero;
996
997 fn zero_point_scalar_mul_satisfied<G>() -> Result<bool>
998 where
999 G: CurveGroup,
1000 G::BaseField: PrimeField,
1001 G::Config: SWCurveConfig,
1002 {
1003 let mut rng = ark_std::test_rng();
1004
1005 let cs = ConstraintSystem::new_ref();
1006 let point_in = Projective::<G::Config>::zero();
1007 let point_out = Projective::<G::Config>::zero();
1008 let scalar = G::ScalarField::rand(&mut rng);
1009
1010 let point_in =
1011 ProjectiveVar::<G::Config, FpVar<G::BaseField>>::new_witness(cs.clone(), || {
1012 Ok(point_in)
1013 })?;
1014 let point_out =
1015 ProjectiveVar::<G::Config, FpVar<G::BaseField>>::new_input(cs.clone(), || {
1016 Ok(point_out)
1017 })?;
1018 let scalar = EmulatedFpVar::new_input(cs.clone(), || Ok(scalar))?;
1019
1020 let mul = point_in.scalar_mul_le(scalar.to_bits_le().unwrap().iter())?;
1021
1022 point_out.enforce_equal(&mul)?;
1023
1024 cs.is_satisfied()
1025 }
1026
1027 #[test]
1028 fn test_zero_point_scalar_mul() {
1029 assert!(zero_point_scalar_mul_satisfied::<ark_bls12_381::G1Projective>().unwrap());
1030 assert!(zero_point_scalar_mul_satisfied::<ark_pallas::Projective>().unwrap());
1031 assert!(zero_point_scalar_mul_satisfied::<ark_mnt4_298::G1Projective>().unwrap());
1032 assert!(zero_point_scalar_mul_satisfied::<ark_mnt6_298::G1Projective>().unwrap());
1033 assert!(zero_point_scalar_mul_satisfied::<ark_bn254::G1Projective>().unwrap());
1034 }
1035}