1use 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 #[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 #[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 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 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 q.x = acc;
181
182 acc = $base::conditional_select(&(acc * p.z), &acc, p.is_identity());
184 }
185
186 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 let tmp = q.x * acc;
195
196 acc = $base::conditional_select(&(acc * p.z), &acc, skip);
198
199 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 *self
234 }
235
236 fn into_subgroup(self) -> CtOption<Self::Subgroup> {
237 CtOption::new(self, 1.into())
239 }
240
241 fn is_torsion_free(&self) -> Choice {
242 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 $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 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) | ((!self_is_zero) & (!other_is_zero) & x1.ct_eq(&x2) & y1.ct_eq(&y2))
308 }
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 let mut acc = $name::identity();
472
473 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 let mut acc = $name::identity();
587
588 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 Self::from_bytes(bytes)
691 }
692
693 fn to_bytes(&self) -> [u8; 32] {
694 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 (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 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 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 fn generator() -> Self {
846 unimplemented!()
847 }
848
849 fn double(&self) -> Self {
850 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 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 fn hash_to_curve<'a>(_domain_prefix: &'a str) -> Box<dyn Fn(&[u8]) -> Self + 'a> {
916 unimplemented!()
917 }
918
919 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 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 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 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 pub const Z: Fp = Fp::from_raw([
1092 0x992d30ecfffffff4,
1093 0x224698fc094cf91b,
1094 0x0000000000000000,
1095 0x4000000000000000,
1096 ]);
1097
1098 pub const THETA: Fp = Fp::from_raw([
1100 0xca330bcc09ac318e,
1101 0x51f64fc4dc888857,
1102 0x4647aef782d5cdc8,
1103 0x0f7bdb65814179b4,
1104 ]);
1105}
1106
1107impl Eq {
1108 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 pub const Z: Fq = Fq::from_raw([
1192 0x8c46eb20fffffff4,
1193 0x224698fc0994a8dd,
1194 0x0000000000000000,
1195 0x4000000000000000,
1196 ]);
1197
1198 pub const THETA: Fq = Fq::from_raw([
1200 0x632cae9872df1b5d,
1201 0x38578ccadf03ac27,
1202 0x53c3808d9e2f2357,
1203 0x2b3483a1ee9a382f,
1204 ]);
1205}