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