snarkvm_curves/templates/twisted_edwards_extended/
projective.rs1use crate::{
17 templates::twisted_edwards_extended::Affine,
18 traits::{AffineCurve, ProjectiveCurve, TwistedEdwardsParameters as Parameters},
19};
20use snarkvm_fields::{Field, One, PrimeField, Zero, impl_add_sub_from_field_ref};
21use snarkvm_utilities::{FromBytes, ToBytes, bititerator::BitIteratorBE, rand::Uniform};
22
23use core::{
24 fmt::{Display, Formatter, Result as FmtResult},
25 hash::{Hash, Hasher},
26 ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign},
27};
28use rand::{
29 Rng,
30 distributions::{Distribution, Standard},
31};
32use std::io::{Read, Result as IoResult, Write};
33
34#[derive(Copy, Clone, Debug)]
35pub struct Projective<P: Parameters> {
36 pub x: P::BaseField,
37 pub y: P::BaseField,
38 pub t: P::BaseField,
39 pub z: P::BaseField,
40}
41
42impl<P: Parameters> Projective<P> {
43 #[inline]
44 pub const fn new(x: P::BaseField, y: P::BaseField, t: P::BaseField, z: P::BaseField) -> Self {
45 Self { x, y, t, z }
46 }
47}
48
49impl<P: Parameters> Zero for Projective<P> {
50 fn zero() -> Self {
51 Self::new(P::BaseField::zero(), P::BaseField::one(), P::BaseField::zero(), P::BaseField::one())
52 }
53
54 fn is_zero(&self) -> bool {
55 self.x.is_zero() && self.y == self.z && !self.y.is_zero() && self.t.is_zero()
56 }
57}
58
59impl<P: Parameters> Default for Projective<P> {
60 #[inline]
61 fn default() -> Self {
62 Self::zero()
63 }
64}
65
66impl<P: Parameters> Display for Projective<P> {
67 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
68 write!(f, "{}", self.to_affine())
69 }
70}
71
72impl<P: Parameters> Hash for Projective<P> {
73 fn hash<H: Hasher>(&self, state: &mut H) {
74 self.to_affine().hash(state);
75 }
76}
77
78impl<P: Parameters> Eq for Projective<P> {}
79
80impl<P: Parameters> PartialEq for Projective<P> {
81 fn eq(&self, other: &Self) -> bool {
82 if self.is_zero() {
83 return other.is_zero();
84 }
85
86 if other.is_zero() {
87 return false;
88 }
89
90 (self.x * other.z) == (other.x * self.z) && (self.y * other.z) == (other.y * self.z)
92 }
93}
94
95impl<P: Parameters> PartialEq<Affine<P>> for Projective<P> {
96 fn eq(&self, other: &Affine<P>) -> bool {
97 if self.is_zero() {
98 return other.is_zero();
99 }
100
101 if other.is_zero() {
102 return false;
103 }
104
105 self.x == (other.x * self.z) && self.y == (other.y * self.z)
107 }
108}
109
110impl<P: Parameters> Distribution<Projective<P>> for Standard {
111 #[inline]
112 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Projective<P> {
113 loop {
114 let x = P::BaseField::rand(rng);
115 let greatest = rng.r#gen();
116
117 if let Some(p) = Affine::from_x_coordinate(x, greatest) {
118 return p.mul_by_cofactor_to_projective();
119 }
120 }
121 }
122}
123
124impl<P: Parameters> ToBytes for Projective<P> {
125 #[inline]
126 fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
127 self.x.write_le(&mut writer)?;
128 self.y.write_le(&mut writer)?;
129 self.t.write_le(&mut writer)?;
130 self.z.write_le(writer)
131 }
132}
133
134impl<P: Parameters> FromBytes for Projective<P> {
135 #[inline]
136 fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
137 let x = P::BaseField::read_le(&mut reader)?;
138 let y = P::BaseField::read_le(&mut reader)?;
139 let t = P::BaseField::read_le(&mut reader)?;
140 let z = P::BaseField::read_le(reader)?;
141 Ok(Self::new(x, y, t, z))
142 }
143}
144
145impl<P: Parameters> ProjectiveCurve for Projective<P> {
146 type Affine = Affine<P>;
147 type BaseField = P::BaseField;
148 type ScalarField = P::ScalarField;
149
150 fn prime_subgroup_generator() -> Self {
151 Affine::prime_subgroup_generator().into()
152 }
153
154 fn is_normalized(&self) -> bool {
155 self.z.is_one()
156 }
157
158 fn batch_normalization(v: &mut [Self]) {
159 let mut prod = Vec::with_capacity(v.len());
165 let mut tmp = P::BaseField::one();
166 for g in v
167 .iter_mut()
168 .filter(|g| !g.is_normalized())
170 {
171 tmp.mul_assign(&g.z);
172 prod.push(tmp);
173 }
174
175 tmp = tmp.inverse().unwrap(); for (g, s) in v
180 .iter_mut()
181 .rev()
183 .filter(|g| !g.is_normalized())
185 .zip(
187 prod.into_iter()
188 .rev()
189 .skip(1)
190 .chain(Some(P::BaseField::one())),
191 )
192 {
193 let newtmp = tmp * g.z;
195 g.z = tmp * s;
196 tmp = newtmp;
197 }
198
199 for g in v.iter_mut().filter(|g| !g.is_normalized()) {
201 g.x *= &g.z; g.y *= &g.z;
203 g.t *= &g.z;
204 g.z = P::BaseField::one(); }
206 }
207
208 #[allow(clippy::many_single_char_names)]
209 fn add_assign_mixed(&mut self, other: &Self::Affine) {
210 let a = self.x * other.x;
212 let b = self.y * other.y;
214 let c = P::EDWARDS_D * self.t * other.t;
216 let d = self.z;
218 let e = (self.x + self.y) * (other.x + other.y) - a - b;
220 let f = d - c;
222 let g = d + c;
224 let h = b - P::mul_by_a(&a);
226 self.x = e * f;
228 self.y = g * h;
230 self.t = e * h;
232 self.z = f * g;
234 }
235
236 #[inline]
237 fn double(&self) -> Self {
238 let mut result = *self;
239 result.double_in_place();
240 result
241 }
242
243 #[inline]
244 fn double_in_place(&mut self) {
245 let a = self.x.square();
252 let b = self.y.square();
254 let c = self.z.square().double();
256 let d = P::mul_by_a(&a);
258 let e = (self.x + self.y).square() - a - b;
260 let g = d + b;
262 let f = g - c;
264 let h = d - b;
266 self.x = e * f;
268 self.y = g * h;
270 self.t = e * h;
272 self.z = f * g;
274 }
275
276 fn to_affine(&self) -> Affine<P> {
277 (*self).into()
278 }
279}
280
281impl<P: Parameters> Neg for Projective<P> {
282 type Output = Self;
283
284 fn neg(mut self) -> Self {
285 self.x = -self.x;
286 self.t = -self.t;
287 self
288 }
289}
290
291impl_add_sub_from_field_ref!(Projective, Parameters);
292
293impl<'a, P: Parameters> Add<&'a Self> for Projective<P> {
294 type Output = Self;
295
296 fn add(self, other: &'a Self) -> Self {
297 let mut copy = self;
298 copy += other;
299 copy
300 }
301}
302
303impl<'a, P: Parameters> AddAssign<&'a Self> for Projective<P> {
304 #[allow(clippy::many_single_char_names)]
305 #[allow(clippy::suspicious_op_assign_impl)]
306 fn add_assign(&mut self, other: &'a Self) {
307 let a = self.x * other.x;
313
314 let b = self.y * other.y;
316
317 let c = P::EDWARDS_D * self.t * other.t;
319
320 let d = self.z * other.z;
322
323 let h = b - P::mul_by_a(&a);
325
326 let e = (self.x + self.y) * (other.x + other.y) - a - b;
328
329 let f = d - c;
331
332 let g = d + c;
334
335 self.x = e * f;
337
338 self.y = g * h;
340
341 self.t = e * h;
343
344 self.z = f * g;
346 }
347}
348
349impl<'a, P: Parameters> Sub<&'a Self> for Projective<P> {
350 type Output = Self;
351
352 fn sub(self, other: &'a Self) -> Self {
353 let mut copy = self;
354 copy -= other;
355 copy
356 }
357}
358
359impl<'a, P: Parameters> SubAssign<&'a Self> for Projective<P> {
360 fn sub_assign(&mut self, other: &'a Self) {
361 *self += &(-(*other));
362 }
363}
364
365impl<P: Parameters> Mul<P::ScalarField> for Projective<P> {
366 type Output = Self;
367
368 #[allow(clippy::suspicious_arithmetic_impl)]
370 #[inline]
371 fn mul(self, other: P::ScalarField) -> Self {
372 let mut res = Self::zero();
373
374 let mut found_one = false;
375
376 for i in BitIteratorBE::new(other.to_bigint()) {
377 if found_one {
378 res.double_in_place();
379 } else {
380 found_one = i;
381 }
382
383 if i {
384 res += self;
385 }
386 }
387
388 res
389 }
390}
391
392impl<P: Parameters> MulAssign<P::ScalarField> for Projective<P> {
393 fn mul_assign(&mut self, other: P::ScalarField) {
395 *self = *self * other
396 }
397}
398
399impl<P: Parameters> From<Affine<P>> for Projective<P> {
401 fn from(p: Affine<P>) -> Projective<P> {
402 Self::new(p.x, p.y, p.x * p.y, P::BaseField::one())
403 }
404}