nam_jubjub/
lib.rs

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