ark_ec/models/double_odd/
group.rs1use ark_serialize::{
2 CanonicalDeserialize, CanonicalSerialize, Compress, SerializationError, Valid, Validate,
3};
4use ark_std::{
5 borrow::Borrow,
6 fmt::{Debug, Display, Formatter, Result as FmtResult},
7 hash::{Hash, Hasher},
8 io::{Read, Write},
9 ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign},
10 rand::{
11 distributions::{Distribution, Standard},
12 Rng,
13 },
14 vec::Vec,
15 Zero,
16};
17use educe::Educe;
18
19use ark_ff::{fields::Field, AdditiveGroup, PrimeField, ToConstraintField, UniformRand};
20
21use zeroize::Zeroize;
22
23#[cfg(feature = "parallel")]
24use rayon::prelude::*;
25
26use super::{Affine, DOCurveConfig};
27use crate::{
28 scalar_mul::{variable_base::VariableBaseMSM, ScalarMul},
29 AffineRepr, CurveGroup, PrimeGroup,
30};
31
32#[derive(Educe)]
40#[educe(Copy, Clone)]
41#[must_use]
42pub struct Projective<P: DOCurveConfig> {
43 pub e: P::BaseField,
45 pub z: P::BaseField,
47 pub u: P::BaseField,
49 pub t: P::BaseField,
51}
52
53impl<P: DOCurveConfig> Display for Projective<P> {
54 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
55 write!(f, "{}", Affine::from(*self))
56 }
57}
58
59impl<P: DOCurveConfig> Debug for Projective<P> {
60 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
61 match self.is_zero() {
62 true => write!(f, "infinity"),
63 false => write!(f, "({}, {}, {}, {})", self.e, self.z, self.u, self.t),
64 }
65 }
66}
67
68impl<P: DOCurveConfig> Eq for Projective<P> {}
69impl<P: DOCurveConfig> PartialEq for Projective<P> {
70 fn eq(&self, other: &Self) -> bool {
71 if self.is_zero() {
72 return other.is_zero();
73 }
74 if other.is_zero() {
75 return false;
76 }
77 self.e * other.u == other.e * self.u
78 }
79}
80
81impl<P: DOCurveConfig> PartialEq<Affine<P>> for Projective<P> {
82 fn eq(&self, other: &Affine<P>) -> bool {
83 *self == other.into_group()
84 }
85}
86
87impl<P: DOCurveConfig> Hash for Projective<P> {
88 fn hash<H: Hasher>(&self, state: &mut H) {
89 self.into_affine().hash(state)
90 }
91}
92
93impl<P: DOCurveConfig> Distribution<Projective<P>> for Standard {
94 #[inline]
96 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Projective<P> {
97 loop {
98 let u = P::BaseField::rand(rng);
99 let greatest = rng.gen();
100
101 if let Some(p) = Affine::get_point_from_u_unchecked(u, greatest) {
102 return p.into();
103 }
104 }
105 }
106}
107
108impl<P: DOCurveConfig> Default for Projective<P> {
109 #[inline]
110 fn default() -> Self {
111 Self::zero()
112 }
113}
114
115impl<P: DOCurveConfig> Projective<P> {
116 pub const fn new_unchecked(
119 e: P::BaseField,
120 z: P::BaseField,
121 u: P::BaseField,
122 t: P::BaseField,
123 ) -> Self {
124 Self { e, z, u, t }
125 }
126
127 pub fn new(e: P::BaseField, z: P::BaseField, u: P::BaseField, t: P::BaseField) -> Self {
130 let p = Self::new_unchecked(e, z, u, t);
131 assert!(p.into_affine().is_on_curve(), "not_on_curve");
132 p
133 }
134}
135
136impl<P: DOCurveConfig> Zeroize for Projective<P> {
137 fn zeroize(&mut self) {
138 self.e.zeroize();
139 self.u.zeroize();
140 self.z.zeroize();
141 self.t.zeroize();
142 }
143}
144
145impl<P: DOCurveConfig> Zero for Projective<P> {
146 #[inline]
151 fn zero() -> Self {
152 Self::new_unchecked(
153 P::BaseField::ONE,
154 P::BaseField::ONE,
155 P::BaseField::ZERO,
156 P::BaseField::ZERO,
157 )
158 }
159
160 #[inline]
161 fn is_zero(&self) -> bool {
165 self.u == P::BaseField::ZERO
166 }
167}
168
169impl<P: DOCurveConfig> AdditiveGroup for Projective<P> {
170 type Scalar = P::ScalarField;
171
172 const ZERO: Self = Self::new_unchecked(
173 P::BaseField::ONE,
174 P::BaseField::ONE,
175 P::BaseField::ZERO,
176 P::BaseField::ZERO,
177 );
178
179 fn double_in_place(&mut self) -> &mut Self {
183 self.z = -P::get_c().double() * self.t.square(); self.t = self.e;
185 self.e.square_in_place(); self.z += self.e; self.z += (P::COEFF_A * self.u.square()).double(); self.t *= self.u;
190 self.t.double_in_place(); self.u = self.t; self.t.square_in_place(); self.u *= self.z; self.z.square_in_place(); self.e.square_in_place(); self.e.double_in_place(); self.e += -self.z + (P::COEFF_A * self.t); self
203 }
204}
205
206impl<P: DOCurveConfig> PrimeGroup for Projective<P> {
207 type ScalarField = P::ScalarField;
208
209 #[inline]
210 fn generator() -> Self {
211 Affine::generator().into()
212 }
213
214 #[inline]
215 fn mul_bigint(&self, other: impl AsRef<[u64]>) -> Self {
216 P::mul_projective(self, other.as_ref())
217 }
218}
219
220impl<P: DOCurveConfig> CurveGroup for Projective<P> {
221 type Config = P;
222 type BaseField = P::BaseField;
223 type Affine = Affine<P>;
224 type FullGroup = Affine<P>;
225
226 #[inline]
227 fn normalize_batch(v: &[Self]) -> Vec<Self::Affine> {
228 let mut z_s = v.iter().map(|g| g.z).collect::<Vec<_>>();
229 ark_ff::batch_inversion(&mut z_s);
230
231 ark_std::cfg_iter!(v)
233 .zip(z_s)
234 .map(|(g, z)| match g.is_zero() {
235 true => Affine::identity(),
236 false => {
237 let e = g.e * z;
238 let u = g.u * z;
239
240 Affine::new_unchecked(e, u)
241 },
242 })
243 .collect()
244 }
245}
246
247impl<P: DOCurveConfig> Neg for Projective<P> {
248 type Output = Self;
249
250 #[inline]
251 fn neg(mut self) -> Self {
252 self.u = -self.u;
253 self
254 }
255}
256
257impl<P: DOCurveConfig, T: Borrow<Affine<P>>> AddAssign<T> for Projective<P> {
258 fn add_assign(&mut self, other: T) {
262 let other = other.borrow();
263 let othert = other.u.square();
264 let n1 = self.e * other.e;
265 let n2 = self.z;
266 let n3 = self.u * other.u;
267 let n4 = self.t * othert;
268
269 let n5 = self.z * othert + self.t;
270 let n6 = (self.e + self.u) * (other.e + other.u) - n1 - n3;
271 let c = P::get_c();
272 let cn4 = c * n4;
273 let n7 = n2 - cn4;
274
275 let n3d = n3.double();
276
277 self.e = (n2 + cn4) * (n1 - P::COEFF_A * n3d) + c * n3d * n5;
278 self.z = n7.square();
279 self.t = n6.square();
280 self.u = n7 * n6;
281 }
282}
283
284impl<P: DOCurveConfig, T: Borrow<Affine<P>>> Add<T> for Projective<P> {
285 type Output = Self;
286 fn add(mut self, other: T) -> Self {
287 let other = other.borrow();
288 self += other;
289 self
290 }
291}
292
293impl<P: DOCurveConfig, T: Borrow<Affine<P>>> SubAssign<T> for Projective<P> {
294 fn sub_assign(&mut self, other: T) {
295 *self += -(*other.borrow());
296 }
297}
298
299impl<P: DOCurveConfig, T: Borrow<Affine<P>>> Sub<T> for Projective<P> {
300 type Output = Self;
301 fn sub(mut self, other: T) -> Self {
302 self -= other.borrow();
303 self
304 }
305}
306
307ark_ff::impl_additive_ops_from_ref!(Projective, DOCurveConfig);
308
309impl<'a, P: DOCurveConfig> Add<&'a Self> for Projective<P> {
310 type Output = Self;
311
312 #[inline]
313 fn add(mut self, other: &'a Self) -> Self {
314 self += other;
315 self
316 }
317}
318
319impl<'a, P: DOCurveConfig> AddAssign<&'a Self> for Projective<P> {
320 fn add_assign(&mut self, other: &'a Self) {
322 if self.is_zero() {
323 *self = *other;
324 return;
325 }
326
327 if other.is_zero() {
328 return;
329 }
330
331 let n1 = self.e * other.e;
332 let n2 = self.z * other.z;
333 let n3 = self.u * other.u;
334 let n4 = self.t * other.t;
335
336 let n5 = (self.z + self.t) * (other.z + other.t) - n2 - n4;
337 self.t = (self.e + self.u) * (other.e + other.u) - n1 - n3;
338 let c = P::get_c();
339 let cn4 = c * n4;
340 self.z = n2 - cn4;
341
342 let n3d = n3.double();
343
344 self.e = (n2 + cn4) * (n1 - P::COEFF_A * n3d) + c * n3d * n5;
345 self.u = self.z * self.t;
346 self.z.square_in_place();
347 self.t.square_in_place();
348 }
349}
350
351impl<'a, P: DOCurveConfig> Sub<&'a Self> for Projective<P> {
352 type Output = Self;
353
354 #[inline]
355 fn sub(mut self, other: &'a Self) -> Self {
356 self -= other;
357 self
358 }
359}
360
361impl<'a, P: DOCurveConfig> SubAssign<&'a Self> for Projective<P> {
362 fn sub_assign(&mut self, other: &'a Self) {
363 *self += &(-(*other));
364 }
365}
366
367impl<P: DOCurveConfig, T: Borrow<P::ScalarField>> MulAssign<T> for Projective<P> {
368 fn mul_assign(&mut self, other: T) {
369 *self = self.mul_bigint(other.borrow().into_bigint())
370 }
371}
372
373impl<P: DOCurveConfig, T: Borrow<P::ScalarField>> Mul<T> for Projective<P> {
374 type Output = Self;
375
376 #[inline]
377 fn mul(mut self, other: T) -> Self {
378 self *= other;
379 self
380 }
381}
382
383impl<P: DOCurveConfig> From<Affine<P>> for Projective<P> {
384 #[inline]
385 fn from(p: Affine<P>) -> Self {
386 let u = p.u;
387 let e = p.e;
388 let z = P::BaseField::ONE;
389 let t = u.square();
390
391 Self::new_unchecked(e, z, u, t)
392 }
393}
394
395impl<P: DOCurveConfig> CanonicalSerialize for Projective<P> {
396 #[inline]
397 fn serialize_with_mode<W: Write>(
398 &self,
399 writer: W,
400 compress: Compress,
401 ) -> Result<(), SerializationError> {
402 let aff = Affine::<P>::from(*self);
403 P::serialize_with_mode(&aff, writer, compress)
404 }
405
406 #[inline]
407 fn serialized_size(&self, compress: Compress) -> usize {
408 P::serialized_size(compress)
409 }
410}
411
412impl<P: DOCurveConfig> Valid for Projective<P> {
413 fn check(&self) -> Result<(), SerializationError> {
414 self.into_affine().check()
415 }
416
417 fn batch_check<'a>(
418 batch: impl Iterator<Item = &'a Self> + Send,
419 ) -> Result<(), SerializationError>
420 where
421 Self: 'a,
422 {
423 let batch = batch.copied().collect::<Vec<_>>();
424 let batch = Self::normalize_batch(&batch);
425 Affine::batch_check(batch.iter())
426 }
427}
428
429impl<P: DOCurveConfig> CanonicalDeserialize for Projective<P> {
430 fn deserialize_with_mode<R: Read>(
431 reader: R,
432 compress: Compress,
433 validate: Validate,
434 ) -> Result<Self, SerializationError> {
435 let aff = P::deserialize_with_mode(reader, compress, validate)?;
436 Ok(aff.into())
437 }
438}
439
440impl<M: DOCurveConfig, ConstraintF: Field> ToConstraintField<ConstraintF> for Projective<M>
441where
442 M::BaseField: ToConstraintField<ConstraintF>,
443{
444 #[inline]
445 fn to_field_elements(&self) -> Option<Vec<ConstraintF>> {
446 Affine::from(*self).to_field_elements()
447 }
448}
449
450impl<P: DOCurveConfig> ScalarMul for Projective<P> {
451 type MulBase = Affine<P>;
452 const NEGATION_IS_CHEAP: bool = true;
453
454 fn batch_convert_to_mul_base(bases: &[Self]) -> Vec<Self::MulBase> {
455 Self::normalize_batch(bases)
456 }
457}
458
459impl<P: DOCurveConfig> VariableBaseMSM for Projective<P> {
460 type Bucket = Self;
461 const ZERO_BUCKET: Self = Self::ZERO;
462
463 fn msm(bases: &[Self::MulBase], bigints: &[Self::ScalarField]) -> Result<Self, usize> {
464 P::msm(bases, bigints)
465 }
466}
467
468impl<P: DOCurveConfig, T: Borrow<Affine<P>>> core::iter::Sum<T> for Projective<P> {
469 fn sum<I: Iterator<Item = T>>(iter: I) -> Self {
470 iter.fold(Self::zero(), |sum, x| sum + x.borrow())
471 }
472}