Skip to main content

curve25519_dalek/
edwards.rs

1// -*- mode: rust; -*-
2//
3// This file is part of curve25519-dalek.
4// Copyright (c) 2016-2021 isis lovecruft
5// Copyright (c) 2016-2020 Henry de Valence
6// See LICENSE for licensing information.
7//
8// Authors:
9// - isis agora lovecruft <[email protected]>
10// - Henry de Valence <[email protected]>
11
12//! Group operations for Curve25519, in Edwards form.
13//!
14//! ## Encoding and Decoding
15//!
16//! Encoding is done by converting to and from a `CompressedEdwardsY`
17//! struct, which is a typed wrapper around `[u8; 32]`.
18//!
19//! ## Equality Testing
20//!
21//! The `EdwardsPoint` struct implements the [`subtle::ConstantTimeEq`]
22//! trait for constant-time equality checking, and also uses this to
23//! ensure `Eq` equality checking runs in constant time.
24//!
25//! ## Cofactor-related functions
26//!
27//! The order of the group of points on the curve \\(\mathcal E\\)
28//! is \\(|\mathcal E| = 8\ell \\), so its structure is \\( \mathcal
29//! E = \mathcal E\[8\] \times \mathcal E[\ell]\\).  The torsion
30//! subgroup \\( \mathcal E\[8\] \\) consists of eight points of small
31//! order.  Technically, all of \\(\mathcal E\\) is torsion, but we
32//! use the word only to refer to the small \\(\mathcal E\[8\]\\) part, not
33//! the large prime-order \\(\mathcal E[\ell]\\) part.
34//!
35//! To test if a point is in \\( \mathcal E\[8\] \\), use
36//! [`EdwardsPoint::is_small_order`].
37//!
38//! To test if a point is in \\( \mathcal E[\ell] \\), use
39//! [`EdwardsPoint::is_torsion_free`].
40//!
41//! To multiply by the cofactor, use [`EdwardsPoint::mul_by_cofactor`].
42//!
43//! To avoid dealing with cofactors entirely, consider using Ristretto.
44//!
45//! ## Scalars
46//!
47//! Scalars are represented by the [`Scalar`] struct. To construct a scalar, see
48//! [`Scalar::from_canonical_bytes`] or [`Scalar::from_bytes_mod_order_wide`].
49//!
50//! ## Scalar Multiplication
51//!
52//! Scalar multiplication on Edwards points is provided by:
53//!
54//! * the `*` operator between a `Scalar` and a `EdwardsPoint`, which
55//!   performs constant-time variable-base scalar multiplication;
56//!
57//! * the `*` operator between a `Scalar` and a
58//!   `EdwardsBasepointTable`, which performs constant-time fixed-base
59//!   scalar multiplication;
60//!
61//! * an implementation of the
62//!   [`MultiscalarMul`](../traits/trait.MultiscalarMul.html) trait for
63//!   constant-time variable-base multiscalar multiplication;
64//!
65//! * an implementation of the
66//!   [`VartimeMultiscalarMul`](../traits/trait.VartimeMultiscalarMul.html)
67//!   trait for variable-time variable-base multiscalar multiplication;
68//!
69//! ## Implementation
70//!
71//! The Edwards arithmetic is implemented using the “extended twisted
72//! coordinates” of Hisil, Wong, Carter, and Dawson, and the
73//! corresponding complete formulas.  For more details,
74//! see the [`curve_models` submodule][curve_models]
75//! of the internal documentation.
76//!
77//! ## Validity Checking
78//!
79//! There is no function for checking whether a point is valid.
80//! Instead, the `EdwardsPoint` struct is guaranteed to hold a valid
81//! point on the curve.
82//!
83//! We use the Rust type system to make invalid points
84//! unrepresentable: `EdwardsPoint` objects can only be created via
85//! successful decompression of a compressed point, or else by
86//! operations on other (valid) `EdwardsPoint`s.
87//!
88//! [curve_models]: https://docs.rs/curve25519-dalek/latest/curve25519_dalek/backend/serial/curve_models/index.html
89
90// We allow non snake_case names because coordinates in projective space are
91// traditionally denoted by the capitalisation of their respective
92// counterparts in affine space.  Yeah, you heard me, rustc, I'm gonna have my
93// affine and projective cakes and eat both of them too.
94#![allow(non_snake_case)]
95
96mod affine;
97
98use cfg_if::cfg_if;
99use core::array::TryFromSliceError;
100use core::borrow::Borrow;
101use core::fmt::Debug;
102use core::iter::Sum;
103use core::ops::{Add, Neg, Sub};
104use core::ops::{AddAssign, SubAssign};
105use core::ops::{Mul, MulAssign};
106
107#[cfg(feature = "digest")]
108use digest::{
109    FixedOutput, HashMarker, array::typenum::U64, common::BlockSizeUser, consts::True,
110    typenum::IsGreater,
111};
112
113#[cfg(feature = "group")]
114use {
115    group::{GroupEncoding, cofactor::CofactorGroup, prime::PrimeGroup},
116    rand_core::TryRng,
117    subtle::CtOption,
118};
119
120#[cfg(feature = "rand_core")]
121use rand_core::Rng;
122
123use subtle::Choice;
124use subtle::ConditionallyNegatable;
125use subtle::ConditionallySelectable;
126use subtle::ConstantTimeEq;
127
128#[cfg(feature = "zeroize")]
129use zeroize::Zeroize;
130
131use crate::constants;
132
133use crate::field::FieldElement;
134use crate::scalar::{Scalar, clamp_integer};
135
136use crate::montgomery::MontgomeryPoint;
137
138use crate::backend::serial::curve_models::AffineNielsPoint;
139use crate::backend::serial::curve_models::CompletedPoint;
140use crate::backend::serial::curve_models::ProjectiveNielsPoint;
141use crate::backend::serial::curve_models::ProjectivePoint;
142
143#[cfg(feature = "precomputed-tables")]
144use crate::window::{
145    LookupTableRadix16, LookupTableRadix32, LookupTableRadix64, LookupTableRadix128,
146    LookupTableRadix256,
147};
148
149#[cfg(feature = "precomputed-tables")]
150use crate::traits::BasepointTable;
151
152use crate::traits::ValidityCheck;
153use crate::traits::{Identity, IsIdentity};
154
155use affine::AffinePoint;
156
157#[cfg(feature = "alloc")]
158use crate::traits::MultiscalarMul;
159#[cfg(feature = "alloc")]
160use crate::traits::{VartimeMultiscalarMul, VartimePrecomputedMultiscalarMul};
161#[cfg(feature = "alloc")]
162use alloc::vec::Vec;
163
164// ------------------------------------------------------------------------
165// Compressed points
166// ------------------------------------------------------------------------
167
168/// In "Edwards y" / "Ed25519" format, the curve point \\((x,y)\\) is
169/// determined by the \\(y\\)-coordinate and the sign of \\(x\\).
170///
171/// The first 255 bits of a `CompressedEdwardsY` represent the
172/// \\(y\\)-coordinate.  The high bit of the 32nd byte gives the sign of \\(x\\).
173#[allow(clippy::derived_hash_with_manual_eq)]
174#[derive(Copy, Clone, Hash)]
175pub struct CompressedEdwardsY(pub [u8; 32]);
176
177impl ConstantTimeEq for CompressedEdwardsY {
178    fn ct_eq(&self, other: &CompressedEdwardsY) -> Choice {
179        self.as_bytes().ct_eq(other.as_bytes())
180    }
181}
182
183impl Eq for CompressedEdwardsY {}
184impl PartialEq for CompressedEdwardsY {
185    fn eq(&self, other: &Self) -> bool {
186        self.ct_eq(other).into()
187    }
188}
189
190impl Debug for CompressedEdwardsY {
191    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
192        write!(f, "CompressedEdwardsY: {:?}", self.as_bytes())
193    }
194}
195
196impl CompressedEdwardsY {
197    /// View this `CompressedEdwardsY` as an array of bytes.
198    pub const fn as_bytes(&self) -> &[u8; 32] {
199        &self.0
200    }
201
202    /// Copy this `CompressedEdwardsY` to an array of bytes.
203    pub const fn to_bytes(&self) -> [u8; 32] {
204        self.0
205    }
206
207    /// Attempt to decompress to an `EdwardsPoint`.
208    ///
209    /// Returns `None` if the input is not the \\(y\\)-coordinate of a
210    /// curve point.
211    pub fn decompress(&self) -> Option<EdwardsPoint> {
212        let (is_valid_y_coord, X, Y, Z) = decompress::step_1(self);
213
214        if is_valid_y_coord.into() {
215            Some(decompress::step_2(self, X, Y, Z))
216        } else {
217            None
218        }
219    }
220}
221
222mod decompress {
223    use super::*;
224
225    #[rustfmt::skip] // keep alignment of explanatory comments
226    pub(super) fn step_1(
227        repr: &CompressedEdwardsY,
228    ) -> (Choice, FieldElement, FieldElement, FieldElement) {
229        let Y = FieldElement::from_bytes(repr.as_bytes());
230        let Z = FieldElement::ONE;
231        let YY = Y.square();
232        let u = &YY - &Z;                            // u =  y²-1
233        let v = &(&YY * &constants::EDWARDS_D) + &Z; // v = dy²+1
234        let (is_valid_y_coord, X) = FieldElement::sqrt_ratio_i(&u, &v);
235
236        (is_valid_y_coord, X, Y, Z)
237    }
238
239    #[rustfmt::skip]
240    pub(super) fn step_2(
241        repr: &CompressedEdwardsY,
242        mut X: FieldElement,
243        Y: FieldElement,
244        Z: FieldElement,
245    ) -> EdwardsPoint {
246         // FieldElement::sqrt_ratio_i always returns the nonnegative square root,
247         // so we negate according to the supplied sign bit.
248        let compressed_sign_bit = Choice::from(repr.as_bytes()[31] >> 7);
249        X.conditional_negate(compressed_sign_bit);
250
251        EdwardsPoint {
252            X,
253            Y,
254            Z,
255            T: &X * &Y,
256        }
257    }
258}
259
260impl TryFrom<&[u8]> for CompressedEdwardsY {
261    type Error = TryFromSliceError;
262
263    fn try_from(slice: &[u8]) -> Result<CompressedEdwardsY, TryFromSliceError> {
264        Self::from_slice(slice)
265    }
266}
267
268// ------------------------------------------------------------------------
269// Serde support
270// ------------------------------------------------------------------------
271// Serializes to and from `EdwardsPoint` directly, doing compression
272// and decompression internally.  This means that users can create
273// structs containing `EdwardsPoint`s and use Serde's derived
274// serializers to serialize those structures.
275
276#[cfg(feature = "digest")]
277use constants::ED25519_SQRTAM2;
278#[cfg(feature = "serde")]
279use serde::de::Visitor;
280#[cfg(feature = "serde")]
281use serde::{Deserialize, Deserializer, Serialize, Serializer};
282
283#[cfg(feature = "serde")]
284impl Serialize for EdwardsPoint {
285    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
286    where
287        S: Serializer,
288    {
289        use serde::ser::SerializeTuple;
290        let mut tup = serializer.serialize_tuple(32)?;
291        for byte in self.compress().as_bytes().iter() {
292            tup.serialize_element(byte)?;
293        }
294        tup.end()
295    }
296}
297
298#[cfg(feature = "serde")]
299impl Serialize for CompressedEdwardsY {
300    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
301    where
302        S: Serializer,
303    {
304        use serde::ser::SerializeTuple;
305        let mut tup = serializer.serialize_tuple(32)?;
306        for byte in self.as_bytes().iter() {
307            tup.serialize_element(byte)?;
308        }
309        tup.end()
310    }
311}
312
313#[cfg(feature = "serde")]
314impl<'de> Deserialize<'de> for EdwardsPoint {
315    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
316    where
317        D: Deserializer<'de>,
318    {
319        struct EdwardsPointVisitor;
320
321        impl<'de> Visitor<'de> for EdwardsPointVisitor {
322            type Value = EdwardsPoint;
323
324            fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
325                formatter.write_str("a valid point in Edwards y + sign format")
326            }
327
328            fn visit_seq<A>(self, mut seq: A) -> Result<EdwardsPoint, A::Error>
329            where
330                A: serde::de::SeqAccess<'de>,
331            {
332                let mut bytes = [0u8; 32];
333                #[allow(clippy::needless_range_loop)]
334                for i in 0..32 {
335                    bytes[i] = seq
336                        .next_element()?
337                        .ok_or_else(|| serde::de::Error::invalid_length(i, &"expected 32 bytes"))?;
338                }
339                CompressedEdwardsY(bytes)
340                    .decompress()
341                    .ok_or_else(|| serde::de::Error::custom("decompression failed"))
342            }
343        }
344
345        deserializer.deserialize_tuple(32, EdwardsPointVisitor)
346    }
347}
348
349#[cfg(feature = "serde")]
350impl<'de> Deserialize<'de> for CompressedEdwardsY {
351    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
352    where
353        D: Deserializer<'de>,
354    {
355        struct CompressedEdwardsYVisitor;
356
357        impl<'de> Visitor<'de> for CompressedEdwardsYVisitor {
358            type Value = CompressedEdwardsY;
359
360            fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
361                formatter.write_str("32 bytes of data")
362            }
363
364            fn visit_seq<A>(self, mut seq: A) -> Result<CompressedEdwardsY, A::Error>
365            where
366                A: serde::de::SeqAccess<'de>,
367            {
368                let mut bytes = [0u8; 32];
369                #[allow(clippy::needless_range_loop)]
370                for i in 0..32 {
371                    bytes[i] = seq
372                        .next_element()?
373                        .ok_or_else(|| serde::de::Error::invalid_length(i, &"expected 32 bytes"))?;
374                }
375                Ok(CompressedEdwardsY(bytes))
376            }
377        }
378
379        deserializer.deserialize_tuple(32, CompressedEdwardsYVisitor)
380    }
381}
382
383// ------------------------------------------------------------------------
384// Internal point representations
385// ------------------------------------------------------------------------
386
387/// An `EdwardsPoint` represents a point on the Edwards form of Curve25519.
388#[derive(Copy, Clone)]
389#[allow(missing_docs)]
390pub struct EdwardsPoint {
391    pub(crate) X: FieldElement,
392    pub(crate) Y: FieldElement,
393    pub(crate) Z: FieldElement,
394    pub(crate) T: FieldElement,
395}
396
397// ------------------------------------------------------------------------
398// Constructors
399// ------------------------------------------------------------------------
400
401impl Identity for CompressedEdwardsY {
402    fn identity() -> CompressedEdwardsY {
403        CompressedEdwardsY([
404            1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
405            0, 0, 0,
406        ])
407    }
408}
409
410impl Default for CompressedEdwardsY {
411    fn default() -> CompressedEdwardsY {
412        CompressedEdwardsY::identity()
413    }
414}
415
416impl CompressedEdwardsY {
417    /// Construct a `CompressedEdwardsY` from a slice of bytes.
418    ///
419    /// # Errors
420    ///
421    /// Returns [`TryFromSliceError`] if the input `bytes` slice does not have
422    /// a length of 32.
423    pub fn from_slice(bytes: &[u8]) -> Result<CompressedEdwardsY, TryFromSliceError> {
424        bytes.try_into().map(CompressedEdwardsY)
425    }
426}
427
428impl Identity for EdwardsPoint {
429    fn identity() -> EdwardsPoint {
430        EdwardsPoint {
431            X: FieldElement::ZERO,
432            Y: FieldElement::ONE,
433            Z: FieldElement::ONE,
434            T: FieldElement::ZERO,
435        }
436    }
437}
438
439impl Default for EdwardsPoint {
440    fn default() -> EdwardsPoint {
441        EdwardsPoint::identity()
442    }
443}
444
445// ------------------------------------------------------------------------
446// Zeroize implementations for wiping points from memory
447// ------------------------------------------------------------------------
448
449#[cfg(feature = "zeroize")]
450impl Zeroize for CompressedEdwardsY {
451    /// Reset this `CompressedEdwardsY` to the compressed form of the identity element.
452    fn zeroize(&mut self) {
453        self.0.zeroize();
454        self.0[0] = 1;
455    }
456}
457
458#[cfg(feature = "zeroize")]
459impl Zeroize for EdwardsPoint {
460    /// Reset this `EdwardsPoint` to the identity element.
461    fn zeroize(&mut self) {
462        self.X.zeroize();
463        self.Y = FieldElement::ONE;
464        self.Z = FieldElement::ONE;
465        self.T.zeroize();
466    }
467}
468
469// ------------------------------------------------------------------------
470// Validity checks (for debugging, not CT)
471// ------------------------------------------------------------------------
472
473impl ValidityCheck for EdwardsPoint {
474    fn is_valid(&self) -> bool {
475        let point_on_curve = self.as_projective().is_valid();
476        let on_segre_image = (&self.X * &self.Y) == (&self.Z * &self.T);
477
478        point_on_curve && on_segre_image
479    }
480}
481
482// ------------------------------------------------------------------------
483// Constant-time assignment
484// ------------------------------------------------------------------------
485
486impl ConditionallySelectable for EdwardsPoint {
487    fn conditional_select(a: &EdwardsPoint, b: &EdwardsPoint, choice: Choice) -> EdwardsPoint {
488        EdwardsPoint {
489            X: FieldElement::conditional_select(&a.X, &b.X, choice),
490            Y: FieldElement::conditional_select(&a.Y, &b.Y, choice),
491            Z: FieldElement::conditional_select(&a.Z, &b.Z, choice),
492            T: FieldElement::conditional_select(&a.T, &b.T, choice),
493        }
494    }
495}
496
497// ------------------------------------------------------------------------
498// Equality
499// ------------------------------------------------------------------------
500
501impl ConstantTimeEq for EdwardsPoint {
502    fn ct_eq(&self, other: &EdwardsPoint) -> Choice {
503        // We would like to check that the point (X/Z, Y/Z) is equal to
504        // the point (X'/Z', Y'/Z') without converting into affine
505        // coordinates (x, y) and (x', y'), which requires two inversions.
506        // We have that X = xZ and X' = x'Z'. Thus, x = x' is equivalent to
507        // (xZ)Z' = (x'Z')Z, and similarly for the y-coordinate.
508
509        (&self.X * &other.Z).ct_eq(&(&other.X * &self.Z))
510            & (&self.Y * &other.Z).ct_eq(&(&other.Y * &self.Z))
511    }
512}
513
514impl PartialEq for EdwardsPoint {
515    fn eq(&self, other: &EdwardsPoint) -> bool {
516        self.ct_eq(other).into()
517    }
518}
519
520impl Eq for EdwardsPoint {}
521
522// ------------------------------------------------------------------------
523// Point conversions
524// ------------------------------------------------------------------------
525
526impl EdwardsPoint {
527    /// Convert to a ProjectiveNielsPoint
528    pub(crate) fn as_projective_niels(&self) -> ProjectiveNielsPoint {
529        ProjectiveNielsPoint {
530            Y_plus_X: &self.Y + &self.X,
531            Y_minus_X: &self.Y - &self.X,
532            Z: self.Z,
533            T2d: &self.T * &constants::EDWARDS_D2,
534        }
535    }
536
537    /// Convert the representation of this point from extended
538    /// coordinates to projective coordinates.
539    ///
540    /// Free.
541    pub(crate) const fn as_projective(&self) -> ProjectivePoint {
542        ProjectivePoint {
543            X: self.X,
544            Y: self.Y,
545            Z: self.Z,
546        }
547    }
548
549    /// Dehomogenize to a `AffineNielsPoint`.
550    /// Mainly for testing.
551    pub(crate) fn as_affine_niels(&self) -> AffineNielsPoint {
552        let recip = self.Z.invert();
553        let x = &self.X * &recip;
554        let y = &self.Y * &recip;
555        let xy2d = &(&x * &y) * &constants::EDWARDS_D2;
556        AffineNielsPoint {
557            y_plus_x: &y + &x,
558            y_minus_x: &y - &x,
559            xy2d,
560        }
561    }
562
563    /// Dehomogenize to `AffinePoint`.
564    pub(crate) fn to_affine(self) -> AffinePoint {
565        let recip = self.Z.invert();
566        let x = &self.X * &recip;
567        let y = &self.Y * &recip;
568        AffinePoint { x, y }
569    }
570
571    /// Convert this `EdwardsPoint` on the Edwards model to the
572    /// corresponding `MontgomeryPoint` on the Montgomery model.
573    ///
574    /// This function has one exceptional case; the identity point of
575    /// the Edwards curve is sent to the 2-torsion point \\((0,0)\\)
576    /// on the Montgomery curve.
577    ///
578    /// Note that this is a one-way conversion, since the Montgomery
579    /// model does not retain sign information.
580    pub fn to_montgomery(&self) -> MontgomeryPoint {
581        // We have u = (1+y)/(1-y) = (Z+Y)/(Z-Y).
582        //
583        // The denominator is zero only when y=1, the identity point of
584        // the Edwards curve.  Since 0.invert() = 0, in this case we
585        // compute the 2-torsion point (0,0).
586        let U = &self.Z + &self.Y;
587        let W = &self.Z - &self.Y;
588        let u = &U * &W.invert();
589        MontgomeryPoint(u.to_bytes())
590    }
591
592    /// Converts a large batch of points to Edwards at once. This has the same
593    /// behavior on identity elements as [`Self::to_montgomery`].
594    #[cfg(feature = "alloc")]
595    pub fn to_montgomery_batch(eds: &[Self]) -> Vec<MontgomeryPoint> {
596        // Do the same thing as the above function. u = (1+y)/(1-y) = (Z+Y)/(Z-Y).
597        // We will do this in a batch, ie compute (Z-Y) for all the input
598        // points, then invert them all at once
599
600        // Compute the denominators in a batch
601        let mut denominators = eds.iter().map(|p| &p.Z - &p.Y).collect::<Vec<_>>();
602        FieldElement::invert_batch_alloc(&mut denominators);
603
604        // Now compute the Montgomery u coordinate for every point
605        let mut ret = Vec::with_capacity(eds.len());
606        for (ed, d) in eds.iter().zip(denominators.iter()) {
607            let u = &(&ed.Z + &ed.Y) * d;
608            ret.push(MontgomeryPoint(u.to_bytes()));
609        }
610
611        ret
612    }
613
614    /// Compress this point to `CompressedEdwardsY` format.
615    pub fn compress(&self) -> CompressedEdwardsY {
616        self.to_affine().compress()
617    }
618
619    /// Compress several `EdwardsPoint`s into `CompressedEdwardsY` format, using a batch inversion
620    /// for a significant speedup.
621    pub fn compress_batch<const N: usize>(inputs: &[EdwardsPoint; N]) -> [CompressedEdwardsY; N] {
622        let mut zs: [_; N] = core::array::from_fn(|i| inputs[i].Z);
623        FieldElement::invert_batch(&mut zs);
624
625        core::array::from_fn(|i| {
626            let x = &inputs[i].X * &zs[i];
627            let y = &inputs[i].Y * &zs[i];
628            AffinePoint { x, y }.compress()
629        })
630    }
631    /// Compress several `EdwardsPoint`s into `CompressedEdwardsY` format, using a batch inversion
632    /// for a significant speedup.
633    #[cfg(feature = "alloc")]
634    pub fn compress_batch_alloc(inputs: &[EdwardsPoint]) -> Vec<CompressedEdwardsY> {
635        let mut zs = inputs.iter().map(|input| input.Z).collect::<Vec<_>>();
636        FieldElement::invert_batch_alloc(&mut zs);
637
638        inputs
639            .iter()
640            .zip(&zs)
641            .map(|(input, recip)| {
642                let x = &input.X * recip;
643                let y = &input.Y * recip;
644                AffinePoint { x, y }.compress()
645            })
646            .collect()
647    }
648
649    #[cfg(feature = "digest")]
650    // The function `map_to_curve` calculates an [EdwardsPoint] from a [FieldElement].
651    fn map_to_curve(fe: FieldElement) -> EdwardsPoint {
652        let c1 = ED25519_SQRTAM2;
653
654        // 1.  (xMn, xMd, yMn, yMd) = map_to_curve_elligator2_curve25519(u)
655        let (xMn, xMd, yMn, yMd) = crate::montgomery::elligator_encode(&fe);
656        // 2.  xn = xMn * yMd
657        let xn = &xMn * &yMd;
658        // 3.  xn = xn * c1
659        let xn = &xn * &c1;
660        // 4.  xd = xMd * yMn
661        let xd = &xMd * &yMn;
662        // 5.  yn = xMn - xMd
663        let yn = &xMn - &xMd;
664        // 6.  yd = xMn + xMd
665        let yd = &xMn + &xMd;
666        // 7. tv1 = xd * yd
667        let tv1 = &xd * &yd;
668        // 8.   e = tv1 == 0
669        let e = tv1.ct_eq(&FieldElement::ZERO);
670        // 9.  xn = CMOV(xn, 0, e)
671        let xn = FieldElement::conditional_select(&xn, &FieldElement::ZERO, e);
672        // 10. xd = CMOV(xd, 1, e)
673        let xd = FieldElement::conditional_select(&xd, &FieldElement::ONE, e);
674        // 11. yn = CMOV(yn, 1, e)
675        let yn = FieldElement::conditional_select(&yn, &FieldElement::ONE, e);
676        // 12. yd = CMOV(yd, 1, e)
677        let yd = FieldElement::conditional_select(&yd, &FieldElement::ONE, e);
678        // 13. return (xn, xd, yn, yd)
679
680        EdwardsPoint {
681            X: &xn * &yd,
682            Y: &xd * &yn,
683            Z: &xd * &yd,
684            T: &xn * &yn,
685        }
686    }
687
688    #[cfg(feature = "digest")]
689    /// Perform encode to curve per RFC 9380, with explicit hash function and domain separator
690    /// `domain_sep`, using the Twisted Edwards Elligator 2 method. The input is the concatenation
691    /// of the elements of `bytes`. Likewise for the domain separator with `domain_sep`. At least
692    /// one element of `domain_sep`, MUST be nonempty, and the concatenation MUST NOT exceed 255
693    /// bytes.
694    ///
695    /// The specification names SHA-512 as an example of a secure hash to use with this function,
696    /// but you may use any 512-bit hash within reason (see the
697    /// [`spec`](https://www.rfc-editor.org/rfc/rfc9380.html#section-5.2) for details).
698    ///
699    /// # Warning
700    /// `encode_to_curve` is a nonuniform encoding from byte strings to points in `G`. That is,
701    /// the distribution of its output is not uniformly random in `G`: the set of possible outputs
702    /// of encode_to_curve is only a fraction of the points in `G`, and some points in this set
703    /// are more likely to be output than others.
704    ///
705    /// If your application needs the distribution of the output to be statistically close to
706    /// uniform in `G`, use [Self::hash_to_curve] instead.
707    ///
708    /// # Panics
709    /// Panics if `domain_sep.collect().len() == 0` or `> 255`
710    pub fn encode_to_curve<D>(bytes: &[&[u8]], domain_sep: &[&[u8]]) -> EdwardsPoint
711    where
712        D: BlockSizeUser + Default + FixedOutput<OutputSize = U64> + HashMarker,
713        D::BlockSize: IsGreater<D::OutputSize, Output = True>,
714    {
715        // For reference see
716        // https://www.rfc-editor.org/rfc/rfc9380.html#name-elligator-2-method-2
717
718        let fe = FieldElement::hash_to_field::<D, 1>(bytes, domain_sep);
719        let Q = Self::map_to_curve(fe[0]);
720        Q.mul_by_cofactor()
721    }
722
723    #[cfg(feature = "digest")]
724    /// Perform a hash to curve per RFC 9380, with explicit hash function and domain separator
725    /// `domain_sep`, using the Twisted Edwards Elligator 2 method. The input is the concatenation
726    /// of the elements of `bytes`. Likewise for the domain separator with `domain_sep`. At least
727    /// one element of `domain_sep`, MUST be nonempty, and the concatenation MUST NOT exceed
728    /// 255 bytes.
729    ///
730    /// The specification names SHA-512 as an example of a secure hash to use with this function,
731    /// but you may use any 512-bit hash within reason (see the
732    /// [`spec`](https://www.rfc-editor.org/rfc/rfc9380.html#section-5.2) for details).
733    ///
734    /// # Panics
735    /// Panics if `domain_sep.collect().len() == 0` or `> 255`
736    pub fn hash_to_curve<D>(bytes: &[&[u8]], domain_sep: &[&[u8]]) -> EdwardsPoint
737    where
738        D: BlockSizeUser + Default + FixedOutput<OutputSize = U64> + HashMarker,
739        D::BlockSize: IsGreater<D::OutputSize, Output = True>,
740    {
741        // For reference see
742        // https://www.rfc-editor.org/rfc/rfc9380.html#name-elligator-2-method-2
743
744        let fe = FieldElement::hash_to_field::<D, 2>(bytes, domain_sep);
745        let Q0 = Self::map_to_curve(fe[0]);
746        let Q1 = Self::map_to_curve(fe[1]);
747
748        let R = Q0 + Q1;
749        R.mul_by_cofactor()
750    }
751
752    /// Return an `EdwardsPoint` chosen uniformly at random using a user-provided RNG.
753    ///
754    /// # Inputs
755    ///
756    /// * `rng`: any RNG which implements `Rng`
757    ///
758    /// # Returns
759    ///
760    /// A random `EdwardsPoint`.
761    ///
762    /// # Implementation
763    ///
764    /// Uses rejection sampling, generating a random `CompressedEdwardsY` and then attempting point
765    /// decompression, rejecting invalid points.
766    #[cfg(feature = "rand_core")]
767    pub fn random<R: Rng + ?Sized>(rng: &mut R) -> Self {
768        let mut repr = CompressedEdwardsY([0u8; 32]);
769        loop {
770            rng.fill_bytes(&mut repr.0);
771            if let Some(p) = repr.decompress() {
772                if !IsIdentity::is_identity(&p) {
773                    break p;
774                }
775            }
776        }
777    }
778}
779
780// ------------------------------------------------------------------------
781// Doubling
782// ------------------------------------------------------------------------
783
784impl EdwardsPoint {
785    /// Add this point to itself.
786    pub(crate) fn double(&self) -> EdwardsPoint {
787        self.as_projective().double().as_extended()
788    }
789}
790
791// ------------------------------------------------------------------------
792// Addition and Subtraction
793// ------------------------------------------------------------------------
794
795impl<'a> Add<&'a EdwardsPoint> for &EdwardsPoint {
796    type Output = EdwardsPoint;
797    fn add(self, other: &'a EdwardsPoint) -> EdwardsPoint {
798        (self + &other.as_projective_niels()).as_extended()
799    }
800}
801
802define_add_variants!(
803    LHS = EdwardsPoint,
804    RHS = EdwardsPoint,
805    Output = EdwardsPoint
806);
807
808impl<'a> AddAssign<&'a EdwardsPoint> for EdwardsPoint {
809    fn add_assign(&mut self, _rhs: &'a EdwardsPoint) {
810        *self = (self as &EdwardsPoint) + _rhs;
811    }
812}
813
814define_add_assign_variants!(LHS = EdwardsPoint, RHS = EdwardsPoint);
815
816impl<'a> Sub<&'a EdwardsPoint> for &EdwardsPoint {
817    type Output = EdwardsPoint;
818    fn sub(self, other: &'a EdwardsPoint) -> EdwardsPoint {
819        (self - &other.as_projective_niels()).as_extended()
820    }
821}
822
823define_sub_variants!(
824    LHS = EdwardsPoint,
825    RHS = EdwardsPoint,
826    Output = EdwardsPoint
827);
828
829impl<'a> SubAssign<&'a EdwardsPoint> for EdwardsPoint {
830    fn sub_assign(&mut self, _rhs: &'a EdwardsPoint) {
831        *self = (self as &EdwardsPoint) - _rhs;
832    }
833}
834
835define_sub_assign_variants!(LHS = EdwardsPoint, RHS = EdwardsPoint);
836
837impl<T> Sum<T> for EdwardsPoint
838where
839    T: Borrow<EdwardsPoint>,
840{
841    fn sum<I>(iter: I) -> Self
842    where
843        I: Iterator<Item = T>,
844    {
845        iter.fold(EdwardsPoint::identity(), |acc, item| acc + item.borrow())
846    }
847}
848
849// ------------------------------------------------------------------------
850// Negation
851// ------------------------------------------------------------------------
852
853impl Neg for &EdwardsPoint {
854    type Output = EdwardsPoint;
855
856    fn neg(self) -> EdwardsPoint {
857        EdwardsPoint {
858            X: -(&self.X),
859            Y: self.Y,
860            Z: self.Z,
861            T: -(&self.T),
862        }
863    }
864}
865
866impl Neg for EdwardsPoint {
867    type Output = EdwardsPoint;
868
869    fn neg(self) -> EdwardsPoint {
870        -&self
871    }
872}
873
874// ------------------------------------------------------------------------
875// Scalar multiplication
876// ------------------------------------------------------------------------
877
878impl<'a> MulAssign<&'a Scalar> for EdwardsPoint {
879    fn mul_assign(&mut self, scalar: &'a Scalar) {
880        let result = (self as &EdwardsPoint) * scalar;
881        *self = result;
882    }
883}
884
885define_mul_assign_variants!(LHS = EdwardsPoint, RHS = Scalar);
886
887define_mul_variants!(LHS = EdwardsPoint, RHS = Scalar, Output = EdwardsPoint);
888define_mul_variants!(LHS = Scalar, RHS = EdwardsPoint, Output = EdwardsPoint);
889
890impl<'a> Mul<&'a Scalar> for &EdwardsPoint {
891    type Output = EdwardsPoint;
892    /// Scalar multiplication: compute `scalar * self`.
893    ///
894    /// For scalar multiplication of a basepoint,
895    /// `EdwardsBasepointTable` is approximately 4x faster.
896    fn mul(self, scalar: &'a Scalar) -> EdwardsPoint {
897        crate::backend::variable_base_mul(self, scalar)
898    }
899}
900
901impl<'a> Mul<&'a EdwardsPoint> for &Scalar {
902    type Output = EdwardsPoint;
903
904    /// Scalar multiplication: compute `scalar * self`.
905    ///
906    /// For scalar multiplication of a basepoint,
907    /// `EdwardsBasepointTable` is approximately 4x faster.
908    fn mul(self, point: &'a EdwardsPoint) -> EdwardsPoint {
909        point * self
910    }
911}
912
913impl EdwardsPoint {
914    /// Fixed-base scalar multiplication by the Ed25519 base point.
915    ///
916    /// Uses precomputed basepoint tables when the `precomputed-tables` feature
917    /// is enabled, trading off increased code size for ~4x better performance.
918    pub fn mul_base(scalar: &Scalar) -> Self {
919        #[cfg(not(feature = "precomputed-tables"))]
920        {
921            scalar * constants::ED25519_BASEPOINT_POINT
922        }
923
924        #[cfg(feature = "precomputed-tables")]
925        {
926            scalar * constants::ED25519_BASEPOINT_TABLE
927        }
928    }
929
930    /// Multiply this point by `clamp_integer(bytes)`. For a description of clamping, see
931    /// [`clamp_integer`].
932    pub fn mul_clamped(self, bytes: [u8; 32]) -> Self {
933        // We have to construct a Scalar that is not reduced mod l, which breaks scalar invariant
934        // #2. But #2 is not necessary for correctness of variable-base multiplication. All that
935        // needs to hold is invariant #1, i.e., the scalar is less than 2^255. This is guaranteed
936        // by clamping.
937        // Further, we don't do any reduction or arithmetic with this clamped value, so there's no
938        // issues arising from the fact that the curve point is not necessarily in the prime-order
939        // subgroup.
940        let s = Scalar {
941            bytes: clamp_integer(bytes),
942        };
943        s * self
944    }
945
946    /// Multiply the basepoint by `clamp_integer(bytes)`. For a description of clamping, see
947    /// [`clamp_integer`].
948    pub fn mul_base_clamped(bytes: [u8; 32]) -> Self {
949        // See reasoning in Self::mul_clamped why it is OK to make an unreduced Scalar here. We
950        // note that fixed-base multiplication is also defined for all values of `bytes` less than
951        // 2^255.
952        let s = Scalar {
953            bytes: clamp_integer(bytes),
954        };
955        Self::mul_base(&s)
956    }
957}
958
959// ------------------------------------------------------------------------
960// Multiscalar Multiplication impls
961// ------------------------------------------------------------------------
962
963// These use the iterator's size hint and the target settings to
964// forward to a specific backend implementation.
965
966#[cfg(feature = "alloc")]
967impl MultiscalarMul for EdwardsPoint {
968    type Point = EdwardsPoint;
969
970    fn multiscalar_mul<I, J>(scalars: I, points: J) -> EdwardsPoint
971    where
972        I: IntoIterator,
973        I::Item: Borrow<Scalar>,
974        J: IntoIterator,
975        J::Item: Borrow<EdwardsPoint>,
976    {
977        // Sanity-check lengths of input iterators
978        let mut scalars = scalars.into_iter();
979        let mut points = points.into_iter();
980
981        // Lower and upper bounds on iterators
982        let (s_lo, s_hi) = scalars.by_ref().size_hint();
983        let (p_lo, p_hi) = points.by_ref().size_hint();
984
985        // They should all be equal
986        assert_eq!(s_lo, p_lo);
987        assert_eq!(s_hi, Some(s_lo));
988        assert_eq!(p_hi, Some(p_lo));
989
990        // Now we know there's a single size.  When we do
991        // size-dependent algorithm dispatch, use this as the hint.
992        let _size = s_lo;
993
994        crate::backend::straus_multiscalar_mul(scalars, points)
995    }
996}
997
998#[cfg(feature = "alloc")]
999impl VartimeMultiscalarMul for EdwardsPoint {
1000    type Point = EdwardsPoint;
1001
1002    fn optional_multiscalar_mul<I, J>(scalars: I, points: J) -> Option<EdwardsPoint>
1003    where
1004        I: IntoIterator,
1005        I::Item: Borrow<Scalar>,
1006        J: IntoIterator<Item = Option<EdwardsPoint>>,
1007    {
1008        // Sanity-check lengths of input iterators
1009        let mut scalars = scalars.into_iter();
1010        let mut points = points.into_iter();
1011
1012        // Lower and upper bounds on iterators
1013        let (s_lo, s_hi) = scalars.by_ref().size_hint();
1014        let (p_lo, p_hi) = points.by_ref().size_hint();
1015
1016        // They should all be equal
1017        assert_eq!(s_lo, p_lo);
1018        assert_eq!(s_hi, Some(s_lo));
1019        assert_eq!(p_hi, Some(p_lo));
1020
1021        // Now we know there's a single size.
1022        // Use this as the hint to decide which algorithm to use.
1023        let size = s_lo;
1024
1025        if size < 190 {
1026            crate::backend::straus_optional_multiscalar_mul(scalars, points)
1027        } else {
1028            crate::backend::pippenger_optional_multiscalar_mul(scalars, points)
1029        }
1030    }
1031}
1032
1033/// Precomputation for variable-time multiscalar multiplication with `EdwardsPoint`s.
1034// This wraps the inner implementation in a facade type so that we can
1035// decouple stability of the inner type from the stability of the
1036// outer type.
1037#[cfg(feature = "alloc")]
1038pub struct VartimeEdwardsPrecomputation(crate::backend::VartimePrecomputedStraus);
1039
1040#[cfg(feature = "alloc")]
1041impl VartimePrecomputedMultiscalarMul for VartimeEdwardsPrecomputation {
1042    type Point = EdwardsPoint;
1043
1044    fn new<I>(static_points: I) -> Self
1045    where
1046        I: IntoIterator,
1047        I::Item: Borrow<Self::Point>,
1048    {
1049        Self(crate::backend::VartimePrecomputedStraus::new(static_points))
1050    }
1051
1052    fn len(&self) -> usize {
1053        self.0.len()
1054    }
1055
1056    fn is_empty(&self) -> bool {
1057        self.0.is_empty()
1058    }
1059
1060    fn optional_mixed_multiscalar_mul<I, J, K>(
1061        &self,
1062        static_scalars: I,
1063        dynamic_scalars: J,
1064        dynamic_points: K,
1065    ) -> Option<Self::Point>
1066    where
1067        I: IntoIterator,
1068        I::Item: Borrow<Scalar>,
1069        J: IntoIterator,
1070        J::Item: Borrow<Scalar>,
1071        K: IntoIterator<Item = Option<Self::Point>>,
1072    {
1073        self.0
1074            .optional_mixed_multiscalar_mul(static_scalars, dynamic_scalars, dynamic_points)
1075    }
1076}
1077
1078impl EdwardsPoint {
1079    /// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the Ed25519 basepoint.
1080    pub fn vartime_double_scalar_mul_basepoint(
1081        a: &Scalar,
1082        A: &EdwardsPoint,
1083        b: &Scalar,
1084    ) -> EdwardsPoint {
1085        crate::backend::vartime_double_base_mul(a, A, b)
1086    }
1087}
1088
1089#[cfg(feature = "precomputed-tables")]
1090macro_rules! impl_basepoint_table {
1091    (Name = $name:ident, LookupTable = $table:ident, Point = $point:ty, Radix = $radix:expr, Additions = $adds:expr) => {
1092        /// A precomputed table of multiples of a basepoint, for accelerating
1093        /// fixed-base scalar multiplication.  One table, for the Ed25519
1094        /// basepoint, is provided in the [`constants`] module.
1095        ///
1096        /// The basepoint tables are reasonably large, so they should probably be boxed.
1097        ///
1098        /// The sizes for the tables and the number of additions required for one scalar
1099        /// multiplication are as follows:
1100        ///
1101        /// * [`EdwardsBasepointTableRadix16`]: 30KB, 64A
1102        ///   (this is the default size, and is used for
1103        ///   [`constants::ED25519_BASEPOINT_TABLE`])
1104        /// * [`EdwardsBasepointTableRadix64`]: 120KB, 43A
1105        /// * [`EdwardsBasepointTableRadix128`]: 240KB, 37A
1106        /// * [`EdwardsBasepointTableRadix256`]: 480KB, 33A
1107        ///
1108        /// # Why 33 additions for radix-256?
1109        ///
1110        /// Normally, the radix-256 tables would allow for only 32 additions per scalar
1111        /// multiplication.  However, due to the fact that standardised definitions of
1112        /// legacy protocols—such as x25519—require allowing unreduced 255-bit scalars
1113        /// invariants, when converting such an unreduced scalar's representation to
1114        /// radix-\\(2^{8}\\), we cannot guarantee the carry bit will fit in the last
1115        /// coefficient (the coefficients are `i8`s).  When, \\(w\\), the power-of-2 of
1116        /// the radix, is \\(w < 8\\), we can fold the final carry onto the last
1117        /// coefficient, \\(d\\), because \\(d < 2^{w/2}\\), so
1118        /// $$
1119        ///     d + carry \cdot 2^{w} = d + 1 \cdot 2^{w} < 2^{w+1} < 2^{8}
1120        /// $$
1121        /// When \\(w = 8\\), we can't fit \\(carry \cdot 2^{w}\\) into an `i8`, so we
1122        /// add the carry bit onto an additional coefficient.
1123        #[derive(Clone)]
1124        #[repr(transparent)]
1125        pub struct $name(pub(crate) [$table<AffineNielsPoint>; 32]);
1126
1127        impl BasepointTable for $name {
1128            type Point = $point;
1129
1130            /// Create a table of precomputed multiples of `basepoint`.
1131            fn create(basepoint: &$point) -> $name {
1132                // XXX use init_with
1133                let mut table = $name([$table::default(); 32]);
1134                let mut P = *basepoint;
1135                for i in 0..32 {
1136                    // P = (2w)^i * B
1137                    table.0[i] = $table::from(&P);
1138                    P = P.mul_by_pow_2($radix + $radix);
1139                }
1140                table
1141            }
1142
1143            /// Get the basepoint for this table as an `EdwardsPoint`.
1144            fn basepoint(&self) -> $point {
1145                // self.0[0].select(1) = 1*(16^2)^0*B
1146                // but as an `AffineNielsPoint`, so add identity to convert to extended.
1147                (&<$point>::identity() + &self.0[0].select(1)).as_extended()
1148            }
1149
1150            /// The computation uses Pippeneger's algorithm, as described for the
1151            /// specific case of radix-16 on page 13 of the Ed25519 paper.
1152            ///
1153            /// # Piggenger's Algorithm Generalised
1154            ///
1155            /// Write the scalar \\(a\\) in radix-\\(w\\), where \\(w\\) is a power of
1156            /// 2, with coefficients in \\([\frac{-w}{2},\frac{w}{2})\\), i.e.,
1157            /// $$
1158            ///     a = a\_0 + a\_1 w\^1 + \cdots + a\_{x} w\^{x},
1159            /// $$
1160            /// with
1161            /// $$
1162            /// \begin{aligned}
1163            ///     \frac{-w}{2} \leq a_i < \frac{w}{2}
1164            ///     &&\cdots&&
1165            ///     \frac{-w}{2} \leq a\_{x} \leq \frac{w}{2}
1166            /// \end{aligned}
1167            /// $$
1168            /// and the number of additions, \\(x\\), is given by
1169            /// \\(x = \lceil \frac{256}{w} \rceil\\). Then
1170            /// $$
1171            ///     a B = a\_0 B + a\_1 w\^1 B + \cdots + a\_{x-1} w\^{x-1} B.
1172            /// $$
1173            /// Grouping even and odd coefficients gives
1174            /// $$
1175            /// \begin{aligned}
1176            ///     a B = \quad a\_0 w\^0 B +& a\_2 w\^2 B + \cdots + a\_{x-2} w\^{x-2} B    \\\\
1177            ///               + a\_1 w\^1 B +& a\_3 w\^3 B + \cdots + a\_{x-1} w\^{x-1} B    \\\\
1178            ///         = \quad(a\_0 w\^0 B +& a\_2 w\^2 B + \cdots + a\_{x-2} w\^{x-2} B)   \\\\
1179            ///             + w(a\_1 w\^0 B +& a\_3 w\^2 B + \cdots + a\_{x-1} w\^{x-2} B).  \\\\
1180            /// \end{aligned}
1181            /// $$
1182            /// For each \\(i = 0 \ldots 31\\), we create a lookup table of
1183            /// $$
1184            /// [w\^{2i} B, \ldots, \frac{w}{2}\cdot w\^{2i} B],
1185            /// $$
1186            /// and use it to select \\( y \cdot w\^{2i} \cdot B \\) in constant time.
1187            ///
1188            /// The radix-\\(w\\) representation requires that the scalar is bounded
1189            /// by \\(2\^{255}\\), which is always the case.
1190            ///
1191            /// The above algorithm is trivially generalised to other powers-of-2 radices.
1192            fn mul_base(&self, scalar: &Scalar) -> $point {
1193                let a = scalar.as_radix_2w($radix);
1194
1195                let tables = &self.0;
1196                let mut P = <$point>::identity();
1197
1198                for i in (0..$adds).filter(|x| x % 2 == 1) {
1199                    P = (&P + &tables[i / 2].select(a[i])).as_extended();
1200                }
1201
1202                P = P.mul_by_pow_2($radix);
1203
1204                for i in (0..$adds).filter(|x| x % 2 == 0) {
1205                    P = (&P + &tables[i / 2].select(a[i])).as_extended();
1206                }
1207
1208                P
1209            }
1210        }
1211
1212        impl<'a, 'b> Mul<&'b Scalar> for &'a $name {
1213            type Output = $point;
1214
1215            /// Construct an `EdwardsPoint` from a `Scalar` \\(a\\) by
1216            /// computing the multiple \\(aB\\) of this basepoint \\(B\\).
1217            fn mul(self, scalar: &'b Scalar) -> $point {
1218                // delegate to a private function so that its documentation appears in internal docs
1219                self.mul_base(scalar)
1220            }
1221        }
1222
1223        impl<'a, 'b> Mul<&'a $name> for &'b Scalar {
1224            type Output = $point;
1225
1226            /// Construct an `EdwardsPoint` from a `Scalar` \\(a\\) by
1227            /// computing the multiple \\(aB\\) of this basepoint \\(B\\).
1228            fn mul(self, basepoint_table: &'a $name) -> $point {
1229                basepoint_table * self
1230            }
1231        }
1232
1233        impl Debug for $name {
1234            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1235                write!(f, "{:?}([\n", stringify!($name))?;
1236                for i in 0..32 {
1237                    write!(f, "\t{:?},\n", &self.0[i])?;
1238                }
1239                write!(f, "])")
1240            }
1241        }
1242    };
1243} // End macro_rules! impl_basepoint_table
1244
1245// The number of additions required is ceil(256/w) where w is the radix representation.
1246cfg_if! {
1247    if #[cfg(feature = "precomputed-tables")] {
1248        impl_basepoint_table! {
1249            Name = EdwardsBasepointTable,
1250            LookupTable = LookupTableRadix16,
1251            Point = EdwardsPoint,
1252            Radix = 4,
1253            Additions = 64
1254        }
1255        impl_basepoint_table! {
1256            Name = EdwardsBasepointTableRadix32,
1257            LookupTable = LookupTableRadix32,
1258            Point = EdwardsPoint,
1259            Radix = 5,
1260            Additions = 52
1261        }
1262        impl_basepoint_table! {
1263            Name = EdwardsBasepointTableRadix64,
1264            LookupTable = LookupTableRadix64,
1265            Point = EdwardsPoint,
1266            Radix = 6,
1267            Additions = 43
1268        }
1269        impl_basepoint_table! {
1270            Name = EdwardsBasepointTableRadix128,
1271            LookupTable = LookupTableRadix128,
1272            Point = EdwardsPoint,
1273            Radix = 7,
1274            Additions = 37
1275        }
1276        impl_basepoint_table! {
1277            Name = EdwardsBasepointTableRadix256,
1278            LookupTable = LookupTableRadix256,
1279            Point = EdwardsPoint,
1280            Radix = 8,
1281            Additions = 33
1282        }
1283
1284        /// A type-alias for [`EdwardsBasepointTable`] because the latter is
1285        /// used as a constructor in the [`constants`] module.
1286        //
1287        // Same as for `LookupTableRadix16`, we have to define `EdwardsBasepointTable`
1288        // first, because it's used as a constructor, and then provide a type alias for
1289        // it.
1290        pub type EdwardsBasepointTableRadix16 = EdwardsBasepointTable;
1291    }
1292}
1293
1294#[cfg(feature = "precomputed-tables")]
1295macro_rules! impl_basepoint_table_conversions {
1296    (LHS = $lhs:ty, RHS = $rhs:ty) => {
1297        impl<'a> From<&'a $lhs> for $rhs {
1298            fn from(table: &'a $lhs) -> $rhs {
1299                <$rhs>::create(&table.basepoint())
1300            }
1301        }
1302
1303        impl<'a> From<&'a $rhs> for $lhs {
1304            fn from(table: &'a $rhs) -> $lhs {
1305                <$lhs>::create(&table.basepoint())
1306            }
1307        }
1308    };
1309}
1310
1311cfg_if! {
1312    if #[cfg(feature = "precomputed-tables")] {
1313        // Conversions from radix 16
1314        impl_basepoint_table_conversions! {
1315            LHS = EdwardsBasepointTableRadix16,
1316            RHS = EdwardsBasepointTableRadix32
1317        }
1318        impl_basepoint_table_conversions! {
1319            LHS = EdwardsBasepointTableRadix16,
1320            RHS = EdwardsBasepointTableRadix64
1321        }
1322        impl_basepoint_table_conversions! {
1323            LHS = EdwardsBasepointTableRadix16,
1324            RHS = EdwardsBasepointTableRadix128
1325        }
1326        impl_basepoint_table_conversions! {
1327            LHS = EdwardsBasepointTableRadix16,
1328            RHS = EdwardsBasepointTableRadix256
1329        }
1330
1331        // Conversions from radix 32
1332        impl_basepoint_table_conversions! {
1333            LHS = EdwardsBasepointTableRadix32,
1334            RHS = EdwardsBasepointTableRadix64
1335        }
1336        impl_basepoint_table_conversions! {
1337            LHS = EdwardsBasepointTableRadix32,
1338            RHS = EdwardsBasepointTableRadix128
1339        }
1340        impl_basepoint_table_conversions! {
1341            LHS = EdwardsBasepointTableRadix32,
1342            RHS = EdwardsBasepointTableRadix256
1343        }
1344
1345        // Conversions from radix 64
1346        impl_basepoint_table_conversions! {
1347            LHS = EdwardsBasepointTableRadix64,
1348            RHS = EdwardsBasepointTableRadix128
1349        }
1350        impl_basepoint_table_conversions! {
1351            LHS = EdwardsBasepointTableRadix64,
1352            RHS = EdwardsBasepointTableRadix256
1353        }
1354
1355        // Conversions from radix 128
1356        impl_basepoint_table_conversions! {
1357            LHS = EdwardsBasepointTableRadix128,
1358            RHS = EdwardsBasepointTableRadix256
1359        }
1360    }
1361}
1362
1363impl EdwardsPoint {
1364    /// Multiply by the cofactor: return \\(\[8\]P\\).
1365    pub fn mul_by_cofactor(&self) -> EdwardsPoint {
1366        self.mul_by_pow_2(3)
1367    }
1368
1369    /// Compute \\([2\^k] P \\) by successive doublings. Requires \\( k > 0 \\).
1370    pub(crate) fn mul_by_pow_2(&self, k: u32) -> EdwardsPoint {
1371        debug_assert!(k > 0);
1372        let mut r: CompletedPoint;
1373        let mut s = self.as_projective();
1374        for _ in 0..(k - 1) {
1375            r = s.double();
1376            s = r.as_projective();
1377        }
1378        // Unroll last iteration so we can go directly as_extended()
1379        s.double().as_extended()
1380    }
1381
1382    /// Determine if this point is of small order.
1383    ///
1384    /// # Return
1385    ///
1386    /// * `true` if `self` is in the torsion subgroup \\( \mathcal E\[8\] \\);
1387    /// * `false` if `self` is not in the torsion subgroup \\( \mathcal E\[8\] \\).
1388    ///
1389    /// # Example
1390    ///
1391    /// ```
1392    /// use curve25519_dalek::constants;
1393    ///
1394    /// // Generator of the prime-order subgroup
1395    /// let P = constants::ED25519_BASEPOINT_POINT;
1396    /// // Generator of the torsion subgroup
1397    /// let Q = constants::EIGHT_TORSION[1];
1398    ///
1399    /// // P has large order
1400    /// assert_eq!(P.is_small_order(), false);
1401    ///
1402    /// // Q has small order
1403    /// assert_eq!(Q.is_small_order(), true);
1404    /// ```
1405    pub fn is_small_order(&self) -> bool {
1406        self.mul_by_cofactor().is_identity()
1407    }
1408
1409    /// Determine if this point is “torsion-free”, i.e., is contained in
1410    /// the prime-order subgroup.
1411    ///
1412    /// # Return
1413    ///
1414    /// * `true` if `self` has zero torsion component and is in the
1415    ///   prime-order subgroup;
1416    /// * `false` if `self` has a nonzero torsion component and is not
1417    ///   in the prime-order subgroup.
1418    ///
1419    /// # Example
1420    ///
1421    /// ```
1422    /// use curve25519_dalek::constants;
1423    ///
1424    /// // Generator of the prime-order subgroup
1425    /// let P = constants::ED25519_BASEPOINT_POINT;
1426    /// // Generator of the torsion subgroup
1427    /// let Q = constants::EIGHT_TORSION[1];
1428    ///
1429    /// // P is torsion-free
1430    /// assert_eq!(P.is_torsion_free(), true);
1431    ///
1432    /// // P + Q is not torsion-free
1433    /// assert_eq!((P+Q).is_torsion_free(), false);
1434    /// ```
1435    pub fn is_torsion_free(&self) -> bool {
1436        (self * constants::BASEPOINT_ORDER).is_identity()
1437    }
1438}
1439
1440// ------------------------------------------------------------------------
1441// Debug traits
1442// ------------------------------------------------------------------------
1443
1444impl Debug for EdwardsPoint {
1445    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1446        write!(
1447            f,
1448            "EdwardsPoint{{\n\tX: {:?},\n\tY: {:?},\n\tZ: {:?},\n\tT: {:?}\n}}",
1449            &self.X, &self.Y, &self.Z, &self.T
1450        )
1451    }
1452}
1453
1454// ------------------------------------------------------------------------
1455// group traits
1456// ------------------------------------------------------------------------
1457
1458// Use the full trait path to avoid Group::identity overlapping Identity::identity in the
1459// rest of the module (e.g. tests).
1460#[cfg(feature = "group")]
1461impl group::Group for EdwardsPoint {
1462    type Scalar = Scalar;
1463
1464    fn try_random<R: TryRng + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
1465        let mut repr = CompressedEdwardsY([0u8; 32]);
1466        loop {
1467            rng.try_fill_bytes(&mut repr.0)?;
1468            if let Some(p) = repr.decompress() {
1469                if !IsIdentity::is_identity(&p) {
1470                    break Ok(p);
1471                }
1472            }
1473        }
1474    }
1475
1476    fn identity() -> Self {
1477        Identity::identity()
1478    }
1479
1480    fn generator() -> Self {
1481        constants::ED25519_BASEPOINT_POINT
1482    }
1483
1484    fn is_identity(&self) -> Choice {
1485        self.ct_eq(&Identity::identity())
1486    }
1487
1488    fn double(&self) -> Self {
1489        self.double()
1490    }
1491}
1492
1493#[cfg(feature = "group")]
1494impl GroupEncoding for EdwardsPoint {
1495    type Repr = [u8; 32];
1496
1497    fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
1498        let repr = CompressedEdwardsY(*bytes);
1499        let (is_valid_y_coord, X, Y, Z) = decompress::step_1(&repr);
1500        CtOption::new(decompress::step_2(&repr, X, Y, Z), is_valid_y_coord)
1501    }
1502
1503    fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
1504        // Just use the checked API; there are no checks we can skip.
1505        Self::from_bytes(bytes)
1506    }
1507
1508    fn to_bytes(&self) -> Self::Repr {
1509        self.compress().to_bytes()
1510    }
1511}
1512
1513/// A `SubgroupPoint` represents a point on the Edwards form of Curve25519, that is
1514/// guaranteed to be in the prime-order subgroup.
1515#[cfg(feature = "group")]
1516#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
1517pub struct SubgroupPoint(EdwardsPoint);
1518
1519#[cfg(feature = "group")]
1520impl From<SubgroupPoint> for EdwardsPoint {
1521    fn from(p: SubgroupPoint) -> Self {
1522        p.0
1523    }
1524}
1525
1526#[cfg(feature = "group")]
1527impl Neg for SubgroupPoint {
1528    type Output = Self;
1529
1530    fn neg(self) -> Self::Output {
1531        SubgroupPoint(-self.0)
1532    }
1533}
1534
1535#[cfg(feature = "group")]
1536impl Add<&SubgroupPoint> for &SubgroupPoint {
1537    type Output = SubgroupPoint;
1538    fn add(self, other: &SubgroupPoint) -> SubgroupPoint {
1539        SubgroupPoint(self.0 + other.0)
1540    }
1541}
1542
1543#[cfg(feature = "group")]
1544define_add_variants!(
1545    LHS = SubgroupPoint,
1546    RHS = SubgroupPoint,
1547    Output = SubgroupPoint
1548);
1549
1550#[cfg(feature = "group")]
1551impl Add<&SubgroupPoint> for &EdwardsPoint {
1552    type Output = EdwardsPoint;
1553    fn add(self, other: &SubgroupPoint) -> EdwardsPoint {
1554        self + other.0
1555    }
1556}
1557
1558#[cfg(feature = "group")]
1559define_add_variants!(
1560    LHS = EdwardsPoint,
1561    RHS = SubgroupPoint,
1562    Output = EdwardsPoint
1563);
1564
1565#[cfg(feature = "group")]
1566impl AddAssign<&SubgroupPoint> for SubgroupPoint {
1567    fn add_assign(&mut self, rhs: &SubgroupPoint) {
1568        self.0 += rhs.0
1569    }
1570}
1571
1572#[cfg(feature = "group")]
1573define_add_assign_variants!(LHS = SubgroupPoint, RHS = SubgroupPoint);
1574
1575#[cfg(feature = "group")]
1576impl AddAssign<&SubgroupPoint> for EdwardsPoint {
1577    fn add_assign(&mut self, rhs: &SubgroupPoint) {
1578        *self += rhs.0
1579    }
1580}
1581
1582#[cfg(feature = "group")]
1583define_add_assign_variants!(LHS = EdwardsPoint, RHS = SubgroupPoint);
1584
1585#[cfg(feature = "group")]
1586impl Sub<&SubgroupPoint> for &SubgroupPoint {
1587    type Output = SubgroupPoint;
1588    fn sub(self, other: &SubgroupPoint) -> SubgroupPoint {
1589        SubgroupPoint(self.0 - other.0)
1590    }
1591}
1592
1593#[cfg(feature = "group")]
1594define_sub_variants!(
1595    LHS = SubgroupPoint,
1596    RHS = SubgroupPoint,
1597    Output = SubgroupPoint
1598);
1599
1600#[cfg(feature = "group")]
1601impl Sub<&SubgroupPoint> for &EdwardsPoint {
1602    type Output = EdwardsPoint;
1603    fn sub(self, other: &SubgroupPoint) -> EdwardsPoint {
1604        self - other.0
1605    }
1606}
1607
1608#[cfg(feature = "group")]
1609define_sub_variants!(
1610    LHS = EdwardsPoint,
1611    RHS = SubgroupPoint,
1612    Output = EdwardsPoint
1613);
1614
1615#[cfg(feature = "group")]
1616impl SubAssign<&SubgroupPoint> for SubgroupPoint {
1617    fn sub_assign(&mut self, rhs: &SubgroupPoint) {
1618        self.0 -= rhs.0;
1619    }
1620}
1621
1622#[cfg(feature = "group")]
1623define_sub_assign_variants!(LHS = SubgroupPoint, RHS = SubgroupPoint);
1624
1625#[cfg(feature = "group")]
1626impl SubAssign<&SubgroupPoint> for EdwardsPoint {
1627    fn sub_assign(&mut self, rhs: &SubgroupPoint) {
1628        *self -= rhs.0;
1629    }
1630}
1631
1632#[cfg(feature = "group")]
1633define_sub_assign_variants!(LHS = EdwardsPoint, RHS = SubgroupPoint);
1634
1635#[cfg(feature = "group")]
1636impl<T> Sum<T> for SubgroupPoint
1637where
1638    T: Borrow<SubgroupPoint>,
1639{
1640    fn sum<I>(iter: I) -> Self
1641    where
1642        I: Iterator<Item = T>,
1643    {
1644        use group::Group;
1645        iter.fold(SubgroupPoint::identity(), |acc, item| acc + item.borrow())
1646    }
1647}
1648
1649#[cfg(feature = "group")]
1650impl Mul<&Scalar> for &SubgroupPoint {
1651    type Output = SubgroupPoint;
1652
1653    /// Scalar multiplication: compute `scalar * self`.
1654    ///
1655    /// For scalar multiplication of a basepoint,
1656    /// `EdwardsBasepointTable` is approximately 4x faster.
1657    fn mul(self, scalar: &Scalar) -> SubgroupPoint {
1658        SubgroupPoint(self.0 * scalar)
1659    }
1660}
1661
1662#[cfg(feature = "group")]
1663define_mul_variants!(LHS = Scalar, RHS = SubgroupPoint, Output = SubgroupPoint);
1664
1665#[cfg(feature = "group")]
1666impl Mul<&SubgroupPoint> for &Scalar {
1667    type Output = SubgroupPoint;
1668
1669    /// Scalar multiplication: compute `scalar * self`.
1670    ///
1671    /// For scalar multiplication of a basepoint,
1672    /// `EdwardsBasepointTable` is approximately 4x faster.
1673    fn mul(self, point: &SubgroupPoint) -> SubgroupPoint {
1674        point * self
1675    }
1676}
1677
1678#[cfg(feature = "group")]
1679define_mul_variants!(LHS = SubgroupPoint, RHS = Scalar, Output = SubgroupPoint);
1680
1681#[cfg(feature = "group")]
1682impl MulAssign<&Scalar> for SubgroupPoint {
1683    fn mul_assign(&mut self, scalar: &Scalar) {
1684        self.0 *= scalar;
1685    }
1686}
1687
1688#[cfg(feature = "group")]
1689define_mul_assign_variants!(LHS = SubgroupPoint, RHS = Scalar);
1690
1691#[cfg(feature = "group")]
1692impl ConstantTimeEq for SubgroupPoint {
1693    fn ct_eq(&self, other: &SubgroupPoint) -> Choice {
1694        self.0.ct_eq(&other.0)
1695    }
1696}
1697
1698#[cfg(feature = "group")]
1699impl ConditionallySelectable for SubgroupPoint {
1700    fn conditional_select(a: &SubgroupPoint, b: &SubgroupPoint, choice: Choice) -> SubgroupPoint {
1701        SubgroupPoint(EdwardsPoint::conditional_select(&a.0, &b.0, choice))
1702    }
1703}
1704
1705#[cfg(all(feature = "group", feature = "zeroize"))]
1706impl Zeroize for SubgroupPoint {
1707    fn zeroize(&mut self) {
1708        self.0.zeroize();
1709    }
1710}
1711
1712#[cfg(feature = "group")]
1713impl group::Group for SubgroupPoint {
1714    type Scalar = Scalar;
1715
1716    fn try_random<R: TryRng + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
1717        use group::ff::Field;
1718
1719        // This will almost never loop, but `Group::random` is documented as returning a
1720        // non-identity element.
1721        let s = loop {
1722            let s: Scalar = Field::try_random(rng)?;
1723            if !s.is_zero_vartime() {
1724                break s;
1725            }
1726        };
1727
1728        // This gives an element of the prime-order subgroup.
1729        Ok(Self::generator() * s)
1730    }
1731
1732    fn identity() -> Self {
1733        SubgroupPoint(Identity::identity())
1734    }
1735
1736    fn generator() -> Self {
1737        SubgroupPoint(EdwardsPoint::generator())
1738    }
1739
1740    fn is_identity(&self) -> Choice {
1741        self.0.ct_eq(&Identity::identity())
1742    }
1743
1744    fn double(&self) -> Self {
1745        SubgroupPoint(self.0.double())
1746    }
1747}
1748
1749#[cfg(feature = "group")]
1750impl GroupEncoding for SubgroupPoint {
1751    type Repr = <EdwardsPoint as GroupEncoding>::Repr;
1752
1753    fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
1754        EdwardsPoint::from_bytes(bytes).and_then(|p| p.into_subgroup())
1755    }
1756
1757    fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
1758        EdwardsPoint::from_bytes_unchecked(bytes).and_then(|p| p.into_subgroup())
1759    }
1760
1761    fn to_bytes(&self) -> Self::Repr {
1762        self.0.compress().to_bytes()
1763    }
1764}
1765
1766#[cfg(feature = "group")]
1767impl PrimeGroup for SubgroupPoint {}
1768
1769#[cfg(feature = "group")]
1770impl CofactorGroup for EdwardsPoint {
1771    type Subgroup = SubgroupPoint;
1772
1773    fn clear_cofactor(&self) -> Self::Subgroup {
1774        SubgroupPoint(self.mul_by_cofactor())
1775    }
1776
1777    fn into_subgroup(self) -> CtOption<Self::Subgroup> {
1778        CtOption::new(SubgroupPoint(self), CofactorGroup::is_torsion_free(&self))
1779    }
1780
1781    fn is_torsion_free(&self) -> Choice {
1782        (self * constants::BASEPOINT_ORDER).ct_eq(&Self::identity())
1783    }
1784}
1785
1786// ------------------------------------------------------------------------
1787// Tests
1788// ------------------------------------------------------------------------
1789
1790#[cfg(test)]
1791mod test {
1792    use super::*;
1793    use getrandom::{
1794        SysRng,
1795        rand_core::{TryRng, UnwrapErr},
1796    };
1797
1798    #[cfg(feature = "alloc")]
1799    use alloc::vec::Vec;
1800
1801    #[cfg(feature = "precomputed-tables")]
1802    use crate::constants::ED25519_BASEPOINT_TABLE;
1803
1804    /// X coordinate of the basepoint.
1805    /// = 15112221349535400772501151409588531511454012693041857206046113283949847762202
1806    static BASE_X_COORD_BYTES: [u8; 32] = [
1807        0x1a, 0xd5, 0x25, 0x8f, 0x60, 0x2d, 0x56, 0xc9, 0xb2, 0xa7, 0x25, 0x95, 0x60, 0xc7, 0x2c,
1808        0x69, 0x5c, 0xdc, 0xd6, 0xfd, 0x31, 0xe2, 0xa4, 0xc0, 0xfe, 0x53, 0x6e, 0xcd, 0xd3, 0x36,
1809        0x69, 0x21,
1810    ];
1811
1812    /// Compressed Edwards Y form of 2*basepoint.
1813    static BASE2_CMPRSSD: CompressedEdwardsY = CompressedEdwardsY([
1814        0xc9, 0xa3, 0xf8, 0x6a, 0xae, 0x46, 0x5f, 0xe, 0x56, 0x51, 0x38, 0x64, 0x51, 0x0f, 0x39,
1815        0x97, 0x56, 0x1f, 0xa2, 0xc9, 0xe8, 0x5e, 0xa2, 0x1d, 0xc2, 0x29, 0x23, 0x09, 0xf3, 0xcd,
1816        0x60, 0x22,
1817    ]);
1818
1819    /// Compressed Edwards Y form of 16*basepoint.
1820    static BASE16_CMPRSSD: CompressedEdwardsY = CompressedEdwardsY([
1821        0xeb, 0x27, 0x67, 0xc1, 0x37, 0xab, 0x7a, 0xd8, 0x27, 0x9c, 0x07, 0x8e, 0xff, 0x11, 0x6a,
1822        0xb0, 0x78, 0x6e, 0xad, 0x3a, 0x2e, 0x0f, 0x98, 0x9f, 0x72, 0xc3, 0x7f, 0x82, 0xf2, 0x96,
1823        0x96, 0x70,
1824    ]);
1825
1826    /// 4493907448824000747700850167940867464579944529806937181821189941592931634714
1827    pub static A_SCALAR: Scalar = Scalar {
1828        bytes: [
1829            0x1a, 0x0e, 0x97, 0x8a, 0x90, 0xf6, 0x62, 0x2d, 0x37, 0x47, 0x02, 0x3f, 0x8a, 0xd8,
1830            0x26, 0x4d, 0xa7, 0x58, 0xaa, 0x1b, 0x88, 0xe0, 0x40, 0xd1, 0x58, 0x9e, 0x7b, 0x7f,
1831            0x23, 0x76, 0xef, 0x09,
1832        ],
1833    };
1834
1835    /// 2506056684125797857694181776241676200180934651973138769173342316833279714961
1836    pub static B_SCALAR: Scalar = Scalar {
1837        bytes: [
1838            0x91, 0x26, 0x7a, 0xcf, 0x25, 0xc2, 0x09, 0x1b, 0xa2, 0x17, 0x74, 0x7b, 0x66, 0xf0,
1839            0xb3, 0x2e, 0x9d, 0xf2, 0xa5, 0x67, 0x41, 0xcf, 0xda, 0xc4, 0x56, 0xa7, 0xd4, 0xaa,
1840            0xb8, 0x60, 0x8a, 0x05,
1841        ],
1842    };
1843
1844    /// A_SCALAR * basepoint, computed with ed25519.py
1845    pub static A_TIMES_BASEPOINT: CompressedEdwardsY = CompressedEdwardsY([
1846        0xea, 0x27, 0xe2, 0x60, 0x53, 0xdf, 0x1b, 0x59, 0x56, 0xf1, 0x4d, 0x5d, 0xec, 0x3c, 0x34,
1847        0xc3, 0x84, 0xa2, 0x69, 0xb7, 0x4c, 0xc3, 0x80, 0x3e, 0xa8, 0xe2, 0xe7, 0xc9, 0x42, 0x5e,
1848        0x40, 0xa5,
1849    ]);
1850
1851    /// A_SCALAR * (A_TIMES_BASEPOINT) + B_SCALAR * BASEPOINT
1852    /// computed with ed25519.py
1853    static DOUBLE_SCALAR_MULT_RESULT: CompressedEdwardsY = CompressedEdwardsY([
1854        0x7d, 0xfd, 0x6c, 0x45, 0xaf, 0x6d, 0x6e, 0x0e, 0xba, 0x20, 0x37, 0x1a, 0x23, 0x64, 0x59,
1855        0xc4, 0xc0, 0x46, 0x83, 0x43, 0xde, 0x70, 0x4b, 0x85, 0x09, 0x6f, 0xfe, 0x35, 0x4f, 0x13,
1856        0x2b, 0x42,
1857    ]);
1858
1859    /// Test round-trip decompression for the basepoint.
1860    #[test]
1861    fn basepoint_decompression_compression() {
1862        let base_X = FieldElement::from_bytes(&BASE_X_COORD_BYTES);
1863        let bp = constants::ED25519_BASEPOINT_COMPRESSED
1864            .decompress()
1865            .unwrap();
1866        assert!(bp.is_valid());
1867        // Check that decompression actually gives the correct X coordinate
1868        assert_eq!(base_X, bp.X);
1869        assert_eq!(bp.compress(), constants::ED25519_BASEPOINT_COMPRESSED);
1870    }
1871
1872    /// Test sign handling in decompression
1873    #[test]
1874    fn decompression_sign_handling() {
1875        // Manually set the high bit of the last byte to flip the sign
1876        let mut minus_basepoint_bytes = *constants::ED25519_BASEPOINT_COMPRESSED.as_bytes();
1877        minus_basepoint_bytes[31] |= 1 << 7;
1878        let minus_basepoint = CompressedEdwardsY(minus_basepoint_bytes)
1879            .decompress()
1880            .unwrap();
1881        // Test projective coordinates exactly since we know they should
1882        // only differ by a flipped sign.
1883        assert_eq!(minus_basepoint.X, -(&constants::ED25519_BASEPOINT_POINT.X));
1884        assert_eq!(minus_basepoint.Y, constants::ED25519_BASEPOINT_POINT.Y);
1885        assert_eq!(minus_basepoint.Z, constants::ED25519_BASEPOINT_POINT.Z);
1886        assert_eq!(minus_basepoint.T, -(&constants::ED25519_BASEPOINT_POINT.T));
1887    }
1888
1889    /// Test that computing 1*basepoint gives the correct basepoint.
1890    #[cfg(feature = "precomputed-tables")]
1891    #[test]
1892    fn basepoint_mult_one_vs_basepoint() {
1893        let bp = ED25519_BASEPOINT_TABLE * &Scalar::ONE;
1894        let compressed = bp.compress();
1895        assert_eq!(compressed, constants::ED25519_BASEPOINT_COMPRESSED);
1896    }
1897
1898    /// Test that `EdwardsBasepointTable::basepoint()` gives the correct basepoint.
1899    #[cfg(feature = "precomputed-tables")]
1900    #[test]
1901    fn basepoint_table_basepoint_function_correct() {
1902        let bp = ED25519_BASEPOINT_TABLE.basepoint();
1903        assert_eq!(bp.compress(), constants::ED25519_BASEPOINT_COMPRESSED);
1904    }
1905
1906    /// Test `impl Add<EdwardsPoint> for EdwardsPoint`
1907    /// using basepoint + basepoint versus the 2*basepoint constant.
1908    #[test]
1909    fn basepoint_plus_basepoint_vs_basepoint2() {
1910        let bp = constants::ED25519_BASEPOINT_POINT;
1911        let bp_added = bp + bp;
1912        assert_eq!(bp_added.compress(), BASE2_CMPRSSD);
1913    }
1914
1915    /// Test `impl Add<ProjectiveNielsPoint> for EdwardsPoint`
1916    /// using the basepoint, basepoint2 constants
1917    #[test]
1918    fn basepoint_plus_basepoint_projective_niels_vs_basepoint2() {
1919        let bp = constants::ED25519_BASEPOINT_POINT;
1920        let bp_added = (&bp + &bp.as_projective_niels()).as_extended();
1921        assert_eq!(bp_added.compress(), BASE2_CMPRSSD);
1922    }
1923
1924    /// Test `impl Add<AffineNielsPoint> for EdwardsPoint`
1925    /// using the basepoint, basepoint2 constants
1926    #[test]
1927    fn basepoint_plus_basepoint_affine_niels_vs_basepoint2() {
1928        let bp = constants::ED25519_BASEPOINT_POINT;
1929        let bp_affine_niels = bp.as_affine_niels();
1930        let bp_added = (&bp + &bp_affine_niels).as_extended();
1931        assert_eq!(bp_added.compress(), BASE2_CMPRSSD);
1932    }
1933
1934    /// Check that equality of `EdwardsPoints` handles projective
1935    /// coordinates correctly.
1936    #[test]
1937    fn extended_point_equality_handles_scaling() {
1938        let mut two_bytes = [0u8; 32];
1939        two_bytes[0] = 2;
1940        let id1 = EdwardsPoint::identity();
1941        let id2 = EdwardsPoint {
1942            X: FieldElement::ZERO,
1943            Y: FieldElement::from_bytes(&two_bytes),
1944            Z: FieldElement::from_bytes(&two_bytes),
1945            T: FieldElement::ZERO,
1946        };
1947        assert!(bool::from(id1.ct_eq(&id2)));
1948    }
1949
1950    /// Sanity check for conversion to precomputed points
1951    #[cfg(feature = "precomputed-tables")]
1952    #[test]
1953    fn to_affine_niels_clears_denominators() {
1954        // construct a point as aB so it has denominators (ie. Z != 1)
1955        let aB = ED25519_BASEPOINT_TABLE * &A_SCALAR;
1956        let aB_affine_niels = aB.as_affine_niels();
1957        let also_aB = (&EdwardsPoint::identity() + &aB_affine_niels).as_extended();
1958        assert_eq!(aB.compress(), also_aB.compress());
1959    }
1960
1961    /// Test mul_base versus a known scalar multiple from ed25519.py
1962    #[test]
1963    fn basepoint_mult_vs_ed25519py() {
1964        let aB = EdwardsPoint::mul_base(&A_SCALAR);
1965        assert_eq!(aB.compress(), A_TIMES_BASEPOINT);
1966    }
1967
1968    /// Test that multiplication by the basepoint order kills the basepoint
1969    #[test]
1970    fn basepoint_mult_by_basepoint_order() {
1971        let should_be_id = EdwardsPoint::mul_base(&constants::BASEPOINT_ORDER);
1972        assert!(should_be_id.is_identity());
1973    }
1974
1975    /// Test precomputed basepoint mult
1976    #[cfg(feature = "precomputed-tables")]
1977    #[test]
1978    fn test_precomputed_basepoint_mult() {
1979        let aB_1 = ED25519_BASEPOINT_TABLE * &A_SCALAR;
1980        let aB_2 = constants::ED25519_BASEPOINT_POINT * A_SCALAR;
1981        assert_eq!(aB_1.compress(), aB_2.compress());
1982    }
1983
1984    /// Test scalar_mul versus a known scalar multiple from ed25519.py
1985    #[test]
1986    fn scalar_mul_vs_ed25519py() {
1987        let aB = constants::ED25519_BASEPOINT_POINT * A_SCALAR;
1988        assert_eq!(aB.compress(), A_TIMES_BASEPOINT);
1989    }
1990
1991    /// Test basepoint.double() versus the 2*basepoint constant.
1992    #[test]
1993    fn basepoint_double_vs_basepoint2() {
1994        assert_eq!(
1995            constants::ED25519_BASEPOINT_POINT.double().compress(),
1996            BASE2_CMPRSSD
1997        );
1998    }
1999
2000    /// Test that computing 2*basepoint is the same as basepoint.double()
2001    #[test]
2002    fn basepoint_mult_two_vs_basepoint2() {
2003        let two = Scalar::from(2u64);
2004        let bp2 = EdwardsPoint::mul_base(&two);
2005        assert_eq!(bp2.compress(), BASE2_CMPRSSD);
2006    }
2007
2008    /// Test that all the basepoint table types compute the same results.
2009    #[cfg(feature = "precomputed-tables")]
2010    #[test]
2011    fn basepoint_tables() {
2012        let P = &constants::ED25519_BASEPOINT_POINT;
2013        let a = A_SCALAR;
2014
2015        let table_radix16 = EdwardsBasepointTableRadix16::create(P);
2016        let table_radix32 = EdwardsBasepointTableRadix32::create(P);
2017        let table_radix64 = EdwardsBasepointTableRadix64::create(P);
2018        let table_radix128 = EdwardsBasepointTableRadix128::create(P);
2019        let table_radix256 = EdwardsBasepointTableRadix256::create(P);
2020
2021        let aP = (ED25519_BASEPOINT_TABLE * &a).compress();
2022        let aP16 = (&table_radix16 * &a).compress();
2023        let aP32 = (&table_radix32 * &a).compress();
2024        let aP64 = (&table_radix64 * &a).compress();
2025        let aP128 = (&table_radix128 * &a).compress();
2026        let aP256 = (&table_radix256 * &a).compress();
2027
2028        assert_eq!(aP, aP16);
2029        assert_eq!(aP16, aP32);
2030        assert_eq!(aP32, aP64);
2031        assert_eq!(aP64, aP128);
2032        assert_eq!(aP128, aP256);
2033    }
2034
2035    /// Check unreduced scalar multiplication by the basepoint tables is the same no matter what
2036    /// radix the table is.
2037    #[cfg(feature = "precomputed-tables")]
2038    #[test]
2039    fn basepoint_tables_unreduced_scalar() {
2040        let P = &constants::ED25519_BASEPOINT_POINT;
2041        let a = crate::scalar::test::LARGEST_UNREDUCED_SCALAR;
2042
2043        let table_radix16 = EdwardsBasepointTableRadix16::create(P);
2044        let table_radix32 = EdwardsBasepointTableRadix32::create(P);
2045        let table_radix64 = EdwardsBasepointTableRadix64::create(P);
2046        let table_radix128 = EdwardsBasepointTableRadix128::create(P);
2047        let table_radix256 = EdwardsBasepointTableRadix256::create(P);
2048
2049        let aP = (ED25519_BASEPOINT_TABLE * &a).compress();
2050        let aP16 = (&table_radix16 * &a).compress();
2051        let aP32 = (&table_radix32 * &a).compress();
2052        let aP64 = (&table_radix64 * &a).compress();
2053        let aP128 = (&table_radix128 * &a).compress();
2054        let aP256 = (&table_radix256 * &a).compress();
2055
2056        assert_eq!(aP, aP16);
2057        assert_eq!(aP16, aP32);
2058        assert_eq!(aP32, aP64);
2059        assert_eq!(aP64, aP128);
2060        assert_eq!(aP128, aP256);
2061    }
2062
2063    /// Check that converting to projective and then back to extended round-trips.
2064    #[test]
2065    fn basepoint_projective_extended_round_trip() {
2066        assert_eq!(
2067            constants::ED25519_BASEPOINT_POINT
2068                .as_projective()
2069                .as_extended()
2070                .compress(),
2071            constants::ED25519_BASEPOINT_COMPRESSED
2072        );
2073    }
2074
2075    /// Test computing 16*basepoint vs mul_by_pow_2(4)
2076    #[test]
2077    fn basepoint16_vs_mul_by_pow_2_4() {
2078        let bp16 = constants::ED25519_BASEPOINT_POINT.mul_by_pow_2(4);
2079        assert_eq!(bp16.compress(), BASE16_CMPRSSD);
2080    }
2081
2082    /// Check that mul_base_clamped and mul_clamped agree
2083    #[test]
2084    fn mul_base_clamped() {
2085        let mut csprng = UnwrapErr(SysRng);
2086
2087        // Make a random curve point in the curve. Give it torsion to make things interesting.
2088        #[cfg(feature = "precomputed-tables")]
2089        let random_point = {
2090            let mut b = [0u8; 32];
2091            csprng.try_fill_bytes(&mut b).unwrap();
2092            EdwardsPoint::mul_base_clamped(b) + constants::EIGHT_TORSION[1]
2093        };
2094        // Make a basepoint table from the random point. We'll use this with mul_base_clamped
2095        #[cfg(feature = "precomputed-tables")]
2096        let random_table = EdwardsBasepointTableRadix256::create(&random_point);
2097
2098        // Now test scalar mult. agreement on the default basepoint as well as random_point
2099
2100        // Test that mul_base_clamped and mul_clamped agree on a large integer. Even after
2101        // clamping, this integer is not reduced mod l.
2102        let a_bytes = [0xff; 32];
2103        assert_eq!(
2104            EdwardsPoint::mul_base_clamped(a_bytes),
2105            constants::ED25519_BASEPOINT_POINT.mul_clamped(a_bytes)
2106        );
2107        #[cfg(feature = "precomputed-tables")]
2108        assert_eq!(
2109            random_table.mul_base_clamped(a_bytes),
2110            random_point.mul_clamped(a_bytes)
2111        );
2112
2113        // Test agreement on random integers
2114        for _ in 0..100 {
2115            // This will be reduced mod l with probability l / 2^256 ≈ 6.25%
2116            let mut a_bytes = [0u8; 32];
2117            csprng.try_fill_bytes(&mut a_bytes).unwrap();
2118
2119            assert_eq!(
2120                EdwardsPoint::mul_base_clamped(a_bytes),
2121                constants::ED25519_BASEPOINT_POINT.mul_clamped(a_bytes)
2122            );
2123            #[cfg(feature = "precomputed-tables")]
2124            assert_eq!(
2125                random_table.mul_base_clamped(a_bytes),
2126                random_point.mul_clamped(a_bytes)
2127            );
2128        }
2129    }
2130
2131    #[test]
2132    #[cfg(feature = "alloc")]
2133    fn impl_sum() {
2134        // Test that sum works for non-empty iterators
2135        let BASE = constants::ED25519_BASEPOINT_POINT;
2136
2137        let s1 = Scalar::from(999u64);
2138        let P1 = BASE * s1;
2139
2140        let s2 = Scalar::from(333u64);
2141        let P2 = BASE * s2;
2142
2143        let vec = vec![P1, P2];
2144        let sum: EdwardsPoint = vec.iter().sum();
2145
2146        assert_eq!(sum, P1 + P2);
2147
2148        // Test that sum works for the empty iterator
2149        let empty_vector: Vec<EdwardsPoint> = vec![];
2150        let sum: EdwardsPoint = empty_vector.iter().sum();
2151
2152        assert_eq!(sum, EdwardsPoint::identity());
2153
2154        // Test that sum works on owning iterators
2155        let s = Scalar::from(2u64);
2156        let mapped = vec.iter().map(|x| x * s);
2157        let sum: EdwardsPoint = mapped.sum();
2158
2159        assert_eq!(sum, P1 * s + P2 * s);
2160    }
2161
2162    /// Test that the conditional assignment trait works for AffineNielsPoints.
2163    #[test]
2164    fn conditional_assign_for_affine_niels_point() {
2165        let id = AffineNielsPoint::identity();
2166        let mut p1 = AffineNielsPoint::identity();
2167        let bp = constants::ED25519_BASEPOINT_POINT.as_affine_niels();
2168
2169        p1.conditional_assign(&bp, Choice::from(0));
2170        assert_eq!(p1, id);
2171        p1.conditional_assign(&bp, Choice::from(1));
2172        assert_eq!(p1, bp);
2173    }
2174
2175    #[test]
2176    fn is_small_order() {
2177        // The basepoint has large prime order
2178        assert!(!constants::ED25519_BASEPOINT_POINT.is_small_order());
2179        // constants::EIGHT_TORSION has all points of small order.
2180        for torsion_point in &constants::EIGHT_TORSION {
2181            assert!(torsion_point.is_small_order());
2182        }
2183    }
2184
2185    #[test]
2186    fn compressed_identity() {
2187        assert_eq!(
2188            EdwardsPoint::identity().compress(),
2189            CompressedEdwardsY::identity()
2190        );
2191
2192        assert_eq!(
2193            EdwardsPoint::compress_batch(&[EdwardsPoint::identity()]),
2194            [CompressedEdwardsY::identity()]
2195        );
2196        #[cfg(feature = "alloc")]
2197        assert_eq!(
2198            &EdwardsPoint::compress_batch_alloc(&[EdwardsPoint::identity()]),
2199            &[CompressedEdwardsY::identity()]
2200        );
2201    }
2202
2203    #[cfg(feature = "rand_core")]
2204    #[test]
2205    fn compress_batch() {
2206        let mut rng = UnwrapErr(SysRng);
2207
2208        // TODO(tarcieri): proptests?
2209
2210        // Make some test points deterministically then randomly
2211        const TEST_VEC_LEN: usize = 117;
2212        let points: [EdwardsPoint; TEST_VEC_LEN] = core::array::from_fn(|i| {
2213            if i < 17 {
2214                // The first 17 are multiple of the basepoint
2215                constants::ED25519_BASEPOINT_POINT * Scalar::from(i as u64)
2216            } else {
2217                // The rest are random
2218                EdwardsPoint::random(&mut rng)
2219            }
2220        });
2221
2222        // Compress the points individually. This is our reference result
2223        let expected_compressed = core::array::from_fn(|i| points[i].compress());
2224
2225        // Check that the batch-compressed points match the individually compressed ones
2226        assert_eq!(EdwardsPoint::compress_batch(&points), expected_compressed);
2227
2228        // Check that the batch-compressed (with alloc) points match the individually compressed
2229        // ones
2230        #[cfg(feature = "alloc")]
2231        assert_eq!(
2232            EdwardsPoint::compress_batch_alloc(&points),
2233            expected_compressed
2234        );
2235    }
2236
2237    #[test]
2238    fn is_identity() {
2239        assert!(EdwardsPoint::identity().is_identity());
2240        assert!(!constants::ED25519_BASEPOINT_POINT.is_identity());
2241    }
2242
2243    /// Rust's debug builds have overflow and underflow trapping,
2244    /// and enable `debug_assert!()`.  This performs many scalar
2245    /// multiplications to attempt to trigger possible overflows etc.
2246    ///
2247    /// For instance, the `u64` `Mul` implementation for
2248    /// `FieldElements` requires the input `Limb`s to be bounded by
2249    /// 2^54, but we cannot enforce this dynamically at runtime, or
2250    /// statically at compile time (until Rust gets type-level
2251    /// integers, at which point we can encode "bits of headroom" into
2252    /// the type system and prove correctness).
2253    #[test]
2254    fn monte_carlo_overflow_underflow_debug_assert_test() {
2255        let mut P = constants::ED25519_BASEPOINT_POINT;
2256        // N.B. each scalar_mul does 1407 field mults, 1024 field squarings,
2257        // so this does ~ 1M of each operation.
2258        for _ in 0..1_000 {
2259            P *= &A_SCALAR;
2260        }
2261    }
2262
2263    #[test]
2264    fn scalarmult_extended_point_works_both_ways() {
2265        let G: EdwardsPoint = constants::ED25519_BASEPOINT_POINT;
2266        let s: Scalar = A_SCALAR;
2267
2268        let P1 = G * s;
2269        let P2 = s * G;
2270
2271        assert!(P1.compress().to_bytes() == P2.compress().to_bytes());
2272    }
2273
2274    // A single iteration of a consistency check for MSM.
2275    #[cfg(all(feature = "alloc", feature = "rand_core"))]
2276    fn multiscalar_consistency_iter(n: usize) {
2277        let mut rng = UnwrapErr(SysRng);
2278
2279        // Construct random coefficients x0, ..., x_{n-1},
2280        // followed by some extra hardcoded ones.
2281        let xs = (0..n).map(|_| Scalar::random(&mut rng)).collect::<Vec<_>>();
2282        let check = xs.iter().map(|xi| xi * xi).sum::<Scalar>();
2283
2284        // Construct points G_i = x_i * B
2285        let Gs = xs.iter().map(EdwardsPoint::mul_base).collect::<Vec<_>>();
2286
2287        // Compute H1 = <xs, Gs> (consttime)
2288        let H1 = EdwardsPoint::multiscalar_mul(&xs, &Gs);
2289        // Compute H2 = <xs, Gs> (vartime)
2290        let H2 = EdwardsPoint::vartime_multiscalar_mul(&xs, &Gs);
2291        // Compute H3 = <xs, Gs> = sum(xi^2) * B
2292        let H3 = EdwardsPoint::mul_base(&check);
2293
2294        assert_eq!(H1, H3);
2295        assert_eq!(H2, H3);
2296    }
2297
2298    // Use different multiscalar sizes to hit different internal
2299    // parameters.
2300
2301    #[test]
2302    #[cfg(all(feature = "alloc", feature = "rand_core"))]
2303    fn multiscalar_consistency_n_100() {
2304        let iters = 50;
2305        for _ in 0..iters {
2306            multiscalar_consistency_iter(100);
2307        }
2308    }
2309
2310    #[test]
2311    #[cfg(all(feature = "alloc", feature = "rand_core"))]
2312    fn multiscalar_consistency_n_250() {
2313        let iters = 50;
2314        for _ in 0..iters {
2315            multiscalar_consistency_iter(250);
2316        }
2317    }
2318
2319    #[test]
2320    #[cfg(all(feature = "alloc", feature = "rand_core"))]
2321    fn multiscalar_consistency_n_500() {
2322        let iters = 50;
2323        for _ in 0..iters {
2324            multiscalar_consistency_iter(500);
2325        }
2326    }
2327
2328    #[test]
2329    #[cfg(all(feature = "alloc", feature = "rand_core"))]
2330    fn multiscalar_consistency_n_1000() {
2331        let iters = 50;
2332        for _ in 0..iters {
2333            multiscalar_consistency_iter(1000);
2334        }
2335    }
2336
2337    #[test]
2338    #[cfg(all(feature = "alloc", feature = "rand_core"))]
2339    fn batch_to_montgomery() {
2340        let mut rng = UnwrapErr(SysRng);
2341
2342        let scalars = (0..128)
2343            .map(|_| Scalar::random(&mut rng))
2344            .collect::<Vec<_>>();
2345
2346        let points = scalars
2347            .iter()
2348            .map(EdwardsPoint::mul_base)
2349            .collect::<Vec<_>>();
2350
2351        let single_monts = points
2352            .iter()
2353            .map(EdwardsPoint::to_montgomery)
2354            .collect::<Vec<_>>();
2355
2356        for i in [0, 1, 2, 3, 10, 50, 128] {
2357            let invs = EdwardsPoint::to_montgomery_batch(&points[..i]);
2358            assert_eq!(&invs, &single_monts[..i]);
2359        }
2360    }
2361
2362    #[test]
2363    #[cfg(all(feature = "alloc", feature = "rand_core"))]
2364    fn vartime_precomputed_vs_nonprecomputed_multiscalar() {
2365        let mut rng = UnwrapErr(SysRng);
2366
2367        let static_scalars = (0..128)
2368            .map(|_| Scalar::random(&mut rng))
2369            .collect::<Vec<_>>();
2370
2371        let dynamic_scalars = (0..128)
2372            .map(|_| Scalar::random(&mut rng))
2373            .collect::<Vec<_>>();
2374
2375        let check_scalar: Scalar = static_scalars
2376            .iter()
2377            .chain(dynamic_scalars.iter())
2378            .map(|s| s * s)
2379            .sum();
2380
2381        let static_points = static_scalars
2382            .iter()
2383            .map(EdwardsPoint::mul_base)
2384            .collect::<Vec<_>>();
2385        let dynamic_points = dynamic_scalars
2386            .iter()
2387            .map(EdwardsPoint::mul_base)
2388            .collect::<Vec<_>>();
2389
2390        let precomputation = VartimeEdwardsPrecomputation::new(static_points.iter());
2391
2392        assert_eq!(precomputation.len(), 128);
2393        assert!(!precomputation.is_empty());
2394
2395        let P = precomputation.vartime_mixed_multiscalar_mul(
2396            &static_scalars,
2397            &dynamic_scalars,
2398            &dynamic_points,
2399        );
2400
2401        use crate::traits::VartimeMultiscalarMul;
2402        let Q = EdwardsPoint::vartime_multiscalar_mul(
2403            static_scalars.iter().chain(dynamic_scalars.iter()),
2404            static_points.iter().chain(dynamic_points.iter()),
2405        );
2406
2407        let R = EdwardsPoint::mul_base(&check_scalar);
2408
2409        assert_eq!(P.compress(), R.compress());
2410        assert_eq!(Q.compress(), R.compress());
2411    }
2412
2413    mod vartime {
2414        use super::super::*;
2415        use super::{A_SCALAR, A_TIMES_BASEPOINT, B_SCALAR, DOUBLE_SCALAR_MULT_RESULT};
2416
2417        /// Test double_scalar_mul_vartime vs ed25519.py
2418        #[test]
2419        fn double_scalar_mul_basepoint_vs_ed25519py() {
2420            let A = A_TIMES_BASEPOINT.decompress().unwrap();
2421            let result =
2422                EdwardsPoint::vartime_double_scalar_mul_basepoint(&A_SCALAR, &A, &B_SCALAR);
2423            assert_eq!(result.compress(), DOUBLE_SCALAR_MULT_RESULT);
2424        }
2425
2426        #[test]
2427        #[cfg(feature = "alloc")]
2428        fn multiscalar_mul_vs_ed25519py() {
2429            let A = A_TIMES_BASEPOINT.decompress().unwrap();
2430            let result = EdwardsPoint::vartime_multiscalar_mul(
2431                &[A_SCALAR, B_SCALAR],
2432                &[A, constants::ED25519_BASEPOINT_POINT],
2433            );
2434            assert_eq!(result.compress(), DOUBLE_SCALAR_MULT_RESULT);
2435        }
2436
2437        #[test]
2438        #[cfg(feature = "alloc")]
2439        fn multiscalar_mul_vartime_vs_consttime() {
2440            let A = A_TIMES_BASEPOINT.decompress().unwrap();
2441            let result_vartime = EdwardsPoint::vartime_multiscalar_mul(
2442                &[A_SCALAR, B_SCALAR],
2443                &[A, constants::ED25519_BASEPOINT_POINT],
2444            );
2445            let result_consttime = EdwardsPoint::multiscalar_mul(
2446                &[A_SCALAR, B_SCALAR],
2447                &[A, constants::ED25519_BASEPOINT_POINT],
2448            );
2449
2450            assert_eq!(result_vartime.compress(), result_consttime.compress());
2451        }
2452    }
2453
2454    #[test]
2455    #[cfg(feature = "serde")]
2456    fn serde_postcard_basepoint_roundtrip() {
2457        let encoded = postcard::to_allocvec(&constants::ED25519_BASEPOINT_POINT).unwrap();
2458        let enc_compressed =
2459            postcard::to_allocvec(&constants::ED25519_BASEPOINT_COMPRESSED).unwrap();
2460        assert_eq!(encoded, enc_compressed);
2461
2462        // Check that the encoding is 32 bytes exactly
2463        assert_eq!(encoded.len(), 32);
2464
2465        let dec_uncompressed: EdwardsPoint = postcard::from_bytes(&encoded).unwrap();
2466        let dec_compressed: CompressedEdwardsY = postcard::from_bytes(&encoded).unwrap();
2467
2468        assert_eq!(dec_uncompressed, constants::ED25519_BASEPOINT_POINT);
2469        assert_eq!(dec_compressed, constants::ED25519_BASEPOINT_COMPRESSED);
2470
2471        // Check that the encoding itself matches the usual one.
2472        // serde::Deserialize on fixed-size arrays calls tuple deserialization. postcard
2473        // (de)serializes tuples by just doing each element and that's it.
2474        let raw_bytes = constants::ED25519_BASEPOINT_COMPRESSED.as_bytes();
2475        let bp: EdwardsPoint = postcard::from_bytes(raw_bytes).unwrap();
2476        assert_eq!(bp, constants::ED25519_BASEPOINT_POINT);
2477    }
2478
2479    // Hash-to-curve test vectors from
2480    // https://www.rfc-editor.org/rfc/rfc9380.html#appendix-J.5.2
2481    // These are of the form (input_msg, output_x, output_y)
2482    #[cfg(all(feature = "alloc", feature = "digest"))]
2483    const RFC_ENCODE_TO_CURVE_KAT: &[(&[u8], &str, &str)] = &[
2484        (
2485            b"",
2486            "1ff2b70ecf862799e11b7ae744e3489aa058ce805dd323a936375a84695e76da",
2487            "222e314d04a4d5725e9f2aff9fb2a6b69ef375a1214eb19021ceab2d687f0f9b",
2488        ),
2489        (
2490            b"abc",
2491            "5f13cc69c891d86927eb37bd4afc6672360007c63f68a33ab423a3aa040fd2a8",
2492            "67732d50f9a26f73111dd1ed5dba225614e538599db58ba30aaea1f5c827fa42",
2493        ),
2494        (
2495            b"abcdef0123456789",
2496            "1dd2fefce934ecfd7aae6ec998de088d7dd03316aa1847198aecf699ba6613f1",
2497            "2f8a6c24dd1adde73909cada6a4a137577b0f179d336685c4a955a0a8e1a86fb",
2498        ),
2499        (
2500            b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\
2501            qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
2502            "35fbdc5143e8a97afd3096f2b843e07df72e15bfca2eaf6879bf97c5d3362f73",
2503            "2af6ff6ef5ebba128b0774f4296cb4c2279a074658b083b8dcca91f57a603450",
2504        ),
2505        (
2506            b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
2507            aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
2508            aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
2509            aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
2510            aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
2511            aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
2512            "6e5e1f37e99345887fc12111575fc1c3e36df4b289b8759d23af14d774b66bff",
2513            "2c90c3d39eb18ff291d33441b35f3262cdd307162cc97c31bfcc7a4245891a37"
2514        )
2515    ];
2516
2517    #[cfg(all(feature = "alloc", feature = "digest"))]
2518    fn hex_str_to_fe(hex_str: &str) -> FieldElement {
2519        let mut bytes = hex::decode(hex_str).unwrap().to_vec();
2520        bytes.reverse();
2521        FieldElement::from_bytes(&bytes.try_into().unwrap())
2522    }
2523
2524    #[test]
2525    #[cfg(all(feature = "alloc", feature = "digest"))]
2526    fn elligator_encode_to_curve_test_vectors() {
2527        let dst = b"QUUX-V01-CS02-with-edwards25519_XMD:SHA-512_ELL2_NU_";
2528        for (index, vector) in RFC_ENCODE_TO_CURVE_KAT.iter().enumerate() {
2529            let input = vector.0;
2530
2531            let expected_output = {
2532                let x = hex_str_to_fe(vector.1);
2533                let y = hex_str_to_fe(vector.2);
2534                AffinePoint { x, y }.to_edwards()
2535            };
2536
2537            let computed = EdwardsPoint::encode_to_curve::<sha2::Sha512>(&[&input], &[dst]);
2538            assert_eq!(computed, expected_output, "Failed in test {}", index);
2539        }
2540    }
2541
2542    // Hash-to-curve test vectors from
2543    // https://www.rfc-editor.org/rfc/rfc9380.html#appendix-J.5.1
2544    // These are of the form (input_msg, output_x, output_y)
2545    #[cfg(all(feature = "alloc", feature = "digest"))]
2546    const RFC_HASH_TO_CURVE_KAT: &[(&[u8], &str, &str)] = &[
2547        (
2548            b"",
2549            "3c3da6925a3c3c268448dcabb47ccde5439559d9599646a8260e47b1e4822fc6",
2550            "09a6c8561a0b22bef63124c588ce4c62ea83a3c899763af26d795302e115dc21",
2551        ),
2552
2553        (
2554            b"abc",
2555            "608040b42285cc0d72cbb3985c6b04c935370c7361f4b7fbdb1ae7f8c1a8ecad",
2556            "1a8395b88338f22e435bbd301183e7f20a5f9de643f11882fb237f88268a5531",
2557        ),
2558
2559        (
2560            b"abcdef0123456789",
2561            "6d7fabf47a2dc03fe7d47f7dddd21082c5fb8f86743cd020f3fb147d57161472",
2562            "53060a3d140e7fbcda641ed3cf42c88a75411e648a1add71217f70ea8ec561a6",
2563        ),
2564        (
2565            b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\
2566            qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
2567            "5fb0b92acedd16f3bcb0ef83f5c7b7a9466b5f1e0d8d217421878ea3686f8524",
2568            "2eca15e355fcfa39d2982f67ddb0eea138e2994f5956ed37b7f72eea5e89d2f7",
2569        ),
2570        (
2571            b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
2572            aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
2573            aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
2574            aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
2575            aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\
2576            aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
2577            "0efcfde5898a839b00997fbe40d2ebe950bc81181afbd5cd6b9618aa336c1e8c",
2578            "6dc2fc04f266c5c27f236a80b14f92ccd051ef1ff027f26a07f8c0f327d8f995"
2579        )
2580    ];
2581
2582    #[test]
2583    #[cfg(all(feature = "alloc", feature = "digest"))]
2584    fn elligator_hash_to_curve_test_vectors() {
2585        let dst = b"QUUX-V01-CS02-with-edwards25519_XMD:SHA-512_ELL2_RO_";
2586        for (index, vector) in RFC_HASH_TO_CURVE_KAT.iter().enumerate() {
2587            let input = vector.0;
2588
2589            let expected_output = {
2590                let x = hex_str_to_fe(vector.1);
2591                let y = hex_str_to_fe(vector.2);
2592
2593                AffinePoint { x, y }.to_edwards()
2594            };
2595
2596            let computed = EdwardsPoint::hash_to_curve::<sha2::Sha512>(&[&input], &[dst]);
2597
2598            assert_eq!(expected_output, computed, "Failed in test {}", index);
2599        }
2600    }
2601}