curve25519_dalek/
ristretto.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// We allow non snake_case names because coordinates in projective space are
13// traditionally denoted by the capitalisation of their respective
14// counterparts in affine space.  Yeah, you heard me, rustc, I'm gonna have my
15// affine and projective cakes and eat both of them too.
16#![allow(non_snake_case)]
17
18//! An implementation of [Ristretto][ristretto_main], which provides a
19//! prime-order group.
20//!
21//! # The Ristretto Group
22//!
23//! Ristretto is a modification of Mike Hamburg's Decaf scheme to work
24//! with cofactor-\\(8\\) curves, such as Curve25519.
25//!
26//! The introduction of the Decaf paper, [_Decaf:
27//! Eliminating cofactors through point
28//! compression_](https://eprint.iacr.org/2015/673.pdf), notes that while
29//! most cryptographic systems require a group of prime order, most
30//! concrete implementations using elliptic curve groups fall short –
31//! they either provide a group of prime order, but with incomplete or
32//! variable-time addition formulae (for instance, most Weierstrass
33//! models), or else they provide a fast and safe implementation of a
34//! group whose order is not quite a prime \\(q\\), but \\(hq\\) for a
35//! small cofactor \\(h\\) (for instance, Edwards curves, which have
36//! cofactor at least \\(4\\)).
37//!
38//! This abstraction mismatch is commonly “handled” by pushing the
39//! complexity upwards, adding ad-hoc protocol modifications.  But
40//! these modifications require careful analysis and are a recurring
41//! source of [vulnerabilities][cryptonote] and [design
42//! complications][ed25519_hkd].
43//!
44//! Instead, Decaf (and Ristretto) use a quotient group to implement a
45//! prime-order group using a non-prime-order curve.  This provides
46//! the correct abstraction for cryptographic systems, while retaining
47//! the speed and safety benefits of an Edwards curve.
48//!
49//! Decaf is named “after the procedure which divides the effect of
50//! coffee by \\(4\\)”.  However, Curve25519 has a cofactor of
51//! \\(8\\).  To eliminate its cofactor, Ristretto restricts further;
52//! this [additional restriction][ristretto_coffee] gives the
53//! _Ristretto_ encoding.
54//!
55//! More details on why Ristretto is necessary can be found in the
56//! [Why Ristretto?][why_ristretto] section of the Ristretto website.
57//!
58//! Ristretto
59//! points are provided in `curve25519-dalek` by the `RistrettoPoint`
60//! struct.
61//!
62//! ## Encoding and Decoding
63//!
64//! Encoding is done by converting to and from a `CompressedRistretto`
65//! struct, which is a typed wrapper around `[u8; 32]`.
66//!
67//! The encoding is not batchable, but it is possible to
68//! double-and-encode in a batch using
69//! `RistrettoPoint::double_and_compress_batch`.
70//!
71//! ## Equality Testing
72//!
73//! Testing equality of points on an Edwards curve in projective
74//! coordinates requires an expensive inversion.  By contrast, equality
75//! checking in the Ristretto group can be done in projective
76//! coordinates without requiring an inversion, so it is much faster.
77//!
78//! The `RistrettoPoint` struct implements the
79//! [`subtle::ConstantTimeEq`] trait for constant-time equality
80//! checking, and also uses this to ensure `Eq` equality checking
81//! runs in constant time.
82//!
83//! ## Scalars
84//!
85//! Scalars are represented by the `Scalar` struct.  Each scalar has a
86//! canonical representative mod the group order.  To attempt to load
87//! a supposedly-canonical scalar, use
88//! `Scalar::from_canonical_bytes()`. To check whether a
89//! representative is canonical, use `Scalar::is_canonical()`.
90//!
91//! ## Scalar Multiplication
92//!
93//! Scalar multiplication on Ristretto points is provided by:
94//!
95//! * the `*` operator between a `Scalar` and a `RistrettoPoint`, which
96//!   performs constant-time variable-base scalar multiplication;
97//!
98//! * the `*` operator between a `Scalar` and a
99//!   `RistrettoBasepointTable`, which performs constant-time fixed-base
100//!   scalar multiplication;
101//!
102//! * an implementation of the
103//!   [`MultiscalarMul`](../traits/trait.MultiscalarMul.html) trait for
104//!   constant-time variable-base multiscalar multiplication;
105//!
106//! * an implementation of the
107//!   [`VartimeMultiscalarMul`](../traits/trait.VartimeMultiscalarMul.html)
108//!   trait for variable-time variable-base multiscalar multiplication;
109//!
110//! ## Random Points and Hashing to Ristretto
111//!
112//! The Ristretto group comes equipped with an Elligator map.  This is
113//! used to implement
114//!
115//! * `RistrettoPoint::random()`, which generates random points from an
116//!   RNG - enabled by `rand_core` feature;
117//!
118//! * `RistrettoPoint::from_hash()` and
119//!   `RistrettoPoint::hash_from_bytes()`, which perform hashing to the
120//!   group.
121//!
122//! The Elligator map itself is not currently exposed.
123//!
124//! ## Implementation
125//!
126//! The Decaf suggestion is to use a quotient group, such as \\(\mathcal
127//! E / \mathcal E\[4\]\\) or \\(2 \mathcal E / \mathcal E\[2\] \\), to
128//! implement a prime-order group using a non-prime-order curve.
129//!
130//! This requires only changing
131//!
132//! 1. the function for equality checking (so that two representatives
133//!    of the same coset are considered equal);
134//! 2. the function for encoding (so that two representatives of the
135//!    same coset are encoded as identical bitstrings);
136//! 3. the function for decoding (so that only the canonical encoding of
137//!    a coset is accepted).
138//!
139//! Internally, each coset is represented by a curve point; two points
140//! \\( P, Q \\) may represent the same coset in the same way that two
141//! points with different \\(X,Y,Z\\) coordinates may represent the
142//! same point.  The group operations are carried out with no overhead
143//! using Edwards formulas.
144//!
145//! Notes on the details of the encoding can be found in the
146//! [Details][ristretto_notes] section of the Ristretto website.
147//!
148//! [cryptonote]:
149//! https://moderncrypto.org/mail-archive/curves/2017/000898.html
150//! [ed25519_hkd]:
151//! https://moderncrypto.org/mail-archive/curves/2017/000858.html
152//! [ristretto_coffee]:
153//! https://en.wikipedia.org/wiki/Ristretto
154//! [ristretto_notes]:
155//! https://ristretto.group/details/index.html
156//! [why_ristretto]:
157//! https://ristretto.group/why_ristretto.html
158//! [ristretto_main]:
159//! https://ristretto.group/
160
161#[cfg(feature = "alloc")]
162use alloc::vec::Vec;
163
164use core::array::TryFromSliceError;
165use core::borrow::Borrow;
166use core::fmt::Debug;
167use core::iter::Sum;
168use core::ops::{Add, Neg, Sub};
169use core::ops::{AddAssign, SubAssign};
170use core::ops::{Mul, MulAssign};
171
172#[cfg(any(test, feature = "rand_core"))]
173use rand_core::CryptoRngCore;
174
175#[cfg(feature = "digest")]
176use digest::generic_array::typenum::U64;
177#[cfg(feature = "digest")]
178use digest::Digest;
179
180use crate::constants;
181use crate::field::FieldElement;
182
183#[cfg(feature = "group")]
184use {
185    group::{cofactor::CofactorGroup, prime::PrimeGroup, GroupEncoding},
186    rand_core::RngCore,
187    subtle::CtOption,
188};
189
190use subtle::Choice;
191use subtle::ConditionallyNegatable;
192use subtle::ConditionallySelectable;
193use subtle::ConstantTimeEq;
194
195#[cfg(feature = "zeroize")]
196use zeroize::Zeroize;
197
198#[cfg(feature = "precomputed-tables")]
199use crate::edwards::EdwardsBasepointTable;
200use crate::edwards::EdwardsPoint;
201
202use crate::scalar::Scalar;
203
204#[cfg(feature = "precomputed-tables")]
205use crate::traits::BasepointTable;
206use crate::traits::Identity;
207#[cfg(feature = "alloc")]
208use crate::traits::{MultiscalarMul, VartimeMultiscalarMul, VartimePrecomputedMultiscalarMul};
209
210// ------------------------------------------------------------------------
211// Compressed points
212// ------------------------------------------------------------------------
213
214/// A Ristretto point, in compressed wire format.
215///
216/// The Ristretto encoding is canonical, so two points are equal if and
217/// only if their encodings are equal.
218#[derive(Copy, Clone, Eq, PartialEq, Hash)]
219pub struct CompressedRistretto(pub [u8; 32]);
220
221impl ConstantTimeEq for CompressedRistretto {
222    fn ct_eq(&self, other: &CompressedRistretto) -> Choice {
223        self.as_bytes().ct_eq(other.as_bytes())
224    }
225}
226
227impl CompressedRistretto {
228    /// Copy the bytes of this `CompressedRistretto`.
229    pub const fn to_bytes(&self) -> [u8; 32] {
230        self.0
231    }
232
233    /// View this `CompressedRistretto` as an array of bytes.
234    pub const fn as_bytes(&self) -> &[u8; 32] {
235        &self.0
236    }
237
238    /// Construct a `CompressedRistretto` from a slice of bytes.
239    ///
240    /// # Errors
241    ///
242    /// Returns [`TryFromSliceError`] if the input `bytes` slice does not have
243    /// a length of 32.
244    pub fn from_slice(bytes: &[u8]) -> Result<CompressedRistretto, TryFromSliceError> {
245        bytes.try_into().map(CompressedRistretto)
246    }
247
248    /// Attempt to decompress to an `RistrettoPoint`.
249    ///
250    /// # Return
251    ///
252    /// - `Some(RistrettoPoint)` if `self` was the canonical encoding of a point;
253    ///
254    /// - `None` if `self` was not the canonical encoding of a point.
255    pub fn decompress(&self) -> Option<RistrettoPoint> {
256        let (s_encoding_is_canonical, s_is_negative, s) = decompress::step_1(self);
257
258        if (!s_encoding_is_canonical | s_is_negative).into() {
259            return None;
260        }
261
262        let (ok, t_is_negative, y_is_zero, res) = decompress::step_2(s);
263
264        if (!ok | t_is_negative | y_is_zero).into() {
265            None
266        } else {
267            Some(res)
268        }
269    }
270}
271
272mod decompress {
273    use super::*;
274
275    pub(super) fn step_1(repr: &CompressedRistretto) -> (Choice, Choice, FieldElement) {
276        // Step 1. Check s for validity:
277        // 1.a) s must be 32 bytes (we get this from the type system)
278        // 1.b) s < p
279        // 1.c) s is nonnegative
280        //
281        // Our decoding routine ignores the high bit, so the only
282        // possible failure for 1.b) is if someone encodes s in 0..18
283        // as s+p in 2^255-19..2^255-1.  We can check this by
284        // converting back to bytes, and checking that we get the
285        // original input, since our encoding routine is canonical.
286
287        let s = FieldElement::from_bytes(repr.as_bytes());
288        let s_bytes_check = s.to_bytes();
289        let s_encoding_is_canonical = s_bytes_check[..].ct_eq(repr.as_bytes());
290        let s_is_negative = s.is_negative();
291
292        (s_encoding_is_canonical, s_is_negative, s)
293    }
294
295    pub(super) fn step_2(s: FieldElement) -> (Choice, Choice, Choice, RistrettoPoint) {
296        // Step 2.  Compute (X:Y:Z:T).
297        let one = FieldElement::ONE;
298        let ss = s.square();
299        let u1 = &one - &ss; //  1 + as²
300        let u2 = &one + &ss; //  1 - as²    where a=-1
301        let u2_sqr = u2.square(); // (1 - as²)²
302
303        // v == ad(1+as²)² - (1-as²)²            where d=-121665/121666
304        let v = &(&(-&constants::EDWARDS_D) * &u1.square()) - &u2_sqr;
305
306        let (ok, I) = (&v * &u2_sqr).invsqrt(); // 1/sqrt(v*u_2²)
307
308        let Dx = &I * &u2; // 1/sqrt(v)
309        let Dy = &I * &(&Dx * &v); // 1/u2
310
311        // x == | 2s/sqrt(v) | == + sqrt(4s²/(ad(1+as²)² - (1-as²)²))
312        let mut x = &(&s + &s) * &Dx;
313        let x_neg = x.is_negative();
314        x.conditional_negate(x_neg);
315
316        // y == (1-as²)/(1+as²)
317        let y = &u1 * &Dy;
318
319        // t == ((1+as²) sqrt(4s²/(ad(1+as²)² - (1-as²)²)))/(1-as²)
320        let t = &x * &y;
321
322        (
323            ok,
324            t.is_negative(),
325            y.is_zero(),
326            RistrettoPoint(EdwardsPoint {
327                X: x,
328                Y: y,
329                Z: one,
330                T: t,
331            }),
332        )
333    }
334}
335
336impl Identity for CompressedRistretto {
337    fn identity() -> CompressedRistretto {
338        CompressedRistretto([0u8; 32])
339    }
340}
341
342impl Default for CompressedRistretto {
343    fn default() -> CompressedRistretto {
344        CompressedRistretto::identity()
345    }
346}
347
348impl TryFrom<&[u8]> for CompressedRistretto {
349    type Error = TryFromSliceError;
350
351    fn try_from(slice: &[u8]) -> Result<CompressedRistretto, TryFromSliceError> {
352        Self::from_slice(slice)
353    }
354}
355
356// ------------------------------------------------------------------------
357// Serde support
358// ------------------------------------------------------------------------
359// Serializes to and from `RistrettoPoint` directly, doing compression
360// and decompression internally.  This means that users can create
361// structs containing `RistrettoPoint`s and use Serde's derived
362// serializers to serialize those structures.
363
364#[cfg(feature = "serde")]
365use serde::de::Visitor;
366#[cfg(feature = "serde")]
367use serde::{Deserialize, Deserializer, Serialize, Serializer};
368
369#[cfg(feature = "serde")]
370impl Serialize for RistrettoPoint {
371    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
372    where
373        S: Serializer,
374    {
375        use serde::ser::SerializeTuple;
376        let mut tup = serializer.serialize_tuple(32)?;
377        for byte in self.compress().as_bytes().iter() {
378            tup.serialize_element(byte)?;
379        }
380        tup.end()
381    }
382}
383
384#[cfg(feature = "serde")]
385impl Serialize for CompressedRistretto {
386    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
387    where
388        S: Serializer,
389    {
390        use serde::ser::SerializeTuple;
391        let mut tup = serializer.serialize_tuple(32)?;
392        for byte in self.as_bytes().iter() {
393            tup.serialize_element(byte)?;
394        }
395        tup.end()
396    }
397}
398
399#[cfg(feature = "serde")]
400impl<'de> Deserialize<'de> for RistrettoPoint {
401    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
402    where
403        D: Deserializer<'de>,
404    {
405        struct RistrettoPointVisitor;
406
407        impl<'de> Visitor<'de> for RistrettoPointVisitor {
408            type Value = RistrettoPoint;
409
410            fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
411                formatter.write_str("a valid point in Ristretto format")
412            }
413
414            fn visit_seq<A>(self, mut seq: A) -> Result<RistrettoPoint, A::Error>
415            where
416                A: serde::de::SeqAccess<'de>,
417            {
418                let mut bytes = [0u8; 32];
419                #[allow(clippy::needless_range_loop)]
420                for i in 0..32 {
421                    bytes[i] = seq
422                        .next_element()?
423                        .ok_or_else(|| serde::de::Error::invalid_length(i, &"expected 32 bytes"))?;
424                }
425                CompressedRistretto(bytes)
426                    .decompress()
427                    .ok_or_else(|| serde::de::Error::custom("decompression failed"))
428            }
429        }
430
431        deserializer.deserialize_tuple(32, RistrettoPointVisitor)
432    }
433}
434
435#[cfg(feature = "serde")]
436impl<'de> Deserialize<'de> for CompressedRistretto {
437    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
438    where
439        D: Deserializer<'de>,
440    {
441        struct CompressedRistrettoVisitor;
442
443        impl<'de> Visitor<'de> for CompressedRistrettoVisitor {
444            type Value = CompressedRistretto;
445
446            fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
447                formatter.write_str("32 bytes of data")
448            }
449
450            fn visit_seq<A>(self, mut seq: A) -> Result<CompressedRistretto, A::Error>
451            where
452                A: serde::de::SeqAccess<'de>,
453            {
454                let mut bytes = [0u8; 32];
455                #[allow(clippy::needless_range_loop)]
456                for i in 0..32 {
457                    bytes[i] = seq
458                        .next_element()?
459                        .ok_or_else(|| serde::de::Error::invalid_length(i, &"expected 32 bytes"))?;
460                }
461                Ok(CompressedRistretto(bytes))
462            }
463        }
464
465        deserializer.deserialize_tuple(32, CompressedRistrettoVisitor)
466    }
467}
468
469// ------------------------------------------------------------------------
470// Internal point representations
471// ------------------------------------------------------------------------
472
473/// A `RistrettoPoint` represents a point in the Ristretto group for
474/// Curve25519.  Ristretto, a variant of Decaf, constructs a
475/// prime-order group as a quotient group of a subgroup of (the
476/// Edwards form of) Curve25519.
477///
478/// Internally, a `RistrettoPoint` is implemented as a wrapper type
479/// around `EdwardsPoint`, with custom equality, compression, and
480/// decompression routines to account for the quotient.  This means that
481/// operations on `RistrettoPoint`s are exactly as fast as operations on
482/// `EdwardsPoint`s.
483///
484#[derive(Copy, Clone)]
485pub struct RistrettoPoint(pub(crate) EdwardsPoint);
486
487impl RistrettoPoint {
488    /// Compress this point using the Ristretto encoding.
489    pub fn compress(&self) -> CompressedRistretto {
490        let mut X = self.0.X;
491        let mut Y = self.0.Y;
492        let Z = &self.0.Z;
493        let T = &self.0.T;
494
495        let u1 = &(Z + &Y) * &(Z - &Y);
496        let u2 = &X * &Y;
497        // Ignore return value since this is always square
498        let (_, invsqrt) = (&u1 * &u2.square()).invsqrt();
499        let i1 = &invsqrt * &u1;
500        let i2 = &invsqrt * &u2;
501        let z_inv = &i1 * &(&i2 * T);
502        let mut den_inv = i2;
503
504        let iX = &X * &constants::SQRT_M1;
505        let iY = &Y * &constants::SQRT_M1;
506        let ristretto_magic = &constants::INVSQRT_A_MINUS_D;
507        let enchanted_denominator = &i1 * ristretto_magic;
508
509        let rotate = (T * &z_inv).is_negative();
510
511        X.conditional_assign(&iY, rotate);
512        Y.conditional_assign(&iX, rotate);
513        den_inv.conditional_assign(&enchanted_denominator, rotate);
514
515        Y.conditional_negate((&X * &z_inv).is_negative());
516
517        let mut s = &den_inv * &(Z - &Y);
518        let s_is_negative = s.is_negative();
519        s.conditional_negate(s_is_negative);
520
521        CompressedRistretto(s.to_bytes())
522    }
523
524    /// Double-and-compress a batch of points.  The Ristretto encoding
525    /// is not batchable, since it requires an inverse square root.
526    ///
527    /// However, given input points \\( P\_1, \ldots, P\_n, \\)
528    /// it is possible to compute the encodings of their doubles \\(
529    /// \mathrm{enc}( \[2\]P\_1), \ldots, \mathrm{enc}( \[2\]P\_n ) \\)
530    /// in a batch.
531    ///
532    #[cfg_attr(feature = "rand_core", doc = "```")]
533    #[cfg_attr(not(feature = "rand_core"), doc = "```ignore")]
534    /// # use curve25519_dalek::ristretto::RistrettoPoint;
535    /// use rand_core::OsRng;
536    ///
537    /// # // Need fn main() here in comment so the doctest compiles
538    /// # // See https://doc.rust-lang.org/book/documentation.html#documentation-as-tests
539    /// # fn main() {
540    /// let mut rng = OsRng;
541    ///
542    /// let points: Vec<RistrettoPoint> =
543    ///     (0..32).map(|_| RistrettoPoint::random(&mut rng)).collect();
544    ///
545    /// let compressed = RistrettoPoint::double_and_compress_batch(&points);
546    ///
547    /// for (P, P2_compressed) in points.iter().zip(compressed.iter()) {
548    ///     assert_eq!(*P2_compressed, (P + P).compress());
549    /// }
550    /// # }
551    /// ```
552    #[cfg(feature = "alloc")]
553    pub fn double_and_compress_batch<'a, I>(points: I) -> Vec<CompressedRistretto>
554    where
555        I: IntoIterator<Item = &'a RistrettoPoint>,
556    {
557        #[derive(Copy, Clone, Debug)]
558        struct BatchCompressState {
559            e: FieldElement,
560            f: FieldElement,
561            g: FieldElement,
562            h: FieldElement,
563            eg: FieldElement,
564            fh: FieldElement,
565        }
566
567        impl BatchCompressState {
568            fn efgh(&self) -> FieldElement {
569                &self.eg * &self.fh
570            }
571        }
572
573        impl<'a> From<&'a RistrettoPoint> for BatchCompressState {
574            #[rustfmt::skip] // keep alignment of explanatory comments
575            fn from(P: &'a RistrettoPoint) -> BatchCompressState {
576                let XX = P.0.X.square();
577                let YY = P.0.Y.square();
578                let ZZ = P.0.Z.square();
579                let dTT = &P.0.T.square() * &constants::EDWARDS_D;
580
581                let e = &P.0.X * &(&P.0.Y + &P.0.Y); // = 2*X*Y
582                let f = &ZZ + &dTT;                  // = Z^2 + d*T^2
583                let g = &YY + &XX;                   // = Y^2 - a*X^2
584                let h = &ZZ - &dTT;                  // = Z^2 - d*T^2
585
586                let eg = &e * &g;
587                let fh = &f * &h;
588
589                BatchCompressState{ e, f, g, h, eg, fh }
590            }
591        }
592
593        let states: Vec<BatchCompressState> =
594            points.into_iter().map(BatchCompressState::from).collect();
595
596        let mut invs: Vec<FieldElement> = states.iter().map(|state| state.efgh()).collect();
597
598        FieldElement::batch_invert(&mut invs[..]);
599
600        states
601            .iter()
602            .zip(invs.iter())
603            .map(|(state, inv): (&BatchCompressState, &FieldElement)| {
604                let Zinv = &state.eg * inv;
605                let Tinv = &state.fh * inv;
606
607                let mut magic = constants::INVSQRT_A_MINUS_D;
608
609                let negcheck1 = (&state.eg * &Zinv).is_negative();
610
611                let mut e = state.e;
612                let mut g = state.g;
613                let mut h = state.h;
614
615                let minus_e = -&e;
616                let f_times_sqrta = &state.f * &constants::SQRT_M1;
617
618                e.conditional_assign(&state.g, negcheck1);
619                g.conditional_assign(&minus_e, negcheck1);
620                h.conditional_assign(&f_times_sqrta, negcheck1);
621
622                magic.conditional_assign(&constants::SQRT_M1, negcheck1);
623
624                let negcheck2 = (&(&h * &e) * &Zinv).is_negative();
625
626                g.conditional_negate(negcheck2);
627
628                let mut s = &(&h - &g) * &(&magic * &(&g * &Tinv));
629
630                let s_is_negative = s.is_negative();
631                s.conditional_negate(s_is_negative);
632
633                CompressedRistretto(s.to_bytes())
634            })
635            .collect()
636    }
637
638    /// Return the coset self + E\[4\], for debugging.
639    fn coset4(&self) -> [EdwardsPoint; 4] {
640        [
641            self.0,
642            self.0 + constants::EIGHT_TORSION[2],
643            self.0 + constants::EIGHT_TORSION[4],
644            self.0 + constants::EIGHT_TORSION[6],
645        ]
646    }
647
648    /// Computes the Ristretto Elligator map. This is the
649    /// [`MAP`](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-ristretto255-decaf448-04#section-4.3.4)
650    /// function defined in the Ristretto spec.
651    ///
652    /// # Note
653    ///
654    /// This method is not public because it's just used for hashing
655    /// to a point -- proper elligator support is deferred for now.
656    pub(crate) fn elligator_ristretto_flavor(r_0: &FieldElement) -> RistrettoPoint {
657        let i = &constants::SQRT_M1;
658        let d = &constants::EDWARDS_D;
659        let one_minus_d_sq = &constants::ONE_MINUS_EDWARDS_D_SQUARED;
660        let d_minus_one_sq = &constants::EDWARDS_D_MINUS_ONE_SQUARED;
661        let mut c = constants::MINUS_ONE;
662
663        let one = FieldElement::ONE;
664
665        let r = i * &r_0.square();
666        let N_s = &(&r + &one) * one_minus_d_sq;
667        let D = &(&c - &(d * &r)) * &(&r + d);
668
669        let (Ns_D_is_sq, mut s) = FieldElement::sqrt_ratio_i(&N_s, &D);
670        let mut s_prime = &s * r_0;
671        let s_prime_is_pos = !s_prime.is_negative();
672        s_prime.conditional_negate(s_prime_is_pos);
673
674        s.conditional_assign(&s_prime, !Ns_D_is_sq);
675        c.conditional_assign(&r, !Ns_D_is_sq);
676
677        let N_t = &(&(&c * &(&r - &one)) * d_minus_one_sq) - &D;
678        let s_sq = s.square();
679
680        use crate::backend::serial::curve_models::CompletedPoint;
681
682        // The conversion from W_i is exactly the conversion from P1xP1.
683        RistrettoPoint(
684            CompletedPoint {
685                X: &(&s + &s) * &D,
686                Z: &N_t * &constants::SQRT_AD_MINUS_ONE,
687                Y: &FieldElement::ONE - &s_sq,
688                T: &FieldElement::ONE + &s_sq,
689            }
690            .as_extended(),
691        )
692    }
693
694    #[cfg(any(test, feature = "rand_core"))]
695    /// Return a `RistrettoPoint` chosen uniformly at random using a user-provided RNG.
696    ///
697    /// # Inputs
698    ///
699    /// * `rng`: any RNG which implements `CryptoRngCore`
700    ///   (i.e. `CryptoRng` + `RngCore`) interface.
701    ///
702    /// # Returns
703    ///
704    /// A random element of the Ristretto group.
705    ///
706    /// # Implementation
707    ///
708    /// Uses the Ristretto-flavoured Elligator 2 map, so that the
709    /// discrete log of the output point with respect to any other
710    /// point should be unknown.  The map is applied twice and the
711    /// results are added, to ensure a uniform distribution.
712    pub fn random<R: CryptoRngCore + ?Sized>(rng: &mut R) -> Self {
713        let mut uniform_bytes = [0u8; 64];
714        rng.fill_bytes(&mut uniform_bytes);
715
716        RistrettoPoint::from_uniform_bytes(&uniform_bytes)
717    }
718
719    #[cfg(feature = "digest")]
720    /// Hash a slice of bytes into a `RistrettoPoint`.
721    ///
722    /// Takes a type parameter `D`, which is any `Digest` producing 64
723    /// bytes of output.
724    ///
725    /// Convenience wrapper around `from_hash`.
726    ///
727    /// # Implementation
728    ///
729    /// Uses the Ristretto-flavoured Elligator 2 map, so that the
730    /// discrete log of the output point with respect to any other
731    /// point should be unknown.  The map is applied twice and the
732    /// results are added, to ensure a uniform distribution.
733    ///
734    /// # Example
735    ///
736    #[cfg_attr(feature = "digest", doc = "```")]
737    #[cfg_attr(not(feature = "digest"), doc = "```ignore")]
738    /// # use curve25519_dalek::ristretto::RistrettoPoint;
739    /// use sha2::Sha512;
740    ///
741    /// # // Need fn main() here in comment so the doctest compiles
742    /// # // See https://doc.rust-lang.org/book/documentation.html#documentation-as-tests
743    /// # fn main() {
744    /// let msg = "To really appreciate architecture, you may even need to commit a murder";
745    /// let P = RistrettoPoint::hash_from_bytes::<Sha512>(msg.as_bytes());
746    /// # }
747    /// ```
748    ///
749    pub fn hash_from_bytes<D>(input: &[u8]) -> RistrettoPoint
750    where
751        D: Digest<OutputSize = U64> + Default,
752    {
753        let mut hash = D::default();
754        hash.update(input);
755        RistrettoPoint::from_hash(hash)
756    }
757
758    #[cfg(feature = "digest")]
759    /// Construct a `RistrettoPoint` from an existing `Digest` instance.
760    ///
761    /// Use this instead of `hash_from_bytes` if it is more convenient
762    /// to stream data into the `Digest` than to pass a single byte
763    /// slice.
764    pub fn from_hash<D>(hash: D) -> RistrettoPoint
765    where
766        D: Digest<OutputSize = U64> + Default,
767    {
768        // dealing with generic arrays is clumsy, until const generics land
769        let output = hash.finalize();
770        let mut output_bytes = [0u8; 64];
771        output_bytes.copy_from_slice(output.as_slice());
772
773        RistrettoPoint::from_uniform_bytes(&output_bytes)
774    }
775
776    /// Construct a `RistrettoPoint` from 64 bytes of data.
777    ///
778    /// If the input bytes are uniformly distributed, the resulting
779    /// point will be uniformly distributed over the group, and its
780    /// discrete log with respect to other points should be unknown.
781    ///
782    /// # Implementation
783    ///
784    /// This function splits the input array into two 32-byte halves,
785    /// takes the low 255 bits of each half mod p, applies the
786    /// Ristretto-flavored Elligator map to each, and adds the results.
787    pub fn from_uniform_bytes(bytes: &[u8; 64]) -> RistrettoPoint {
788        // This follows the one-way map construction from the Ristretto RFC:
789        // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-ristretto255-decaf448-04#section-4.3.4
790        let mut r_1_bytes = [0u8; 32];
791        r_1_bytes.copy_from_slice(&bytes[0..32]);
792        let r_1 = FieldElement::from_bytes(&r_1_bytes);
793        let R_1 = RistrettoPoint::elligator_ristretto_flavor(&r_1);
794
795        let mut r_2_bytes = [0u8; 32];
796        r_2_bytes.copy_from_slice(&bytes[32..64]);
797        let r_2 = FieldElement::from_bytes(&r_2_bytes);
798        let R_2 = RistrettoPoint::elligator_ristretto_flavor(&r_2);
799
800        // Applying Elligator twice and adding the results ensures a
801        // uniform distribution.
802        R_1 + R_2
803    }
804}
805
806impl Identity for RistrettoPoint {
807    fn identity() -> RistrettoPoint {
808        RistrettoPoint(EdwardsPoint::identity())
809    }
810}
811
812impl Default for RistrettoPoint {
813    fn default() -> RistrettoPoint {
814        RistrettoPoint::identity()
815    }
816}
817
818// ------------------------------------------------------------------------
819// Equality
820// ------------------------------------------------------------------------
821
822impl PartialEq for RistrettoPoint {
823    fn eq(&self, other: &RistrettoPoint) -> bool {
824        self.ct_eq(other).into()
825    }
826}
827
828impl ConstantTimeEq for RistrettoPoint {
829    /// Test equality between two `RistrettoPoint`s.
830    ///
831    /// # Returns
832    ///
833    /// * `Choice(1)` if the two `RistrettoPoint`s are equal;
834    /// * `Choice(0)` otherwise.
835    fn ct_eq(&self, other: &RistrettoPoint) -> Choice {
836        let X1Y2 = &self.0.X * &other.0.Y;
837        let Y1X2 = &self.0.Y * &other.0.X;
838        let X1X2 = &self.0.X * &other.0.X;
839        let Y1Y2 = &self.0.Y * &other.0.Y;
840
841        X1Y2.ct_eq(&Y1X2) | X1X2.ct_eq(&Y1Y2)
842    }
843}
844
845impl Eq for RistrettoPoint {}
846
847// ------------------------------------------------------------------------
848// Arithmetic
849// ------------------------------------------------------------------------
850
851impl<'a> Add<&'a RistrettoPoint> for &RistrettoPoint {
852    type Output = RistrettoPoint;
853
854    fn add(self, other: &'a RistrettoPoint) -> RistrettoPoint {
855        RistrettoPoint(self.0 + other.0)
856    }
857}
858
859define_add_variants!(
860    LHS = RistrettoPoint,
861    RHS = RistrettoPoint,
862    Output = RistrettoPoint
863);
864
865impl AddAssign<&RistrettoPoint> for RistrettoPoint {
866    fn add_assign(&mut self, _rhs: &RistrettoPoint) {
867        *self = (self as &RistrettoPoint) + _rhs;
868    }
869}
870
871define_add_assign_variants!(LHS = RistrettoPoint, RHS = RistrettoPoint);
872
873impl<'a> Sub<&'a RistrettoPoint> for &RistrettoPoint {
874    type Output = RistrettoPoint;
875
876    fn sub(self, other: &'a RistrettoPoint) -> RistrettoPoint {
877        RistrettoPoint(self.0 - other.0)
878    }
879}
880
881define_sub_variants!(
882    LHS = RistrettoPoint,
883    RHS = RistrettoPoint,
884    Output = RistrettoPoint
885);
886
887impl SubAssign<&RistrettoPoint> for RistrettoPoint {
888    fn sub_assign(&mut self, _rhs: &RistrettoPoint) {
889        *self = (self as &RistrettoPoint) - _rhs;
890    }
891}
892
893define_sub_assign_variants!(LHS = RistrettoPoint, RHS = RistrettoPoint);
894
895impl<T> Sum<T> for RistrettoPoint
896where
897    T: Borrow<RistrettoPoint>,
898{
899    fn sum<I>(iter: I) -> Self
900    where
901        I: Iterator<Item = T>,
902    {
903        iter.fold(RistrettoPoint::identity(), |acc, item| acc + item.borrow())
904    }
905}
906
907impl Neg for &RistrettoPoint {
908    type Output = RistrettoPoint;
909
910    fn neg(self) -> RistrettoPoint {
911        RistrettoPoint(-&self.0)
912    }
913}
914
915impl Neg for RistrettoPoint {
916    type Output = RistrettoPoint;
917
918    fn neg(self) -> RistrettoPoint {
919        -&self
920    }
921}
922
923impl<'a> MulAssign<&'a Scalar> for RistrettoPoint {
924    fn mul_assign(&mut self, scalar: &'a Scalar) {
925        let result = (self as &RistrettoPoint) * scalar;
926        *self = result;
927    }
928}
929
930impl<'a> Mul<&'a Scalar> for &RistrettoPoint {
931    type Output = RistrettoPoint;
932    /// Scalar multiplication: compute `scalar * self`.
933    fn mul(self, scalar: &'a Scalar) -> RistrettoPoint {
934        RistrettoPoint(self.0 * scalar)
935    }
936}
937
938impl<'a> Mul<&'a RistrettoPoint> for &Scalar {
939    type Output = RistrettoPoint;
940
941    /// Scalar multiplication: compute `self * scalar`.
942    fn mul(self, point: &'a RistrettoPoint) -> RistrettoPoint {
943        RistrettoPoint(self * point.0)
944    }
945}
946
947impl RistrettoPoint {
948    /// Fixed-base scalar multiplication by the Ristretto base point.
949    ///
950    /// Uses precomputed basepoint tables when the `precomputed-tables` feature
951    /// is enabled, trading off increased code size for ~4x better performance.
952    pub fn mul_base(scalar: &Scalar) -> Self {
953        #[cfg(not(feature = "precomputed-tables"))]
954        {
955            scalar * constants::RISTRETTO_BASEPOINT_POINT
956        }
957
958        #[cfg(feature = "precomputed-tables")]
959        {
960            scalar * constants::RISTRETTO_BASEPOINT_TABLE
961        }
962    }
963}
964
965define_mul_assign_variants!(LHS = RistrettoPoint, RHS = Scalar);
966
967define_mul_variants!(LHS = RistrettoPoint, RHS = Scalar, Output = RistrettoPoint);
968define_mul_variants!(LHS = Scalar, RHS = RistrettoPoint, Output = RistrettoPoint);
969
970// ------------------------------------------------------------------------
971// Multiscalar Multiplication impls
972// ------------------------------------------------------------------------
973
974// These use iterator combinators to unwrap the underlying points and
975// forward to the EdwardsPoint implementations.
976
977#[cfg(feature = "alloc")]
978impl MultiscalarMul for RistrettoPoint {
979    type Point = RistrettoPoint;
980
981    fn multiscalar_mul<I, J>(scalars: I, points: J) -> RistrettoPoint
982    where
983        I: IntoIterator,
984        I::Item: Borrow<Scalar>,
985        J: IntoIterator,
986        J::Item: Borrow<RistrettoPoint>,
987    {
988        let extended_points = points.into_iter().map(|P| P.borrow().0);
989        RistrettoPoint(EdwardsPoint::multiscalar_mul(scalars, extended_points))
990    }
991}
992
993#[cfg(feature = "alloc")]
994impl VartimeMultiscalarMul for RistrettoPoint {
995    type Point = RistrettoPoint;
996
997    fn optional_multiscalar_mul<I, J>(scalars: I, points: J) -> Option<RistrettoPoint>
998    where
999        I: IntoIterator,
1000        I::Item: Borrow<Scalar>,
1001        J: IntoIterator<Item = Option<RistrettoPoint>>,
1002    {
1003        let extended_points = points.into_iter().map(|opt_P| opt_P.map(|P| P.0));
1004
1005        EdwardsPoint::optional_multiscalar_mul(scalars, extended_points).map(RistrettoPoint)
1006    }
1007}
1008
1009/// Precomputation for variable-time multiscalar multiplication with `RistrettoPoint`s.
1010///
1011/// Note that for large numbers of `RistrettoPoint`s, this functionality may be less
1012/// efficient than the corresponding `VartimeMultiscalarMul` implementation.
1013// This wraps the inner implementation in a facade type so that we can
1014// decouple stability of the inner type from the stability of the
1015// outer type.
1016#[cfg(feature = "alloc")]
1017pub struct VartimeRistrettoPrecomputation(crate::backend::VartimePrecomputedStraus);
1018
1019#[cfg(feature = "alloc")]
1020impl VartimePrecomputedMultiscalarMul for VartimeRistrettoPrecomputation {
1021    type Point = RistrettoPoint;
1022
1023    fn new<I>(static_points: I) -> Self
1024    where
1025        I: IntoIterator,
1026        I::Item: Borrow<Self::Point>,
1027    {
1028        Self(crate::backend::VartimePrecomputedStraus::new(
1029            static_points.into_iter().map(|P| P.borrow().0),
1030        ))
1031    }
1032
1033    fn len(&self) -> usize {
1034        self.0.len()
1035    }
1036
1037    fn is_empty(&self) -> bool {
1038        self.0.is_empty()
1039    }
1040
1041    fn optional_mixed_multiscalar_mul<I, J, K>(
1042        &self,
1043        static_scalars: I,
1044        dynamic_scalars: J,
1045        dynamic_points: K,
1046    ) -> Option<Self::Point>
1047    where
1048        I: IntoIterator,
1049        I::Item: Borrow<Scalar>,
1050        J: IntoIterator,
1051        J::Item: Borrow<Scalar>,
1052        K: IntoIterator<Item = Option<Self::Point>>,
1053    {
1054        self.0
1055            .optional_mixed_multiscalar_mul(
1056                static_scalars,
1057                dynamic_scalars,
1058                dynamic_points.into_iter().map(|P_opt| P_opt.map(|P| P.0)),
1059            )
1060            .map(RistrettoPoint)
1061    }
1062}
1063
1064impl RistrettoPoint {
1065    /// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the
1066    /// Ristretto basepoint.
1067    pub fn vartime_double_scalar_mul_basepoint(
1068        a: &Scalar,
1069        A: &RistrettoPoint,
1070        b: &Scalar,
1071    ) -> RistrettoPoint {
1072        RistrettoPoint(EdwardsPoint::vartime_double_scalar_mul_basepoint(
1073            a, &A.0, b,
1074        ))
1075    }
1076}
1077
1078/// A precomputed table of multiples of a basepoint, used to accelerate
1079/// scalar multiplication.
1080///
1081/// A precomputed table of multiples of the Ristretto basepoint is
1082/// available in the `constants` module:
1083/// ```
1084/// use curve25519_dalek::constants::RISTRETTO_BASEPOINT_TABLE;
1085/// use curve25519_dalek::scalar::Scalar;
1086///
1087/// let a = Scalar::from(87329482u64);
1088/// let P = &a * RISTRETTO_BASEPOINT_TABLE;
1089/// ```
1090#[cfg(feature = "precomputed-tables")]
1091#[derive(Clone)]
1092#[repr(transparent)]
1093pub struct RistrettoBasepointTable(pub(crate) EdwardsBasepointTable);
1094
1095#[cfg(feature = "precomputed-tables")]
1096impl<'b> Mul<&'b Scalar> for &RistrettoBasepointTable {
1097    type Output = RistrettoPoint;
1098
1099    fn mul(self, scalar: &'b Scalar) -> RistrettoPoint {
1100        RistrettoPoint(&self.0 * scalar)
1101    }
1102}
1103
1104#[cfg(feature = "precomputed-tables")]
1105impl<'a> Mul<&'a RistrettoBasepointTable> for &Scalar {
1106    type Output = RistrettoPoint;
1107
1108    fn mul(self, basepoint_table: &'a RistrettoBasepointTable) -> RistrettoPoint {
1109        RistrettoPoint(self * &basepoint_table.0)
1110    }
1111}
1112
1113#[cfg(feature = "precomputed-tables")]
1114impl RistrettoBasepointTable {
1115    /// Create a precomputed table of multiples of the given `basepoint`.
1116    pub fn create(basepoint: &RistrettoPoint) -> RistrettoBasepointTable {
1117        RistrettoBasepointTable(EdwardsBasepointTable::create(&basepoint.0))
1118    }
1119
1120    /// Get the basepoint for this table as a `RistrettoPoint`.
1121    pub fn basepoint(&self) -> RistrettoPoint {
1122        RistrettoPoint(self.0.basepoint())
1123    }
1124}
1125
1126// ------------------------------------------------------------------------
1127// Constant-time conditional selection
1128// ------------------------------------------------------------------------
1129
1130impl ConditionallySelectable for RistrettoPoint {
1131    /// Conditionally select between `self` and `other`.
1132    ///
1133    /// # Example
1134    ///
1135    /// ```
1136    /// use subtle::ConditionallySelectable;
1137    /// use subtle::Choice;
1138    /// #
1139    /// # use curve25519_dalek::traits::Identity;
1140    /// # use curve25519_dalek::ristretto::RistrettoPoint;
1141    /// # use curve25519_dalek::constants;
1142    /// # fn main() {
1143    ///
1144    /// let A = RistrettoPoint::identity();
1145    /// let B = constants::RISTRETTO_BASEPOINT_POINT;
1146    ///
1147    /// let mut P = A;
1148    ///
1149    /// P = RistrettoPoint::conditional_select(&A, &B, Choice::from(0));
1150    /// assert_eq!(P, A);
1151    /// P = RistrettoPoint::conditional_select(&A, &B, Choice::from(1));
1152    /// assert_eq!(P, B);
1153    /// # }
1154    /// ```
1155    fn conditional_select(
1156        a: &RistrettoPoint,
1157        b: &RistrettoPoint,
1158        choice: Choice,
1159    ) -> RistrettoPoint {
1160        RistrettoPoint(EdwardsPoint::conditional_select(&a.0, &b.0, choice))
1161    }
1162}
1163
1164// ------------------------------------------------------------------------
1165// Debug traits
1166// ------------------------------------------------------------------------
1167
1168impl Debug for CompressedRistretto {
1169    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1170        write!(f, "CompressedRistretto: {:?}", self.as_bytes())
1171    }
1172}
1173
1174impl Debug for RistrettoPoint {
1175    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1176        let coset = self.coset4();
1177        write!(
1178            f,
1179            "RistrettoPoint: coset \n{:?}\n{:?}\n{:?}\n{:?}",
1180            coset[0], coset[1], coset[2], coset[3]
1181        )
1182    }
1183}
1184
1185// ------------------------------------------------------------------------
1186// group traits
1187// ------------------------------------------------------------------------
1188
1189// Use the full trait path to avoid Group::identity overlapping Identity::identity in the
1190// rest of the module (e.g. tests).
1191#[cfg(feature = "group")]
1192impl group::Group for RistrettoPoint {
1193    type Scalar = Scalar;
1194
1195    fn random(mut rng: impl RngCore) -> Self {
1196        // NOTE: this is duplicated due to different `rng` bounds
1197        let mut uniform_bytes = [0u8; 64];
1198        rng.fill_bytes(&mut uniform_bytes);
1199        RistrettoPoint::from_uniform_bytes(&uniform_bytes)
1200    }
1201
1202    fn identity() -> Self {
1203        Identity::identity()
1204    }
1205
1206    fn generator() -> Self {
1207        constants::RISTRETTO_BASEPOINT_POINT
1208    }
1209
1210    fn is_identity(&self) -> Choice {
1211        self.ct_eq(&Identity::identity())
1212    }
1213
1214    fn double(&self) -> Self {
1215        self + self
1216    }
1217}
1218
1219#[cfg(feature = "group")]
1220impl GroupEncoding for RistrettoPoint {
1221    type Repr = [u8; 32];
1222
1223    fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
1224        let (s_encoding_is_canonical, s_is_negative, s) =
1225            decompress::step_1(&CompressedRistretto(*bytes));
1226
1227        let s_is_valid = s_encoding_is_canonical & !s_is_negative;
1228
1229        let (ok, t_is_negative, y_is_zero, res) = decompress::step_2(s);
1230
1231        CtOption::new(res, s_is_valid & ok & !t_is_negative & !y_is_zero)
1232    }
1233
1234    fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
1235        // Just use the checked API; the checks we could skip aren't expensive.
1236        Self::from_bytes(bytes)
1237    }
1238
1239    fn to_bytes(&self) -> Self::Repr {
1240        self.compress().to_bytes()
1241    }
1242}
1243
1244#[cfg(feature = "group")]
1245impl PrimeGroup for RistrettoPoint {}
1246
1247/// Ristretto has a cofactor of 1.
1248#[cfg(feature = "group")]
1249impl CofactorGroup for RistrettoPoint {
1250    type Subgroup = Self;
1251
1252    fn clear_cofactor(&self) -> Self::Subgroup {
1253        *self
1254    }
1255
1256    fn into_subgroup(self) -> CtOption<Self::Subgroup> {
1257        CtOption::new(self, Choice::from(1))
1258    }
1259
1260    fn is_torsion_free(&self) -> Choice {
1261        Choice::from(1)
1262    }
1263}
1264
1265// ------------------------------------------------------------------------
1266// Zeroize traits
1267// ------------------------------------------------------------------------
1268
1269#[cfg(feature = "zeroize")]
1270impl Zeroize for CompressedRistretto {
1271    fn zeroize(&mut self) {
1272        self.0.zeroize();
1273    }
1274}
1275
1276#[cfg(feature = "zeroize")]
1277impl Zeroize for RistrettoPoint {
1278    fn zeroize(&mut self) {
1279        self.0.zeroize();
1280    }
1281}
1282
1283// ------------------------------------------------------------------------
1284// Tests
1285// ------------------------------------------------------------------------
1286
1287#[cfg(test)]
1288mod test {
1289    use super::*;
1290    use crate::edwards::CompressedEdwardsY;
1291
1292    use rand_core::OsRng;
1293
1294    #[test]
1295    #[cfg(feature = "serde")]
1296    fn serde_bincode_basepoint_roundtrip() {
1297        use bincode;
1298
1299        let encoded = bincode::serialize(&constants::RISTRETTO_BASEPOINT_POINT).unwrap();
1300        let enc_compressed =
1301            bincode::serialize(&constants::RISTRETTO_BASEPOINT_COMPRESSED).unwrap();
1302        assert_eq!(encoded, enc_compressed);
1303
1304        // Check that the encoding is 32 bytes exactly
1305        assert_eq!(encoded.len(), 32);
1306
1307        let dec_uncompressed: RistrettoPoint = bincode::deserialize(&encoded).unwrap();
1308        let dec_compressed: CompressedRistretto = bincode::deserialize(&encoded).unwrap();
1309
1310        assert_eq!(dec_uncompressed, constants::RISTRETTO_BASEPOINT_POINT);
1311        assert_eq!(dec_compressed, constants::RISTRETTO_BASEPOINT_COMPRESSED);
1312
1313        // Check that the encoding itself matches the usual one
1314        let raw_bytes = constants::RISTRETTO_BASEPOINT_COMPRESSED.as_bytes();
1315        let bp: RistrettoPoint = bincode::deserialize(raw_bytes).unwrap();
1316        assert_eq!(bp, constants::RISTRETTO_BASEPOINT_POINT);
1317    }
1318
1319    #[test]
1320    fn scalarmult_ristrettopoint_works_both_ways() {
1321        let P = constants::RISTRETTO_BASEPOINT_POINT;
1322        let s = Scalar::from(999u64);
1323
1324        let P1 = P * s;
1325        let P2 = s * P;
1326
1327        assert!(P1.compress().as_bytes() == P2.compress().as_bytes());
1328    }
1329
1330    #[test]
1331    #[cfg(feature = "alloc")]
1332    fn impl_sum() {
1333        // Test that sum works for non-empty iterators
1334        let BASE = constants::RISTRETTO_BASEPOINT_POINT;
1335
1336        let s1 = Scalar::from(999u64);
1337        let P1 = BASE * s1;
1338
1339        let s2 = Scalar::from(333u64);
1340        let P2 = BASE * s2;
1341
1342        let vec = vec![P1, P2];
1343        let sum: RistrettoPoint = vec.iter().sum();
1344
1345        assert_eq!(sum, P1 + P2);
1346
1347        // Test that sum works for the empty iterator
1348        let empty_vector: Vec<RistrettoPoint> = vec![];
1349        let sum: RistrettoPoint = empty_vector.iter().sum();
1350
1351        assert_eq!(sum, RistrettoPoint::identity());
1352
1353        // Test that sum works on owning iterators
1354        let s = Scalar::from(2u64);
1355        let mapped = vec.iter().map(|x| x * s);
1356        let sum: RistrettoPoint = mapped.sum();
1357
1358        assert_eq!(sum, P1 * s + P2 * s);
1359    }
1360
1361    #[test]
1362    fn decompress_negative_s_fails() {
1363        // constants::d is neg, so decompression should fail as |d| != d.
1364        let bad_compressed = CompressedRistretto(constants::EDWARDS_D.to_bytes());
1365        assert!(bad_compressed.decompress().is_none());
1366    }
1367
1368    #[test]
1369    fn decompress_id() {
1370        let compressed_id = CompressedRistretto::identity();
1371        let id = compressed_id.decompress().unwrap();
1372        let mut identity_in_coset = false;
1373        for P in &id.coset4() {
1374            if P.compress() == CompressedEdwardsY::identity() {
1375                identity_in_coset = true;
1376            }
1377        }
1378        assert!(identity_in_coset);
1379    }
1380
1381    #[test]
1382    fn compress_id() {
1383        let id = RistrettoPoint::identity();
1384        assert_eq!(id.compress(), CompressedRistretto::identity());
1385    }
1386
1387    #[test]
1388    fn basepoint_roundtrip() {
1389        let bp_compressed_ristretto = constants::RISTRETTO_BASEPOINT_POINT.compress();
1390        let bp_recaf = bp_compressed_ristretto.decompress().unwrap().0;
1391        // Check that bp_recaf differs from bp by a point of order 4
1392        let diff = constants::RISTRETTO_BASEPOINT_POINT.0 - bp_recaf;
1393        let diff4 = diff.mul_by_pow_2(2);
1394        assert_eq!(diff4.compress(), CompressedEdwardsY::identity());
1395    }
1396
1397    #[test]
1398    fn encodings_of_small_multiples_of_basepoint() {
1399        // Table of encodings of i*basepoint
1400        // Generated using ristretto.sage
1401        let compressed = [
1402            CompressedRistretto([
1403                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,
1404                0, 0, 0, 0,
1405            ]),
1406            CompressedRistretto([
1407                226, 242, 174, 10, 106, 188, 78, 113, 168, 132, 169, 97, 197, 0, 81, 95, 88, 227,
1408                11, 106, 165, 130, 221, 141, 182, 166, 89, 69, 224, 141, 45, 118,
1409            ]),
1410            CompressedRistretto([
1411                106, 73, 50, 16, 247, 73, 156, 209, 127, 236, 181, 16, 174, 12, 234, 35, 161, 16,
1412                232, 213, 185, 1, 248, 172, 173, 211, 9, 92, 115, 163, 185, 25,
1413            ]),
1414            CompressedRistretto([
1415                148, 116, 31, 93, 93, 82, 117, 94, 206, 79, 35, 240, 68, 238, 39, 213, 209, 234,
1416                30, 43, 209, 150, 180, 98, 22, 107, 22, 21, 42, 157, 2, 89,
1417            ]),
1418            CompressedRistretto([
1419                218, 128, 134, 39, 115, 53, 139, 70, 111, 250, 223, 224, 179, 41, 58, 179, 217,
1420                253, 83, 197, 234, 108, 149, 83, 88, 245, 104, 50, 45, 175, 106, 87,
1421            ]),
1422            CompressedRistretto([
1423                232, 130, 177, 49, 1, 107, 82, 193, 211, 51, 112, 128, 24, 124, 247, 104, 66, 62,
1424                252, 203, 181, 23, 187, 73, 90, 184, 18, 196, 22, 15, 244, 78,
1425            ]),
1426            CompressedRistretto([
1427                246, 71, 70, 211, 201, 43, 19, 5, 14, 216, 216, 2, 54, 167, 240, 0, 124, 59, 63,
1428                150, 47, 91, 167, 147, 209, 154, 96, 30, 187, 29, 244, 3,
1429            ]),
1430            CompressedRistretto([
1431                68, 245, 53, 32, 146, 110, 200, 31, 189, 90, 56, 120, 69, 190, 183, 223, 133, 169,
1432                106, 36, 236, 225, 135, 56, 189, 207, 166, 167, 130, 42, 23, 109,
1433            ]),
1434            CompressedRistretto([
1435                144, 50, 147, 216, 242, 40, 126, 190, 16, 226, 55, 77, 193, 165, 62, 11, 200, 135,
1436                229, 146, 105, 159, 2, 208, 119, 213, 38, 60, 221, 85, 96, 28,
1437            ]),
1438            CompressedRistretto([
1439                2, 98, 42, 206, 143, 115, 3, 163, 28, 175, 198, 63, 143, 196, 143, 220, 22, 225,
1440                200, 200, 210, 52, 178, 240, 214, 104, 82, 130, 169, 7, 96, 49,
1441            ]),
1442            CompressedRistretto([
1443                32, 112, 111, 215, 136, 178, 114, 10, 30, 210, 165, 218, 212, 149, 43, 1, 244, 19,
1444                188, 240, 231, 86, 77, 232, 205, 200, 22, 104, 158, 45, 185, 95,
1445            ]),
1446            CompressedRistretto([
1447                188, 232, 63, 139, 165, 221, 47, 165, 114, 134, 76, 36, 186, 24, 16, 249, 82, 43,
1448                198, 0, 74, 254, 149, 135, 122, 199, 50, 65, 202, 253, 171, 66,
1449            ]),
1450            CompressedRistretto([
1451                228, 84, 158, 225, 107, 154, 160, 48, 153, 202, 32, 140, 103, 173, 175, 202, 250,
1452                76, 63, 62, 78, 83, 3, 222, 96, 38, 227, 202, 143, 248, 68, 96,
1453            ]),
1454            CompressedRistretto([
1455                170, 82, 224, 0, 223, 46, 22, 245, 95, 177, 3, 47, 195, 59, 196, 39, 66, 218, 214,
1456                189, 90, 143, 192, 190, 1, 103, 67, 108, 89, 72, 80, 31,
1457            ]),
1458            CompressedRistretto([
1459                70, 55, 107, 128, 244, 9, 178, 157, 194, 181, 246, 240, 197, 37, 145, 153, 8, 150,
1460                229, 113, 111, 65, 71, 124, 211, 0, 133, 171, 127, 16, 48, 30,
1461            ]),
1462            CompressedRistretto([
1463                224, 196, 24, 247, 200, 217, 196, 205, 215, 57, 91, 147, 234, 18, 79, 58, 217, 144,
1464                33, 187, 104, 29, 252, 51, 2, 169, 217, 154, 46, 83, 230, 78,
1465            ]),
1466        ];
1467        let mut bp = RistrettoPoint::identity();
1468        for point in compressed {
1469            assert_eq!(bp.compress(), point);
1470            bp += constants::RISTRETTO_BASEPOINT_POINT;
1471        }
1472    }
1473
1474    #[test]
1475    fn four_torsion_basepoint() {
1476        let bp = constants::RISTRETTO_BASEPOINT_POINT;
1477        let bp_coset = bp.coset4();
1478        for point in bp_coset {
1479            assert_eq!(bp, RistrettoPoint(point));
1480        }
1481    }
1482
1483    #[test]
1484    fn four_torsion_random() {
1485        let mut rng = OsRng;
1486        let P = RistrettoPoint::mul_base(&Scalar::random(&mut rng));
1487        let P_coset = P.coset4();
1488        for point in P_coset {
1489            assert_eq!(P, RistrettoPoint(point));
1490        }
1491    }
1492
1493    #[test]
1494    fn elligator_vs_ristretto_sage() {
1495        // Test vectors extracted from ristretto.sage.
1496        //
1497        // Notice that all of the byte sequences have bit 255 set to 0; this is because
1498        // ristretto.sage does not mask the high bit of a field element.  When the high bit is set,
1499        // the ristretto.sage elligator implementation gives different results, since it takes a
1500        // different field element as input.
1501        let bytes: [[u8; 32]; 16] = [
1502            [
1503                184, 249, 135, 49, 253, 123, 89, 113, 67, 160, 6, 239, 7, 105, 211, 41, 192, 249,
1504                185, 57, 9, 102, 70, 198, 15, 127, 7, 26, 160, 102, 134, 71,
1505            ],
1506            [
1507                229, 14, 241, 227, 75, 9, 118, 60, 128, 153, 226, 21, 183, 217, 91, 136, 98, 0,
1508                231, 156, 124, 77, 82, 139, 142, 134, 164, 169, 169, 62, 250, 52,
1509            ],
1510            [
1511                115, 109, 36, 220, 180, 223, 99, 6, 204, 169, 19, 29, 169, 68, 84, 23, 21, 109,
1512                189, 149, 127, 205, 91, 102, 172, 35, 112, 35, 134, 69, 186, 34,
1513            ],
1514            [
1515                16, 49, 96, 107, 171, 199, 164, 9, 129, 16, 64, 62, 241, 63, 132, 173, 209, 160,
1516                112, 215, 105, 50, 157, 81, 253, 105, 1, 154, 229, 25, 120, 83,
1517            ],
1518            [
1519                156, 131, 161, 162, 236, 251, 5, 187, 167, 171, 17, 178, 148, 210, 90, 207, 86, 21,
1520                79, 161, 167, 215, 234, 1, 136, 242, 182, 248, 38, 85, 79, 86,
1521            ],
1522            [
1523                251, 177, 124, 54, 18, 101, 75, 235, 245, 186, 19, 46, 133, 157, 229, 64, 10, 136,
1524                181, 185, 78, 144, 254, 167, 137, 49, 107, 10, 61, 10, 21, 25,
1525            ],
1526            [
1527                232, 193, 20, 68, 240, 77, 186, 77, 183, 40, 44, 86, 150, 31, 198, 212, 76, 81, 3,
1528                217, 197, 8, 126, 128, 126, 152, 164, 208, 153, 44, 189, 77,
1529            ],
1530            [
1531                173, 229, 149, 177, 37, 230, 30, 69, 61, 56, 172, 190, 219, 115, 167, 194, 71, 134,
1532                59, 75, 28, 244, 118, 26, 162, 97, 64, 16, 15, 189, 30, 64,
1533            ],
1534            [
1535                106, 71, 61, 107, 250, 117, 42, 151, 91, 202, 212, 100, 52, 188, 190, 21, 125, 218,
1536                31, 18, 253, 241, 160, 133, 57, 242, 3, 164, 189, 68, 111, 75,
1537            ],
1538            [
1539                112, 204, 182, 90, 220, 198, 120, 73, 173, 107, 193, 17, 227, 40, 162, 36, 150,
1540                141, 235, 55, 172, 183, 12, 39, 194, 136, 43, 153, 244, 118, 91, 89,
1541            ],
1542            [
1543                111, 24, 203, 123, 254, 189, 11, 162, 51, 196, 163, 136, 204, 143, 10, 222, 33,
1544                112, 81, 205, 34, 35, 8, 66, 90, 6, 164, 58, 170, 177, 34, 25,
1545            ],
1546            [
1547                225, 183, 30, 52, 236, 82, 6, 183, 109, 25, 227, 181, 25, 82, 41, 193, 80, 77, 161,
1548                80, 242, 203, 79, 204, 136, 245, 131, 110, 237, 106, 3, 58,
1549            ],
1550            [
1551                207, 246, 38, 56, 30, 86, 176, 90, 27, 200, 61, 42, 221, 27, 56, 210, 79, 178, 189,
1552                120, 68, 193, 120, 167, 77, 185, 53, 197, 124, 128, 191, 126,
1553            ],
1554            [
1555                1, 136, 215, 80, 240, 46, 63, 147, 16, 244, 230, 207, 82, 189, 74, 50, 106, 169,
1556                138, 86, 30, 131, 214, 202, 166, 125, 251, 228, 98, 24, 36, 21,
1557            ],
1558            [
1559                210, 207, 228, 56, 155, 116, 207, 54, 84, 195, 251, 215, 249, 199, 116, 75, 109,
1560                239, 196, 251, 194, 246, 252, 228, 70, 146, 156, 35, 25, 39, 241, 4,
1561            ],
1562            [
1563                34, 116, 123, 9, 8, 40, 93, 189, 9, 103, 57, 103, 66, 227, 3, 2, 157, 107, 134,
1564                219, 202, 74, 230, 154, 78, 107, 219, 195, 214, 14, 84, 80,
1565            ],
1566        ];
1567        let encoded_images: [CompressedRistretto; 16] = [
1568            CompressedRistretto([
1569                176, 157, 237, 97, 66, 29, 140, 166, 168, 94, 26, 157, 212, 216, 229, 160, 195,
1570                246, 232, 239, 169, 112, 63, 193, 64, 32, 152, 69, 11, 190, 246, 86,
1571            ]),
1572            CompressedRistretto([
1573                234, 141, 77, 203, 181, 225, 250, 74, 171, 62, 15, 118, 78, 212, 150, 19, 131, 14,
1574                188, 238, 194, 244, 141, 138, 166, 162, 83, 122, 228, 201, 19, 26,
1575            ]),
1576            CompressedRistretto([
1577                232, 231, 51, 92, 5, 168, 80, 36, 173, 179, 104, 68, 186, 149, 68, 40, 140, 170,
1578                27, 103, 99, 140, 21, 242, 43, 62, 250, 134, 208, 255, 61, 89,
1579            ]),
1580            CompressedRistretto([
1581                208, 120, 140, 129, 177, 179, 237, 159, 252, 160, 28, 13, 206, 5, 211, 241, 192,
1582                218, 1, 97, 130, 241, 20, 169, 119, 46, 246, 29, 79, 80, 77, 84,
1583            ]),
1584            CompressedRistretto([
1585                202, 11, 236, 145, 58, 12, 181, 157, 209, 6, 213, 88, 75, 147, 11, 119, 191, 139,
1586                47, 142, 33, 36, 153, 193, 223, 183, 178, 8, 205, 120, 248, 110,
1587            ]),
1588            CompressedRistretto([
1589                26, 66, 231, 67, 203, 175, 116, 130, 32, 136, 62, 253, 215, 46, 5, 214, 166, 248,
1590                108, 237, 216, 71, 244, 173, 72, 133, 82, 6, 143, 240, 104, 41,
1591            ]),
1592            CompressedRistretto([
1593                40, 157, 102, 96, 201, 223, 200, 197, 150, 181, 106, 83, 103, 126, 143, 33, 145,
1594                230, 78, 6, 171, 146, 210, 143, 112, 5, 245, 23, 183, 138, 18, 120,
1595            ]),
1596            CompressedRistretto([
1597                220, 37, 27, 203, 239, 196, 176, 131, 37, 66, 188, 243, 185, 250, 113, 23, 167,
1598                211, 154, 243, 168, 215, 54, 171, 159, 36, 195, 81, 13, 150, 43, 43,
1599            ]),
1600            CompressedRistretto([
1601                232, 121, 176, 222, 183, 196, 159, 90, 238, 193, 105, 52, 101, 167, 244, 170, 121,
1602                114, 196, 6, 67, 152, 80, 185, 221, 7, 83, 105, 176, 208, 224, 121,
1603            ]),
1604            CompressedRistretto([
1605                226, 181, 183, 52, 241, 163, 61, 179, 221, 207, 220, 73, 245, 242, 25, 236, 67, 84,
1606                179, 222, 167, 62, 167, 182, 32, 9, 92, 30, 165, 127, 204, 68,
1607            ]),
1608            CompressedRistretto([
1609                226, 119, 16, 242, 200, 139, 240, 87, 11, 222, 92, 146, 156, 243, 46, 119, 65, 59,
1610                1, 248, 92, 183, 50, 175, 87, 40, 206, 53, 208, 220, 148, 13,
1611            ]),
1612            CompressedRistretto([
1613                70, 240, 79, 112, 54, 157, 228, 146, 74, 122, 216, 88, 232, 62, 158, 13, 14, 146,
1614                115, 117, 176, 222, 90, 225, 244, 23, 94, 190, 150, 7, 136, 96,
1615            ]),
1616            CompressedRistretto([
1617                22, 71, 241, 103, 45, 193, 195, 144, 183, 101, 154, 50, 39, 68, 49, 110, 51, 44,
1618                62, 0, 229, 113, 72, 81, 168, 29, 73, 106, 102, 40, 132, 24,
1619            ]),
1620            CompressedRistretto([
1621                196, 133, 107, 11, 130, 105, 74, 33, 204, 171, 133, 221, 174, 193, 241, 36, 38,
1622                179, 196, 107, 219, 185, 181, 253, 228, 47, 155, 42, 231, 73, 41, 78,
1623            ]),
1624            CompressedRistretto([
1625                58, 255, 225, 197, 115, 208, 160, 143, 39, 197, 82, 69, 143, 235, 92, 170, 74, 40,
1626                57, 11, 171, 227, 26, 185, 217, 207, 90, 185, 197, 190, 35, 60,
1627            ]),
1628            CompressedRistretto([
1629                88, 43, 92, 118, 223, 136, 105, 145, 238, 186, 115, 8, 214, 112, 153, 253, 38, 108,
1630                205, 230, 157, 130, 11, 66, 101, 85, 253, 110, 110, 14, 148, 112,
1631            ]),
1632        ];
1633        for i in 0..16 {
1634            let r_0 = FieldElement::from_bytes(&bytes[i]);
1635            let Q = RistrettoPoint::elligator_ristretto_flavor(&r_0);
1636            assert_eq!(Q.compress(), encoded_images[i]);
1637        }
1638    }
1639
1640    // Known answer tests for the one-way mapping function in the Ristretto RFC
1641    #[test]
1642    fn one_way_map() {
1643        // These inputs are from
1644        // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-ristretto255-decaf448-04#appendix-A.3
1645        let test_vectors: &[([u8; 64], CompressedRistretto)] = &[
1646            (
1647                [
1648                    0x5d, 0x1b, 0xe0, 0x9e, 0x3d, 0x0c, 0x82, 0xfc, 0x53, 0x81, 0x12, 0x49, 0x0e,
1649                    0x35, 0x70, 0x19, 0x79, 0xd9, 0x9e, 0x06, 0xca, 0x3e, 0x2b, 0x5b, 0x54, 0xbf,
1650                    0xfe, 0x8b, 0x4d, 0xc7, 0x72, 0xc1, 0x4d, 0x98, 0xb6, 0x96, 0xa1, 0xbb, 0xfb,
1651                    0x5c, 0xa3, 0x2c, 0x43, 0x6c, 0xc6, 0x1c, 0x16, 0x56, 0x37, 0x90, 0x30, 0x6c,
1652                    0x79, 0xea, 0xca, 0x77, 0x05, 0x66, 0x8b, 0x47, 0xdf, 0xfe, 0x5b, 0xb6,
1653                ],
1654                CompressedRistretto([
1655                    0x30, 0x66, 0xf8, 0x2a, 0x1a, 0x74, 0x7d, 0x45, 0x12, 0x0d, 0x17, 0x40, 0xf1,
1656                    0x43, 0x58, 0x53, 0x1a, 0x8f, 0x04, 0xbb, 0xff, 0xe6, 0xa8, 0x19, 0xf8, 0x6d,
1657                    0xfe, 0x50, 0xf4, 0x4a, 0x0a, 0x46,
1658                ]),
1659            ),
1660            (
1661                [
1662                    0xf1, 0x16, 0xb3, 0x4b, 0x8f, 0x17, 0xce, 0xb5, 0x6e, 0x87, 0x32, 0xa6, 0x0d,
1663                    0x91, 0x3d, 0xd1, 0x0c, 0xce, 0x47, 0xa6, 0xd5, 0x3b, 0xee, 0x92, 0x04, 0xbe,
1664                    0x8b, 0x44, 0xf6, 0x67, 0x8b, 0x27, 0x01, 0x02, 0xa5, 0x69, 0x02, 0xe2, 0x48,
1665                    0x8c, 0x46, 0x12, 0x0e, 0x92, 0x76, 0xcf, 0xe5, 0x46, 0x38, 0x28, 0x6b, 0x9e,
1666                    0x4b, 0x3c, 0xdb, 0x47, 0x0b, 0x54, 0x2d, 0x46, 0xc2, 0x06, 0x8d, 0x38,
1667                ],
1668                CompressedRistretto([
1669                    0xf2, 0x6e, 0x5b, 0x6f, 0x7d, 0x36, 0x2d, 0x2d, 0x2a, 0x94, 0xc5, 0xd0, 0xe7,
1670                    0x60, 0x2c, 0xb4, 0x77, 0x3c, 0x95, 0xa2, 0xe5, 0xc3, 0x1a, 0x64, 0xf1, 0x33,
1671                    0x18, 0x9f, 0xa7, 0x6e, 0xd6, 0x1b,
1672                ]),
1673            ),
1674            (
1675                [
1676                    0x84, 0x22, 0xe1, 0xbb, 0xda, 0xab, 0x52, 0x93, 0x8b, 0x81, 0xfd, 0x60, 0x2e,
1677                    0xff, 0xb6, 0xf8, 0x91, 0x10, 0xe1, 0xe5, 0x72, 0x08, 0xad, 0x12, 0xd9, 0xad,
1678                    0x76, 0x7e, 0x2e, 0x25, 0x51, 0x0c, 0x27, 0x14, 0x07, 0x75, 0xf9, 0x33, 0x70,
1679                    0x88, 0xb9, 0x82, 0xd8, 0x3d, 0x7f, 0xcf, 0x0b, 0x2f, 0xa1, 0xed, 0xff, 0xe5,
1680                    0x19, 0x52, 0xcb, 0xe7, 0x36, 0x5e, 0x95, 0xc8, 0x6e, 0xaf, 0x32, 0x5c,
1681                ],
1682                CompressedRistretto([
1683                    0x00, 0x6c, 0xcd, 0x2a, 0x9e, 0x68, 0x67, 0xe6, 0xa2, 0xc5, 0xce, 0xa8, 0x3d,
1684                    0x33, 0x02, 0xcc, 0x9d, 0xe1, 0x28, 0xdd, 0x2a, 0x9a, 0x57, 0xdd, 0x8e, 0xe7,
1685                    0xb9, 0xd7, 0xff, 0xe0, 0x28, 0x26,
1686                ]),
1687            ),
1688            (
1689                [
1690                    0xac, 0x22, 0x41, 0x51, 0x29, 0xb6, 0x14, 0x27, 0xbf, 0x46, 0x4e, 0x17, 0xba,
1691                    0xee, 0x8d, 0xb6, 0x59, 0x40, 0xc2, 0x33, 0xb9, 0x8a, 0xfc, 0xe8, 0xd1, 0x7c,
1692                    0x57, 0xbe, 0xeb, 0x78, 0x76, 0xc2, 0x15, 0x0d, 0x15, 0xaf, 0x1c, 0xb1, 0xfb,
1693                    0x82, 0x4b, 0xbd, 0x14, 0x95, 0x5f, 0x2b, 0x57, 0xd0, 0x8d, 0x38, 0x8a, 0xab,
1694                    0x43, 0x1a, 0x39, 0x1c, 0xfc, 0x33, 0xd5, 0xba, 0xfb, 0x5d, 0xbb, 0xaf,
1695                ],
1696                CompressedRistretto([
1697                    0xf8, 0xf0, 0xc8, 0x7c, 0xf2, 0x37, 0x95, 0x3c, 0x58, 0x90, 0xae, 0xc3, 0x99,
1698                    0x81, 0x69, 0x00, 0x5d, 0xae, 0x3e, 0xca, 0x1f, 0xbb, 0x04, 0x54, 0x8c, 0x63,
1699                    0x59, 0x53, 0xc8, 0x17, 0xf9, 0x2a,
1700                ]),
1701            ),
1702            (
1703                [
1704                    0x16, 0x5d, 0x69, 0x7a, 0x1e, 0xf3, 0xd5, 0xcf, 0x3c, 0x38, 0x56, 0x5b, 0xee,
1705                    0xfc, 0xf8, 0x8c, 0x0f, 0x28, 0x2b, 0x8e, 0x7d, 0xbd, 0x28, 0x54, 0x4c, 0x48,
1706                    0x34, 0x32, 0xf1, 0xce, 0xc7, 0x67, 0x5d, 0xeb, 0xea, 0x8e, 0xbb, 0x4e, 0x5f,
1707                    0xe7, 0xd6, 0xf6, 0xe5, 0xdb, 0x15, 0xf1, 0x55, 0x87, 0xac, 0x4d, 0x4d, 0x4a,
1708                    0x1d, 0xe7, 0x19, 0x1e, 0x0c, 0x1c, 0xa6, 0x66, 0x4a, 0xbc, 0xc4, 0x13,
1709                ],
1710                CompressedRistretto([
1711                    0xae, 0x81, 0xe7, 0xde, 0xdf, 0x20, 0xa4, 0x97, 0xe1, 0x0c, 0x30, 0x4a, 0x76,
1712                    0x5c, 0x17, 0x67, 0xa4, 0x2d, 0x6e, 0x06, 0x02, 0x97, 0x58, 0xd2, 0xd7, 0xe8,
1713                    0xef, 0x7c, 0xc4, 0xc4, 0x11, 0x79,
1714                ]),
1715            ),
1716            (
1717                [
1718                    0xa8, 0x36, 0xe6, 0xc9, 0xa9, 0xca, 0x9f, 0x1e, 0x8d, 0x48, 0x62, 0x73, 0xad,
1719                    0x56, 0xa7, 0x8c, 0x70, 0xcf, 0x18, 0xf0, 0xce, 0x10, 0xab, 0xb1, 0xc7, 0x17,
1720                    0x2d, 0xdd, 0x60, 0x5d, 0x7f, 0xd2, 0x97, 0x98, 0x54, 0xf4, 0x7a, 0xe1, 0xcc,
1721                    0xf2, 0x04, 0xa3, 0x31, 0x02, 0x09, 0x5b, 0x42, 0x00, 0xe5, 0xbe, 0xfc, 0x04,
1722                    0x65, 0xac, 0xcc, 0x26, 0x31, 0x75, 0x48, 0x5f, 0x0e, 0x17, 0xea, 0x5c,
1723                ],
1724                CompressedRistretto([
1725                    0xe2, 0x70, 0x56, 0x52, 0xff, 0x9f, 0x5e, 0x44, 0xd3, 0xe8, 0x41, 0xbf, 0x1c,
1726                    0x25, 0x1c, 0xf7, 0xdd, 0xdb, 0x77, 0xd1, 0x40, 0x87, 0x0d, 0x1a, 0xb2, 0xed,
1727                    0x64, 0xf1, 0xa9, 0xce, 0x86, 0x28,
1728                ]),
1729            ),
1730            (
1731                [
1732                    0x2c, 0xdc, 0x11, 0xea, 0xeb, 0x95, 0xda, 0xf0, 0x11, 0x89, 0x41, 0x7c, 0xdd,
1733                    0xdb, 0xf9, 0x59, 0x52, 0x99, 0x3a, 0xa9, 0xcb, 0x9c, 0x64, 0x0e, 0xb5, 0x05,
1734                    0x8d, 0x09, 0x70, 0x2c, 0x74, 0x62, 0x2c, 0x99, 0x65, 0xa6, 0x97, 0xa3, 0xb3,
1735                    0x45, 0xec, 0x24, 0xee, 0x56, 0x33, 0x5b, 0x55, 0x6e, 0x67, 0x7b, 0x30, 0xe6,
1736                    0xf9, 0x0a, 0xc7, 0x7d, 0x78, 0x10, 0x64, 0xf8, 0x66, 0xa3, 0xc9, 0x82,
1737                ],
1738                CompressedRistretto([
1739                    0x80, 0xbd, 0x07, 0x26, 0x25, 0x11, 0xcd, 0xde, 0x48, 0x63, 0xf8, 0xa7, 0x43,
1740                    0x4c, 0xef, 0x69, 0x67, 0x50, 0x68, 0x1c, 0xb9, 0x51, 0x0e, 0xea, 0x55, 0x70,
1741                    0x88, 0xf7, 0x6d, 0x9e, 0x50, 0x65,
1742                ]),
1743            ),
1744            (
1745                [
1746                    0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1747                    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1748                    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1749                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1750                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1751                ],
1752                CompressedRistretto([
1753                    0x30, 0x42, 0x82, 0x79, 0x10, 0x23, 0xb7, 0x31, 0x28, 0xd2, 0x77, 0xbd, 0xcb,
1754                    0x5c, 0x77, 0x46, 0xef, 0x2e, 0xac, 0x08, 0xdd, 0xe9, 0xf2, 0x98, 0x33, 0x79,
1755                    0xcb, 0x8e, 0x5e, 0xf0, 0x51, 0x7f,
1756                ]),
1757            ),
1758            (
1759                [
1760                    0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1761                    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1762                    0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1763                    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1764                    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1765                ],
1766                CompressedRistretto([
1767                    0x30, 0x42, 0x82, 0x79, 0x10, 0x23, 0xb7, 0x31, 0x28, 0xd2, 0x77, 0xbd, 0xcb,
1768                    0x5c, 0x77, 0x46, 0xef, 0x2e, 0xac, 0x08, 0xdd, 0xe9, 0xf2, 0x98, 0x33, 0x79,
1769                    0xcb, 0x8e, 0x5e, 0xf0, 0x51, 0x7f,
1770                ]),
1771            ),
1772            (
1773                [
1774                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1775                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1776                    0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1777                    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1778                    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
1779                ],
1780                CompressedRistretto([
1781                    0x30, 0x42, 0x82, 0x79, 0x10, 0x23, 0xb7, 0x31, 0x28, 0xd2, 0x77, 0xbd, 0xcb,
1782                    0x5c, 0x77, 0x46, 0xef, 0x2e, 0xac, 0x08, 0xdd, 0xe9, 0xf2, 0x98, 0x33, 0x79,
1783                    0xcb, 0x8e, 0x5e, 0xf0, 0x51, 0x7f,
1784                ]),
1785            ),
1786            (
1787                [
1788                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1789                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1790                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1791                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1792                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
1793                ],
1794                CompressedRistretto([
1795                    0x30, 0x42, 0x82, 0x79, 0x10, 0x23, 0xb7, 0x31, 0x28, 0xd2, 0x77, 0xbd, 0xcb,
1796                    0x5c, 0x77, 0x46, 0xef, 0x2e, 0xac, 0x08, 0xdd, 0xe9, 0xf2, 0x98, 0x33, 0x79,
1797                    0xcb, 0x8e, 0x5e, 0xf0, 0x51, 0x7f,
1798                ]),
1799            ),
1800        ];
1801        // Check that onewaymap(input) == output for all the above vectors
1802        for (input, output) in test_vectors {
1803            let Q = RistrettoPoint::from_uniform_bytes(input);
1804            assert_eq!(&Q.compress(), output);
1805        }
1806    }
1807
1808    #[test]
1809    fn random_roundtrip() {
1810        let mut rng = OsRng;
1811        for _ in 0..100 {
1812            let P = RistrettoPoint::mul_base(&Scalar::random(&mut rng));
1813            let compressed_P = P.compress();
1814            let Q = compressed_P.decompress().unwrap();
1815            assert_eq!(P, Q);
1816        }
1817    }
1818
1819    #[test]
1820    #[cfg(all(feature = "alloc", feature = "rand_core"))]
1821    fn double_and_compress_1024_random_points() {
1822        let mut rng = OsRng;
1823
1824        let mut points: Vec<RistrettoPoint> = (0..1024)
1825            .map(|_| RistrettoPoint::random(&mut rng))
1826            .collect();
1827        points[500] = RistrettoPoint::identity();
1828
1829        let compressed = RistrettoPoint::double_and_compress_batch(&points);
1830
1831        for (P, P2_compressed) in points.iter().zip(compressed.iter()) {
1832            assert_eq!(*P2_compressed, (P + P).compress());
1833        }
1834    }
1835
1836    #[test]
1837    #[cfg(feature = "alloc")]
1838    fn vartime_precomputed_vs_nonprecomputed_multiscalar() {
1839        let mut rng = rand::thread_rng();
1840
1841        let static_scalars = (0..128)
1842            .map(|_| Scalar::random(&mut rng))
1843            .collect::<Vec<_>>();
1844
1845        let dynamic_scalars = (0..128)
1846            .map(|_| Scalar::random(&mut rng))
1847            .collect::<Vec<_>>();
1848
1849        let check_scalar: Scalar = static_scalars
1850            .iter()
1851            .chain(dynamic_scalars.iter())
1852            .map(|s| s * s)
1853            .sum();
1854
1855        let static_points = static_scalars
1856            .iter()
1857            .map(RistrettoPoint::mul_base)
1858            .collect::<Vec<_>>();
1859        let dynamic_points = dynamic_scalars
1860            .iter()
1861            .map(RistrettoPoint::mul_base)
1862            .collect::<Vec<_>>();
1863
1864        let precomputation = VartimeRistrettoPrecomputation::new(static_points.iter());
1865
1866        assert_eq!(precomputation.len(), 128);
1867        assert!(!precomputation.is_empty());
1868
1869        let P = precomputation.vartime_mixed_multiscalar_mul(
1870            &static_scalars,
1871            &dynamic_scalars,
1872            &dynamic_points,
1873        );
1874
1875        use crate::traits::VartimeMultiscalarMul;
1876        let Q = RistrettoPoint::vartime_multiscalar_mul(
1877            static_scalars.iter().chain(dynamic_scalars.iter()),
1878            static_points.iter().chain(dynamic_points.iter()),
1879        );
1880
1881        let R = RistrettoPoint::mul_base(&check_scalar);
1882
1883        assert_eq!(P.compress(), R.compress());
1884        assert_eq!(Q.compress(), R.compress());
1885    }
1886
1887    #[test]
1888    #[cfg(feature = "alloc")]
1889    fn partial_precomputed_mixed_multiscalar_empty() {
1890        let mut rng = rand::thread_rng();
1891
1892        let n_static = 16;
1893        let n_dynamic = 8;
1894
1895        let static_points = (0..n_static)
1896            .map(|_| RistrettoPoint::random(&mut rng))
1897            .collect::<Vec<_>>();
1898
1899        // Use zero scalars
1900        let static_scalars = Vec::new();
1901
1902        let dynamic_points = (0..n_dynamic)
1903            .map(|_| RistrettoPoint::random(&mut rng))
1904            .collect::<Vec<_>>();
1905
1906        let dynamic_scalars = (0..n_dynamic)
1907            .map(|_| Scalar::random(&mut rng))
1908            .collect::<Vec<_>>();
1909
1910        // Compute the linear combination using precomputed multiscalar multiplication
1911        let precomputation = VartimeRistrettoPrecomputation::new(static_points.iter());
1912        let result_multiscalar = precomputation.vartime_mixed_multiscalar_mul(
1913            &static_scalars,
1914            &dynamic_scalars,
1915            &dynamic_points,
1916        );
1917
1918        // Compute the linear combination manually
1919        let mut result_manual = RistrettoPoint::identity();
1920        for i in 0..static_scalars.len() {
1921            result_manual += static_points[i] * static_scalars[i];
1922        }
1923        for i in 0..n_dynamic {
1924            result_manual += dynamic_points[i] * dynamic_scalars[i];
1925        }
1926
1927        assert_eq!(result_multiscalar, result_manual);
1928    }
1929
1930    #[test]
1931    #[cfg(feature = "alloc")]
1932    fn partial_precomputed_mixed_multiscalar() {
1933        let mut rng = rand::thread_rng();
1934
1935        let n_static = 16;
1936        let n_dynamic = 8;
1937
1938        let static_points = (0..n_static)
1939            .map(|_| RistrettoPoint::random(&mut rng))
1940            .collect::<Vec<_>>();
1941
1942        // Use one fewer scalars
1943        let static_scalars = (0..n_static - 1)
1944            .map(|_| Scalar::random(&mut rng))
1945            .collect::<Vec<_>>();
1946
1947        let dynamic_points = (0..n_dynamic)
1948            .map(|_| RistrettoPoint::random(&mut rng))
1949            .collect::<Vec<_>>();
1950
1951        let dynamic_scalars = (0..n_dynamic)
1952            .map(|_| Scalar::random(&mut rng))
1953            .collect::<Vec<_>>();
1954
1955        // Compute the linear combination using precomputed multiscalar multiplication
1956        let precomputation = VartimeRistrettoPrecomputation::new(static_points.iter());
1957        let result_multiscalar = precomputation.vartime_mixed_multiscalar_mul(
1958            &static_scalars,
1959            &dynamic_scalars,
1960            &dynamic_points,
1961        );
1962
1963        // Compute the linear combination manually
1964        let mut result_manual = RistrettoPoint::identity();
1965        for i in 0..static_scalars.len() {
1966            result_manual += static_points[i] * static_scalars[i];
1967        }
1968        for i in 0..n_dynamic {
1969            result_manual += dynamic_points[i] * dynamic_scalars[i];
1970        }
1971
1972        assert_eq!(result_multiscalar, result_manual);
1973    }
1974
1975    #[test]
1976    #[cfg(feature = "alloc")]
1977    fn partial_precomputed_multiscalar() {
1978        let mut rng = rand::thread_rng();
1979
1980        let n_static = 16;
1981
1982        let static_points = (0..n_static)
1983            .map(|_| RistrettoPoint::random(&mut rng))
1984            .collect::<Vec<_>>();
1985
1986        // Use one fewer scalars
1987        let static_scalars = (0..n_static - 1)
1988            .map(|_| Scalar::random(&mut rng))
1989            .collect::<Vec<_>>();
1990
1991        // Compute the linear combination using precomputed multiscalar multiplication
1992        let precomputation = VartimeRistrettoPrecomputation::new(static_points.iter());
1993        let result_multiscalar = precomputation.vartime_multiscalar_mul(&static_scalars);
1994
1995        // Compute the linear combination manually
1996        let mut result_manual = RistrettoPoint::identity();
1997        for i in 0..static_scalars.len() {
1998            result_manual += static_points[i] * static_scalars[i];
1999        }
2000
2001        assert_eq!(result_multiscalar, result_manual);
2002    }
2003
2004    #[test]
2005    #[cfg(feature = "alloc")]
2006    fn partial_precomputed_multiscalar_empty() {
2007        let mut rng = rand::thread_rng();
2008
2009        let n_static = 16;
2010
2011        let static_points = (0..n_static)
2012            .map(|_| RistrettoPoint::random(&mut rng))
2013            .collect::<Vec<_>>();
2014
2015        // Use zero scalars
2016        let static_scalars = Vec::new();
2017
2018        // Compute the linear combination using precomputed multiscalar multiplication
2019        let precomputation = VartimeRistrettoPrecomputation::new(static_points.iter());
2020        let result_multiscalar = precomputation.vartime_multiscalar_mul(&static_scalars);
2021
2022        // Compute the linear combination manually
2023        let mut result_manual = RistrettoPoint::identity();
2024        for i in 0..static_scalars.len() {
2025            result_manual += static_points[i] * static_scalars[i];
2026        }
2027
2028        assert_eq!(result_multiscalar, result_manual);
2029    }
2030}