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