fullcodec_jubjub/
lib.rs

1//! This crate provides an implementation of the **Jubjub** elliptic curve and
2//! its associated field arithmetic.
3//! See [`README.md`](https://github.com/zkcrypto/jubjub/blob/master/README.md)
4// for more details about Jubjub.
5//!
6//! # API
7//!
8//! * `JubJubAffine` / `JubJubExtended` which are implementations of Jubjub
9//!   group arithmetic
10//! * `AffineNielsPoint` / `ExtendedNielsPoint` which are pre-processed Jubjub
11//!   points
12//! * `BlsScalar`, which is the base field of Jubjub
13//! * `Fr`, which is the scalar field of Jubjub
14//! * `batch_normalize` for converting many `JubJubExtended`s into
15//!   `JubJubAffine`s efficiently.
16//!
17//! # Constant Time
18//!
19//! All operations are constant time unless explicitly noted; these functions
20//! will contain "vartime" in their name and they will be documented as variable
21//! time.
22//!
23//! This crate uses the `subtle` crate to perform constant-time operations.
24
25#![cfg_attr(not(feature = "std"), no_std)]
26// Catch documentation errors caused by code changes.
27#![deny(rustdoc::broken_intra_doc_links)]
28#![deny(missing_debug_implementations)]
29#![deny(missing_docs)]
30#![deny(unsafe_code)]
31// This lint is described at
32// https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_arithmetic_impl
33// In our library, some of the arithmetic will necessarily involve various
34// binary operators, and so this lint is triggered unnecessarily.
35#![allow(clippy::suspicious_arithmetic_impl)]
36
37#[cfg(test)]
38#[macro_use]
39extern crate std;
40
41#[cfg(feature = "canon")]
42use canonical_derive::Canon;
43use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
44use dusk_bytes::{Error as BytesError, Serializable};
45use subtle;
46use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
47
48#[macro_use]
49mod util;
50mod fr;
51
52/// Implementation of ElGamal encryption scheme with JubJub
53pub mod elgamal;
54
55pub use bls12_381::BlsScalar;
56pub use fr::Fr as JubJubScalar;
57
58pub(crate) use fr::Fr;
59
60/// A better name than Fr.
61pub type Scalar = Fr;
62
63const FR_MODULUS_BYTES: [u8; 32] = [
64    183, 44, 247, 214, 94, 14, 151, 208, 130, 16, 200, 204, 147, 32, 104, 166,
65    0, 59, 52, 1, 1, 59, 103, 6, 169, 175, 51, 101, 234, 180, 125, 14,
66];
67
68/// This represents a Jubjub point in the affine `(x, y)`
69/// coordinates.
70#[derive(Clone, Copy, Debug)]
71#[cfg_attr(feature = "canon", derive(Canon))]
72pub struct JubJubAffine {
73    x: BlsScalar,
74    y: BlsScalar,
75}
76
77impl Neg for JubJubAffine {
78    type Output = JubJubAffine;
79
80    /// This computes the negation of a point `P = (x, y)`
81    /// as `-P = (-x, y)`.
82    #[inline]
83    fn neg(self) -> JubJubAffine {
84        JubJubAffine {
85            x: -self.x,
86            y: self.y,
87        }
88    }
89}
90
91impl ConstantTimeEq for JubJubAffine {
92    fn ct_eq(&self, other: &Self) -> Choice {
93        self.x.ct_eq(&other.x) & self.y.ct_eq(&other.y)
94    }
95}
96
97impl PartialEq for JubJubAffine {
98    fn eq(&self, other: &Self) -> bool {
99        self.ct_eq(other).unwrap_u8() == 1
100    }
101}
102
103impl ConditionallySelectable for JubJubAffine {
104    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
105        JubJubAffine {
106            x: BlsScalar::conditional_select(&a.x, &b.x, choice),
107            y: BlsScalar::conditional_select(&a.y, &b.y, choice),
108        }
109    }
110}
111
112/// Use a fixed generator point.
113/// The point is then reduced according to the prime field. We need only to
114/// state the coordinates, so users can exploit its properties
115/// which are proven by tests, checking:
116/// - It lies on the curve,
117/// - Is of prime order,
118/// - Is not the identity point.
119/// Using:
120///     x = 0x3fd2814c43ac65a6f1fbf02d0fd6cce62e3ebb21fd6c54ed4df7b7ffec7beaca
121//      y = 0x0000000000000000000000000000000000000000000000000000000000000012
122pub const GENERATOR: JubJubAffine = JubJubAffine {
123    x: BlsScalar::from_raw([
124        0x4df7b7ffec7beaca,
125        0x2e3ebb21fd6c54ed,
126        0xf1fbf02d0fd6cce6,
127        0x3fd2814c43ac65a6,
128    ]),
129    y: BlsScalar::from_raw([
130        0x0000000000000012,
131        000000000000000000,
132        000000000000000000,
133        000000000000,
134    ]),
135};
136
137/// [`GENERATOR`] in [`JubJubExtended`] form
138pub const GENERATOR_EXTENDED: JubJubExtended = JubJubExtended {
139    x: GENERATOR.x,
140    y: GENERATOR.y,
141    z: BlsScalar::one(),
142    t1: GENERATOR.x,
143    t2: GENERATOR.y,
144};
145
146/// GENERATOR NUMS which is obtained following the specs in:
147/// https://app.gitbook.com/@dusk-network/s/specs/specifications/poseidon/pedersen-commitment-scheme
148/// The counter = 18 and the hash function used to compute it was blake2b
149/// Using:
150///     x = 0x5e67b8f316f414f7bd9514c773fd4456931e316a39fe4541921710179df76377
151//      y = 0x43d80eb3b2f3eb1b7b162dbeeb3b34fd9949ba0f82a5507a6705b707162e3ef8
152pub const GENERATOR_NUMS: JubJubAffine = JubJubAffine {
153    x: BlsScalar::from_raw([
154        0x921710179df76377,
155        0x931e316a39fe4541,
156        0xbd9514c773fd4456,
157        0x5e67b8f316f414f7,
158    ]),
159    y: BlsScalar::from_raw([
160        0x6705b707162e3ef8,
161        0x9949ba0f82a5507a,
162        0x7b162dbeeb3b34fd,
163        0x43d80eb3b2f3eb1b,
164    ]),
165};
166
167/// [`GENERATOR_NUMS`] in [`JubJubExtended`] form
168pub const GENERATOR_NUMS_EXTENDED: JubJubExtended = JubJubExtended {
169    x: GENERATOR_NUMS.x,
170    y: GENERATOR_NUMS.y,
171    z: BlsScalar::one(),
172    t1: GENERATOR_NUMS.x,
173    t2: GENERATOR_NUMS.y,
174};
175
176// 202, 234, 123, 236, 255, 183, 247, 77, 237, 84, 108, 253, 33, 187, 62, 46,
177// 230, 204, 214,15, 45, 240, 251, 241, 166, 101, 172, 67, 76, 129, 210, 63,
178
179// 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
180// 0, 0, 0, 0, 0, 0, 0,
181
182/// This represents an extended point `(X, Y, Z, T1, T2)`
183/// with `Z` nonzero, corresponding to the affine point
184/// `(X/Z, Y/Z)`. We always have `T1 * T2 = XY/Z`.
185///
186/// You can do the following things with a point in this
187/// form:
188///
189/// * Convert it into a point in the affine form.
190/// * Add it to an `JubJubExtended`, `AffineNielsPoint` or `ExtendedNielsPoint`.
191/// * Double it using `double()`.
192/// * Compare it with another extended point using `PartialEq` or `ct_eq()`.
193#[derive(Clone, Copy, Debug)]
194#[cfg_attr(feature = "canon", derive(Canon))]
195pub struct JubJubExtended {
196    x: BlsScalar,
197    y: BlsScalar,
198    z: BlsScalar,
199    t1: BlsScalar,
200    t2: BlsScalar,
201}
202
203impl ConstantTimeEq for JubJubExtended {
204    fn ct_eq(&self, other: &Self) -> Choice {
205        // (x/z, y/z) = (x'/z', y'/z') is implied by
206        //      (xz'z = x'z'z) and
207        //      (yz'z = y'z'z)
208        // as z and z' are always nonzero.
209
210        (&self.x * &other.z).ct_eq(&(&other.x * &self.z))
211            & (&self.y * &other.z).ct_eq(&(&other.y * &self.z))
212    }
213}
214
215impl ConditionallySelectable for JubJubExtended {
216    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
217        JubJubExtended {
218            x: BlsScalar::conditional_select(&a.x, &b.x, choice),
219            y: BlsScalar::conditional_select(&a.y, &b.y, choice),
220            z: BlsScalar::conditional_select(&a.z, &b.z, choice),
221            t1: BlsScalar::conditional_select(&a.t1, &b.t1, choice),
222            t2: BlsScalar::conditional_select(&a.t2, &b.t2, choice),
223        }
224    }
225}
226
227impl PartialEq for JubJubExtended {
228    fn eq(&self, other: &Self) -> bool {
229        self.ct_eq(other).unwrap_u8() == 1
230    }
231}
232
233impl Neg for JubJubExtended {
234    type Output = JubJubExtended;
235
236    /// Computes the negation of a point `P = (X, Y, Z, T)`
237    /// as `-P = (-X, Y, Z, -T1, T2)`. The choice of `T1`
238    /// is made without loss of generality.
239    #[inline]
240    fn neg(self) -> JubJubExtended {
241        JubJubExtended {
242            x: -self.x,
243            y: self.y,
244            z: self.z,
245            t1: -self.t1,
246            t2: self.t2,
247        }
248    }
249}
250
251impl From<JubJubAffine> for JubJubExtended {
252    /// Constructs an extended point (with `Z = 1`) from
253    /// an affine point using the map `(x, y) => (x, y, 1, x, y)`.
254    fn from(affine: JubJubAffine) -> JubJubExtended {
255        JubJubExtended {
256            x: affine.x,
257            y: affine.y,
258            z: BlsScalar::one(),
259            t1: affine.x,
260            t2: affine.y,
261        }
262    }
263}
264
265impl<'a> From<&'a JubJubExtended> for JubJubAffine {
266    /// Constructs an affine point from an extended point
267    /// using the map `(X, Y, Z, T1, T2) => (XZ, Y/Z)`
268    /// as Z is always nonzero. **This requires a field inversion
269    /// and so it is recommended to perform these in a batch
270    /// using [`batch_normalize`](crate::batch_normalize) instead.**
271    fn from(extended: &'a JubJubExtended) -> JubJubAffine {
272        // Z coordinate is always nonzero, so this is
273        // its inverse.
274        let zinv = extended.z.invert().unwrap();
275
276        JubJubAffine {
277            x: extended.x * &zinv,
278            y: extended.y * &zinv,
279        }
280    }
281}
282
283impl From<JubJubExtended> for JubJubAffine {
284    fn from(extended: JubJubExtended) -> JubJubAffine {
285        JubJubAffine::from(&extended)
286    }
287}
288
289/// This is a pre-processed version of an affine point `(x, y)`
290/// in the form `(y + x, y - x, x * y * 2d)`. This can be added to an
291/// [`JubJubExtended`](crate::JubJubExtended).
292#[derive(Clone, Copy, Debug)]
293pub struct AffineNielsPoint {
294    y_plus_x: BlsScalar,
295    y_minus_x: BlsScalar,
296    t2d: BlsScalar,
297}
298
299impl AffineNielsPoint {
300    /// Constructs this point from the neutral element `(0, 1)`.
301    pub const fn identity() -> Self {
302        AffineNielsPoint {
303            y_plus_x: BlsScalar::one(),
304            y_minus_x: BlsScalar::one(),
305            t2d: BlsScalar::zero(),
306        }
307    }
308
309    #[inline]
310    fn multiply(&self, by: &[u8; 32]) -> JubJubExtended {
311        let zero = AffineNielsPoint::identity();
312
313        let mut acc = JubJubExtended::identity();
314
315        // This is a simple double-and-add implementation of point
316        // multiplication, moving from most significant to least
317        // significant bit of the scalar.
318        //
319        // We skip the leading four bits because they're always
320        // unset for Fr.
321        for bit in by
322            .iter()
323            .rev()
324            .flat_map(|byte| {
325                (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8))
326            })
327            .skip(4)
328        {
329            acc = acc.double();
330            acc += AffineNielsPoint::conditional_select(&zero, &self, bit);
331        }
332
333        acc
334    }
335
336    /// Multiplies this point by the specific little-endian bit pattern in the
337    /// given byte array, ignoring the highest four bits.
338    pub fn multiply_bits(&self, by: &[u8; 32]) -> JubJubExtended {
339        self.multiply(by)
340    }
341}
342
343impl<'a, 'b> Mul<&'b Fr> for &'a AffineNielsPoint {
344    type Output = JubJubExtended;
345
346    fn mul(self, other: &'b Fr) -> JubJubExtended {
347        self.multiply(&other.to_bytes())
348    }
349}
350
351impl_binops_multiplicative_mixed!(AffineNielsPoint, Fr, JubJubExtended);
352
353impl ConditionallySelectable for AffineNielsPoint {
354    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
355        AffineNielsPoint {
356            y_plus_x: BlsScalar::conditional_select(
357                &a.y_plus_x,
358                &b.y_plus_x,
359                choice,
360            ),
361            y_minus_x: BlsScalar::conditional_select(
362                &a.y_minus_x,
363                &b.y_minus_x,
364                choice,
365            ),
366            t2d: BlsScalar::conditional_select(&a.t2d, &b.t2d, choice),
367        }
368    }
369}
370
371/// This is a pre-processed version of an extended point `(X, Y, Z, T1, T2)`
372/// in the form `(Y + X, Y - X, Z, T1 * T2 * 2d)`.
373#[derive(Clone, Copy, Debug)]
374pub struct ExtendedNielsPoint {
375    y_plus_x: BlsScalar,
376    y_minus_x: BlsScalar,
377    z: BlsScalar,
378    t2d: BlsScalar,
379}
380
381impl ConditionallySelectable for ExtendedNielsPoint {
382    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
383        ExtendedNielsPoint {
384            y_plus_x: BlsScalar::conditional_select(
385                &a.y_plus_x,
386                &b.y_plus_x,
387                choice,
388            ),
389            y_minus_x: BlsScalar::conditional_select(
390                &a.y_minus_x,
391                &b.y_minus_x,
392                choice,
393            ),
394            z: BlsScalar::conditional_select(&a.z, &b.z, choice),
395            t2d: BlsScalar::conditional_select(&a.t2d, &b.t2d, choice),
396        }
397    }
398}
399
400impl ExtendedNielsPoint {
401    /// Constructs this point from the neutral element `(0, 1)`.
402    pub const fn identity() -> Self {
403        ExtendedNielsPoint {
404            y_plus_x: BlsScalar::one(),
405            y_minus_x: BlsScalar::one(),
406            z: BlsScalar::one(),
407            t2d: BlsScalar::zero(),
408        }
409    }
410
411    #[inline]
412    fn multiply(&self, by: &[u8; 32]) -> JubJubExtended {
413        let zero = ExtendedNielsPoint::identity();
414
415        let mut acc = JubJubExtended::identity();
416
417        // This is a simple double-and-add implementation of point
418        // multiplication, moving from most significant to least
419        // significant bit of the scalar.
420        //
421        // We skip the leading four bits because they're always
422        // unset for Fr.
423        for bit in by
424            .iter()
425            .rev()
426            .flat_map(|byte| {
427                (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8))
428            })
429            .skip(4)
430        {
431            acc = acc.double();
432            acc += ExtendedNielsPoint::conditional_select(&zero, &self, bit);
433        }
434
435        acc
436    }
437
438    /// Multiplies this point by the specific little-endian bit pattern in the
439    /// given byte array, ignoring the highest four bits.
440    pub fn multiply_bits(&self, by: &[u8; 32]) -> JubJubExtended {
441        self.multiply(by)
442    }
443}
444
445impl<'a, 'b> Mul<&'b Fr> for &'a ExtendedNielsPoint {
446    type Output = JubJubExtended;
447
448    fn mul(self, other: &'b Fr) -> JubJubExtended {
449        self.multiply(&other.to_bytes())
450    }
451}
452
453impl_binops_multiplicative_mixed!(ExtendedNielsPoint, Fr, JubJubExtended);
454
455/// `d = -(10240/10241)`
456pub const EDWARDS_D: BlsScalar = BlsScalar::from_raw([
457    0x01065fd6d6343eb1,
458    0x292d7f6d37579d26,
459    0xf5fd9207e6bd7fd4,
460    0x2a9318e74bfa2b48,
461]);
462
463/// `2*EDWARDS_D`
464pub const EDWARDS_D2: BlsScalar = BlsScalar::from_raw([
465    0x020cbfadac687d62,
466    0x525afeda6eaf3a4c,
467    0xebfb240fcd7affa8,
468    0x552631ce97f45691,
469]);
470
471impl Serializable<32> for JubJubAffine {
472    type Error = BytesError;
473
474    /// Converts this element into its byte representation.
475    fn to_bytes(&self) -> [u8; Self::SIZE] {
476        let mut tmp = self.y.to_bytes();
477        let x = self.x.to_bytes();
478
479        // Encode the sign of the x-coordinate in the most
480        // significant bit.
481        tmp[31] |= x[0] << 7;
482
483        tmp
484    }
485
486    /// Attempts to interpret a byte representation of an
487    /// affine point, failing if the element is not on
488    /// the curve or non-canonical.
489    ///
490    /// NOTE: ZIP 216 is enabled by default and the only way to interact with
491    /// serialization.
492    /// See: <https://zips.z.cash/zip-0216> for more details.
493    fn from_bytes(b: &[u8; Self::SIZE]) -> Result<Self, Self::Error> {
494        let mut b = b.clone();
495
496        // Grab the sign bit from the representation
497        let sign = b[31] >> 7;
498
499        // Mask away the sign bit
500        b[31] &= 0b0111_1111;
501
502        // Interpret what remains as the y-coordinate
503        let y = BlsScalar::from_bytes(&b)?;
504
505        // -x^2 + y^2 = 1 + d.x^2.y^2
506        // -x^2 = 1 + d.x^2.y^2 - y^2    (rearrange)
507        // -x^2 - d.x^2.y^2 = 1 - y^2    (rearrange)
508        // x^2 + d.x^2.y^2 = y^2 - 1     (flip signs)
509        // x^2 (1 + d.y^2) = y^2 - 1     (factor)
510        // x^2 = (y^2 - 1) / (1 + d.y^2) (isolate x^2)
511        // We know that (1 + d.y^2) is nonzero for all y:
512        //   (1 + d.y^2) = 0
513        //   d.y^2 = -1
514        //   y^2 = -(1 / d)   No solutions, as -(1 / d) is not a square
515
516        let y2 = y.square();
517
518        Option::from(
519            ((y2 - BlsScalar::one())
520                * ((BlsScalar::one() + EDWARDS_D * &y2)
521                    .invert()
522                    .unwrap_or(BlsScalar::zero())))
523            .sqrt()
524            .and_then(|x| {
525                // Fix the sign of `x` if necessary
526                let flip_sign = Choice::from((x.to_bytes()[0] ^ sign) & 1);
527                let x = BlsScalar::conditional_select(&x, &-x, flip_sign);
528                // If x == 0, flip_sign == sign_bit. We therefore want to reject
529                // the encoding as non-canonical if all of the
530                // following occur:
531                // - x == 0
532                // - flip_sign == true
533                let x_is_zero = x.ct_eq(&BlsScalar::zero());
534                CtOption::new(JubJubAffine { x, y }, !(x_is_zero & flip_sign))
535            }),
536        )
537        .ok_or(BytesError::InvalidData)
538    }
539}
540
541impl JubJubAffine {
542    /// Constructs the neutral element `(0, 1)`.
543    pub const fn identity() -> Self {
544        JubJubAffine {
545            x: BlsScalar::zero(),
546            y: BlsScalar::one(),
547        }
548    }
549
550    /// Multiplies this point by the cofactor, producing an
551    /// `JubJubExtended`
552    pub fn mul_by_cofactor(&self) -> JubJubExtended {
553        JubJubExtended::from(*self).mul_by_cofactor()
554    }
555
556    /// Determines if this point is of small order.
557    pub fn is_small_order(&self) -> Choice {
558        JubJubExtended::from(*self).is_small_order()
559    }
560
561    /// Determines if this point is torsion free and so is
562    /// in the prime order subgroup.
563    pub fn is_torsion_free(&self) -> Choice {
564        JubJubExtended::from(*self).is_torsion_free()
565    }
566
567    /// Determines if this point is prime order, or in other words that
568    /// the smallest scalar multiplied by this point that produces the
569    /// identity is `r`. This is equivalent to checking that the point
570    /// is both torsion free and not the identity.
571    pub fn is_prime_order(&self) -> Choice {
572        let extended = JubJubExtended::from(*self);
573        extended.is_torsion_free() & (!extended.is_identity())
574    }
575
576    /// Returns the `x`-coordinate of this point.
577    pub fn get_x(&self) -> BlsScalar {
578        self.x
579    }
580
581    /// Returns the `y`-coordinate of this point.
582    pub fn get_y(&self) -> BlsScalar {
583        self.y
584    }
585
586    /// Performs a pre-processing step that produces an `AffineNielsPoint`
587    /// for use in multiple additions.
588    pub const fn to_niels(&self) -> AffineNielsPoint {
589        AffineNielsPoint {
590            y_plus_x: BlsScalar::add(&self.y, &self.x),
591            y_minus_x: BlsScalar::sub(&self.y, &self.x),
592            t2d: BlsScalar::mul(&BlsScalar::mul(&self.x, &self.y), &EDWARDS_D2),
593        }
594    }
595
596    /// Constructs an JubJubAffine given `x` and `y` without checking
597    /// that the point is on the curve.
598    pub const fn from_raw_unchecked(
599        x: BlsScalar,
600        y: BlsScalar,
601    ) -> JubJubAffine {
602        JubJubAffine { x, y }
603    }
604
605    /// This is only for debugging purposes and not
606    /// exposed in the public API. Checks that this
607    /// point is on the curve.
608    #[cfg(test)]
609    fn is_on_curve_vartime(&self) -> bool {
610        let x2 = self.x.square();
611        let y2 = self.y.square();
612
613        &y2 - &x2 == BlsScalar::one() + &EDWARDS_D * &x2 * &y2
614    }
615}
616
617impl JubJubExtended {
618    /// Returns the `x`-coordinate of this point.
619    pub fn get_x(&self) -> BlsScalar {
620        self.x
621    }
622
623    /// Returns the `y`-coordinate of this point.
624    pub fn get_y(&self) -> BlsScalar {
625        self.y
626    }
627
628    /// Returns the `z`-coordinate of this point.
629    pub fn get_z(&self) -> BlsScalar {
630        self.z
631    }
632
633    /// Returns the `t1`-coordinate of this point.
634    pub fn get_t1(&self) -> BlsScalar {
635        self.t1
636    }
637
638    /// Returns the `t2`-coordinate of this point.
639    pub fn get_t2(&self) -> BlsScalar {
640        self.t2
641    }
642
643    /// Constructs an extended point from the neutral element `(0, 1)`.
644    pub const fn identity() -> Self {
645        JubJubExtended {
646            x: BlsScalar::zero(),
647            y: BlsScalar::one(),
648            z: BlsScalar::one(),
649            t1: BlsScalar::zero(),
650            t2: BlsScalar::zero(),
651        }
652    }
653
654    /// Determines if this point is the identity.
655    pub fn is_identity(&self) -> Choice {
656        // If this point is the identity, then
657        //     x = 0 * z = 0
658        // and y = 1 * z = z
659        self.x.ct_eq(&BlsScalar::zero()) & self.y.ct_eq(&self.z)
660    }
661
662    /// Determines if this point is of small order.
663    pub fn is_small_order(&self) -> Choice {
664        // We only need to perform two doublings, since the 2-torsion
665        // points are (0, 1) and (0, -1), and so we only need to check
666        // that the x-coordinate of the result is zero to see if the
667        // point is small order.
668        self.double().double().x.ct_eq(&BlsScalar::zero())
669    }
670
671    /// Determines if this point is torsion free and so is contained
672    /// in the prime order subgroup.
673    pub fn is_torsion_free(&self) -> Choice {
674        self.multiply(&FR_MODULUS_BYTES).is_identity()
675    }
676
677    /// Determines if this point is prime order, or in other words that
678    /// the smallest scalar multiplied by this point that produces the
679    /// identity is `r`. This is equivalent to checking that the point
680    /// is both torsion free and not the identity.
681    pub fn is_prime_order(&self) -> Choice {
682        self.is_torsion_free() & (!self.is_identity())
683    }
684
685    /// Multiplies this element by the cofactor `8`.
686    pub fn mul_by_cofactor(&self) -> JubJubExtended {
687        self.double().double().double()
688    }
689
690    /// Performs a pre-processing step that produces an `ExtendedNielsPoint`
691    /// for use in multiple additions.
692    pub fn to_niels(&self) -> ExtendedNielsPoint {
693        ExtendedNielsPoint {
694            y_plus_x: &self.y + &self.x,
695            y_minus_x: &self.y - &self.x,
696            z: self.z,
697            t2d: &self.t1 * &self.t2 * EDWARDS_D2,
698        }
699    }
700
701    /// Returns two scalars suitable for hashing that represent the
702    /// Extended Point.
703    pub fn to_hash_inputs(&self) -> [BlsScalar; 2] {
704        // The same JubJubAffine can have different JubJubExtended
705        // representations, therefore we convert from Extended to Affine
706        // before hashing, to ensure deterministic result
707        let p = JubJubAffine::from(self);
708        [p.x, p.y]
709    }
710
711    /// Computes the doubling of a point more efficiently than a point can
712    /// be added to itself.
713    pub fn double(&self) -> JubJubExtended {
714        // Doubling is more efficient (three multiplications, four squarings)
715        // when we work within the projective coordinate space (U:Z, V:Z). We
716        // rely on the most efficient formula, "dbl-2008-bbjlp", as described
717        // in Section 6 of "Twisted Edwards Curves" by Bernstein et al.
718        //
719        // See <https://hyperelliptic.org/EFD/g1p/auto-twisted-projective.html#doubling-dbl-2008-bbjlp>
720        // for more information.
721        //
722        // We differ from the literature in that we use (x, y) rather than
723        // (x, y) coordinates. We also have the constant `a = -1` implied. Let
724        // us rewrite the procedure of doubling (x, y, z) to produce (X, Y, Z)
725        // as follows:
726        //
727        // B = (x + y)^2
728        // C = x^2
729        // D = y^2
730        // F = D - C
731        // H = 2 * z^2
732        // J = F - H
733        // X = (B - C - D) * J
734        // Y = F * (- C - D)
735        // Z = F * J
736        //
737        // If we compute K = D + C, we can rewrite this:
738        //
739        // B = (x + y)^2
740        // C = x^2
741        // D = y^2
742        // F = D - C
743        // K = D + C
744        // H = 2 * z^2
745        // J = F - H
746        // X = (B - K) * J
747        // Y = F * (-K)
748        // Z = F * J
749        //
750        // In order to avoid the unnecessary negation of K,
751        // we will negate J, transforming the result into
752        // an equivalent point with a negated z-coordinate.
753        //
754        // B = (x + y)^2
755        // C = x^2
756        // D = y^2
757        // F = D - C
758        // K = D + C
759        // H = 2 * z^2
760        // J = H - F
761        // X = (B - K) * J
762        // Y = F * K
763        // Z = F * J
764        //
765        // Let us rename some variables to simplify:
766        //
767        // XY2 = (x + y)^2
768        // XX = x^2
769        // YY = y^2
770        // YYmXX = YY - XX
771        // YYpXX = YY + XX
772        // ZZ2 = 2 * z^2
773        // J = ZZ2 - YYmXX
774        // X = (XY2 - YYpXX) * J
775        // Y = YYmXX * YYXX
776        // Z = YYmXX * J
777        //
778        // We wish to obtain two factors of T = XY / Z.
779        //
780        // XY / Z
781        // =
782        // (XY2 - YYpXX) * (ZZ2 - VVmUU) * YYmXX * YYpXX / YYmXX / (ZZ2 - YYmXX)
783        // =
784        // (XY2 - YYpXX) * YYmXX * YYpXX / YYmXX
785        // =
786        // (XY2 - YYpXX) * YYpXX
787        //
788        // and so we have that T1 = (XY2 - YYpXX) and T2 = YYpXX.
789
790        let xx = self.x.square();
791        let yy = self.y.square();
792        let zz2 = self.z.square().double();
793        let xy2 = (&self.x + &self.y).square();
794        let yy_plus_xx = &yy + &xx;
795        let yy_minus_xx = &yy - &xx;
796
797        // The remaining arithmetic is exactly the process of converting
798        // from a completed point to an extended point.
799        CompletedPoint {
800            x: &xy2 - &yy_plus_xx,
801            y: yy_plus_xx,
802            z: yy_minus_xx,
803            t: &zz2 - &yy_minus_xx,
804        }
805        .into_extended()
806    }
807
808    #[inline]
809    fn multiply(self, by: &[u8; 32]) -> Self {
810        self.to_niels().multiply(by)
811    }
812
813    /// This is only for debugging purposes and not
814    /// exposed in the public API. Checks that this
815    /// point is on the curve.
816    #[cfg(test)]
817    fn is_on_curve_vartime(&self) -> bool {
818        let affine = JubJubAffine::from(*self);
819
820        self.z != BlsScalar::zero()
821            && affine.is_on_curve_vartime()
822            && (affine.x * affine.y * self.z == self.t1 * self.t2)
823    }
824}
825
826impl<'a, 'b> Mul<&'b Fr> for &'a JubJubExtended {
827    type Output = JubJubExtended;
828
829    fn mul(self, other: &'b Fr) -> JubJubExtended {
830        self.multiply(&other.to_bytes())
831    }
832}
833
834impl_binops_multiplicative!(JubJubExtended, Fr);
835
836impl<'a, 'b> Add<&'b ExtendedNielsPoint> for &'a JubJubExtended {
837    type Output = JubJubExtended;
838
839    #[allow(clippy::suspicious_arithmetic_impl)]
840    fn add(self, other: &'b ExtendedNielsPoint) -> JubJubExtended {
841        // We perform addition in the extended coordinates. Here we use
842        // a formula presented by Hisil, Wong, Carter and Dawson in
843        // "Twisted Edward Curves Revisited" which only requires 8M.
844        //
845        // A = (Y1 - X1) * (Y2 - X2)
846        // B = (Y1 + X1) * (Y2 + X2)
847        // C = 2d * T1 * T2
848        // D = 2 * Z1 * Z2
849        // E = B - A
850        // F = D - C
851        // G = D + C
852        // H = B + A
853        // X3 = E * F
854        // Y3 = G * H
855        // Z3 = F * G
856        // T3 = E * H
857
858        let a = (&self.y - &self.x) * &other.y_minus_x;
859        let b = (&self.y + &self.x) * &other.y_plus_x;
860        let c = &self.t1 * &self.t2 * &other.t2d;
861        let d = (&self.z * &other.z).double();
862
863        // The remaining arithmetic is exactly the process of converting
864        // from a completed point to an extended point.
865        CompletedPoint {
866            x: &b - &a,
867            y: &b + &a,
868            z: &d + &c,
869            t: &d - &c,
870        }
871        .into_extended()
872    }
873}
874
875impl<'a, 'b> Sub<&'b ExtendedNielsPoint> for &'a JubJubExtended {
876    type Output = JubJubExtended;
877
878    #[allow(clippy::suspicious_arithmetic_impl)]
879    fn sub(self, other: &'b ExtendedNielsPoint) -> JubJubExtended {
880        let a = (&self.y - &self.x) * &other.y_plus_x;
881        let b = (&self.y + &self.x) * &other.y_minus_x;
882        let c = &self.t1 * &self.t2 * &other.t2d;
883        let d = (&self.z * &other.z).double();
884
885        CompletedPoint {
886            x: &b - &a,
887            y: &b + &a,
888            z: &d - &c,
889            t: &d + &c,
890        }
891        .into_extended()
892    }
893}
894
895impl_binops_additive!(JubJubExtended, ExtendedNielsPoint);
896
897impl<'a, 'b> Add<&'b AffineNielsPoint> for &'a JubJubExtended {
898    type Output = JubJubExtended;
899
900    #[allow(clippy::suspicious_arithmetic_impl)]
901    fn add(self, other: &'b AffineNielsPoint) -> JubJubExtended {
902        // This is identical to the addition formula for `ExtendedNielsPoint`,
903        // except we can assume that `other.z` is one, so that we perform
904        // 7 multiplications.
905
906        let a = (&self.y - &self.x) * &other.y_minus_x;
907        let b = (&self.y + &self.x) * &other.y_plus_x;
908        let c = &self.t1 * &self.t2 * &other.t2d;
909        let d = self.z.double();
910
911        // The remaining arithmetic is exactly the process of converting
912        // from a completed point to an extended point.
913        CompletedPoint {
914            x: &b - &a,
915            y: &b + &a,
916            z: &d + &c,
917            t: &d - &c,
918        }
919        .into_extended()
920    }
921}
922
923impl<'a, 'b> Sub<&'b AffineNielsPoint> for &'a JubJubExtended {
924    type Output = JubJubExtended;
925
926    #[allow(clippy::suspicious_arithmetic_impl)]
927    fn sub(self, other: &'b AffineNielsPoint) -> JubJubExtended {
928        let a = (&self.y - &self.x) * &other.y_plus_x;
929        let b = (&self.y + &self.x) * &other.y_minus_x;
930        let c = &self.t1 * &self.t2 * &other.t2d;
931        let d = self.z.double();
932
933        CompletedPoint {
934            x: &b - &a,
935            y: &b + &a,
936            z: &d - &c,
937            t: &d + &c,
938        }
939        .into_extended()
940    }
941}
942
943impl_binops_additive!(JubJubExtended, AffineNielsPoint);
944
945impl<'a, 'b> Add<&'b JubJubExtended> for &'a JubJubExtended {
946    type Output = JubJubExtended;
947
948    #[inline]
949    fn add(self, other: &'b JubJubExtended) -> JubJubExtended {
950        self + other.to_niels()
951    }
952}
953
954impl<'a, 'b> Sub<&'b JubJubExtended> for &'a JubJubExtended {
955    type Output = JubJubExtended;
956
957    #[inline]
958    fn sub(self, other: &'b JubJubExtended) -> JubJubExtended {
959        self - other.to_niels()
960    }
961}
962
963impl_binops_additive!(JubJubExtended, JubJubExtended);
964
965impl<'a, 'b> Add<&'b JubJubAffine> for &'a JubJubExtended {
966    type Output = JubJubExtended;
967
968    #[inline]
969    fn add(self, other: &'b JubJubAffine) -> JubJubExtended {
970        self + other.to_niels()
971    }
972}
973
974impl<'a, 'b> Sub<&'b JubJubAffine> for &'a JubJubExtended {
975    type Output = JubJubExtended;
976
977    #[inline]
978    fn sub(self, other: &'b JubJubAffine) -> JubJubExtended {
979        self - other.to_niels()
980    }
981}
982
983impl_binops_additive!(JubJubExtended, JubJubAffine);
984
985/// This is a "completed" point produced during a point doubling or
986/// addition routine. These points exist in the `(X:Z, Y:T)` model
987/// of the curve. This is not exposed in the API because it is
988/// an implementation detail.
989struct CompletedPoint {
990    x: BlsScalar,
991    y: BlsScalar,
992    z: BlsScalar,
993    t: BlsScalar,
994}
995
996impl CompletedPoint {
997    /// This converts a completed point into an extended point by
998    /// homogenizing:
999    ///
1000    /// (x/z, y/t) = (x/z * t/t, y/t * z/z) = (xt/zt, yz/zt)
1001    ///
1002    /// The resulting T coordinate is xtyz/zt = xy, and so
1003    /// T1 = x, T2 = y, without loss of generality.
1004    #[inline]
1005    fn into_extended(self) -> JubJubExtended {
1006        JubJubExtended {
1007            x: &self.x * &self.t,
1008            y: &self.y * &self.z,
1009            z: &self.z * &self.t,
1010            t1: self.x,
1011            t2: self.y,
1012        }
1013    }
1014}
1015
1016impl Default for JubJubAffine {
1017    /// Returns the identity.
1018    fn default() -> JubJubAffine {
1019        JubJubAffine::identity()
1020    }
1021}
1022
1023impl Default for JubJubExtended {
1024    /// Returns the identity.
1025    fn default() -> JubJubExtended {
1026        JubJubExtended::identity()
1027    }
1028}
1029
1030/// This takes a mutable slice of `JubJubExtended`s and "normalizes" them using
1031/// only a single inversion for the entire batch. This normalization results in
1032/// all of the points having a Z-coordinate of one. Further, an iterator is
1033/// returned which can be used to obtain `JubJubAffine`s for each element in the
1034/// slice.
1035///
1036/// This costs 5 multiplications per element, and a field inversion.
1037pub fn batch_normalize<'a>(
1038    y: &'a mut [JubJubExtended],
1039) -> impl Iterator<Item = JubJubAffine> + 'a {
1040    let mut acc = BlsScalar::one();
1041    for p in y.iter_mut() {
1042        // We use the `t1` field of `JubJubExtended` to store the product
1043        // of previous z-coordinates seen.
1044        p.t1 = acc;
1045        acc *= &p.z;
1046    }
1047
1048    // This is the inverse, as all z-coordinates are nonzero.
1049    acc = acc.invert().unwrap();
1050
1051    for p in y.iter_mut().rev() {
1052        let mut q = *p;
1053
1054        // Compute tmp = 1/z
1055        let tmp = q.t1 * acc;
1056
1057        // Cancel out z-coordinate in denominator of `acc`
1058        acc *= &q.z;
1059
1060        // Set the coordinates to the correct value
1061        q.x *= &tmp; // Multiply by 1/z
1062        q.y *= &tmp; // Multiply by 1/z
1063        q.z = BlsScalar::one(); // z-coordinate is now one
1064        q.t1 = q.x;
1065        q.t2 = q.y;
1066
1067        *p = q;
1068    }
1069
1070    // All extended points are now normalized, but the type
1071    // doesn't encode this fact. Let us offer affine points
1072    // to the caller.
1073
1074    y.iter().map(|p| JubJubAffine { x: p.x, y: p.y })
1075}
1076
1077#[test]
1078fn test_is_on_curve_var() {
1079    assert!(JubJubAffine::identity().is_on_curve_vartime());
1080}
1081
1082#[test]
1083fn test_affine_point_generator_has_order_p() {
1084    assert_eq!(GENERATOR.is_prime_order().unwrap_u8(), 1);
1085}
1086
1087#[test]
1088fn test_extended_point_generator_has_order_p() {
1089    assert_eq!(GENERATOR_EXTENDED.is_prime_order().unwrap_u8(), 1);
1090}
1091
1092#[test]
1093fn test_affine_point_generator_nums_has_order_p() {
1094    assert_eq!(GENERATOR_NUMS.is_prime_order().unwrap_u8(), 1);
1095}
1096
1097#[test]
1098fn test_affine_point_generator_is_not_identity() {
1099    assert_ne!(
1100        JubJubExtended::from(GENERATOR.mul_by_cofactor()),
1101        JubJubExtended::identity()
1102    );
1103}
1104
1105#[test]
1106fn test_extended_point_generator_is_not_identity() {
1107    assert_ne!(
1108        GENERATOR_EXTENDED.mul_by_cofactor(),
1109        JubJubExtended::identity()
1110    );
1111}
1112
1113#[test]
1114fn test_affine_point_generator_nums_is_not_identity() {
1115    assert_ne!(
1116        JubJubExtended::from(GENERATOR_NUMS.mul_by_cofactor()),
1117        JubJubExtended::identity()
1118    );
1119}
1120
1121#[test]
1122fn test_d_is_non_quadratic_residue() {
1123    assert!(EDWARDS_D.sqrt().is_none().unwrap_u8() == 1);
1124    assert!((-EDWARDS_D).sqrt().is_none().unwrap_u8() == 1);
1125    assert!((-EDWARDS_D).invert().unwrap().sqrt().is_none().unwrap_u8() == 1);
1126}
1127
1128#[test]
1129fn test_affine_niels_point_identity() {
1130    assert_eq!(
1131        AffineNielsPoint::identity().y_plus_x,
1132        JubJubAffine::identity().to_niels().y_plus_x
1133    );
1134    assert_eq!(
1135        AffineNielsPoint::identity().y_minus_x,
1136        JubJubAffine::identity().to_niels().y_minus_x
1137    );
1138    assert_eq!(
1139        AffineNielsPoint::identity().t2d,
1140        JubJubAffine::identity().to_niels().t2d
1141    );
1142}
1143
1144#[test]
1145fn test_extended_niels_point_identity() {
1146    assert_eq!(
1147        ExtendedNielsPoint::identity().y_plus_x,
1148        JubJubExtended::identity().to_niels().y_plus_x
1149    );
1150    assert_eq!(
1151        ExtendedNielsPoint::identity().y_minus_x,
1152        JubJubExtended::identity().to_niels().y_minus_x
1153    );
1154    assert_eq!(
1155        ExtendedNielsPoint::identity().z,
1156        JubJubExtended::identity().to_niels().z
1157    );
1158    assert_eq!(
1159        ExtendedNielsPoint::identity().t2d,
1160        JubJubExtended::identity().to_niels().t2d
1161    );
1162}
1163
1164#[test]
1165fn test_assoc() {
1166    let p = JubJubExtended::from(JubJubAffine {
1167        x: BlsScalar::from_raw([
1168            0x81c571e5d883cfb0,
1169            0x049f7a686f147029,
1170            0xf539c860bc3ea21f,
1171            0x4284715b7ccc8162,
1172        ]),
1173        y: BlsScalar::from_raw([
1174            0xbf096275684bb8ca,
1175            0xc7ba245890af256d,
1176            0x59119f3e86380eb0,
1177            0x3793de182f9fb1d2,
1178        ]),
1179    })
1180    .mul_by_cofactor();
1181    assert!(p.is_on_curve_vartime());
1182
1183    assert_eq!(
1184        (p * Fr::from(1000u64)) * Fr::from(3938u64),
1185        p * (Fr::from(1000u64) * Fr::from(3938u64)),
1186    );
1187}
1188
1189#[test]
1190fn test_batch_normalize() {
1191    let mut p = JubJubExtended::from(JubJubAffine {
1192        x: BlsScalar::from_raw([
1193            0x81c571e5d883cfb0,
1194            0x049f7a686f147029,
1195            0xf539c860bc3ea21f,
1196            0x4284715b7ccc8162,
1197        ]),
1198        y: BlsScalar::from_raw([
1199            0xbf096275684bb8ca,
1200            0xc7ba245890af256d,
1201            0x59119f3e86380eb0,
1202            0x3793de182f9fb1d2,
1203        ]),
1204    })
1205    .mul_by_cofactor();
1206
1207    let mut y = vec![];
1208    for _ in 0..10 {
1209        y.push(p);
1210        p = p.double();
1211    }
1212
1213    for p in &y {
1214        assert!(p.is_on_curve_vartime());
1215    }
1216
1217    let expected: std::vec::Vec<_> =
1218        y.iter().map(|p| JubJubAffine::from(*p)).collect();
1219    let result1: std::vec::Vec<_> = batch_normalize(&mut y).collect();
1220    for i in 0..10 {
1221        assert!(expected[i] == result1[i]);
1222        assert!(y[i].is_on_curve_vartime());
1223        assert!(JubJubAffine::from(y[i]) == expected[i]);
1224    }
1225    let result2: std::vec::Vec<_> = batch_normalize(&mut y).collect();
1226    for i in 0..10 {
1227        assert!(expected[i] == result2[i]);
1228        assert!(y[i].is_on_curve_vartime());
1229        assert!(JubJubAffine::from(y[i]) == expected[i]);
1230    }
1231}
1232
1233#[cfg(test)]
1234const FULL_GENERATOR: JubJubAffine = JubJubAffine::from_raw_unchecked(
1235    BlsScalar::from_raw([
1236        0xe4b3d35df1a7adfe,
1237        0xcaf55d1b29bf81af,
1238        0x8b0f03ddd60a8187,
1239        0x62edcbb8bf3787c8,
1240    ]),
1241    BlsScalar::from_raw([0xb, 0x0, 0x0, 0x0]),
1242);
1243
1244#[cfg(test)]
1245const EIGHT_TORSION: [JubJubAffine; 8] = [
1246    JubJubAffine::from_raw_unchecked(
1247        BlsScalar::from_raw([
1248            0xd92e6a7927200d43,
1249            0x7aa41ac43dae8582,
1250            0xeaaae086a16618d1,
1251            0x71d4df38ba9e7973,
1252        ]),
1253        BlsScalar::from_raw([
1254            0xff0d2068eff496dd,
1255            0x9106ee90f384a4a1,
1256            0x16a13035ad4d7266,
1257            0x4958bdb21966982e,
1258        ]),
1259    ),
1260    JubJubAffine::from_raw_unchecked(
1261        BlsScalar::from_raw([
1262            0xfffeffff00000001,
1263            0x67baa40089fb5bfe,
1264            0xa5e80b39939ed334,
1265            0x73eda753299d7d47,
1266        ]),
1267        BlsScalar::from_raw([0x0, 0x0, 0x0, 0x0]),
1268    ),
1269    JubJubAffine::from_raw_unchecked(
1270        BlsScalar::from_raw([
1271            0xd92e6a7927200d43,
1272            0x7aa41ac43dae8582,
1273            0xeaaae086a16618d1,
1274            0x71d4df38ba9e7973,
1275        ]),
1276        BlsScalar::from_raw([
1277            0xf2df96100b6924,
1278            0xc2b6b5720c79b75d,
1279            0x1c98a7d25c54659e,
1280            0x2a94e9a11036e51a,
1281        ]),
1282    ),
1283    JubJubAffine::from_raw_unchecked(
1284        BlsScalar::from_raw([0x0, 0x0, 0x0, 0x0]),
1285        BlsScalar::from_raw([
1286            0xffffffff00000000,
1287            0x53bda402fffe5bfe,
1288            0x3339d80809a1d805,
1289            0x73eda753299d7d48,
1290        ]),
1291    ),
1292    JubJubAffine::from_raw_unchecked(
1293        BlsScalar::from_raw([
1294            0x26d19585d8dff2be,
1295            0xd919893ec24fd67c,
1296            0x488ef781683bbf33,
1297            0x218c81a6eff03d4,
1298        ]),
1299        BlsScalar::from_raw([
1300            0xf2df96100b6924,
1301            0xc2b6b5720c79b75d,
1302            0x1c98a7d25c54659e,
1303            0x2a94e9a11036e51a,
1304        ]),
1305    ),
1306    JubJubAffine::from_raw_unchecked(
1307        BlsScalar::from_raw([
1308            0x1000000000000,
1309            0xec03000276030000,
1310            0x8d51ccce760304d0,
1311            0x0,
1312        ]),
1313        BlsScalar::from_raw([0x0, 0x0, 0x0, 0x0]),
1314    ),
1315    JubJubAffine::from_raw_unchecked(
1316        BlsScalar::from_raw([
1317            0x26d19585d8dff2be,
1318            0xd919893ec24fd67c,
1319            0x488ef781683bbf33,
1320            0x218c81a6eff03d4,
1321        ]),
1322        BlsScalar::from_raw([
1323            0xff0d2068eff496dd,
1324            0x9106ee90f384a4a1,
1325            0x16a13035ad4d7266,
1326            0x4958bdb21966982e,
1327        ]),
1328    ),
1329    JubJubAffine::from_raw_unchecked(
1330        BlsScalar::from_raw([0x0, 0x0, 0x0, 0x0]),
1331        BlsScalar::from_raw([0x1, 0x0, 0x0, 0x0]),
1332    ),
1333];
1334
1335#[test]
1336fn find_eight_torsion() {
1337    let g = JubJubExtended::from(FULL_GENERATOR);
1338    assert!(g.is_small_order().unwrap_u8() == 0);
1339    let g = g.multiply(&FR_MODULUS_BYTES);
1340    assert!(g.is_small_order().unwrap_u8() == 1);
1341
1342    let mut cur = g;
1343
1344    for (i, point) in EIGHT_TORSION.iter().enumerate() {
1345        let tmp = JubJubAffine::from(cur);
1346        if &tmp != point {
1347            panic!("{}th torsion point should be {:?}", i, tmp);
1348        }
1349
1350        cur += &g;
1351    }
1352}
1353
1354#[test]
1355fn find_curve_generator() {
1356    let mut trial_bytes = [0; 32];
1357    for _ in 0..255 {
1358        let a = JubJubAffine::from_bytes(&trial_bytes);
1359        if a.is_ok() {
1360            let a = a.unwrap();
1361            assert!(a.is_on_curve_vartime());
1362            let b = JubJubExtended::from(a);
1363            let b = b.multiply(&FR_MODULUS_BYTES);
1364            assert!(b.is_small_order().unwrap_u8() == 1);
1365            let b = b.double();
1366            assert!(b.is_small_order().unwrap_u8() == 1);
1367            let b = b.double();
1368            assert!(b.is_small_order().unwrap_u8() == 1);
1369            if b.is_identity().unwrap_u8() == 0 {
1370                let b = b.double();
1371                assert!(b.is_small_order().unwrap_u8() == 1);
1372                assert!(b.is_identity().unwrap_u8() == 1);
1373                assert_eq!(FULL_GENERATOR, a);
1374                assert!(a.mul_by_cofactor().is_torsion_free().unwrap_u8() == 1);
1375                return;
1376            }
1377        }
1378
1379        trial_bytes[0] += 1;
1380    }
1381
1382    panic!("should have found a generator of the curve");
1383}
1384
1385#[test]
1386fn test_small_order() {
1387    for point in EIGHT_TORSION.iter() {
1388        assert!(point.is_small_order().unwrap_u8() == 1);
1389    }
1390}
1391
1392#[ignore]
1393#[test]
1394fn second_gen_nums() {
1395    use blake2::{Blake2b, Digest};
1396    let generator_bytes = GENERATOR.to_bytes();
1397    let mut counter = 0u64;
1398    let mut array = [0u8; 32];
1399    loop {
1400        let mut hasher = Blake2b::new();
1401        hasher.update(generator_bytes);
1402        hasher.update(counter.to_le_bytes());
1403        let res = hasher.finalize();
1404        array.copy_from_slice(&res[0..32]);
1405        if JubJubAffine::from_bytes(&array).is_ok()
1406            && JubJubAffine::from_bytes(&array)
1407                .unwrap()
1408                .is_prime_order()
1409                .unwrap_u8()
1410                == 1
1411        {
1412            assert!(
1413                GENERATOR_NUMS == JubJubAffine::from_bytes(&array).unwrap()
1414            );
1415        }
1416        counter += 1;
1417    }
1418}
1419
1420#[test]
1421fn test_is_identity() {
1422    let a = EIGHT_TORSION[0].mul_by_cofactor();
1423    let b = EIGHT_TORSION[1].mul_by_cofactor();
1424
1425    assert_eq!(a.x, b.x);
1426    assert_eq!(a.y, a.z);
1427    assert_eq!(b.y, b.z);
1428    assert!(a.y != b.y);
1429    assert!(a.z != b.z);
1430
1431    assert!(a.is_identity().unwrap_u8() == 1);
1432    assert!(b.is_identity().unwrap_u8() == 1);
1433
1434    for point in EIGHT_TORSION.iter() {
1435        assert!(point.mul_by_cofactor().is_identity().unwrap_u8() == 1);
1436    }
1437}
1438
1439#[test]
1440fn test_mul_consistency() {
1441    let a = Fr([
1442        0x21e61211d9934f2e,
1443        0xa52c058a693c3e07,
1444        0x9ccb77bfb12d6360,
1445        0x07df2470ec94398e,
1446    ]);
1447    let b = Fr([
1448        0x03336d1cbe19dbe0,
1449        0x0153618f6156a536,
1450        0x2604c9e1fc3c6b15,
1451        0x04ae581ceb028720,
1452    ]);
1453    let c = Fr([
1454        0xd7abf5bb24683f4c,
1455        0x9d7712cc274b7c03,
1456        0x973293db9683789f,
1457        0x0b677e29380a97a7,
1458    ]);
1459    assert_eq!(a * b, c);
1460    let p = JubJubExtended::from(JubJubAffine {
1461        x: BlsScalar::from_raw([
1462            0x81c571e5d883cfb0,
1463            0x049f7a686f147029,
1464            0xf539c860bc3ea21f,
1465            0x4284715b7ccc8162,
1466        ]),
1467        y: BlsScalar::from_raw([
1468            0xbf096275684bb8ca,
1469            0xc7ba245890af256d,
1470            0x59119f3e86380eb0,
1471            0x3793de182f9fb1d2,
1472        ]),
1473    })
1474    .mul_by_cofactor();
1475    assert_eq!(p * c, (p * a) * b);
1476
1477    // Test Mul implemented on ExtendedNielsPoint
1478    assert_eq!(p * c, (p.to_niels() * a) * b);
1479    assert_eq!(p.to_niels() * c, (p * a) * b);
1480    assert_eq!(p.to_niels() * c, (p.to_niels() * a) * b);
1481
1482    // Test Mul implemented on AffineNielsPoint
1483    let p_affine_niels = JubJubAffine::from(p).to_niels();
1484    assert_eq!(p * c, (p_affine_niels * a) * b);
1485    assert_eq!(p_affine_niels * c, (p * a) * b);
1486    assert_eq!(p_affine_niels * c, (p_affine_niels * a) * b);
1487}
1488
1489#[test]
1490fn test_serialization_consistency() {
1491    let gen = FULL_GENERATOR.mul_by_cofactor();
1492    let mut p = gen;
1493
1494    let y = vec![
1495        [
1496            203, 85, 12, 213, 56, 234, 12, 193, 19, 132, 128, 64, 142, 110,
1497            170, 185, 179, 108, 97, 63, 13, 211, 247, 120, 79, 219, 110, 234,
1498            131, 123, 19, 215,
1499        ],
1500        [
1501            113, 154, 240, 230, 224, 198, 208, 170, 104, 15, 59, 126, 151, 222,
1502            233, 195, 203, 195, 167, 129, 89, 121, 240, 142, 51, 166, 64, 250,
1503            184, 202, 154, 177,
1504        ],
1505        [
1506            197, 41, 93, 209, 203, 55, 164, 174, 88, 0, 90, 199, 1, 156, 149,
1507            141, 240, 29, 14, 82, 86, 225, 126, 129, 186, 157, 148, 162, 219,
1508            51, 156, 199,
1509        ],
1510        [
1511            182, 117, 250, 241, 81, 196, 199, 227, 151, 74, 243, 17, 221, 97,
1512            200, 139, 192, 83, 231, 35, 214, 14, 95, 69, 130, 201, 4, 116, 177,
1513            19, 179, 0,
1514        ],
1515        [
1516            118, 41, 29, 200, 60, 189, 119, 252, 78, 40, 230, 18, 208, 221, 38,
1517            214, 176, 250, 4, 10, 77, 101, 26, 216, 193, 198, 226, 84, 25, 177,
1518            230, 185,
1519        ],
1520        [
1521            226, 189, 227, 208, 112, 117, 136, 98, 72, 38, 211, 167, 254, 82,
1522            174, 113, 112, 166, 138, 171, 166, 113, 52, 251, 129, 197, 138, 45,
1523            195, 7, 61, 140,
1524        ],
1525        [
1526            38, 198, 156, 196, 146, 225, 55, 163, 138, 178, 157, 128, 115, 135,
1527            204, 215, 0, 33, 171, 20, 60, 32, 142, 209, 33, 233, 125, 146, 207,
1528            12, 16, 24,
1529        ],
1530        [
1531            17, 187, 231, 83, 165, 36, 232, 184, 140, 205, 195, 252, 166, 85,
1532            59, 86, 3, 226, 211, 67, 179, 29, 238, 181, 102, 142, 58, 63, 57,
1533            89, 174, 138,
1534        ],
1535        [
1536            210, 159, 80, 16, 181, 39, 221, 204, 224, 144, 145, 79, 54, 231, 8,
1537            140, 142, 216, 93, 190, 183, 116, 174, 63, 33, 242, 177, 118, 148,
1538            40, 241, 203,
1539        ],
1540        [
1541            0, 143, 107, 102, 149, 187, 27, 124, 18, 10, 98, 28, 113, 123, 121,
1542            185, 29, 152, 14, 130, 149, 28, 87, 35, 135, 135, 153, 54, 112, 53,
1543            54, 68,
1544        ],
1545        [
1546            178, 131, 85, 160, 214, 51, 208, 157, 196, 152, 247, 93, 202, 56,
1547            81, 239, 155, 122, 59, 188, 237, 253, 11, 169, 208, 236, 12, 4,
1548            163, 211, 88, 97,
1549        ],
1550        [
1551            246, 194, 231, 195, 159, 101, 180, 133, 80, 21, 185, 220, 195, 115,
1552            144, 12, 90, 150, 44, 117, 8, 156, 168, 248, 206, 41, 60, 82, 67,
1553            75, 57, 67,
1554        ],
1555        [
1556            212, 205, 171, 153, 113, 16, 194, 241, 224, 43, 177, 110, 190, 248,
1557            22, 201, 208, 166, 2, 83, 134, 130, 85, 129, 166, 136, 185, 191,
1558            163, 38, 54, 10,
1559        ],
1560        [
1561            8, 60, 190, 39, 153, 222, 119, 23, 142, 237, 12, 110, 146, 9, 19,
1562            219, 143, 64, 161, 99, 199, 77, 39, 148, 70, 213, 246, 227, 150,
1563            178, 237, 178,
1564        ],
1565        [
1566            11, 114, 217, 160, 101, 37, 100, 220, 56, 114, 42, 31, 138, 33, 84,
1567            157, 214, 167, 73, 233, 115, 81, 124, 134, 15, 31, 181, 60, 184,
1568            130, 175, 159,
1569        ],
1570        [
1571            141, 238, 235, 202, 241, 32, 210, 10, 127, 230, 54, 31, 146, 80,
1572            247, 9, 107, 124, 0, 26, 203, 16, 237, 34, 214, 147, 133, 15, 29,
1573            236, 37, 88,
1574        ],
1575    ];
1576
1577    for expected_serialized in y {
1578        assert!(p.is_on_curve_vartime());
1579        let affine = JubJubAffine::from(p);
1580        let serialized = affine.to_bytes();
1581        let deserialized = JubJubAffine::from_bytes(&serialized).unwrap();
1582        assert_eq!(affine, deserialized);
1583        assert_eq!(expected_serialized, serialized);
1584        p = p + &gen;
1585    }
1586}
1587
1588/// Compute a shared secret `secret ยท public` using DHKE protocol
1589pub fn dhke(secret: &Fr, public: &JubJubExtended) -> JubJubAffine {
1590    public.mul(secret).into()
1591}
1592
1593#[test]
1594fn test_zip_216() {
1595    const NON_CANONICAL_ENCODINGS: [[u8; 32]; 2] = [
1596        // (0, 1) with sign bit set to 1.
1597        [
1598            0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1599            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1600            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
1601        ],
1602        // (0, -1) with sign bit set to 1.
1603        [
1604            0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x5b, 0xfe,
1605            0xff, 0x02, 0xa4, 0xbd, 0x53, 0x05, 0xd8, 0xa1, 0x09, 0x08, 0xd8,
1606            0x39, 0x33, 0x48, 0x7d, 0x9d, 0x29, 0x53, 0xa7, 0xed, 0xf3,
1607        ],
1608    ];
1609
1610    for b in &NON_CANONICAL_ENCODINGS {
1611        let mut encoding = *b;
1612
1613        // The normal API should reject the non-canonical encoding.
1614        assert!(bool::from(JubJubAffine::from_bytes(&encoding).is_err()));
1615
1616        // If we clear the sign bit of the non-canonical encoding, it should
1617        // be accepted by the normal API.
1618        encoding[31] &= 0b0111_1111;
1619        assert!(bool::from(JubJubAffine::from_bytes(&encoding).is_ok()));
1620    }
1621}