dusk_jubjub/
lib.rs

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