ironfish_jubjub/
lib.rs

1#![doc = include_str!("../README.md")]
2
3#![no_std]
4// Catch documentation errors caused by code changes.
5#![deny(rustdoc::broken_intra_doc_links)]
6#![deny(missing_debug_implementations)]
7#![deny(missing_docs)]
8#![deny(unsafe_code)]
9// This lint is described at
10// https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_arithmetic_impl
11// In our library, some of the arithmetic will necessarily involve various binary
12// operators, and so this lint is triggered unnecessarily.
13#![allow(clippy::suspicious_arithmetic_impl)]
14
15#[cfg(feature = "alloc")]
16extern crate alloc;
17
18#[cfg(test)]
19#[macro_use]
20extern crate std;
21
22use bitvec::{order::Lsb0, view::AsBits};
23use core::borrow::Borrow;
24use core::fmt;
25use core::iter::Sum;
26use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
27use ff::{BatchInverter, Field};
28use group::{
29    cofactor::{CofactorCurve, CofactorCurveAffine, CofactorGroup},
30    prime::PrimeGroup,
31    Curve, Group, GroupEncoding,
32};
33use lazy_static::lazy_static;
34use rand_core::RngCore;
35use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
36
37#[cfg(feature = "alloc")]
38use alloc::vec::Vec;
39
40#[cfg(feature = "alloc")]
41use group::WnafGroup;
42
43#[macro_use]
44mod util;
45
46mod fr;
47pub use blstrs::Scalar as Fq;
48pub use fr::Fr;
49
50/// Represents an element of the base field $\mathbb{F}_q$ of the Jubjub elliptic curve
51/// construction.
52pub type Base = Fq;
53
54/// Represents an element of the scalar field $\mathbb{F}_r$ of the Jubjub elliptic curve
55/// construction.
56pub type Scalar = Fr;
57
58const FR_MODULUS_BYTES: [u8; 32] = [
59    183, 44, 247, 214, 94, 14, 151, 208, 130, 16, 200, 204, 147, 32, 104, 166, 0, 59, 52, 1, 1, 59,
60    103, 6, 169, 175, 51, 101, 234, 180, 125, 14,
61];
62
63#[cfg(feature = "stats")]
64use core::sync::atomic::AtomicUsize;
65#[cfg(feature = "stats")]
66use core::sync::atomic::Ordering::Relaxed;
67
68#[cfg(feature = "stats")]
69static AFFINE_MULS: AtomicUsize = AtomicUsize::new(0);
70#[cfg(feature = "stats")]
71static EXTENDED_MULS: AtomicUsize = AtomicUsize::new(0);
72#[cfg(all(feature = "stats", feature = "multiply-many"))]
73static EXTENDED_MUL_MANY_CALLS: AtomicUsize = AtomicUsize::new(0);
74#[cfg(all(feature = "stats", feature = "multiply-many"))]
75static EXTENDED_MUL_MANY_OPERANDS: AtomicUsize = AtomicUsize::new(0);
76
77/// Statistics on the operations performed by this crate. Returned by [`stats()`].
78#[cfg(feature = "stats")]
79#[derive(Copy, Clone, PartialEq, Eq, Debug)]
80pub struct Stats {
81    /// Number of affine point multiplications performed so far.
82    pub affine_muls: usize,
83    /// Number of extended point multiplications performed so far.
84    pub extended_muls: usize,
85    /// Number of parallel extended point multiplications performed so far (number of calls to
86    /// [`ExtendedPoint::multiply_many()`] performed so far).
87    #[cfg(feature = "multiply-many")]
88    pub extended_mul_many_calls: usize,
89    /// Total number of operarnds passed to the parallel extended point multiplication function so
90    /// far (total number of items passed to [`ExtendedPoint::multiply_many()`] performed so far).
91    #[cfg(feature = "multiply-many")]
92    pub extended_mul_many_operands: usize,
93}
94
95/// Return statistics on the operations performed by this crate so far.
96#[cfg(feature = "stats")]
97pub fn stats() -> Stats {
98    Stats {
99        affine_muls: AFFINE_MULS.load(Relaxed),
100        extended_muls: EXTENDED_MULS.load(Relaxed),
101        #[cfg(feature = "multiply-many")]
102        extended_mul_many_calls: EXTENDED_MUL_MANY_CALLS.load(Relaxed),
103        #[cfg(feature = "multiply-many")]
104        extended_mul_many_operands: EXTENDED_MUL_MANY_OPERANDS.load(Relaxed),
105    }
106}
107
108/// This represents a Jubjub point in the affine `(u, v)`
109/// coordinates.
110#[derive(Clone, Copy, Debug, Eq)]
111pub struct AffinePoint {
112    u: Fq,
113    v: Fq,
114}
115
116impl fmt::Display for AffinePoint {
117    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
118        write!(f, "{:?}", self)
119    }
120}
121
122impl Neg for AffinePoint {
123    type Output = AffinePoint;
124
125    /// This computes the negation of a point `P = (u, v)`
126    /// as `-P = (-u, v)`.
127    #[inline]
128    fn neg(self) -> AffinePoint {
129        AffinePoint {
130            u: -self.u,
131            v: self.v,
132        }
133    }
134}
135
136impl ConstantTimeEq for AffinePoint {
137    fn ct_eq(&self, other: &Self) -> Choice {
138        self.u.ct_eq(&other.u) & self.v.ct_eq(&other.v)
139    }
140}
141
142impl PartialEq for AffinePoint {
143    fn eq(&self, other: &Self) -> bool {
144        bool::from(self.ct_eq(other))
145    }
146}
147
148impl ConditionallySelectable for AffinePoint {
149    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
150        AffinePoint {
151            u: Fq::conditional_select(&a.u, &b.u, choice),
152            v: Fq::conditional_select(&a.v, &b.v, choice),
153        }
154    }
155}
156
157/// This represents an extended point `(U, V, Z, T1, T2)`
158/// with `Z` nonzero, corresponding to the affine point
159/// `(U/Z, V/Z)`. We always have `T1 * T2 = UV/Z`.
160///
161/// You can do the following things with a point in this
162/// form:
163///
164/// * Convert it into a point in the affine form.
165/// * Add it to an `ExtendedPoint`, `AffineNielsPoint` or `ExtendedNielsPoint`.
166/// * Double it using `double()`.
167/// * Compare it with another extended point using `PartialEq` or `ct_eq()`.
168#[derive(Clone, Copy, Debug, Eq)]
169pub struct ExtendedPoint {
170    u: Fq,
171    v: Fq,
172    z: Fq,
173    t1: Fq,
174    t2: Fq,
175}
176
177impl fmt::Display for ExtendedPoint {
178    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
179        write!(f, "{:?}", self)
180    }
181}
182
183impl ConstantTimeEq for ExtendedPoint {
184    fn ct_eq(&self, other: &Self) -> Choice {
185        // (u/z, v/z) = (u'/z', v'/z') is implied by
186        //      (uz'z = u'z'z) and
187        //      (vz'z = v'z'z)
188        // as z and z' are always nonzero.
189
190        (self.u * other.z).ct_eq(&(other.u * self.z))
191            & (self.v * other.z).ct_eq(&(other.v * self.z))
192    }
193}
194
195impl ConditionallySelectable for ExtendedPoint {
196    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
197        ExtendedPoint {
198            u: Fq::conditional_select(&a.u, &b.u, choice),
199            v: Fq::conditional_select(&a.v, &b.v, choice),
200            z: Fq::conditional_select(&a.z, &b.z, choice),
201            t1: Fq::conditional_select(&a.t1, &b.t1, choice),
202            t2: Fq::conditional_select(&a.t2, &b.t2, choice),
203        }
204    }
205}
206
207impl PartialEq for ExtendedPoint {
208    fn eq(&self, other: &Self) -> bool {
209        bool::from(self.ct_eq(other))
210    }
211}
212
213impl<T> Sum<T> for ExtendedPoint
214where
215    T: Borrow<ExtendedPoint>,
216{
217    fn sum<I>(iter: I) -> Self
218    where
219        I: Iterator<Item = T>,
220    {
221        iter.fold(Self::identity(), |acc, item| acc + item.borrow())
222    }
223}
224
225impl Neg for ExtendedPoint {
226    type Output = ExtendedPoint;
227
228    /// Computes the negation of a point `P = (U, V, Z, T)`
229    /// as `-P = (-U, V, Z, -T1, T2)`. The choice of `T1`
230    /// is made without loss of generality.
231    #[inline]
232    fn neg(self) -> ExtendedPoint {
233        ExtendedPoint {
234            u: -self.u,
235            v: self.v,
236            z: self.z,
237            t1: -self.t1,
238            t2: self.t2,
239        }
240    }
241}
242
243impl From<AffinePoint> for ExtendedPoint {
244    /// Constructs an extended point (with `Z = 1`) from
245    /// an affine point using the map `(u, v) => (u, v, 1, u, v)`.
246    fn from(affine: AffinePoint) -> ExtendedPoint {
247        ExtendedPoint {
248            u: affine.u,
249            v: affine.v,
250            z: Fq::one(),
251            t1: affine.u,
252            t2: affine.v,
253        }
254    }
255}
256
257impl<'a> From<&'a ExtendedPoint> for AffinePoint {
258    /// Constructs an affine point from an extended point
259    /// using the map `(U, V, Z, T1, T2) => (U/Z, V/Z)`
260    /// as Z is always nonzero. **This requires a field inversion
261    /// and so it is recommended to perform these in a batch
262    /// using [`batch_normalize`](crate::batch_normalize) instead.**
263    fn from(extended: &'a ExtendedPoint) -> AffinePoint {
264        // Z coordinate is always nonzero, so this is
265        // its inverse.
266        let zinv = extended.z.invert().unwrap();
267
268        AffinePoint {
269            u: extended.u * zinv,
270            v: extended.v * zinv,
271        }
272    }
273}
274
275impl From<ExtendedPoint> for AffinePoint {
276    fn from(extended: ExtendedPoint) -> AffinePoint {
277        AffinePoint::from(&extended)
278    }
279}
280
281/// This is a pre-processed version of an affine point `(u, v)`
282/// in the form `(v + u, v - u, u * v * 2d)`. This can be added to an
283/// [`ExtendedPoint`](crate::ExtendedPoint).
284#[derive(Clone, Copy, Debug)]
285pub struct AffineNielsPoint {
286    v_plus_u: Fq,
287    v_minus_u: Fq,
288    t2d: Fq,
289}
290
291impl AffineNielsPoint {
292    /// Constructs this point from the neutral element `(0, 1)`.
293    pub fn identity() -> Self {
294        AffineNielsPoint {
295            v_plus_u: Fq::one(),
296            v_minus_u: Fq::one(),
297            t2d: Fq::zero(),
298        }
299    }
300
301    #[inline]
302    fn multiply(&self, by: &[u8; 32]) -> ExtendedPoint {
303        #[cfg(feature = "stats")]
304        AFFINE_MULS.fetch_add(1, Relaxed);
305
306        let zero = AffineNielsPoint::identity();
307
308        let mut acc = ExtendedPoint::identity();
309
310        // This is a simple double-and-add implementation of point
311        // multiplication, moving from most significant to least
312        // significant bit of the scalar.
313        //
314        // We skip the leading four bits because they're always
315        // unset for Fr.
316        for bit in by
317            .as_bits::<Lsb0>()
318            .iter()
319            .rev()
320            .skip(4)
321            .map(|bit| Choice::from(if *bit { 1 } else { 0 }))
322        {
323            acc = acc.double();
324            acc += AffineNielsPoint::conditional_select(&zero, &self, bit);
325        }
326
327        acc
328    }
329
330    /// Multiplies this point by the specific little-endian bit pattern in the
331    /// given byte array, ignoring the highest four bits.
332    pub fn multiply_bits(&self, by: &[u8; 32]) -> ExtendedPoint {
333        self.multiply(by)
334    }
335}
336
337impl<'a, 'b> Mul<&'b Fr> for &'a AffineNielsPoint {
338    type Output = ExtendedPoint;
339
340    fn mul(self, other: &'b Fr) -> ExtendedPoint {
341        self.multiply(&other.to_bytes())
342    }
343}
344
345impl_binops_multiplicative_mixed!(AffineNielsPoint, Fr, ExtendedPoint);
346
347impl ConditionallySelectable for AffineNielsPoint {
348    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
349        AffineNielsPoint {
350            v_plus_u: Fq::conditional_select(&a.v_plus_u, &b.v_plus_u, choice),
351            v_minus_u: Fq::conditional_select(&a.v_minus_u, &b.v_minus_u, choice),
352            t2d: Fq::conditional_select(&a.t2d, &b.t2d, choice),
353        }
354    }
355}
356
357/// This is a pre-processed version of an extended point `(U, V, Z, T1, T2)`
358/// in the form `(V + U, V - U, Z, T1 * T2 * 2d)`.
359#[derive(Clone, Copy, Debug)]
360pub struct ExtendedNielsPoint {
361    v_plus_u: Fq,
362    v_minus_u: Fq,
363    z: Fq,
364    t2d: Fq,
365}
366
367impl ConditionallySelectable for ExtendedNielsPoint {
368    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
369        ExtendedNielsPoint {
370            v_plus_u: Fq::conditional_select(&a.v_plus_u, &b.v_plus_u, choice),
371            v_minus_u: Fq::conditional_select(&a.v_minus_u, &b.v_minus_u, choice),
372            z: Fq::conditional_select(&a.z, &b.z, choice),
373            t2d: Fq::conditional_select(&a.t2d, &b.t2d, choice),
374        }
375    }
376}
377
378impl ExtendedNielsPoint {
379    /// Constructs this point from the neutral element `(0, 1)`.
380    pub fn identity() -> Self {
381        ExtendedNielsPoint {
382            v_plus_u: Fq::one(),
383            v_minus_u: Fq::one(),
384            z: Fq::one(),
385            t2d: Fq::zero(),
386        }
387    }
388
389    #[inline]
390    fn multiply(&self, by: &[u8; 32]) -> ExtendedPoint {
391        #[cfg(feature = "stats")]
392        EXTENDED_MULS.fetch_add(1, Relaxed);
393
394        let zero = ExtendedNielsPoint::identity();
395
396        let mut acc = ExtendedPoint::identity();
397
398        // This is a simple double-and-add implementation of point
399        // multiplication, moving from most significant to least
400        // significant bit of the scalar.
401        //
402        // We skip the leading four bits because they're always
403        // unset for Fr.
404        for bit in by
405            .iter()
406            .rev()
407            .flat_map(|byte| (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8)))
408            .skip(4)
409        {
410            acc = acc.double();
411            acc += ExtendedNielsPoint::conditional_select(&zero, &self, bit);
412        }
413
414        acc
415    }
416
417    /// Multiplies this point by the specific little-endian bit pattern in the
418    /// given byte array, ignoring the highest four bits.
419    pub fn multiply_bits(&self, by: &[u8; 32]) -> ExtendedPoint {
420        self.multiply(by)
421    }
422}
423
424impl<'a, 'b> Mul<&'b Fr> for &'a ExtendedNielsPoint {
425    type Output = ExtendedPoint;
426
427    fn mul(self, other: &'b Fr) -> ExtendedPoint {
428        self.multiply(&other.to_bytes())
429    }
430}
431
432impl_binops_multiplicative_mixed!(ExtendedNielsPoint, Fr, ExtendedPoint);
433
434lazy_static! {
435    // `d = -(10240/10241)`
436    static ref EDWARDS_D: Fq = Fq::from_u64s_le(&[
437        0x0106_5fd6_d634_3eb1,
438        0x292d_7f6d_3757_9d26,
439        0xf5fd_9207_e6bd_7fd4,
440        0x2a93_18e7_4bfa_2b48,
441    ]).unwrap();
442
443    // `2*d`
444    static ref EDWARDS_D2: Fq = Fq::from_u64s_le(&[
445        0x020c_bfad_ac68_7d62,
446        0x525a_feda_6eaf_3a4c,
447        0xebfb_240f_cd7a_ffa8,
448        0x5526_31ce_97f4_5691,
449    ]).unwrap();
450}
451
452
453
454impl AffinePoint {
455    /// Constructs the neutral element `(0, 1)`.
456    pub fn identity() -> Self {
457        AffinePoint {
458            u: Fq::zero(),
459            v: Fq::one(),
460        }
461    }
462
463    /// Determines if this point is the identity.
464    pub fn is_identity(&self) -> Choice {
465        ExtendedPoint::from(*self).is_identity()
466    }
467
468    /// Multiplies this point by the cofactor, producing an
469    /// `ExtendedPoint`
470    pub fn mul_by_cofactor(&self) -> ExtendedPoint {
471        ExtendedPoint::from(*self).mul_by_cofactor()
472    }
473
474    /// Determines if this point is of small order.
475    pub fn is_small_order(&self) -> Choice {
476        ExtendedPoint::from(*self).is_small_order()
477    }
478
479    /// Determines if this point is torsion free and so is
480    /// in the prime order subgroup.
481    pub fn is_torsion_free(&self) -> Choice {
482        ExtendedPoint::from(*self).is_torsion_free()
483    }
484
485    /// Determines if this point is prime order, or in other words that
486    /// the smallest scalar multiplied by this point that produces the
487    /// identity is `r`. This is equivalent to checking that the point
488    /// is both torsion free and not the identity.
489    pub fn is_prime_order(&self) -> Choice {
490        let extended = ExtendedPoint::from(*self);
491        extended.is_torsion_free() & (!extended.is_identity())
492    }
493
494    /// Converts this element into its byte representation.
495    pub fn to_bytes(&self) -> [u8; 32] {
496        let mut tmp = self.v.to_bytes_le();
497        let u = self.u.to_bytes_le();
498
499        // Encode the sign of the u-coordinate in the most
500        // significant bit.
501        tmp[31] |= u[0] << 7;
502
503        tmp
504    }
505
506    /// Attempts to interpret a byte representation of an
507    /// affine point, failing if the element is not on
508    /// the curve or non-canonical.
509    pub fn from_bytes(b: [u8; 32]) -> CtOption<Self> {
510        Self::from_bytes_inner(b, 1.into())
511    }
512
513    /// Attempts to interpret a byte representation of an affine point, failing if the
514    /// element is not on the curve.
515    ///
516    /// Most non-canonical encodings will also cause a failure. However, this API
517    /// preserves (for use in consensus-critical protocols) a bug in the parsing code that
518    /// caused two non-canonical encodings to be **silently** accepted:
519    ///
520    /// - (0, 1), which is the identity;
521    /// - (0, -1), which is a point of order two.
522    ///
523    /// Each of these has a single non-canonical encoding in which the value of the sign
524    /// bit is 1.
525    ///
526    /// See [ZIP 216](https://zips.z.cash/zip-0216) for a more detailed description of the
527    /// bug, as well as its fix.
528    pub fn from_bytes_pre_zip216_compatibility(b: [u8; 32]) -> CtOption<Self> {
529        Self::from_bytes_inner(b, 0.into())
530    }
531
532    fn from_bytes_inner(mut b: [u8; 32], zip_216_enabled: Choice) -> CtOption<Self> {
533        // Grab the sign bit from the representation
534        let sign = b[31] >> 7;
535
536        // Mask away the sign bit
537        b[31] &= 0b0111_1111;
538
539        // Interpret what remains as the v-coordinate
540        Fq::from_bytes_le(&b).and_then(|v| {
541            // -u^2 + v^2 = 1 + d.u^2.v^2
542            // -u^2 = 1 + d.u^2.v^2 - v^2    (rearrange)
543            // -u^2 - d.u^2.v^2 = 1 - v^2    (rearrange)
544            // u^2 + d.u^2.v^2 = v^2 - 1     (flip signs)
545            // u^2 (1 + d.v^2) = v^2 - 1     (factor)
546            // u^2 = (v^2 - 1) / (1 + d.v^2) (isolate u^2)
547            // We know that (1 + d.v^2) is nonzero for all v:
548            //   (1 + d.v^2) = 0
549            //   d.v^2 = -1
550            //   v^2 = -(1 / d)   No solutions, as -(1 / d) is not a square
551
552            let v2 = v.square();
553
554            ((v2 - Fq::one()) * ((Fq::one() + *EDWARDS_D * v2).invert().unwrap_or(Fq::zero())))
555                .sqrt()
556                .and_then(|u| {
557                    // Fix the sign of `u` if necessary
558                    let flip_sign = Choice::from((u.to_bytes_le()[0] ^ sign) & 1);
559                    let u_negated = -u;
560                    let final_u = Fq::conditional_select(&u, &u_negated, flip_sign);
561
562                    // If u == 0, flip_sign == sign_bit. We therefore want to reject the
563                    // encoding as non-canonical if all of the following occur:
564                    // - ZIP 216 is enabled
565                    // - u == 0
566                    // - flip_sign == true
567                    let u_is_zero = u.ct_eq(&Fq::zero());
568                    CtOption::new(
569                        AffinePoint { u: final_u, v },
570                        !(zip_216_enabled & u_is_zero & flip_sign),
571                    )
572                })
573        })
574    }
575
576    /// Attempts to interpret a batch of byte representations of affine points.
577    ///
578    /// Returns None for each element if it is not on the curve, or is non-canonical
579    /// according to ZIP 216.
580    #[cfg(feature = "alloc")]
581    pub fn batch_from_bytes(items: impl Iterator<Item = [u8; 32]>) -> Vec<CtOption<Self>> {
582        use ff::BatchInvert;
583
584        #[derive(Clone, Copy, Default)]
585        struct Item {
586            sign: u8,
587            v: Fq,
588            numerator: Fq,
589            denominator: Fq,
590        }
591
592        impl ConditionallySelectable for Item {
593            fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
594                Item {
595                    sign: u8::conditional_select(&a.sign, &b.sign, choice),
596                    v: Fq::conditional_select(&a.v, &b.v, choice),
597                    numerator: Fq::conditional_select(&a.numerator, &b.numerator, choice),
598                    denominator: Fq::conditional_select(&a.denominator, &b.denominator, choice),
599                }
600            }
601        }
602
603        let items: Vec<_> = items
604            .map(|mut b| {
605                // Grab the sign bit from the representation
606                let sign = b[31] >> 7;
607
608                // Mask away the sign bit
609                b[31] &= 0b0111_1111;
610
611                // Interpret what remains as the v-coordinate
612                Fq::from_bytes_le(&b).map(|v| {
613                    // -u^2 + v^2 = 1 + d.u^2.v^2
614                    // -u^2 = 1 + d.u^2.v^2 - v^2    (rearrange)
615                    // -u^2 - d.u^2.v^2 = 1 - v^2    (rearrange)
616                    // u^2 + d.u^2.v^2 = v^2 - 1     (flip signs)
617                    // u^2 (1 + d.v^2) = v^2 - 1     (factor)
618                    // u^2 = (v^2 - 1) / (1 + d.v^2) (isolate u^2)
619                    // We know that (1 + d.v^2) is nonzero for all v:
620                    //   (1 + d.v^2) = 0
621                    //   d.v^2 = -1
622                    //   v^2 = -(1 / d)   No solutions, as -(1 / d) is not a square
623
624                    let v2 = v.square();
625
626                    Item {
627                        v,
628                        sign,
629                        numerator: (v2 - Fq::one()),
630                        denominator: Fq::one() + *EDWARDS_D * v2,
631                    }
632                })
633            })
634            .collect();
635
636        let mut denominators: Vec<_> = items
637            .iter()
638            .map(|item| item.map(|item| item.denominator).unwrap_or(Fq::zero()))
639            .collect();
640        denominators.iter_mut().batch_invert();
641
642        items
643            .into_iter()
644            .zip(denominators.into_iter())
645            .map(|(item, inv_denominator)| {
646                item.and_then(
647                    |Item {
648                         v, sign, numerator, ..
649                     }| {
650                        (numerator * inv_denominator).sqrt().and_then(|u| {
651                            // Fix the sign of `u` if necessary
652                            let flip_sign = Choice::from((u.to_bytes_le()[0] ^ sign) & 1);
653                            let u_negated = -u;
654                            let final_u = Fq::conditional_select(&u, &u_negated, flip_sign);
655
656                            // If u == 0, flip_sign == sign_bit. We therefore want to reject the
657                            // encoding as non-canonical if all of the following occur:
658                            // - u == 0
659                            // - flip_sign == true
660                            let u_is_zero = u.ct_eq(&Fq::zero());
661                            CtOption::new(AffinePoint { u: final_u, v }, !(u_is_zero & flip_sign))
662                        })
663                    },
664                )
665            })
666            .collect()
667    }
668
669    /// Returns the `u`-coordinate of this point.
670    pub fn get_u(&self) -> Fq {
671        self.u
672    }
673
674    /// Returns the `v`-coordinate of this point.
675    pub fn get_v(&self) -> Fq {
676        self.v
677    }
678
679    /// Returns an `ExtendedPoint` for use in arithmetic operations.
680    pub fn to_extended(&self) -> ExtendedPoint {
681        ExtendedPoint {
682            u: self.u,
683            v: self.v,
684            z: Fq::one(),
685            t1: self.u,
686            t2: self.v,
687        }
688    }
689
690    /// Performs a pre-processing step that produces an `AffineNielsPoint`
691    /// for use in multiple additions.
692    pub fn to_niels(&self) -> AffineNielsPoint {
693        AffineNielsPoint {
694            v_plus_u: Fq::add(self.v, &self.u),
695            v_minus_u: Fq::sub(self.v, &self.u),
696            t2d: Fq::mul(Fq::mul(self.u, &self.v), &*EDWARDS_D2),
697        }
698    }
699
700    /// Constructs an AffinePoint given `u` and `v` without checking
701    /// that the point is on the curve.
702    pub const fn from_raw_unchecked(u: Fq, v: Fq) -> AffinePoint {
703        AffinePoint { u, v }
704    }
705
706    /// This is only for debugging purposes and not
707    /// exposed in the public API. Checks that this
708    /// point is on the curve.
709    #[cfg(test)]
710    fn is_on_curve_vartime(&self) -> bool {
711        let u2 = self.u.square();
712        let v2 = self.v.square();
713
714        v2 - u2 == Fq::one() + *EDWARDS_D * u2 * v2
715    }
716}
717
718impl ExtendedPoint {
719    /// Constructs an extended point from the neutral element `(0, 1)`.
720    pub fn identity() -> Self {
721        ExtendedPoint {
722            u: Fq::zero(),
723            v: Fq::one(),
724            z: Fq::one(),
725            t1: Fq::zero(),
726            t2: Fq::zero(),
727        }
728    }
729
730    /// Determines if this point is the identity.
731    pub fn is_identity(&self) -> Choice {
732        // If this point is the identity, then
733        //     u = 0 * z = 0
734        // and v = 1 * z = z
735        self.u.ct_eq(&Fq::zero()) & self.v.ct_eq(&self.z)
736    }
737
738    /// Determines if this point is of small order.
739    pub fn is_small_order(&self) -> Choice {
740        // We only need to perform two doublings, since the 2-torsion
741        // points are (0, 1) and (0, -1), and so we only need to check
742        // that the u-coordinate of the result is zero to see if the
743        // point is small order.
744        self.double().double().u.ct_eq(&Fq::zero())
745    }
746
747    /// Determines if this point is torsion free and so is contained
748    /// in the prime order subgroup.
749    pub fn is_torsion_free(&self) -> Choice {
750        self.multiply(&FR_MODULUS_BYTES).is_identity()
751    }
752
753    /// Determines if this point is prime order, or in other words that
754    /// the smallest scalar multiplied by this point that produces the
755    /// identity is `r`. This is equivalent to checking that the point
756    /// is both torsion free and not the identity.
757    pub fn is_prime_order(&self) -> Choice {
758        self.is_torsion_free() & (!self.is_identity())
759    }
760
761    /// Multiplies this element by the cofactor `8`.
762    pub fn mul_by_cofactor(&self) -> ExtendedPoint {
763        self.double().double().double()
764    }
765
766    /// Performs a pre-processing step that produces an `ExtendedNielsPoint`
767    /// for use in multiple additions.
768    pub fn to_niels(&self) -> ExtendedNielsPoint {
769        ExtendedNielsPoint {
770            v_plus_u: self.v + self.u,
771            v_minus_u: self.v - self.u,
772            z: self.z,
773            t2d: self.t1 * self.t2 * *EDWARDS_D2,
774        }
775    }
776
777    /// Computes the doubling of a point more efficiently than a point can
778    /// be added to itself.
779    pub fn double(&self) -> ExtendedPoint {
780        // Doubling is more efficient (three multiplications, four squarings)
781        // when we work within the projective coordinate space (U:Z, V:Z). We
782        // rely on the most efficient formula, "dbl-2008-bbjlp", as described
783        // in Section 6 of "Twisted Edwards Curves" by Bernstein et al.
784        //
785        // See <https://hyperelliptic.org/EFD/g1p/auto-twisted-projective.html#doubling-dbl-2008-bbjlp>
786        // for more information.
787        //
788        // We differ from the literature in that we use (u, v) rather than
789        // (x, y) coordinates. We also have the constant `a = -1` implied. Let
790        // us rewrite the procedure of doubling (u, v, z) to produce (U, V, Z)
791        // as follows:
792        //
793        // B = (u + v)^2
794        // C = u^2
795        // D = v^2
796        // F = D - C
797        // H = 2 * z^2
798        // J = F - H
799        // U = (B - C - D) * J
800        // V = F * (- C - D)
801        // Z = F * J
802        //
803        // If we compute K = D + C, we can rewrite this:
804        //
805        // B = (u + v)^2
806        // C = u^2
807        // D = v^2
808        // F = D - C
809        // K = D + C
810        // H = 2 * z^2
811        // J = F - H
812        // U = (B - K) * J
813        // V = F * (-K)
814        // Z = F * J
815        //
816        // In order to avoid the unnecessary negation of K,
817        // we will negate J, transforming the result into
818        // an equivalent point with a negated z-coordinate.
819        //
820        // B = (u + v)^2
821        // C = u^2
822        // D = v^2
823        // F = D - C
824        // K = D + C
825        // H = 2 * z^2
826        // J = H - F
827        // U = (B - K) * J
828        // V = F * K
829        // Z = F * J
830        //
831        // Let us rename some variables to simplify:
832        //
833        // UV2 = (u + v)^2
834        // UU = u^2
835        // VV = v^2
836        // VVmUU = VV - UU
837        // VVpUU = VV + UU
838        // ZZ2 = 2 * z^2
839        // J = ZZ2 - VVmUU
840        // U = (UV2 - VVpUU) * J
841        // V = VVmUU * VVpUU
842        // Z = VVmUU * J
843        //
844        // We wish to obtain two factors of T = UV/Z.
845        //
846        // UV/Z = (UV2 - VVpUU) * (ZZ2 - VVmUU) * VVmUU * VVpUU / VVmUU / (ZZ2 - VVmUU)
847        //      = (UV2 - VVpUU) * VVmUU * VVpUU / VVmUU
848        //      = (UV2 - VVpUU) * VVpUU
849        //
850        // and so we have that T1 = (UV2 - VVpUU) and T2 = VVpUU.
851
852        let uu = self.u.square();
853        let vv = self.v.square();
854        let zz2 = self.z.square().double();
855        let uv2 = (self.u + self.v).square();
856        let vv_plus_uu = vv + uu;
857        let vv_minus_uu = vv - uu;
858
859        // The remaining arithmetic is exactly the process of converting
860        // from a completed point to an extended point.
861        CompletedPoint {
862            u: uv2 - vv_plus_uu,
863            v: vv_plus_uu,
864            z: vv_minus_uu,
865            t: zz2 - vv_minus_uu,
866        }
867        .into_extended()
868    }
869
870    #[inline]
871    fn multiply(self, by: &[u8; 32]) -> Self {
872        self.to_niels().multiply(by)
873    }
874
875    /// Multiplies this point by multiple byte arrays in parallel. This is equivalent to calling
876    /// [`multiply`] repeatedly, except that this method is more efficient.
877    ///
878    /// A single call to `multiply` performs exactly 252 point doublings and 252 point additions.
879    /// If the cost of a doubling is `D` and the cost of an addition is `A`, then the cost of a
880    /// single call to `multiply` is:
881    ///
882    /// ```text
883    /// m = 252 * D + 252 * A
884    ///   = 252 * (D + A)
885    /// ```
886    ///
887    /// A call to `multiply_many` with N arrays performs exactly 252 point doublings, and 252 * N
888    /// additions, therefore its cost is:
889    ///
890    /// ```text
891    /// M(N) = 252 * D + 252 * N * A
892    ///      = 252 * (D + N * A)
893    /// ```
894    ///
895    /// Compared to calling `multiply` multiple times:
896    ///
897    /// ```text
898    /// M(N) / (N * m) = (252 * (D + N * A)) / (252 * N * (D + A))
899    ///                = (D + N * A) / (N * (D + A))
900    ///                = (D / N + A) / (D + A)
901    /// ```
902    ///
903    /// Assuming that the cost of a doubling is about the same as the cost of an addition (which is
904    /// not fully true, but may be a valid approximation), then, using the formula above, we get
905    /// that the speed up of using `multiply_many` compared to using `multiply` ranges between 1x
906    /// and 2x.
907    #[cfg(feature = "multiply-many")]
908    pub fn multiply_many(&self, by: &[[u8; 32]]) -> Vec<ExtendedPoint> {
909        #[cfg(feature = "stats")]
910        EXTENDED_MUL_MANY_CALLS.fetch_add(1, Relaxed);
911        #[cfg(feature = "stats")]
912        EXTENDED_MUL_MANY_OPERANDS.fetch_add(by.len(), Relaxed);
913
914        let mut base = *self;
915        let zero = ExtendedNielsPoint::identity();
916        let mut accs = alloc::vec![ExtendedPoint::identity(); by.len()];
917
918        for bit_index in 0..32 * 8 - 4 {
919            let niels_base = base.to_niels();
920
921            for (array, acc) in by.iter().zip(accs.iter_mut()) {
922                let bit = Choice::from((array[bit_index >> 3] >> (bit_index & 0x7)) & 0b1);
923                *acc += ExtendedNielsPoint::conditional_select(&zero, &niels_base, bit);
924            }
925
926            base = base.double();
927        }
928
929        accs
930    }
931
932    /// Converts a batch of projective elements into affine elements.
933    ///
934    /// This function will panic if `p.len() != q.len()`.
935    ///
936    /// This costs 5 multiplications per element, and a field inversion.
937    fn batch_normalize(p: &[Self], q: &mut [AffinePoint]) {
938        assert_eq!(p.len(), q.len());
939
940        for (p, q) in p.iter().zip(q.iter_mut()) {
941            // We use the `u` field of `AffinePoint` to store the z-coordinate being
942            // inverted, and the `v` field for scratch space.
943            q.u = p.z;
944        }
945
946        BatchInverter::invert_with_internal_scratch(q, |q| &mut q.u, |q| &mut q.v);
947
948        for (p, q) in p.iter().zip(q.iter_mut()).rev() {
949            let tmp = q.u;
950
951            // Set the coordinates to the correct value
952            q.u = p.u * &tmp; // Multiply by 1/z
953            q.v = p.v * &tmp; // Multiply by 1/z
954        }
955    }
956
957    /// This is only for debugging purposes and not
958    /// exposed in the public API. Checks that this
959    /// point is on the curve.
960    #[cfg(test)]
961    fn is_on_curve_vartime(&self) -> bool {
962        let affine = AffinePoint::from(*self);
963
964        self.z != Fq::zero()
965            && affine.is_on_curve_vartime()
966            && (affine.u * affine.v * self.z == self.t1 * self.t2)
967    }
968}
969
970impl<'a, 'b> Mul<&'b Fr> for &'a ExtendedPoint {
971    type Output = ExtendedPoint;
972
973    fn mul(self, other: &'b Fr) -> ExtendedPoint {
974        self.multiply(&other.to_bytes())
975    }
976}
977
978impl_binops_multiplicative!(ExtendedPoint, Fr);
979
980impl<'a, 'b> Add<&'b ExtendedNielsPoint> for &'a ExtendedPoint {
981    type Output = ExtendedPoint;
982
983    #[allow(clippy::suspicious_arithmetic_impl)]
984    fn add(self, other: &'b ExtendedNielsPoint) -> ExtendedPoint {
985        // We perform addition in the extended coordinates. Here we use
986        // a formula presented by Hisil, Wong, Carter and Dawson in
987        // "Twisted Edward Curves Revisited" which only requires 8M.
988        //
989        // A = (V1 - U1) * (V2 - U2)
990        // B = (V1 + U1) * (V2 + U2)
991        // C = 2d * T1 * T2
992        // D = 2 * Z1 * Z2
993        // E = B - A
994        // F = D - C
995        // G = D + C
996        // H = B + A
997        // U3 = E * F
998        // Y3 = G * H
999        // Z3 = F * G
1000        // T3 = E * H
1001
1002        let a = (self.v - self.u) * other.v_minus_u;
1003        let b = (self.v + self.u) * other.v_plus_u;
1004        let c = self.t1 * self.t2 * other.t2d;
1005        let d = (self.z * other.z).double();
1006
1007        // The remaining arithmetic is exactly the process of converting
1008        // from a completed point to an extended point.
1009        CompletedPoint {
1010            u: b - a,
1011            v: b + a,
1012            z: d + c,
1013            t: d - c,
1014        }
1015        .into_extended()
1016    }
1017}
1018
1019impl<'a, 'b> Sub<&'b ExtendedNielsPoint> for &'a ExtendedPoint {
1020    type Output = ExtendedPoint;
1021
1022    #[allow(clippy::suspicious_arithmetic_impl)]
1023    fn sub(self, other: &'b ExtendedNielsPoint) -> ExtendedPoint {
1024        let a = (self.v - self.u) * other.v_plus_u;
1025        let b = (self.v + self.u) * other.v_minus_u;
1026        let c = self.t1 * self.t2 * other.t2d;
1027        let d = (self.z * other.z).double();
1028
1029        CompletedPoint {
1030            u: b - a,
1031            v: b + a,
1032            z: d - c,
1033            t: d + c,
1034        }
1035        .into_extended()
1036    }
1037}
1038
1039impl_binops_additive!(ExtendedPoint, ExtendedNielsPoint);
1040
1041impl<'a, 'b> Add<&'b AffineNielsPoint> for &'a ExtendedPoint {
1042    type Output = ExtendedPoint;
1043
1044    #[allow(clippy::suspicious_arithmetic_impl)]
1045    fn add(self, other: &'b AffineNielsPoint) -> ExtendedPoint {
1046        // This is identical to the addition formula for `ExtendedNielsPoint`,
1047        // except we can assume that `other.z` is one, so that we perform
1048        // 7 multiplications.
1049
1050        let a = (self.v - self.u) * other.v_minus_u;
1051        let b = (self.v + self.u) * other.v_plus_u;
1052        let c = self.t1 * self.t2 * other.t2d;
1053        let d = self.z.double();
1054
1055        // The remaining arithmetic is exactly the process of converting
1056        // from a completed point to an extended point.
1057        CompletedPoint {
1058            u: b - a,
1059            v: b + a,
1060            z: d + c,
1061            t: d - c,
1062        }
1063        .into_extended()
1064    }
1065}
1066
1067impl<'a, 'b> Sub<&'b AffineNielsPoint> for &'a ExtendedPoint {
1068    type Output = ExtendedPoint;
1069
1070    #[allow(clippy::suspicious_arithmetic_impl)]
1071    fn sub(self, other: &'b AffineNielsPoint) -> ExtendedPoint {
1072        let a = (self.v - self.u) * other.v_plus_u;
1073        let b = (self.v + self.u) * other.v_minus_u;
1074        let c = self.t1 * self.t2 * other.t2d;
1075        let d = self.z.double();
1076
1077        CompletedPoint {
1078            u: b - a,
1079            v: b + a,
1080            z: d - c,
1081            t: d + c,
1082        }
1083        .into_extended()
1084    }
1085}
1086
1087impl_binops_additive!(ExtendedPoint, AffineNielsPoint);
1088
1089impl<'a, 'b> Add<&'b ExtendedPoint> for &'a ExtendedPoint {
1090    type Output = ExtendedPoint;
1091
1092    #[inline]
1093    fn add(self, other: &'b ExtendedPoint) -> ExtendedPoint {
1094        self + other.to_niels()
1095    }
1096}
1097
1098impl<'a, 'b> Sub<&'b ExtendedPoint> for &'a ExtendedPoint {
1099    type Output = ExtendedPoint;
1100
1101    #[inline]
1102    fn sub(self, other: &'b ExtendedPoint) -> ExtendedPoint {
1103        self - other.to_niels()
1104    }
1105}
1106
1107impl_binops_additive!(ExtendedPoint, ExtendedPoint);
1108
1109impl<'a, 'b> Add<&'b AffinePoint> for &'a ExtendedPoint {
1110    type Output = ExtendedPoint;
1111
1112    #[inline]
1113    fn add(self, other: &'b AffinePoint) -> ExtendedPoint {
1114        self + other.to_niels()
1115    }
1116}
1117
1118impl<'a, 'b> Sub<&'b AffinePoint> for &'a ExtendedPoint {
1119    type Output = ExtendedPoint;
1120
1121    #[inline]
1122    fn sub(self, other: &'b AffinePoint) -> ExtendedPoint {
1123        self - other.to_niels()
1124    }
1125}
1126
1127impl_binops_additive!(ExtendedPoint, AffinePoint);
1128
1129/// This is a "completed" point produced during a point doubling or
1130/// addition routine. These points exist in the `(U:Z, V:T)` model
1131/// of the curve. This is not exposed in the API because it is
1132/// an implementation detail.
1133struct CompletedPoint {
1134    u: Fq,
1135    v: Fq,
1136    z: Fq,
1137    t: Fq,
1138}
1139
1140impl CompletedPoint {
1141    /// This converts a completed point into an extended point by
1142    /// homogenizing:
1143    ///
1144    /// (u/z, v/t) = (u/z * t/t, v/t * z/z) = (ut/zt, vz/zt)
1145    ///
1146    /// The resulting T coordinate is utvz/zt = uv, and so
1147    /// T1 = u, T2 = v, without loss of generality.
1148    #[inline]
1149    fn into_extended(self) -> ExtendedPoint {
1150        ExtendedPoint {
1151            u: self.u * self.t,
1152            v: self.v * self.z,
1153            z: self.z * self.t,
1154            t1: self.u,
1155            t2: self.v,
1156        }
1157    }
1158}
1159
1160impl Default for AffinePoint {
1161    /// Returns the identity.
1162    fn default() -> AffinePoint {
1163        AffinePoint::identity()
1164    }
1165}
1166
1167impl Default for ExtendedPoint {
1168    /// Returns the identity.
1169    fn default() -> ExtendedPoint {
1170        ExtendedPoint::identity()
1171    }
1172}
1173
1174/// This takes a mutable slice of `ExtendedPoint`s and "normalizes" them using
1175/// only a single inversion for the entire batch. This normalization results in
1176/// all of the points having a Z-coordinate of one. Further, an iterator is
1177/// returned which can be used to obtain `AffinePoint`s for each element in the
1178/// slice.
1179///
1180/// This costs 5 multiplications per element, and a field inversion.
1181pub fn batch_normalize<'a>(v: &'a mut [ExtendedPoint]) -> impl Iterator<Item = AffinePoint> + 'a {
1182    // We use the `t1` field of `ExtendedPoint` for scratch space.
1183    BatchInverter::invert_with_internal_scratch(v, |p| &mut p.z, |p| &mut p.t1);
1184
1185    for p in v.iter_mut() {
1186        let mut q = *p;
1187        let tmp = q.z;
1188
1189        // Set the coordinates to the correct value
1190        q.u *= &tmp; // Multiply by 1/z
1191        q.v *= &tmp; // Multiply by 1/z
1192        q.z = Fq::one(); // z-coordinate is now one
1193        q.t1 = q.u;
1194        q.t2 = q.v;
1195
1196        *p = q;
1197    }
1198
1199    // All extended points are now normalized, but the type
1200    // doesn't encode this fact. Let us offer affine points
1201    // to the caller.
1202
1203    v.iter().map(|p| AffinePoint { u: p.u, v: p.v })
1204}
1205
1206impl<'a, 'b> Mul<&'b Fr> for &'a AffinePoint {
1207    type Output = ExtendedPoint;
1208
1209    fn mul(self, other: &'b Fr) -> ExtendedPoint {
1210        self.to_niels().multiply(&other.to_bytes())
1211    }
1212}
1213
1214impl_binops_multiplicative_mixed!(AffinePoint, Fr, ExtendedPoint);
1215
1216/// This represents a point in the prime-order subgroup of Jubjub, in extended
1217/// coordinates.
1218#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
1219pub struct SubgroupPoint(ExtendedPoint);
1220
1221impl From<SubgroupPoint> for ExtendedPoint {
1222    fn from(val: SubgroupPoint) -> ExtendedPoint {
1223        val.0
1224    }
1225}
1226
1227impl<'a> From<&'a SubgroupPoint> for &'a ExtendedPoint {
1228    fn from(val: &'a SubgroupPoint) -> &'a ExtendedPoint {
1229        &val.0
1230    }
1231}
1232
1233impl fmt::Display for SubgroupPoint {
1234    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1235        write!(f, "{}", self.0)
1236    }
1237}
1238
1239impl ConditionallySelectable for SubgroupPoint {
1240    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
1241        SubgroupPoint(ExtendedPoint::conditional_select(&a.0, &b.0, choice))
1242    }
1243}
1244
1245impl SubgroupPoint {
1246    /// Constructs an AffinePoint given `u` and `v` without checking that the point is on
1247    /// the curve or in the prime-order subgroup.
1248    ///
1249    /// This should only be used for hard-coding constants (e.g. fixed generators); in all
1250    /// other cases, use [`SubgroupPoint::from_bytes`] instead.
1251    ///
1252    /// [`SubgroupPoint::from_bytes`]: SubgroupPoint#impl-GroupEncoding
1253    pub fn from_raw_unchecked(u: Fq, v: Fq) -> Self {
1254        SubgroupPoint(AffinePoint::from_raw_unchecked(u, v).to_extended())
1255    }
1256
1257    /// Return a reference to the underlaying [`ExtendedPoint`].
1258    pub fn as_extended(&self) -> &ExtendedPoint {
1259        &self.0
1260    }
1261}
1262
1263impl<T> Sum<T> for SubgroupPoint
1264where
1265    T: Borrow<SubgroupPoint>,
1266{
1267    fn sum<I>(iter: I) -> Self
1268    where
1269        I: Iterator<Item = T>,
1270    {
1271        iter.fold(Self::identity(), |acc, item| acc + item.borrow())
1272    }
1273}
1274
1275impl Neg for SubgroupPoint {
1276    type Output = SubgroupPoint;
1277
1278    #[inline]
1279    fn neg(self) -> SubgroupPoint {
1280        SubgroupPoint(-self.0)
1281    }
1282}
1283
1284impl Neg for &SubgroupPoint {
1285    type Output = SubgroupPoint;
1286
1287    #[inline]
1288    fn neg(self) -> SubgroupPoint {
1289        SubgroupPoint(-self.0)
1290    }
1291}
1292
1293impl<'a, 'b> Add<&'b SubgroupPoint> for &'a ExtendedPoint {
1294    type Output = ExtendedPoint;
1295
1296    #[inline]
1297    fn add(self, other: &'b SubgroupPoint) -> ExtendedPoint {
1298        self + &other.0
1299    }
1300}
1301
1302impl<'a, 'b> Sub<&'b SubgroupPoint> for &'a ExtendedPoint {
1303    type Output = ExtendedPoint;
1304
1305    #[inline]
1306    fn sub(self, other: &'b SubgroupPoint) -> ExtendedPoint {
1307        self - &other.0
1308    }
1309}
1310
1311impl_binops_additive!(ExtendedPoint, SubgroupPoint);
1312
1313impl<'a, 'b> Add<&'b SubgroupPoint> for &'a SubgroupPoint {
1314    type Output = SubgroupPoint;
1315
1316    #[inline]
1317    fn add(self, other: &'b SubgroupPoint) -> SubgroupPoint {
1318        SubgroupPoint(self.0 + &other.0)
1319    }
1320}
1321
1322impl<'a, 'b> Sub<&'b SubgroupPoint> for &'a SubgroupPoint {
1323    type Output = SubgroupPoint;
1324
1325    #[inline]
1326    fn sub(self, other: &'b SubgroupPoint) -> SubgroupPoint {
1327        SubgroupPoint(self.0 - &other.0)
1328    }
1329}
1330
1331impl_binops_additive!(SubgroupPoint, SubgroupPoint);
1332
1333impl<'a, 'b> Mul<&'b Fr> for &'a SubgroupPoint {
1334    type Output = SubgroupPoint;
1335
1336    fn mul(self, other: &'b Fr) -> SubgroupPoint {
1337        SubgroupPoint(self.0.multiply(&other.to_bytes()))
1338    }
1339}
1340
1341impl_binops_multiplicative!(SubgroupPoint, Fr);
1342
1343impl Group for ExtendedPoint {
1344    type Scalar = Fr;
1345
1346    fn random(mut rng: impl RngCore) -> Self {
1347        loop {
1348            let v = Fq::random(&mut rng);
1349            let flip_sign = rng.next_u32() % 2 != 0;
1350
1351            // See AffinePoint::from_bytes for details.
1352            let v2 = v.square();
1353            let p = ((v2 - Fq::one())
1354                * ((Fq::one() + *EDWARDS_D * v2).invert().unwrap_or(Fq::zero())))
1355            .sqrt()
1356            .map(|u| AffinePoint {
1357                u: if flip_sign { -u } else { u },
1358                v,
1359            });
1360
1361            if p.is_some().into() {
1362                let p = p.unwrap().to_curve();
1363
1364                if bool::from(!p.is_identity()) {
1365                    return p;
1366                }
1367            }
1368        }
1369    }
1370
1371    fn identity() -> Self {
1372        Self::identity()
1373    }
1374
1375    fn generator() -> Self {
1376        AffinePoint::generator().into()
1377    }
1378
1379    fn is_identity(&self) -> Choice {
1380        self.is_identity()
1381    }
1382
1383    #[must_use]
1384    fn double(&self) -> Self {
1385        self.double()
1386    }
1387}
1388
1389impl Group for SubgroupPoint {
1390    type Scalar = Fr;
1391
1392    fn random(mut rng: impl RngCore) -> Self {
1393        loop {
1394            let p = ExtendedPoint::random(&mut rng).clear_cofactor();
1395
1396            if bool::from(!p.is_identity()) {
1397                return p;
1398            }
1399        }
1400    }
1401
1402    fn identity() -> Self {
1403        SubgroupPoint(ExtendedPoint::identity())
1404    }
1405
1406    fn generator() -> Self {
1407        ExtendedPoint::generator().clear_cofactor()
1408    }
1409
1410    fn is_identity(&self) -> Choice {
1411        self.0.is_identity()
1412    }
1413
1414    #[must_use]
1415    fn double(&self) -> Self {
1416        SubgroupPoint(self.0.double())
1417    }
1418}
1419
1420#[cfg(feature = "alloc")]
1421impl WnafGroup for ExtendedPoint {
1422    fn recommended_wnaf_for_num_scalars(num_scalars: usize) -> usize {
1423        // Copied from bls12_381::g1, should be updated.
1424        const RECOMMENDATIONS: [usize; 12] =
1425            [1, 3, 7, 20, 43, 120, 273, 563, 1630, 3128, 7933, 62569];
1426
1427        let mut ret = 4;
1428        for r in &RECOMMENDATIONS {
1429            if num_scalars > *r {
1430                ret += 1;
1431            } else {
1432                break;
1433            }
1434        }
1435
1436        ret
1437    }
1438}
1439
1440impl PrimeGroup for SubgroupPoint {}
1441
1442impl CofactorGroup for ExtendedPoint {
1443    type Subgroup = SubgroupPoint;
1444
1445    fn clear_cofactor(&self) -> Self::Subgroup {
1446        SubgroupPoint(self.mul_by_cofactor())
1447    }
1448
1449    fn into_subgroup(self) -> CtOption<Self::Subgroup> {
1450        CtOption::new(SubgroupPoint(self), self.is_torsion_free())
1451    }
1452
1453    fn is_torsion_free(&self) -> Choice {
1454        self.is_torsion_free()
1455    }
1456}
1457
1458impl Curve for ExtendedPoint {
1459    type AffineRepr = AffinePoint;
1460
1461    fn batch_normalize(p: &[Self], q: &mut [Self::AffineRepr]) {
1462        Self::batch_normalize(p, q);
1463    }
1464
1465    fn to_affine(&self) -> Self::AffineRepr {
1466        self.into()
1467    }
1468}
1469
1470impl CofactorCurve for ExtendedPoint {
1471    type Affine = AffinePoint;
1472}
1473
1474impl CofactorCurveAffine for AffinePoint {
1475    type Scalar = Fr;
1476    type Curve = ExtendedPoint;
1477
1478    fn identity() -> Self {
1479        Self::identity()
1480    }
1481
1482    fn generator() -> Self {
1483        // The point with the lowest positive v-coordinate and positive u-coordinate.
1484        AffinePoint {
1485            u: Fq::from_u64s_le(&[
1486                0xe4b3_d35d_f1a7_adfe,
1487                0xcaf5_5d1b_29bf_81af,
1488                0x8b0f_03dd_d60a_8187,
1489                0x62ed_cbb8_bf37_87c8,
1490            ]).unwrap(),
1491            v: Fq::from_u64s_le(&[
1492                0x0000_0000_0000_000b,
1493                0x0000_0000_0000_0000,
1494                0x0000_0000_0000_0000,
1495                0x0000_0000_0000_0000,
1496            ]).unwrap(),
1497        }
1498    }
1499
1500    fn is_identity(&self) -> Choice {
1501        self.is_identity()
1502    }
1503
1504    fn to_curve(&self) -> Self::Curve {
1505        (*self).into()
1506    }
1507}
1508
1509impl GroupEncoding for ExtendedPoint {
1510    type Repr = [u8; 32];
1511
1512    fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
1513        AffinePoint::from_bytes(*bytes).map(Self::from)
1514    }
1515
1516    fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
1517        // We can't avoid curve checks when parsing a compressed encoding.
1518        AffinePoint::from_bytes(*bytes).map(Self::from)
1519    }
1520
1521    fn to_bytes(&self) -> Self::Repr {
1522        AffinePoint::from(self).to_bytes()
1523    }
1524}
1525
1526impl GroupEncoding for SubgroupPoint {
1527    type Repr = [u8; 32];
1528
1529    fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
1530        ExtendedPoint::from_bytes(bytes).and_then(|p| p.into_subgroup())
1531    }
1532
1533    fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
1534        ExtendedPoint::from_bytes_unchecked(bytes).map(SubgroupPoint)
1535    }
1536
1537    fn to_bytes(&self) -> Self::Repr {
1538        self.0.to_bytes()
1539    }
1540}
1541
1542impl GroupEncoding for AffinePoint {
1543    type Repr = [u8; 32];
1544
1545    fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
1546        Self::from_bytes(*bytes)
1547    }
1548
1549    fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
1550        Self::from_bytes(*bytes)
1551    }
1552
1553    fn to_bytes(&self) -> Self::Repr {
1554        self.to_bytes()
1555    }
1556}
1557
1558#[test]
1559fn test_is_on_curve_var() {
1560    assert!(AffinePoint::identity().is_on_curve_vartime());
1561}
1562
1563#[test]
1564fn test_d_is_non_quadratic_residue() {
1565    assert!(bool::from(EDWARDS_D.sqrt().is_none()));
1566    assert!(bool::from((-*EDWARDS_D).sqrt().is_none()));
1567    assert!(bool::from((-*EDWARDS_D).invert().unwrap().sqrt().is_none()));
1568}
1569
1570#[test]
1571fn test_affine_niels_point_identity() {
1572    assert_eq!(
1573        AffineNielsPoint::identity().v_plus_u,
1574        AffinePoint::identity().to_niels().v_plus_u
1575    );
1576    assert_eq!(
1577        AffineNielsPoint::identity().v_minus_u,
1578        AffinePoint::identity().to_niels().v_minus_u
1579    );
1580    assert_eq!(
1581        AffineNielsPoint::identity().t2d,
1582        AffinePoint::identity().to_niels().t2d
1583    );
1584}
1585
1586#[test]
1587fn test_extended_niels_point_identity() {
1588    assert_eq!(
1589        ExtendedNielsPoint::identity().v_plus_u,
1590        ExtendedPoint::identity().to_niels().v_plus_u
1591    );
1592    assert_eq!(
1593        ExtendedNielsPoint::identity().v_minus_u,
1594        ExtendedPoint::identity().to_niels().v_minus_u
1595    );
1596    assert_eq!(
1597        ExtendedNielsPoint::identity().z,
1598        ExtendedPoint::identity().to_niels().z
1599    );
1600    assert_eq!(
1601        ExtendedNielsPoint::identity().t2d,
1602        ExtendedPoint::identity().to_niels().t2d
1603    );
1604}
1605
1606#[test]
1607fn test_assoc() {
1608    let p = ExtendedPoint::from(AffinePoint {
1609        u: Fq::from_u64s_le(&[
1610            0x81c5_71e5_d883_cfb0,
1611            0x049f_7a68_6f14_7029,
1612            0xf539_c860_bc3e_a21f,
1613            0x4284_715b_7ccc_8162,
1614        ]).unwrap(),
1615        v: Fq::from_u64s_le(&[
1616            0xbf09_6275_684b_b8ca,
1617            0xc7ba_2458_90af_256d,
1618            0x5911_9f3e_8638_0eb0,
1619            0x3793_de18_2f9f_b1d2,
1620        ]).unwrap(),
1621    })
1622    .mul_by_cofactor();
1623    assert!(p.is_on_curve_vartime());
1624
1625    assert_eq!(
1626        (p * Fr::from(1000u64)) * Fr::from(3938u64),
1627        p * (Fr::from(1000u64) * Fr::from(3938u64)),
1628    );
1629}
1630
1631#[test]
1632fn test_batch_normalize() {
1633    let mut p = ExtendedPoint::from(AffinePoint {
1634        u: Fq::from_u64s_le(&[
1635            0x81c5_71e5_d883_cfb0,
1636            0x049f_7a68_6f14_7029,
1637            0xf539_c860_bc3e_a21f,
1638            0x4284_715b_7ccc_8162,
1639        ]).unwrap(),
1640        v: Fq::from_u64s_le(&[
1641            0xbf09_6275_684b_b8ca,
1642            0xc7ba_2458_90af_256d,
1643            0x5911_9f3e_8638_0eb0,
1644            0x3793_de18_2f9f_b1d2,
1645        ]).unwrap(),
1646    })
1647    .mul_by_cofactor();
1648
1649    let mut v = vec![];
1650    for _ in 0..10 {
1651        v.push(p);
1652        p = p.double();
1653    }
1654
1655    for p in &v {
1656        assert!(p.is_on_curve_vartime());
1657    }
1658
1659    let expected: std::vec::Vec<_> = v.iter().map(|p| AffinePoint::from(*p)).collect();
1660    let mut result0 = vec![AffinePoint::identity(); v.len()];
1661    ExtendedPoint::batch_normalize(&v, &mut result0);
1662    for i in 0..10 {
1663        assert!(expected[i] == result0[i]);
1664    }
1665    let result1: std::vec::Vec<_> = batch_normalize(&mut v).collect();
1666    for i in 0..10 {
1667        assert!(expected[i] == result1[i]);
1668        assert!(v[i].is_on_curve_vartime());
1669        assert!(AffinePoint::from(v[i]) == expected[i]);
1670    }
1671    let result2: std::vec::Vec<_> = batch_normalize(&mut v).collect();
1672    for i in 0..10 {
1673        assert!(expected[i] == result2[i]);
1674        assert!(v[i].is_on_curve_vartime());
1675        assert!(AffinePoint::from(v[i]) == expected[i]);
1676    }
1677}
1678
1679#[cfg(test)]
1680fn full_generator() -> AffinePoint {
1681    AffinePoint::from_raw_unchecked(
1682        Fq::from_u64s_le(&[
1683            0xe4b3_d35d_f1a7_adfe,
1684            0xcaf5_5d1b_29bf_81af,
1685            0x8b0f_03dd_d60a_8187,
1686            0x62ed_cbb8_bf37_87c8,
1687        ]).unwrap(),
1688        Fq::from_u64s_le(&[0xb, 0x0, 0x0, 0x0]).unwrap(),
1689    )
1690}
1691
1692#[cfg(test)]
1693fn eight_torsion() -> [AffinePoint; 8] {
1694    [
1695        AffinePoint::from_raw_unchecked(
1696            Fq::from_u64s_le(&[
1697                0xd92e_6a79_2720_0d43,
1698                0x7aa4_1ac4_3dae_8582,
1699                0xeaaa_e086_a166_18d1,
1700                0x71d4_df38_ba9e_7973,
1701            ]).unwrap(),
1702            Fq::from_u64s_le(&[
1703                0xff0d_2068_eff4_96dd,
1704                0x9106_ee90_f384_a4a1,
1705                0x16a1_3035_ad4d_7266,
1706                0x4958_bdb2_1966_982e,
1707            ]).unwrap(),
1708        ),
1709        AffinePoint::from_raw_unchecked(
1710            Fq::from_u64s_le(&[
1711                0xfffe_ffff_0000_0001,
1712                0x67ba_a400_89fb_5bfe,
1713                0xa5e8_0b39_939e_d334,
1714                0x73ed_a753_299d_7d47,
1715            ]).unwrap(),
1716            Fq::from_u64s_le(&[0x0, 0x0, 0x0, 0x0]).unwrap(),
1717        ),
1718        AffinePoint::from_raw_unchecked(
1719            Fq::from_u64s_le(&[
1720                0xd92e_6a79_2720_0d43,
1721                0x7aa4_1ac4_3dae_8582,
1722                0xeaaa_e086_a166_18d1,
1723                0x71d4_df38_ba9e_7973,
1724            ]).unwrap(),
1725            Fq::from_u64s_le(&[
1726                0x00f2_df96_100b_6924,
1727                0xc2b6_b572_0c79_b75d,
1728                0x1c98_a7d2_5c54_659e,
1729                0x2a94_e9a1_1036_e51a,
1730            ]).unwrap(),
1731        ),
1732        AffinePoint::from_raw_unchecked(
1733            Fq::from_u64s_le(&[0x0, 0x0, 0x0, 0x0]).unwrap(),
1734            Fq::from_u64s_le(&[
1735                0xffff_ffff_0000_0000,
1736                0x53bd_a402_fffe_5bfe,
1737                0x3339_d808_09a1_d805,
1738                0x73ed_a753_299d_7d48,
1739            ]).unwrap(),
1740        ),
1741        AffinePoint::from_raw_unchecked(
1742            Fq::from_u64s_le(&[
1743                0x26d1_9585_d8df_f2be,
1744                0xd919_893e_c24f_d67c,
1745                0x488e_f781_683b_bf33,
1746                0x0218_c81a_6eff_03d4,
1747            ]).unwrap(),
1748            Fq::from_u64s_le(&[
1749                0x00f2_df96_100b_6924,
1750                0xc2b6_b572_0c79_b75d,
1751                0x1c98_a7d2_5c54_659e,
1752                0x2a94_e9a1_1036_e51a,
1753            ]).unwrap(),
1754        ),
1755        AffinePoint::from_raw_unchecked(
1756            Fq::from_u64s_le(&[
1757                0x0001_0000_0000_0000,
1758                0xec03_0002_7603_0000,
1759                0x8d51_ccce_7603_04d0,
1760                0x0,
1761            ]).unwrap(),
1762            Fq::from_u64s_le(&[0x0, 0x0, 0x0, 0x0]).unwrap(),
1763        ),
1764        AffinePoint::from_raw_unchecked(
1765            Fq::from_u64s_le(&[
1766                0x26d1_9585_d8df_f2be,
1767                0xd919_893e_c24f_d67c,
1768                0x488e_f781_683b_bf33,
1769                0x0218_c81a_6eff_03d4,
1770            ]).unwrap(),
1771            Fq::from_u64s_le(&[
1772                0xff0d_2068_eff4_96dd,
1773                0x9106_ee90_f384_a4a1,
1774                0x16a1_3035_ad4d_7266,
1775                0x4958_bdb2_1966_982e,
1776            ]).unwrap(),
1777        ),
1778        AffinePoint::from_raw_unchecked(
1779            Fq::from_u64s_le(&[0x0, 0x0, 0x0, 0x0]).unwrap(),
1780            Fq::from_u64s_le(&[0x1, 0x0, 0x0, 0x0]).unwrap(),
1781        ),
1782    ]
1783}
1784
1785#[test]
1786fn find_eight_torsion() {
1787    let g = ExtendedPoint::from(full_generator());
1788    assert!(!bool::from(g.is_small_order()));
1789    let g = g.multiply(&FR_MODULUS_BYTES);
1790    assert!(bool::from(g.is_small_order()));
1791
1792    let mut cur = g;
1793
1794    for (i, point) in eight_torsion().iter().enumerate() {
1795        let tmp = AffinePoint::from(cur);
1796        if &tmp != point {
1797            panic!("{}th torsion point should be {:?}", i, tmp);
1798        }
1799
1800        cur += &g;
1801    }
1802}
1803
1804#[test]
1805fn find_curve_generator() {
1806    let mut trial_bytes = [0; 32];
1807    for _ in 0..255 {
1808        let a = AffinePoint::from_bytes(trial_bytes);
1809        if bool::from(a.is_some()) {
1810            let a = a.unwrap();
1811            assert!(a.is_on_curve_vartime());
1812            let b = ExtendedPoint::from(a);
1813            let b = b.multiply(&FR_MODULUS_BYTES);
1814            assert!(bool::from(b.is_small_order()));
1815            let b = b.double();
1816            assert!(bool::from(b.is_small_order()));
1817            let b = b.double();
1818            assert!(bool::from(b.is_small_order()));
1819            if !bool::from(b.is_identity()) {
1820                let b = b.double();
1821                assert!(bool::from(b.is_small_order()));
1822                assert!(bool::from(b.is_identity()));
1823                assert_eq!(full_generator(), a);
1824                assert_eq!(AffinePoint::generator(), a);
1825                assert!(bool::from(a.mul_by_cofactor().is_torsion_free()));
1826                return;
1827            }
1828        }
1829
1830        trial_bytes[0] += 1;
1831    }
1832
1833    panic!("should have found a generator of the curve");
1834}
1835
1836#[test]
1837fn test_small_order() {
1838    for point in eight_torsion().iter() {
1839        assert!(bool::from(point.is_small_order()));
1840    }
1841}
1842
1843#[test]
1844fn test_is_identity() {
1845    let a = eight_torsion()[0].mul_by_cofactor();
1846    let b = eight_torsion()[1].mul_by_cofactor();
1847
1848    assert_eq!(a.u, b.u);
1849    assert_eq!(a.v, a.z);
1850    assert_eq!(b.v, b.z);
1851    assert!(a.v != b.v);
1852    assert!(a.z != b.z);
1853
1854    assert!(bool::from(a.is_identity()));
1855    assert!(bool::from(b.is_identity()));
1856
1857    for point in eight_torsion().iter() {
1858        assert!(bool::from(point.mul_by_cofactor().is_identity()));
1859    }
1860}
1861
1862#[test]
1863fn test_mul_consistency() {
1864    let a = Fr(blst::blst_fr { l: [
1865        0x21e6_1211_d993_4f2e,
1866        0xa52c_058a_693c_3e07,
1867        0x9ccb_77bf_b12d_6360,
1868        0x07df_2470_ec94_398e,
1869    ]});
1870    let b = Fr(blst::blst_fr { l: [
1871        0x0333_6d1c_be19_dbe0,
1872        0x0153_618f_6156_a536,
1873        0x2604_c9e1_fc3c_6b15,
1874        0x04ae_581c_eb02_8720,
1875    ]});
1876    let c = Fr(blst::blst_fr { l: [
1877        0xd7ab_f5bb_2468_3f4c,
1878        0x9d77_12cc_274b_7c03,
1879        0x9732_93db_9683_789f,
1880        0x0b67_7e29_380a_97a7,
1881    ]});
1882    assert_eq!(a * b, c);
1883    let p = ExtendedPoint::from(AffinePoint {
1884        u: Fq::from_u64s_le(&[
1885            0x81c5_71e5_d883_cfb0,
1886            0x049f_7a68_6f14_7029,
1887            0xf539_c860_bc3e_a21f,
1888            0x4284_715b_7ccc_8162,
1889        ]).unwrap(),
1890        v: Fq::from_u64s_le(&[
1891            0xbf09_6275_684b_b8ca,
1892            0xc7ba_2458_90af_256d,
1893            0x5911_9f3e_8638_0eb0,
1894            0x3793_de18_2f9f_b1d2,
1895        ]).unwrap(),
1896    })
1897    .mul_by_cofactor();
1898    assert_eq!(p * c, (p * a) * b);
1899
1900    // Test Mul implemented on ExtendedNielsPoint
1901    assert_eq!(p * c, (p.to_niels() * a) * b);
1902    assert_eq!(p.to_niels() * c, (p * a) * b);
1903    assert_eq!(p.to_niels() * c, (p.to_niels() * a) * b);
1904
1905    // Test Mul implemented on AffineNielsPoint
1906    let p_affine_niels = AffinePoint::from(p).to_niels();
1907    assert_eq!(p * c, (p_affine_niels * a) * b);
1908    assert_eq!(p_affine_niels * c, (p * a) * b);
1909    assert_eq!(p_affine_niels * c, (p_affine_niels * a) * b);
1910}
1911
1912#[test]
1913#[cfg(feature = "multiply-many")]
1914fn test_mul_many() {
1915    let mut rng = rand::thread_rng();
1916    let p = ExtendedPoint::random(&mut rng);
1917    let inputs = (0..256).map(move |_| rand::random::<[u8; 32]>()).collect::<Vec<_>>();
1918
1919    let results_from_multiply = inputs.iter().map(|bits| p.multiply(bits)).collect::<Vec<_>>();
1920    let results_from_multiply_many = p.multiply_many(&inputs);
1921
1922    assert_eq!(results_from_multiply, results_from_multiply_many);
1923}
1924
1925#[test]
1926fn test_serialization_consistency() {
1927    let gen = full_generator().mul_by_cofactor();
1928    let mut p = gen;
1929
1930    let v = vec![
1931        [
1932            203, 85, 12, 213, 56, 234, 12, 193, 19, 132, 128, 64, 142, 110, 170, 185, 179, 108, 97,
1933            63, 13, 211, 247, 120, 79, 219, 110, 234, 131, 123, 19, 215,
1934        ],
1935        [
1936            113, 154, 240, 230, 224, 198, 208, 170, 104, 15, 59, 126, 151, 222, 233, 195, 203, 195,
1937            167, 129, 89, 121, 240, 142, 51, 166, 64, 250, 184, 202, 154, 177,
1938        ],
1939        [
1940            197, 41, 93, 209, 203, 55, 164, 174, 88, 0, 90, 199, 1, 156, 149, 141, 240, 29, 14, 82,
1941            86, 225, 126, 129, 186, 157, 148, 162, 219, 51, 156, 199,
1942        ],
1943        [
1944            182, 117, 250, 241, 81, 196, 199, 227, 151, 74, 243, 17, 221, 97, 200, 139, 192, 83,
1945            231, 35, 214, 14, 95, 69, 130, 201, 4, 116, 177, 19, 179, 0,
1946        ],
1947        [
1948            118, 41, 29, 200, 60, 189, 119, 252, 78, 40, 230, 18, 208, 221, 38, 214, 176, 250, 4,
1949            10, 77, 101, 26, 216, 193, 198, 226, 84, 25, 177, 230, 185,
1950        ],
1951        [
1952            226, 189, 227, 208, 112, 117, 136, 98, 72, 38, 211, 167, 254, 82, 174, 113, 112, 166,
1953            138, 171, 166, 113, 52, 251, 129, 197, 138, 45, 195, 7, 61, 140,
1954        ],
1955        [
1956            38, 198, 156, 196, 146, 225, 55, 163, 138, 178, 157, 128, 115, 135, 204, 215, 0, 33,
1957            171, 20, 60, 32, 142, 209, 33, 233, 125, 146, 207, 12, 16, 24,
1958        ],
1959        [
1960            17, 187, 231, 83, 165, 36, 232, 184, 140, 205, 195, 252, 166, 85, 59, 86, 3, 226, 211,
1961            67, 179, 29, 238, 181, 102, 142, 58, 63, 57, 89, 174, 138,
1962        ],
1963        [
1964            210, 159, 80, 16, 181, 39, 221, 204, 224, 144, 145, 79, 54, 231, 8, 140, 142, 216, 93,
1965            190, 183, 116, 174, 63, 33, 242, 177, 118, 148, 40, 241, 203,
1966        ],
1967        [
1968            0, 143, 107, 102, 149, 187, 27, 124, 18, 10, 98, 28, 113, 123, 121, 185, 29, 152, 14,
1969            130, 149, 28, 87, 35, 135, 135, 153, 54, 112, 53, 54, 68,
1970        ],
1971        [
1972            178, 131, 85, 160, 214, 51, 208, 157, 196, 152, 247, 93, 202, 56, 81, 239, 155, 122,
1973            59, 188, 237, 253, 11, 169, 208, 236, 12, 4, 163, 211, 88, 97,
1974        ],
1975        [
1976            246, 194, 231, 195, 159, 101, 180, 133, 80, 21, 185, 220, 195, 115, 144, 12, 90, 150,
1977            44, 117, 8, 156, 168, 248, 206, 41, 60, 82, 67, 75, 57, 67,
1978        ],
1979        [
1980            212, 205, 171, 153, 113, 16, 194, 241, 224, 43, 177, 110, 190, 248, 22, 201, 208, 166,
1981            2, 83, 134, 130, 85, 129, 166, 136, 185, 191, 163, 38, 54, 10,
1982        ],
1983        [
1984            8, 60, 190, 39, 153, 222, 119, 23, 142, 237, 12, 110, 146, 9, 19, 219, 143, 64, 161,
1985            99, 199, 77, 39, 148, 70, 213, 246, 227, 150, 178, 237, 178,
1986        ],
1987        [
1988            11, 114, 217, 160, 101, 37, 100, 220, 56, 114, 42, 31, 138, 33, 84, 157, 214, 167, 73,
1989            233, 115, 81, 124, 134, 15, 31, 181, 60, 184, 130, 175, 159,
1990        ],
1991        [
1992            141, 238, 235, 202, 241, 32, 210, 10, 127, 230, 54, 31, 146, 80, 247, 9, 107, 124, 0,
1993            26, 203, 16, 237, 34, 214, 147, 133, 15, 29, 236, 37, 88,
1994        ],
1995    ];
1996
1997    let batched = AffinePoint::batch_from_bytes(v.iter().cloned());
1998
1999    for (expected_serialized, batch_deserialized) in v.into_iter().zip(batched.into_iter()) {
2000        assert!(p.is_on_curve_vartime());
2001        let affine = AffinePoint::from(p);
2002        let serialized = affine.to_bytes();
2003        let deserialized = AffinePoint::from_bytes(serialized).unwrap();
2004        assert_eq!(affine, deserialized);
2005        assert_eq!(affine, batch_deserialized.unwrap());
2006        assert_eq!(expected_serialized, serialized);
2007        p += gen;
2008    }
2009}
2010
2011#[test]
2012fn test_zip_216() {
2013    const NON_CANONICAL_ENCODINGS: [[u8; 32]; 2] = [
2014        // (0, 1) with sign bit set to 1.
2015        [
2016            0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2017            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2018            0x00, 0x00, 0x00, 0x80,
2019        ],
2020        // (0, -1) with sign bit set to 1.
2021        [
2022            0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x5b, 0xfe, 0xff, 0x02, 0xa4,
2023            0xbd, 0x53, 0x05, 0xd8, 0xa1, 0x09, 0x08, 0xd8, 0x39, 0x33, 0x48, 0x7d, 0x9d, 0x29,
2024            0x53, 0xa7, 0xed, 0xf3,
2025        ],
2026    ];
2027
2028    for b in &NON_CANONICAL_ENCODINGS {
2029        {
2030            let mut encoding = *b;
2031
2032            // The normal API should reject the non-canonical encoding.
2033            assert!(bool::from(AffinePoint::from_bytes(encoding).is_none()));
2034
2035            // If we clear the sign bit of the non-canonical encoding, it should be
2036            // accepted by the normal API.
2037            encoding[31] &= 0b0111_1111;
2038            assert!(bool::from(AffinePoint::from_bytes(encoding).is_some()));
2039        }
2040
2041        {
2042            // The bug-preserving API should accept the non-canonical encoding, and the
2043            // resulting point should serialize to a different (canonical) encoding.
2044            let parsed = AffinePoint::from_bytes_pre_zip216_compatibility(*b).unwrap();
2045            let mut encoded = parsed.to_bytes();
2046            assert_ne!(b, &encoded);
2047
2048            // If we set the sign bit of the serialized encoding, it should match the
2049            // non-canonical encoding.
2050            encoded[31] |= 0b1000_0000;
2051            assert_eq!(b, &encoded);
2052        }
2053    }
2054}