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