openzeppelin_crypto/curve/sw/
projective.rs1use alloc::vec::Vec;
7use core::{
8 borrow::Borrow,
9 fmt::{Debug, Display, Formatter},
10 hash::{Hash, Hasher},
11 ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign},
12};
13
14use educe::Educe;
15use num_traits::{One, Zero};
16use zeroize::Zeroize;
17
18use super::{Affine, SWCurveConfig};
19use crate::{
20 bits::BitIteratorBE,
21 curve::{batch_inversion, AffineRepr, CurveGroup, PrimeGroup},
22 field::{group::AdditiveGroup, prime::PrimeField, Field},
23 impl_additive_ops_from_ref,
24};
25
26#[derive(Educe)]
30#[educe(Copy, Clone)]
31#[must_use]
32pub struct Projective<P: SWCurveConfig> {
33 pub x: P::BaseField,
35 pub y: P::BaseField,
37 pub z: P::BaseField,
39}
40
41impl<P: SWCurveConfig> Display for Projective<P> {
42 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
43 write!(f, "{}", Affine::from(*self))
44 }
45}
46
47impl<P: SWCurveConfig> Debug for Projective<P> {
48 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
49 if self.is_zero() {
50 write!(f, "infinity")
51 } else {
52 write!(f, "({}, {}, {})", self.x, self.y, self.z)
53 }
54 }
55}
56
57impl<P: SWCurveConfig> Eq for Projective<P> {}
58impl<P: SWCurveConfig> PartialEq for Projective<P> {
59 fn eq(&self, other: &Self) -> bool {
60 if self.is_zero() {
61 return other.is_zero();
62 }
63
64 if other.is_zero() {
65 return false;
66 }
67
68 let z1z1 = self.z.square();
72 let z2z2 = other.z.square();
73
74 if self.x * z2z2 == other.x * z1z1 {
75 self.y * (z2z2 * other.z) == other.y * (z1z1 * self.z)
76 } else {
77 false
78 }
79 }
80}
81
82impl<P: SWCurveConfig> PartialEq<Affine<P>> for Projective<P> {
83 fn eq(&self, other: &Affine<P>) -> bool {
84 self == &other.into_group()
85 }
86}
87
88impl<P: SWCurveConfig> Hash for Projective<P> {
89 fn hash<H: Hasher>(&self, state: &mut H) {
90 self.into_affine().hash(state);
91 }
92}
93
94impl<P: SWCurveConfig> Default for Projective<P> {
95 #[inline]
96 fn default() -> Self {
97 Self::zero()
98 }
99}
100
101impl<P: SWCurveConfig> Projective<P> {
102 pub const fn new_unchecked(
105 x: P::BaseField,
106 y: P::BaseField,
107 z: P::BaseField,
108 ) -> Self {
109 Self { x, y, z }
110 }
111
112 pub fn new(x: P::BaseField, y: P::BaseField, z: P::BaseField) -> Self {
120 let p = Self::new_unchecked(x, y, z).into_affine();
121 assert!(p.is_on_curve());
122 assert!(p.is_in_prime_order_subgroup());
123 p.into()
124 }
125}
126
127impl<P: SWCurveConfig> Zeroize for Projective<P> {
128 fn zeroize(&mut self) {
129 self.x.zeroize();
130 self.y.zeroize();
131 self.z.zeroize();
132 }
133}
134
135impl<P: SWCurveConfig> Zero for Projective<P> {
136 #[inline]
138 fn zero() -> Self {
139 Self::new_unchecked(
140 P::BaseField::one(),
141 P::BaseField::one(),
142 P::BaseField::zero(),
143 )
144 }
145
146 #[inline]
148 fn is_zero(&self) -> bool {
149 self.z == P::BaseField::ZERO
150 }
151}
152
153impl<P: SWCurveConfig> AdditiveGroup for Projective<P> {
154 type Scalar = P::ScalarField;
155
156 const ZERO: Self = Self::new_unchecked(
157 P::BaseField::ONE,
158 P::BaseField::ONE,
159 P::BaseField::ZERO,
160 );
161
162 fn double_in_place(&mut self) -> &mut Self {
169 if self.is_zero() {
170 return self;
171 }
172
173 if P::COEFF_A == P::BaseField::ZERO {
174 let mut a = self.x;
176 a.square_in_place();
177
178 let mut b = self.y;
180 b.square_in_place();
181
182 let mut c = b;
184 c.square_in_place();
185
186 let d = if [1, 2].contains(&P::BaseField::extension_degree()) {
190 let mut d = self.x;
191 d *= &b;
192 d.double_in_place().double_in_place();
193 d
194 } else {
195 let mut d = self.x;
196 d += &b;
197 d.square_in_place();
198 d -= a;
199 d -= c;
200 d.double_in_place();
201 d
202 };
203
204 let e = a + a.double_in_place();
206
207 self.z *= &self.y;
209 self.z.double_in_place();
210
211 self.x = e;
214 self.x.square_in_place();
215 self.x -= &d.double();
216
217 self.y = d;
219 self.y -= &self.x;
220 self.y *= &e;
221 self.y -= c.double_in_place().double_in_place().double_in_place();
222 self
223 } else {
224 let xx = self.x.square();
227
228 let yy = self.y.square();
230
231 let mut yyyy = yy;
233 yyyy.square_in_place();
234
235 let mut zz = self.z;
237 zz.square_in_place();
238
239 let s = ((self.x + yy).square() - xx - yyyy).double();
241
242 let mut m = xx;
244 m.double_in_place();
245 m += &xx;
246 m += &P::mul_by_a(zz.square());
247
248 self.x = m;
251 self.x.square_in_place();
252 self.x -= s.double();
253
254 self.z *= self.y;
257 self.z.double_in_place();
258
259 self.y = s;
261 self.y -= &self.x;
262 self.y *= &m;
263 self.y -=
264 yyyy.double_in_place().double_in_place().double_in_place();
265
266 self
267 }
268 }
269}
270
271impl<P: SWCurveConfig> PrimeGroup for Projective<P> {
272 type ScalarField = P::ScalarField;
273
274 #[inline]
275 fn generator() -> Self {
276 Affine::generator().into()
277 }
278
279 #[inline]
280 fn mul_bigint(&self, other: impl BitIteratorBE) -> Self {
281 P::mul_projective(self, other)
282 }
283}
284
285impl<P: SWCurveConfig> CurveGroup for Projective<P> {
286 type Affine = Affine<P>;
287 type BaseField = P::BaseField;
288 type Config = P;
289 type FullGroup = Affine<P>;
290
291 #[inline]
304 fn normalize_batch(v: &[Self]) -> Vec<Self::Affine> {
305 let mut z_s = v.iter().map(|g| g.z).collect::<Vec<_>>();
306
307 batch_inversion(&mut z_s);
308
309 v.iter()
311 .zip(z_s)
312 .map(|(g, z)| {
313 if g.is_zero() {
314 Affine::identity()
315 } else {
316 let z2 = z.square();
317 let x = g.x * z2;
318 let y = g.y * z2 * z;
319 Affine::new_unchecked(x, y)
320 }
321 })
322 .collect()
323 }
324}
325
326impl<P: SWCurveConfig> Neg for Projective<P> {
327 type Output = Self;
328
329 #[inline]
330 fn neg(mut self) -> Self {
331 self.y = -self.y;
332 self
333 }
334}
335
336impl<P: SWCurveConfig, T: Borrow<Affine<P>>> AddAssign<T> for Projective<P> {
337 fn add_assign(&mut self, other: T) {
339 let other = other.borrow();
340 if let Some((other_x, other_y)) = other.xy() {
341 if self.is_zero() {
342 self.x = other_x;
343 self.y = other_y;
344 self.z = P::BaseField::one();
345 return;
346 }
347
348 let mut z1z1 = self.z;
350 z1z1.square_in_place();
351
352 let mut u2 = other_x;
354 u2 *= &z1z1;
355
356 let mut s2 = self.z;
358 s2 *= &other_y;
359 s2 *= &z1z1;
360
361 if self.x == u2 {
362 if self.y == s2 {
363 self.double_in_place();
365 } else {
366 *self = Self::zero();
368 }
369 } else {
370 let mut h = u2;
372 h -= &self.x;
373
374 let mut hh = h;
376 hh.square_in_place();
377
378 let mut i = hh;
380 i.double_in_place().double_in_place();
381
382 let mut j = h;
384 j.neg_in_place();
385 j *= &i;
386
387 let mut r = s2;
389 r -= &self.y;
390 r.double_in_place();
391
392 let mut v = self.x;
394 v *= &i;
395
396 self.x = r.square();
398 self.x += &j;
399 self.x -= &v.double();
400
401 v -= &self.x;
403 self.y.double_in_place();
404 self.y = P::BaseField::sum_of_products(&[r, self.y], &[v, j]);
405
406 self.z *= &h;
410 self.z.double_in_place();
411 }
412 }
413 }
414}
415
416impl<P: SWCurveConfig, T: Borrow<Affine<P>>> Add<T> for Projective<P> {
417 type Output = Self;
418
419 fn add(mut self, other: T) -> Self {
420 let other = other.borrow();
421 self += other;
422 self
423 }
424}
425
426impl<P: SWCurveConfig, T: Borrow<Affine<P>>> SubAssign<T> for Projective<P> {
427 fn sub_assign(&mut self, other: T) {
428 *self += -(*other.borrow());
429 }
430}
431
432impl<P: SWCurveConfig, T: Borrow<Affine<P>>> Sub<T> for Projective<P> {
433 type Output = Self;
434
435 fn sub(mut self, other: T) -> Self {
436 self -= other.borrow();
437 self
438 }
439}
440
441impl_additive_ops_from_ref!(Projective, SWCurveConfig);
442
443impl<'a, P: SWCurveConfig> Add<&'a Self> for Projective<P> {
444 type Output = Self;
445
446 #[inline]
447 fn add(mut self, other: &'a Self) -> Self {
448 self += other;
449 self
450 }
451}
452
453impl<'a, P: SWCurveConfig> AddAssign<&'a Self> for Projective<P> {
454 fn add_assign(&mut self, other: &'a Self) {
455 if self.is_zero() {
456 *self = *other;
457 return;
458 }
459
460 if other.is_zero() {
461 return;
462 }
463
464 let z1z1 = self.z.square();
469
470 let z2z2 = other.z.square();
472
473 let mut u1 = self.x;
475 u1 *= &z2z2;
476
477 let mut u2 = other.x;
479 u2 *= &z1z1;
480
481 let mut s1 = self.y;
483 s1 *= &other.z;
484 s1 *= &z2z2;
485
486 let mut s2 = other.y;
488 s2 *= &self.z;
489 s2 *= &z1z1;
490
491 if u1 == u2 {
492 if s1 == s2 {
493 self.double_in_place();
495 } else {
496 *self = Self::zero();
498 }
499 } else {
500 let mut h = u2;
502 h -= &u1;
503
504 let mut i = h;
506 i.double_in_place().square_in_place();
507
508 let mut j = h;
510 j.neg_in_place();
511 j *= &i;
512
513 let mut r = s2;
515 r -= &s1;
516 r.double_in_place();
517
518 let mut v = u1;
520 v *= &i;
521
522 self.x = r;
524 self.x.square_in_place();
525 self.x += &j;
526 self.x -= &(v.double());
527
528 v -= &self.x;
530 self.y = s1;
531 self.y.double_in_place();
532 self.y = P::BaseField::sum_of_products(&[r, self.y], &[v, j]);
533
534 self.z *= other.z;
538 self.z.double_in_place();
539 self.z *= &h;
540 }
541 }
542}
543
544impl<'a, P: SWCurveConfig> Sub<&'a Self> for Projective<P> {
545 type Output = Self;
546
547 #[inline]
548 fn sub(mut self, other: &'a Self) -> Self {
549 self -= other;
550 self
551 }
552}
553
554impl<'a, P: SWCurveConfig> SubAssign<&'a Self> for Projective<P> {
555 fn sub_assign(&mut self, other: &'a Self) {
556 *self += &(-(*other));
557 }
558}
559
560impl<P: SWCurveConfig, T: Borrow<P::ScalarField>> MulAssign<T>
561 for Projective<P>
562{
563 fn mul_assign(&mut self, other: T) {
564 *self = self.mul_bigint(other.borrow().into_bigint());
565 }
566}
567
568impl<P: SWCurveConfig, T: Borrow<P::ScalarField>> Mul<T> for Projective<P> {
569 type Output = Self;
570
571 #[inline]
572 fn mul(mut self, other: T) -> Self {
573 self *= other;
574 self
575 }
576}
577
578impl<P: SWCurveConfig> From<Affine<P>> for Projective<P> {
581 #[inline]
582 fn from(p: Affine<P>) -> Projective<P> {
583 p.xy().map_or(Projective::zero(), |(x, y)| Self {
584 x,
585 y,
586 z: P::BaseField::one(),
587 })
588 }
589}
590
591impl<P: SWCurveConfig, T: Borrow<Affine<P>>> core::iter::Sum<T>
592 for Projective<P>
593{
594 fn sum<I: Iterator<Item = T>>(iter: I) -> Self {
595 iter.fold(Projective::zero(), |sum, x| sum + x.borrow())
596 }
597}