openzeppelin_crypto/curve/te/
projective.rs1use alloc::vec::Vec;
6use core::{
7 borrow::Borrow,
8 fmt::{Display, Formatter},
9 hash::{Hash, Hasher},
10 ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign},
11};
12
13use educe::Educe;
14use num_traits::{One, Zero};
15use zeroize::Zeroize;
16
17use super::{Affine, TECurveConfig};
18use crate::{
19 bits::BitIteratorBE,
20 curve::{batch_inversion, AffineRepr, CurveGroup, PrimeGroup},
21 field::{group::AdditiveGroup, prime::PrimeField, Field},
22 impl_additive_ops_from_ref,
23};
24
25#[derive(Educe)]
31#[educe(Copy, Clone, Eq(bound(P: TECurveConfig)), Debug)]
32#[must_use]
33pub struct Projective<P: TECurveConfig> {
34 pub x: P::BaseField,
36 pub y: P::BaseField,
38 pub t: P::BaseField,
40 pub z: P::BaseField,
42}
43
44impl<P: TECurveConfig> PartialEq<Affine<P>> for Projective<P> {
45 fn eq(&self, other: &Affine<P>) -> bool {
46 self == &other.into_group()
47 }
48}
49
50impl<P: TECurveConfig> Display for Projective<P> {
51 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
52 write!(f, "{}", Affine::from(*self))
53 }
54}
55
56impl<P: TECurveConfig> PartialEq for Projective<P> {
57 fn eq(&self, other: &Self) -> bool {
58 if self.is_zero() {
59 return other.is_zero();
60 }
61
62 if other.is_zero() {
63 return false;
64 }
65
66 (self.x * other.z) == (other.x * self.z)
69 && (self.y * other.z) == (other.y * self.z)
70 }
71}
72
73impl<P: TECurveConfig> Hash for Projective<P> {
74 fn hash<H: Hasher>(&self, state: &mut H) {
75 self.into_affine().hash(state);
76 }
77}
78
79impl<P: TECurveConfig> Default for Projective<P> {
80 #[inline]
81 fn default() -> Self {
82 Self::zero()
83 }
84}
85
86impl<P: TECurveConfig> Projective<P> {
87 pub const fn new_unchecked(
90 x: P::BaseField,
91 y: P::BaseField,
92 t: P::BaseField,
93 z: P::BaseField,
94 ) -> Self {
95 Self { x, y, t, z }
96 }
97
98 pub fn new(
106 x: P::BaseField,
107 y: P::BaseField,
108 t: P::BaseField,
109 z: P::BaseField,
110 ) -> Self {
111 let p = Self::new_unchecked(x, y, t, z).into_affine();
112 assert!(p.is_on_curve());
113 assert!(p.is_in_prime_order_subgroup());
114 p.into()
115 }
116}
117impl<P: TECurveConfig> Zeroize for Projective<P> {
118 fn zeroize(&mut self) {
119 self.x.zeroize();
120 self.y.zeroize();
121 self.t.zeroize();
122 self.z.zeroize();
123 }
124}
125
126impl<P: TECurveConfig> Zero for Projective<P> {
127 fn zero() -> Self {
128 Projective::<P>::ZERO
129 }
130
131 fn is_zero(&self) -> bool {
132 self.x.is_zero()
133 && self.y == self.z
134 && !self.y.is_zero()
135 && self.t.is_zero()
136 }
137}
138
139impl<P: TECurveConfig> AdditiveGroup for Projective<P> {
140 type Scalar = P::ScalarField;
141
142 const ZERO: Self = Self::new_unchecked(
143 P::BaseField::ZERO,
144 P::BaseField::ONE,
145 P::BaseField::ZERO,
146 P::BaseField::ONE,
147 );
148
149 fn double_in_place(&mut self) -> &mut Self {
154 let a = self.x.square();
156 let b = self.y.square();
158 let c = self.z.square().double();
160 let d = P::mul_by_a(a);
162 let e = (self.x + self.y).square() - a - b;
164 let g = d + b;
166 let f = g - c;
168 let h = d - b;
170 self.x = e * f;
172 self.y = g * h;
174 self.t = e * h;
176 self.z = f * g;
178
179 self
180 }
181}
182
183impl<P: TECurveConfig> PrimeGroup for Projective<P> {
184 type ScalarField = P::ScalarField;
185
186 fn generator() -> Self {
187 Affine::generator().into()
188 }
189
190 #[inline]
191 fn mul_bigint(&self, other: impl BitIteratorBE) -> Self {
192 P::mul_projective(self, other)
193 }
194}
195
196impl<P: TECurveConfig> CurveGroup for Projective<P> {
197 type Affine = Affine<P>;
198 type BaseField = P::BaseField;
199 type Config = P;
200 type FullGroup = Affine<P>;
201
202 fn normalize_batch(v: &[Self]) -> Vec<Self::Affine> {
214 assert!(
215 !v.iter().any(|v| v.z.is_zero()),
216 "projective Z coordinate should not be zero"
217 );
218
219 let mut z_s = v.iter().map(|g| g.z).collect::<Vec<_>>();
220
221 batch_inversion(&mut z_s);
222
223 v.iter()
225 .zip(z_s)
226 .map(|(g, z)| {
227 if g.is_zero() {
228 Affine::zero()
229 } else {
230 let x = g.x * z;
231 let y = g.y * z;
232 Affine::new_unchecked(x, y)
233 }
234 })
235 .collect()
236 }
237}
238
239impl<P: TECurveConfig> Neg for Projective<P> {
240 type Output = Self;
241
242 fn neg(mut self) -> Self {
243 self.x = -self.x;
244 self.t = -self.t;
245 self
246 }
247}
248
249impl<P: TECurveConfig, T: Borrow<Affine<P>>> AddAssign<T> for Projective<P> {
250 fn add_assign(&mut self, other: T) {
255 let other = other.borrow();
256 let a = self.x * other.x;
258 let b = self.y * other.y;
260 let c = P::COEFF_D * self.t * other.x * other.y;
262
263 let d = self.z;
265 let e = (self.x + self.y) * (other.x + other.y) - a - b;
267 let f = d - c;
269 let g = d + c;
271 let h = b - P::mul_by_a(a);
273 self.x = e * f;
275 self.y = g * h;
277 self.t = e * h;
279 self.z = f * g;
281 }
282}
283
284impl<P: TECurveConfig, T: Borrow<Affine<P>>> Add<T> for Projective<P> {
285 type Output = Self;
286
287 fn add(mut self, other: T) -> Self {
288 let other = other.borrow();
289 self += other;
290 self
291 }
292}
293
294impl<P: TECurveConfig, T: Borrow<Affine<P>>> SubAssign<T> for Projective<P> {
295 fn sub_assign(&mut self, other: T) {
296 *self += -(*other.borrow());
297 }
298}
299
300impl<P: TECurveConfig, T: Borrow<Affine<P>>> Sub<T> for Projective<P> {
301 type Output = Self;
302
303 fn sub(mut self, other: T) -> Self {
304 self -= other.borrow();
305 self
306 }
307}
308
309impl_additive_ops_from_ref!(Projective, TECurveConfig);
310
311impl<'a, P: TECurveConfig> Add<&'a Self> for Projective<P> {
312 type Output = Self;
313
314 fn add(mut self, other: &'a Self) -> Self {
315 self += other;
316 self
317 }
318}
319
320impl<'a, P: TECurveConfig> Sub<&'a Self> for Projective<P> {
321 type Output = Self;
322
323 fn sub(mut self, other: &'a Self) -> Self {
324 self -= other;
325 self
326 }
327}
328
329impl<'a, P: TECurveConfig> AddAssign<&'a Self> for Projective<P> {
330 fn add_assign(&mut self, other: &'a Self) {
334 let a = self.x * other.x;
336
337 let b = self.y * other.y;
339
340 let c = P::COEFF_D * self.t * other.t;
342
343 let d = self.z * other.z;
345
346 let h = b - P::mul_by_a(a);
348
349 let e = (self.x + self.y) * (other.x + other.y) - a - b;
351
352 let f = d - c;
354
355 let g = d + c;
357
358 self.x = e * f;
360
361 self.y = g * h;
363
364 self.t = e * h;
366
367 self.z = f * g;
369 }
370}
371
372impl<'a, P: TECurveConfig> SubAssign<&'a Self> for Projective<P> {
373 fn sub_assign(&mut self, other: &'a Self) {
374 *self += -(*other);
375 }
376}
377
378impl<P: TECurveConfig, T: Borrow<P::ScalarField>> MulAssign<T>
379 for Projective<P>
380{
381 fn mul_assign(&mut self, other: T) {
382 *self = self.mul_bigint(other.borrow().into_bigint());
383 }
384}
385
386impl<P: TECurveConfig, T: Borrow<P::ScalarField>> Mul<T> for Projective<P> {
387 type Output = Self;
388
389 #[inline]
390 fn mul(mut self, other: T) -> Self {
391 self *= other;
392 self
393 }
394}
395
396impl<P: TECurveConfig, T: Borrow<Affine<P>>> core::iter::Sum<T>
397 for Projective<P>
398{
399 fn sum<I>(iter: I) -> Self
400 where
401 I: Iterator<Item = T>,
402 {
403 iter.fold(Self::zero(), |acc, x| acc + x.borrow())
404 }
405}
406
407impl<P: TECurveConfig> From<Affine<P>> for Projective<P> {
410 fn from(p: Affine<P>) -> Projective<P> {
411 Self::new_unchecked(p.x, p.y, p.x * p.y, P::BaseField::one())
412 }
413}