pasta_curves/
curves.rs

1//! This module contains implementations for the Pallas and Vesta elliptic curve
2//! groups.
3
4use core::cmp;
5use core::fmt;
6use core::iter::Sum;
7use core::ops::{Add, Mul, Neg, Sub};
8
9#[cfg(feature = "alloc")]
10use alloc::boxed::Box;
11
12use ff::{Field, PrimeField};
13use group::{
14    cofactor::{CofactorCurve, CofactorGroup},
15    prime::{PrimeCurve, PrimeCurveAffine, PrimeGroup},
16    Curve as _, Group as _, GroupEncoding,
17};
18use rand::RngCore;
19use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
20
21#[cfg(feature = "alloc")]
22use ff::WithSmallOrderMulGroup;
23
24use super::{Fp, Fq};
25
26#[cfg(feature = "alloc")]
27use crate::arithmetic::{Coordinates, CurveAffine, CurveExt};
28
29macro_rules! new_curve_impl {
30    (($($privacy:tt)*), $name:ident, $name_affine:ident, $iso:ident, $base:ident, $scalar:ident,
31     $curve_id:literal, $a_raw:expr, $b_raw:expr, $curve_type:ident) => {
32        /// Represents a point in the projective coordinate space.
33        #[derive(Copy, Clone, Debug)]
34        #[cfg_attr(feature = "repr-c", repr(C))]
35        $($privacy)* struct $name {
36            x: $base,
37            y: $base,
38            z: $base,
39        }
40
41        impl $name {
42            const fn curve_constant_a() -> $base {
43                $base::from_raw($a_raw)
44            }
45
46            const fn curve_constant_b() -> $base {
47                $base::from_raw($b_raw)
48            }
49        }
50
51        /// Represents a point in the affine coordinate space (or the point at
52        /// infinity).
53        #[derive(Copy, Clone)]
54        #[cfg_attr(feature = "repr-c", repr(C))]
55        $($privacy)* struct $name_affine {
56            x: $base,
57            y: $base,
58        }
59
60        impl fmt::Debug for $name_affine {
61            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
62                if self.is_identity().into() {
63                    write!(f, "Infinity")
64                } else {
65                    write!(f, "({:?}, {:?})", self.x, self.y)
66                }
67            }
68        }
69
70        impl group::Group for $name {
71            type Scalar = $scalar;
72
73            fn random(mut rng: impl RngCore) -> Self {
74                loop {
75                    let x = $base::random(&mut rng);
76                    let ysign = (rng.next_u32() % 2) as u8;
77
78                    let x3 = x.square() * x;
79                    let y = (x3 + $name::curve_constant_b()).sqrt();
80                    if let Some(y) = Option::<$base>::from(y) {
81                        let sign = y.is_odd().unwrap_u8();
82                        let y = if ysign ^ sign == 0 { y } else { -y };
83
84                        let p = $name_affine {
85                            x,
86                            y,
87                        };
88                        break p.to_curve();
89                    }
90                }
91            }
92
93            impl_projective_curve_specific!($name, $base, $curve_type);
94
95            fn identity() -> Self {
96                Self {
97                    x: $base::zero(),
98                    y: $base::zero(),
99                    z: $base::zero(),
100                }
101            }
102
103            fn is_identity(&self) -> Choice {
104                self.z.is_zero()
105            }
106        }
107
108        #[cfg(feature = "alloc")]
109        #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
110        impl group::WnafGroup for $name {
111            fn recommended_wnaf_for_num_scalars(num_scalars: usize) -> usize {
112                // Copied from bls12_381::g1, should be updated.
113                const RECOMMENDATIONS: [usize; 12] =
114                    [1, 3, 7, 20, 43, 120, 273, 563, 1630, 3128, 7933, 62569];
115
116                let mut ret = 4;
117                for r in &RECOMMENDATIONS {
118                    if num_scalars > *r {
119                        ret += 1;
120                    } else {
121                        break;
122                    }
123                }
124
125                ret
126            }
127        }
128
129        #[cfg(feature = "alloc")]
130        #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
131        impl CurveExt for $name {
132            type ScalarExt = $scalar;
133            type Base = $base;
134            type AffineExt = $name_affine;
135
136            const CURVE_ID: &'static str = $curve_id;
137
138            impl_projective_curve_ext!($name, $iso, $base, $curve_type);
139
140            fn a() -> Self::Base {
141                $name::curve_constant_a()
142            }
143
144            fn b() -> Self::Base {
145                $name::curve_constant_b()
146            }
147
148            fn new_jacobian(x: Self::Base, y: Self::Base, z: Self::Base) -> CtOption<Self> {
149                let p = $name { x, y, z };
150                CtOption::new(p, p.is_on_curve())
151            }
152
153            fn jacobian_coordinates(&self) -> ($base, $base, $base) {
154               (self.x, self.y, self.z)
155            }
156
157            fn is_on_curve(&self) -> Choice {
158                // Y^2 = X^3 + AX(Z^4) + b(Z^6)
159                // Y^2 - (X^2 + A(Z^4))X = b(Z^6)
160
161                let z2 = self.z.square();
162                let z4 = z2.square();
163                let z6 = z4 * z2;
164                (self.y.square() - (self.x.square() + $name::curve_constant_a() * z4) * self.x)
165                    .ct_eq(&(z6 * $name::curve_constant_b()))
166                    | self.z.is_zero()
167            }
168        }
169
170        impl group::Curve for $name {
171            type AffineRepr = $name_affine;
172
173            fn batch_normalize(p: &[Self], q: &mut [Self::AffineRepr]) {
174                assert_eq!(p.len(), q.len());
175
176                let mut acc = $base::one();
177                for (p, q) in p.iter().zip(q.iter_mut()) {
178                    // We use the `x` field of $name_affine to store the product
179                    // of previous z-coordinates seen.
180                    q.x = acc;
181
182                    // We will end up skipping all identities in p
183                    acc = $base::conditional_select(&(acc * p.z), &acc, p.is_identity());
184                }
185
186                // This is the inverse, as all z-coordinates are nonzero and the ones
187                // that are not are skipped.
188                acc = acc.invert().unwrap();
189
190                for (p, q) in p.iter().rev().zip(q.iter_mut().rev()) {
191                    let skip = p.is_identity();
192
193                    // Compute tmp = 1/z
194                    let tmp = q.x * acc;
195
196                    // Cancel out z-coordinate in denominator of `acc`
197                    acc = $base::conditional_select(&(acc * p.z), &acc, skip);
198
199                    // Set the coordinates to the correct value
200                    let tmp2 = tmp.square();
201                    let tmp3 = tmp2 * tmp;
202
203                    q.x = p.x * tmp2;
204                    q.y = p.y * tmp3;
205
206                    *q = $name_affine::conditional_select(&q, &$name_affine::identity(), skip);
207                }
208            }
209
210            fn to_affine(&self) -> Self::AffineRepr {
211                let zinv = self.z.invert().unwrap_or($base::zero());
212                let zinv2 = zinv.square();
213                let x = self.x * zinv2;
214                let zinv3 = zinv2 * zinv;
215                let y = self.y * zinv3;
216
217                let tmp = $name_affine {
218                    x,
219                    y,
220                };
221
222                $name_affine::conditional_select(&tmp, &$name_affine::identity(), zinv.is_zero())
223            }
224        }
225
226        impl PrimeGroup for $name {}
227
228        impl CofactorGroup for $name {
229            type Subgroup = $name;
230
231            fn clear_cofactor(&self) -> Self {
232                // This is a prime-order group, with a cofactor of 1.
233                *self
234            }
235
236            fn into_subgroup(self) -> CtOption<Self::Subgroup> {
237                // Nothing to do here.
238                CtOption::new(self, 1.into())
239            }
240
241            fn is_torsion_free(&self) -> Choice {
242                // Shortcut: all points in a prime-order group are torsion free.
243                1.into()
244            }
245        }
246
247        impl PrimeCurve for $name {
248            type Affine = $name_affine;
249        }
250
251        impl CofactorCurve for $name {
252            type Affine = $name_affine;
253        }
254
255        impl GroupEncoding for $name {
256            type Repr = [u8; 32];
257
258            fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
259                $name_affine::from_bytes(bytes).map(Self::from)
260            }
261
262            fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
263                // We can't avoid curve checks when parsing a compressed encoding.
264                $name_affine::from_bytes(bytes).map(Self::from)
265            }
266
267            fn to_bytes(&self) -> Self::Repr {
268                $name_affine::from(self).to_bytes()
269            }
270        }
271
272        impl<'a> From<&'a $name_affine> for $name {
273            fn from(p: &'a $name_affine) -> $name {
274                p.to_curve()
275            }
276        }
277
278        impl From<$name_affine> for $name {
279            fn from(p: $name_affine) -> $name {
280                p.to_curve()
281            }
282        }
283
284        impl Default for $name {
285            fn default() -> $name {
286                $name::identity()
287            }
288        }
289
290        impl ConstantTimeEq for $name {
291            fn ct_eq(&self, other: &Self) -> Choice {
292                // Is (xz^2, yz^3, z) equal to (x'z'^2, yz'^3, z') when converted to affine?
293
294                let z = other.z.square();
295                let x1 = self.x * z;
296                let z = z * other.z;
297                let y1 = self.y * z;
298                let z = self.z.square();
299                let x2 = other.x * z;
300                let z = z * self.z;
301                let y2 = other.y * z;
302
303                let self_is_zero = self.is_identity();
304                let other_is_zero = other.is_identity();
305
306                (self_is_zero & other_is_zero) // Both point at infinity
307                            | ((!self_is_zero) & (!other_is_zero) & x1.ct_eq(&x2) & y1.ct_eq(&y2))
308                // Neither point at infinity, coordinates are the same
309            }
310        }
311
312        impl PartialEq for $name {
313            fn eq(&self, other: &Self) -> bool {
314                self.ct_eq(other).into()
315            }
316        }
317
318        impl cmp::Eq for $name {}
319
320        impl ConditionallySelectable for $name {
321            fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
322                $name {
323                    x: $base::conditional_select(&a.x, &b.x, choice),
324                    y: $base::conditional_select(&a.y, &b.y, choice),
325                    z: $base::conditional_select(&a.z, &b.z, choice),
326                }
327            }
328        }
329
330        impl<'a> Neg for &'a $name {
331            type Output = $name;
332
333            fn neg(self) -> $name {
334                $name {
335                    x: self.x,
336                    y: -self.y,
337                    z: self.z,
338                }
339            }
340        }
341
342        impl Neg for $name {
343            type Output = $name;
344
345            fn neg(self) -> $name {
346                -&self
347            }
348        }
349
350        impl<T> Sum<T> for $name
351        where
352            T: core::borrow::Borrow<$name>,
353        {
354            fn sum<I>(iter: I) -> Self
355            where
356                I: Iterator<Item = T>,
357            {
358                iter.fold(Self::identity(), |acc, item| acc + item.borrow())
359            }
360        }
361
362        impl<'a, 'b> Add<&'a $name> for &'b $name {
363            type Output = $name;
364
365            fn add(self, rhs: &'a $name) -> $name {
366                if bool::from(self.is_identity()) {
367                    *rhs
368                } else if bool::from(rhs.is_identity()) {
369                    *self
370                } else {
371                    let z1z1 = self.z.square();
372                    let z2z2 = rhs.z.square();
373                    let u1 = self.x * z2z2;
374                    let u2 = rhs.x * z1z1;
375                    let s1 = self.y * z2z2 * rhs.z;
376                    let s2 = rhs.y * z1z1 * self.z;
377
378                    if u1 == u2 {
379                        if s1 == s2 {
380                            self.double()
381                        } else {
382                            $name::identity()
383                        }
384                    } else {
385                        let h = u2 - u1;
386                        let i = (h + h).square();
387                        let j = h * i;
388                        let r = s2 - s1;
389                        let r = r + r;
390                        let v = u1 * i;
391                        let x3 = r.square() - j - v - v;
392                        let s1 = s1 * j;
393                        let s1 = s1 + s1;
394                        let y3 = r * (v - x3) - s1;
395                        let z3 = (self.z + rhs.z).square() - z1z1 - z2z2;
396                        let z3 = z3 * h;
397
398                        $name {
399                            x: x3, y: y3, z: z3
400                        }
401                    }
402                }
403            }
404        }
405
406        impl<'a, 'b> Add<&'a $name_affine> for &'b $name {
407            type Output = $name;
408
409            fn add(self, rhs: &'a $name_affine) -> $name {
410                if bool::from(self.is_identity()) {
411                    rhs.to_curve()
412                } else if bool::from(rhs.is_identity()) {
413                    *self
414                } else {
415                    let z1z1 = self.z.square();
416                    let u2 = rhs.x * z1z1;
417                    let s2 = rhs.y * z1z1 * self.z;
418
419                    if self.x == u2 {
420                        if self.y == s2 {
421                            self.double()
422                        } else {
423                            $name::identity()
424                        }
425                    } else {
426                        let h = u2 - self.x;
427                        let hh = h.square();
428                        let i = hh + hh;
429                        let i = i + i;
430                        let j = h * i;
431                        let r = s2 - self.y;
432                        let r = r + r;
433                        let v = self.x * i;
434                        let x3 = r.square() - j - v - v;
435                        let j = self.y * j;
436                        let j = j + j;
437                        let y3 = r * (v - x3) - j;
438                        let z3 = (self.z + h).square() - z1z1 - hh;
439
440                        $name {
441                            x: x3, y: y3, z: z3
442                        }
443                    }
444                }
445            }
446        }
447
448        impl<'a, 'b> Sub<&'a $name> for &'b $name {
449            type Output = $name;
450
451            fn sub(self, other: &'a $name) -> $name {
452                self + (-other)
453            }
454        }
455
456        impl<'a, 'b> Sub<&'a $name_affine> for &'b $name {
457            type Output = $name;
458
459            fn sub(self, other: &'a $name_affine) -> $name {
460                self + (-other)
461            }
462        }
463
464        #[allow(clippy::suspicious_arithmetic_impl)]
465        impl<'a, 'b> Mul<&'b $scalar> for &'a $name {
466            type Output = $name;
467
468            fn mul(self, other: &'b $scalar) -> Self::Output {
469                // TODO: make this faster
470
471                let mut acc = $name::identity();
472
473                // This is a simple double-and-add implementation of point
474                // multiplication, moving from most significant to least
475                // significant bit of the scalar.
476                //
477                // We don't use `PrimeFieldBits::.to_le_bits` here, because that would
478                // force users of this crate to depend on `bitvec` where they otherwise
479                // might not need to.
480                //
481                // NOTE: We skip the leading bit because it's always unset (we are turning
482                // the 32-byte repr into 256 bits, and $scalar::NUM_BITS = 255).
483                for bit in other
484                    .to_repr()
485                    .iter()
486                    .rev()
487                    .flat_map(|byte| (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8)))
488                    .skip(1)
489                {
490                    acc = acc.double();
491                    acc = $name::conditional_select(&acc, &(acc + self), bit);
492                }
493
494                acc
495            }
496        }
497
498        impl<'a> Neg for &'a $name_affine {
499            type Output = $name_affine;
500
501            fn neg(self) -> $name_affine {
502                $name_affine {
503                    x: self.x,
504                    y: -self.y,
505                }
506            }
507        }
508
509        impl Neg for $name_affine {
510            type Output = $name_affine;
511
512            fn neg(self) -> $name_affine {
513                -&self
514            }
515        }
516
517        impl<'a, 'b> Add<&'a $name> for &'b $name_affine {
518            type Output = $name;
519
520            fn add(self, rhs: &'a $name) -> $name {
521                rhs + self
522            }
523        }
524
525        impl<'a, 'b> Add<&'a $name_affine> for &'b $name_affine {
526            type Output = $name;
527
528            fn add(self, rhs: &'a $name_affine) -> $name {
529                if bool::from(self.is_identity()) {
530                    rhs.to_curve()
531                } else if bool::from(rhs.is_identity()) {
532                    self.to_curve()
533                } else {
534                    if self.x == rhs.x {
535                        if self.y == rhs.y {
536                            self.to_curve().double()
537                        } else {
538                            $name::identity()
539                        }
540                    } else {
541                        let h = rhs.x - self.x;
542                        let hh = h.square();
543                        let i = hh + hh;
544                        let i = i + i;
545                        let j = h * i;
546                        let r = rhs.y - self.y;
547                        let r = r + r;
548                        let v = self.x * i;
549                        let x3 = r.square() - j - v - v;
550                        let j = self.y * j;
551                        let j = j + j;
552                        let y3 = r * (v - x3) - j;
553                        let z3 = h + h;
554
555                        $name {
556                            x: x3, y: y3, z: z3
557                        }
558                    }
559                }
560            }
561        }
562
563        impl<'a, 'b> Sub<&'a $name_affine> for &'b $name_affine {
564            type Output = $name;
565
566            fn sub(self, other: &'a $name_affine) -> $name {
567                self + (-other)
568            }
569        }
570
571        impl<'a, 'b> Sub<&'a $name> for &'b $name_affine {
572            type Output = $name;
573
574            fn sub(self, other: &'a $name) -> $name {
575                self + (-other)
576            }
577        }
578
579        #[allow(clippy::suspicious_arithmetic_impl)]
580        impl<'a, 'b> Mul<&'b $scalar> for &'a $name_affine {
581            type Output = $name;
582
583            fn mul(self, other: &'b $scalar) -> Self::Output {
584                // TODO: make this faster
585
586                let mut acc = $name::identity();
587
588                // This is a simple double-and-add implementation of point
589                // multiplication, moving from most significant to least
590                // significant bit of the scalar.
591                //
592                // We don't use `PrimeFieldBits::.to_le_bits` here, because that would
593                // force users of this crate to depend on `bitvec` where they otherwise
594                // might not need to.
595                //
596                // NOTE: We skip the leading bit because it's always unset (we are turning
597                // the 32-byte repr into 256 bits, and $scalar::NUM_BITS = 255).
598                for bit in other
599                    .to_repr()
600                    .iter()
601                    .rev()
602                    .flat_map(|byte| (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8)))
603                    .skip(1)
604                {
605                    acc = acc.double();
606                    acc = $name::conditional_select(&acc, &(acc + self), bit);
607                }
608
609                acc
610            }
611        }
612
613        impl PrimeCurveAffine for $name_affine {
614            type Curve = $name;
615            type Scalar = $scalar;
616
617            impl_affine_curve_specific!($name, $base, $curve_type);
618
619            fn identity() -> Self {
620                Self {
621                    x: $base::zero(),
622                    y: $base::zero(),
623                }
624            }
625
626            fn is_identity(&self) -> Choice {
627                self.x.is_zero() & self.y.is_zero()
628            }
629
630            fn to_curve(&self) -> Self::Curve {
631                $name {
632                    x: self.x,
633                    y: self.y,
634                    z: $base::conditional_select(&$base::one(), &$base::zero(), self.is_identity()),
635                }
636            }
637        }
638
639        impl group::cofactor::CofactorCurveAffine for $name_affine {
640            type Curve = $name;
641            type Scalar = $scalar;
642
643            fn identity() -> Self {
644                <Self as PrimeCurveAffine>::identity()
645            }
646
647            fn generator() -> Self {
648                <Self as PrimeCurveAffine>::generator()
649            }
650
651            fn is_identity(&self) -> Choice {
652                <Self as PrimeCurveAffine>::is_identity(self)
653            }
654
655            fn to_curve(&self) -> Self::Curve {
656                <Self as PrimeCurveAffine>::to_curve(self)
657            }
658        }
659
660        impl GroupEncoding for $name_affine {
661            type Repr = [u8; 32];
662
663            fn from_bytes(bytes: &[u8; 32]) -> CtOption<Self> {
664                let mut tmp = *bytes;
665                let ysign = Choice::from(tmp[31] >> 7);
666                tmp[31] &= 0b0111_1111;
667
668                $base::from_repr(tmp).and_then(|x| {
669                    CtOption::new(Self::identity(), x.is_zero() & (!ysign)).or_else(|| {
670                        let x3 = x.square() * x;
671                        (x3 + $name::curve_constant_b()).sqrt().and_then(|y| {
672                            let sign = y.is_odd();
673
674                            let y = $base::conditional_select(&y, &-y, ysign ^ sign);
675
676                            CtOption::new(
677                                $name_affine {
678                                    x,
679                                    y,
680                                },
681                                Choice::from(1u8),
682                            )
683                        })
684                    })
685                })
686            }
687
688            fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
689                // We can't avoid curve checks when parsing a compressed encoding.
690                Self::from_bytes(bytes)
691            }
692
693            fn to_bytes(&self) -> [u8; 32] {
694                // TODO: not constant time
695                if bool::from(self.is_identity()) {
696                    [0; 32]
697                } else {
698                    let (x, y) = (self.x, self.y);
699                    let sign = y.is_odd().unwrap_u8() << 7;
700                    let mut xbytes = x.to_repr();
701                    xbytes[31] |= sign;
702                    xbytes
703                }
704            }
705        }
706
707        #[cfg(feature = "alloc")]
708        #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
709        impl CurveAffine for $name_affine {
710            type ScalarExt = $scalar;
711            type Base = $base;
712            type CurveExt = $name;
713
714            fn is_on_curve(&self) -> Choice {
715                // y^2 - x^3 - ax ?= b
716                (self.y.square() - (self.x.square() + &$name::curve_constant_a()) * self.x).ct_eq(&$name::curve_constant_b())
717                    | self.is_identity()
718            }
719
720            fn coordinates(&self) -> CtOption<Coordinates<Self>> {
721                CtOption::new(Coordinates { x: self.x, y: self.y }, !self.is_identity())
722            }
723
724            fn from_xy(x: Self::Base, y: Self::Base) -> CtOption<Self> {
725                let p = $name_affine {
726                    x, y,
727                };
728                CtOption::new(p, p.is_on_curve())
729            }
730
731            fn a() -> Self::Base {
732                $name::curve_constant_a()
733            }
734
735            fn b() -> Self::Base {
736                $name::curve_constant_b()
737            }
738        }
739
740        impl Default for $name_affine {
741            fn default() -> $name_affine {
742                $name_affine::identity()
743            }
744        }
745
746        impl<'a> From<&'a $name> for $name_affine {
747            fn from(p: &'a $name) -> $name_affine {
748                p.to_affine()
749            }
750        }
751
752        impl From<$name> for $name_affine {
753            fn from(p: $name) -> $name_affine {
754                p.to_affine()
755            }
756        }
757
758        impl ConstantTimeEq for $name_affine {
759            fn ct_eq(&self, other: &Self) -> Choice {
760                self.x.ct_eq(&other.x) & self.y.ct_eq(&other.y)
761            }
762        }
763
764        impl PartialEq for $name_affine {
765            fn eq(&self, other: &Self) -> bool {
766                self.ct_eq(other).into()
767            }
768        }
769
770        impl cmp::Eq for $name_affine {}
771
772        impl ConditionallySelectable for $name_affine {
773            fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
774                $name_affine {
775                    x: $base::conditional_select(&a.x, &b.x, choice),
776                    y: $base::conditional_select(&a.y, &b.y, choice),
777                }
778            }
779        }
780
781        impl_binops_additive!($name, $name);
782        impl_binops_additive!($name, $name_affine);
783        impl_binops_additive_specify_output!($name_affine, $name_affine, $name);
784        impl_binops_additive_specify_output!($name_affine, $name, $name);
785        impl_binops_multiplicative!($name, $scalar);
786        impl_binops_multiplicative_mixed!($name_affine, $scalar, $name);
787
788        #[cfg(feature = "gpu")]
789        impl ec_gpu::GpuName for $name_affine {
790            fn name() -> alloc::string::String {
791                ec_gpu::name!()
792            }
793        }
794    };
795}
796
797macro_rules! impl_projective_curve_specific {
798    ($name:ident, $base:ident, special_a0_b5) => {
799        fn generator() -> Self {
800            // NOTE: This is specific to b = 5
801
802            const NEGATIVE_ONE: $base = $base::neg(&$base::one());
803            const TWO: $base = $base::from_raw([2, 0, 0, 0]);
804
805            Self {
806                x: NEGATIVE_ONE,
807                y: TWO,
808                z: $base::one(),
809            }
810        }
811
812        fn double(&self) -> Self {
813            // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l
814            //
815            // There are no points of order 2.
816
817            let a = self.x.square();
818            let b = self.y.square();
819            let c = b.square();
820            let d = self.x + b;
821            let d = d.square();
822            let d = d - a - c;
823            let d = d + d;
824            let e = a + a + a;
825            let f = e.square();
826            let z3 = self.z * self.y;
827            let z3 = z3 + z3;
828            let x3 = f - (d + d);
829            let c = c + c;
830            let c = c + c;
831            let c = c + c;
832            let y3 = e * (d - x3) - c;
833
834            let tmp = $name {
835                x: x3,
836                y: y3,
837                z: z3,
838            };
839
840            $name::conditional_select(&tmp, &$name::identity(), self.is_identity())
841        }
842    };
843    ($name:ident, $base:ident, general) => {
844        /// Unimplemented: there is no standard generator for this curve.
845        fn generator() -> Self {
846            unimplemented!()
847        }
848
849        fn double(&self) -> Self {
850            // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#doubling-dbl-2007-bl
851            //
852            // There are no points of order 2.
853
854            let xx = self.x.square();
855            let yy = self.y.square();
856            let a = yy.square();
857            let zz = self.z.square();
858            let s = ((self.x + yy).square() - xx - a).double();
859            let m = xx.double() + xx + $name::curve_constant_a() * zz.square();
860            let x3 = m.square() - s.double();
861            let a = a.double();
862            let a = a.double();
863            let a = a.double();
864            let y3 = m * (s - x3) - a;
865            let z3 = (self.y + self.z).square() - yy - zz;
866
867            let tmp = $name {
868                x: x3,
869                y: y3,
870                z: z3,
871            };
872
873            $name::conditional_select(&tmp, &$name::identity(), self.is_identity())
874        }
875    };
876}
877
878#[cfg(feature = "alloc")]
879macro_rules! impl_projective_curve_ext {
880    ($name:ident, $iso:ident, $base:ident, special_a0_b5) => {
881        fn hash_to_curve<'a>(domain_prefix: &'a str) -> Box<dyn Fn(&[u8]) -> Self + 'a> {
882            use super::hashtocurve;
883
884            Box::new(move |message| {
885                let mut us = [Field::ZERO; 2];
886                hashtocurve::hash_to_field($name::CURVE_ID, domain_prefix, message, &mut us);
887                let q0 = hashtocurve::map_to_curve_simple_swu::<$base, $name, $iso>(
888                    &us[0],
889                    $name::THETA,
890                    $name::Z,
891                );
892                let q1 = hashtocurve::map_to_curve_simple_swu::<$base, $name, $iso>(
893                    &us[1],
894                    $name::THETA,
895                    $name::Z,
896                );
897                let r = q0 + &q1;
898                debug_assert!(bool::from(r.is_on_curve()));
899                hashtocurve::iso_map::<$base, $name, $iso>(&r, &$name::ISOGENY_CONSTANTS)
900            })
901        }
902
903        /// Apply the curve endomorphism by multiplying the x-coordinate
904        /// by an element of multiplicative order 3.
905        fn endo(&self) -> Self {
906            $name {
907                x: self.x * $base::ZETA,
908                y: self.y,
909                z: self.z,
910            }
911        }
912    };
913    ($name:ident, $iso:ident, $base:ident, general) => {
914        /// Unimplemented: hashing to this curve is not supported
915        fn hash_to_curve<'a>(_domain_prefix: &'a str) -> Box<dyn Fn(&[u8]) -> Self + 'a> {
916            unimplemented!()
917        }
918
919        /// Unimplemented: no endomorphism is supported for this curve.
920        fn endo(&self) -> Self {
921            unimplemented!()
922        }
923    };
924}
925
926macro_rules! impl_affine_curve_specific {
927    ($name:ident, $base:ident, special_a0_b5) => {
928        fn generator() -> Self {
929            // NOTE: This is specific to b = 5
930
931            const NEGATIVE_ONE: $base = $base::neg(&$base::from_raw([1, 0, 0, 0]));
932            const TWO: $base = $base::from_raw([2, 0, 0, 0]);
933
934            Self {
935                x: NEGATIVE_ONE,
936                y: TWO,
937            }
938        }
939    };
940    ($name:ident, $base:ident, general) => {
941        /// Unimplemented: there is no standard generator for this curve.
942        fn generator() -> Self {
943            unimplemented!()
944        }
945    };
946}
947
948new_curve_impl!(
949    (pub),
950    Ep,
951    EpAffine,
952    IsoEp,
953    Fp,
954    Fq,
955    "pallas",
956    [0, 0, 0, 0],
957    [5, 0, 0, 0],
958    special_a0_b5
959);
960new_curve_impl!(
961    (pub),
962    Eq,
963    EqAffine,
964    IsoEq,
965    Fq,
966    Fp,
967    "vesta",
968    [0, 0, 0, 0],
969    [5, 0, 0, 0],
970    special_a0_b5
971);
972new_curve_impl!(
973    (pub(crate)),
974    IsoEp,
975    IsoEpAffine,
976    Ep,
977    Fp,
978    Fq,
979    "iso-pallas",
980    [
981        0x92bb4b0b657a014b,
982        0xb74134581a27a59f,
983        0x49be2d7258370742,
984        0x18354a2eb0ea8c9c,
985    ],
986    [1265, 0, 0, 0],
987    general
988);
989new_curve_impl!(
990    (pub(crate)),
991    IsoEq,
992    IsoEqAffine,
993    Eq,
994    Fq,
995    Fp,
996    "iso-vesta",
997    [
998        0xc515ad7242eaa6b1,
999        0x9673928c7d01b212,
1000        0x81639c4d96f78773,
1001        0x267f9b2ee592271a,
1002    ],
1003    [1265, 0, 0, 0],
1004    general
1005);
1006
1007impl Ep {
1008    /// Constants used for computing the isogeny from IsoEp to Ep.
1009    pub const ISOGENY_CONSTANTS: [Fp; 13] = [
1010        Fp::from_raw([
1011            0x775f6034aaaaaaab,
1012            0x4081775473d8375b,
1013            0xe38e38e38e38e38e,
1014            0x0e38e38e38e38e38,
1015        ]),
1016        Fp::from_raw([
1017            0x8cf863b02814fb76,
1018            0x0f93b82ee4b99495,
1019            0x267c7ffa51cf412a,
1020            0x3509afd51872d88e,
1021        ]),
1022        Fp::from_raw([
1023            0x0eb64faef37ea4f7,
1024            0x380af066cfeb6d69,
1025            0x98c7d7ac3d98fd13,
1026            0x17329b9ec5253753,
1027        ]),
1028        Fp::from_raw([
1029            0xeebec06955555580,
1030            0x8102eea8e7b06eb6,
1031            0xc71c71c71c71c71c,
1032            0x1c71c71c71c71c71,
1033        ]),
1034        Fp::from_raw([
1035            0xc47f2ab668bcd71f,
1036            0x9c434ac1c96b6980,
1037            0x5a607fcce0494a79,
1038            0x1d572e7ddc099cff,
1039        ]),
1040        Fp::from_raw([
1041            0x2aa3af1eae5b6604,
1042            0xb4abf9fb9a1fc81c,
1043            0x1d13bf2a7f22b105,
1044            0x325669becaecd5d1,
1045        ]),
1046        Fp::from_raw([
1047            0x5ad985b5e38e38e4,
1048            0x7642b01ad461bad2,
1049            0x4bda12f684bda12f,
1050            0x1a12f684bda12f68,
1051        ]),
1052        Fp::from_raw([
1053            0xc67c31d8140a7dbb,
1054            0x07c9dc17725cca4a,
1055            0x133e3ffd28e7a095,
1056            0x1a84d7ea8c396c47,
1057        ]),
1058        Fp::from_raw([
1059            0x02e2be87d225b234,
1060            0x1765e924f7459378,
1061            0x303216cce1db9ff1,
1062            0x3fb98ff0d2ddcadd,
1063        ]),
1064        Fp::from_raw([
1065            0x93e53ab371c71c4f,
1066            0x0ac03e8e134eb3e4,
1067            0x7b425ed097b425ed,
1068            0x025ed097b425ed09,
1069        ]),
1070        Fp::from_raw([
1071            0x5a28279b1d1b42ae,
1072            0x5941a3a4a97aa1b3,
1073            0x0790bfb3506defb6,
1074            0x0c02c5bcca0e6b7f,
1075        ]),
1076        Fp::from_raw([
1077            0x4d90ab820b12320a,
1078            0xd976bbfabbc5661d,
1079            0x573b3d7f7d681310,
1080            0x17033d3c60c68173,
1081        ]),
1082        Fp::from_raw([
1083            0x992d30ecfffffde5,
1084            0x224698fc094cf91b,
1085            0x0000000000000000,
1086            0x4000000000000000,
1087        ]),
1088    ];
1089
1090    /// Z = -13
1091    pub const Z: Fp = Fp::from_raw([
1092        0x992d30ecfffffff4,
1093        0x224698fc094cf91b,
1094        0x0000000000000000,
1095        0x4000000000000000,
1096    ]);
1097
1098    /// `(F::ROOT_OF_UNITY.invert().unwrap() * z).sqrt().unwrap()`
1099    pub const THETA: Fp = Fp::from_raw([
1100        0xca330bcc09ac318e,
1101        0x51f64fc4dc888857,
1102        0x4647aef782d5cdc8,
1103        0x0f7bdb65814179b4,
1104    ]);
1105}
1106
1107impl Eq {
1108    /// Constants used for computing the isogeny from IsoEq to Eq.
1109    pub const ISOGENY_CONSTANTS: [Fq; 13] = [
1110        Fq::from_raw([
1111            0x43cd42c800000001,
1112            0x0205dd51cfa0961a,
1113            0x8e38e38e38e38e39,
1114            0x38e38e38e38e38e3,
1115        ]),
1116        Fq::from_raw([
1117            0x8b95c6aaf703bcc5,
1118            0x216b8861ec72bd5d,
1119            0xacecf10f5f7c09a2,
1120            0x1d935247b4473d17,
1121        ]),
1122        Fq::from_raw([
1123            0xaeac67bbeb586a3d,
1124            0xd59d03d23b39cb11,
1125            0xed7ee4a9cdf78f8f,
1126            0x18760c7f7a9ad20d,
1127        ]),
1128        Fq::from_raw([
1129            0xfb539a6f0000002b,
1130            0xe1c521a795ac8356,
1131            0x1c71c71c71c71c71,
1132            0x31c71c71c71c71c7,
1133        ]),
1134        Fq::from_raw([
1135            0xb7284f7eaf21a2e9,
1136            0xa3ad678129b604d3,
1137            0x1454798a5b5c56b2,
1138            0x0a2de485568125d5,
1139        ]),
1140        Fq::from_raw([
1141            0xf169c187d2533465,
1142            0x30cd6d53df49d235,
1143            0x0c621de8b91c242a,
1144            0x14735171ee542778,
1145        ]),
1146        Fq::from_raw([
1147            0x6bef1642aaaaaaab,
1148            0x5601f4709a8adcb3,
1149            0xda12f684bda12f68,
1150            0x12f684bda12f684b,
1151        ]),
1152        Fq::from_raw([
1153            0x8bee58e5fb81de63,
1154            0x21d910aefb03b31d,
1155            0xd6767887afbe04d1,
1156            0x2ec9a923da239e8b,
1157        ]),
1158        Fq::from_raw([
1159            0x4986913ab4443034,
1160            0x97a3ca5c24e9ea63,
1161            0x66d1466e9de10e64,
1162            0x19b0d87e16e25788,
1163        ]),
1164        Fq::from_raw([
1165            0x8f64842c55555533,
1166            0x8bc32d36fb21a6a3,
1167            0x425ed097b425ed09,
1168            0x1ed097b425ed097b,
1169        ]),
1170        Fq::from_raw([
1171            0x58dfecce86b2745e,
1172            0x06a767bfc35b5bac,
1173            0x9e7eb64f890a820c,
1174            0x2f44d6c801c1b8bf,
1175        ]),
1176        Fq::from_raw([
1177            0xd43d449776f99d2f,
1178            0x926847fb9ddd76a1,
1179            0x252659ba2b546c7e,
1180            0x3d59f455cafc7668,
1181        ]),
1182        Fq::from_raw([
1183            0x8c46eb20fffffde5,
1184            0x224698fc0994a8dd,
1185            0x0000000000000000,
1186            0x4000000000000000,
1187        ]),
1188    ];
1189
1190    /// Z = -13
1191    pub const Z: Fq = Fq::from_raw([
1192        0x8c46eb20fffffff4,
1193        0x224698fc0994a8dd,
1194        0x0000000000000000,
1195        0x4000000000000000,
1196    ]);
1197
1198    /// `(F::ROOT_OF_UNITY.invert().unwrap() * z).sqrt().unwrap()`
1199    pub const THETA: Fq = Fq::from_raw([
1200        0x632cae9872df1b5d,
1201        0x38578ccadf03ac27,
1202        0x53c3808d9e2f2357,
1203        0x2b3483a1ee9a382f,
1204    ]);
1205}