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