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 the Rust `Eq` trait for variable-time equality
81//! checking.
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.as_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.as_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.as_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, 'b> Add<&'b RistrettoPoint> for &'a RistrettoPoint {
852    type Output = RistrettoPoint;
853
854    fn add(self, other: &'b 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<'b> AddAssign<&'b 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, 'b> Sub<&'b RistrettoPoint> for &'a RistrettoPoint {
874    type Output = RistrettoPoint;
875
876    fn sub(self, other: &'b 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<'b> SubAssign<&'b 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<'a> Neg for &'a 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<'b> MulAssign<&'b Scalar> for RistrettoPoint {
924    fn mul_assign(&mut self, scalar: &'b Scalar) {
925        let result = (self as &RistrettoPoint) * scalar;
926        *self = result;
927    }
928}
929
930impl<'a, 'b> Mul<&'b Scalar> for &'a RistrettoPoint {
931    type Output = RistrettoPoint;
932    /// Scalar multiplication: compute `scalar * self`.
933    fn mul(self, scalar: &'b Scalar) -> RistrettoPoint {
934        RistrettoPoint(self.0 * scalar)
935    }
936}
937
938impl<'a, 'b> Mul<&'b RistrettoPoint> for &'a Scalar {
939    type Output = RistrettoPoint;
940
941    /// Scalar multiplication: compute `self * scalar`.
942    fn mul(self, point: &'b 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// This wraps the inner implementation in a facade type so that we can
1011// decouple stability of the inner type from the stability of the
1012// outer type.
1013#[cfg(feature = "alloc")]
1014pub struct VartimeRistrettoPrecomputation(crate::backend::VartimePrecomputedStraus);
1015
1016#[cfg(feature = "alloc")]
1017impl VartimePrecomputedMultiscalarMul for VartimeRistrettoPrecomputation {
1018    type Point = RistrettoPoint;
1019
1020    fn new<I>(static_points: I) -> Self
1021    where
1022        I: IntoIterator,
1023        I::Item: Borrow<Self::Point>,
1024    {
1025        Self(crate::backend::VartimePrecomputedStraus::new(
1026            static_points.into_iter().map(|P| P.borrow().0),
1027        ))
1028    }
1029
1030    fn optional_mixed_multiscalar_mul<I, J, K>(
1031        &self,
1032        static_scalars: I,
1033        dynamic_scalars: J,
1034        dynamic_points: K,
1035    ) -> Option<Self::Point>
1036    where
1037        I: IntoIterator,
1038        I::Item: Borrow<Scalar>,
1039        J: IntoIterator,
1040        J::Item: Borrow<Scalar>,
1041        K: IntoIterator<Item = Option<Self::Point>>,
1042    {
1043        self.0
1044            .optional_mixed_multiscalar_mul(
1045                static_scalars,
1046                dynamic_scalars,
1047                dynamic_points.into_iter().map(|P_opt| P_opt.map(|P| P.0)),
1048            )
1049            .map(RistrettoPoint)
1050    }
1051}
1052
1053impl RistrettoPoint {
1054    /// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the
1055    /// Ristretto basepoint.
1056    pub fn vartime_double_scalar_mul_basepoint(
1057        a: &Scalar,
1058        A: &RistrettoPoint,
1059        b: &Scalar,
1060    ) -> RistrettoPoint {
1061        RistrettoPoint(EdwardsPoint::vartime_double_scalar_mul_basepoint(
1062            a, &A.0, b,
1063        ))
1064    }
1065}
1066
1067/// A precomputed table of multiples of a basepoint, used to accelerate
1068/// scalar multiplication.
1069///
1070/// A precomputed table of multiples of the Ristretto basepoint is
1071/// available in the `constants` module:
1072/// ```
1073/// use curve25519_dalek::constants::RISTRETTO_BASEPOINT_TABLE;
1074/// use curve25519_dalek::scalar::Scalar;
1075///
1076/// let a = Scalar::from(87329482u64);
1077/// let P = &a * RISTRETTO_BASEPOINT_TABLE;
1078/// ```
1079#[cfg(feature = "precomputed-tables")]
1080#[derive(Clone)]
1081#[repr(transparent)]
1082pub struct RistrettoBasepointTable(pub(crate) EdwardsBasepointTable);
1083
1084#[cfg(feature = "precomputed-tables")]
1085impl<'a, 'b> Mul<&'b Scalar> for &'a RistrettoBasepointTable {
1086    type Output = RistrettoPoint;
1087
1088    fn mul(self, scalar: &'b Scalar) -> RistrettoPoint {
1089        RistrettoPoint(&self.0 * scalar)
1090    }
1091}
1092
1093#[cfg(feature = "precomputed-tables")]
1094impl<'a, 'b> Mul<&'a RistrettoBasepointTable> for &'b Scalar {
1095    type Output = RistrettoPoint;
1096
1097    fn mul(self, basepoint_table: &'a RistrettoBasepointTable) -> RistrettoPoint {
1098        RistrettoPoint(self * &basepoint_table.0)
1099    }
1100}
1101
1102#[cfg(feature = "precomputed-tables")]
1103impl RistrettoBasepointTable {
1104    /// Create a precomputed table of multiples of the given `basepoint`.
1105    pub fn create(basepoint: &RistrettoPoint) -> RistrettoBasepointTable {
1106        RistrettoBasepointTable(EdwardsBasepointTable::create(&basepoint.0))
1107    }
1108
1109    /// Get the basepoint for this table as a `RistrettoPoint`.
1110    pub fn basepoint(&self) -> RistrettoPoint {
1111        RistrettoPoint(self.0.basepoint())
1112    }
1113}
1114
1115// ------------------------------------------------------------------------
1116// Constant-time conditional selection
1117// ------------------------------------------------------------------------
1118
1119impl ConditionallySelectable for RistrettoPoint {
1120    /// Conditionally select between `self` and `other`.
1121    ///
1122    /// # Example
1123    ///
1124    /// ```
1125    /// use subtle::ConditionallySelectable;
1126    /// use subtle::Choice;
1127    /// #
1128    /// # use curve25519_dalek::traits::Identity;
1129    /// # use curve25519_dalek::ristretto::RistrettoPoint;
1130    /// # use curve25519_dalek::constants;
1131    /// # fn main() {
1132    ///
1133    /// let A = RistrettoPoint::identity();
1134    /// let B = constants::RISTRETTO_BASEPOINT_POINT;
1135    ///
1136    /// let mut P = A;
1137    ///
1138    /// P = RistrettoPoint::conditional_select(&A, &B, Choice::from(0));
1139    /// assert_eq!(P, A);
1140    /// P = RistrettoPoint::conditional_select(&A, &B, Choice::from(1));
1141    /// assert_eq!(P, B);
1142    /// # }
1143    /// ```
1144    fn conditional_select(
1145        a: &RistrettoPoint,
1146        b: &RistrettoPoint,
1147        choice: Choice,
1148    ) -> RistrettoPoint {
1149        RistrettoPoint(EdwardsPoint::conditional_select(&a.0, &b.0, choice))
1150    }
1151}
1152
1153// ------------------------------------------------------------------------
1154// Debug traits
1155// ------------------------------------------------------------------------
1156
1157impl Debug for CompressedRistretto {
1158    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1159        write!(f, "CompressedRistretto: {:?}", self.as_bytes())
1160    }
1161}
1162
1163impl Debug for RistrettoPoint {
1164    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1165        let coset = self.coset4();
1166        write!(
1167            f,
1168            "RistrettoPoint: coset \n{:?}\n{:?}\n{:?}\n{:?}",
1169            coset[0], coset[1], coset[2], coset[3]
1170        )
1171    }
1172}
1173
1174// ------------------------------------------------------------------------
1175// group traits
1176// ------------------------------------------------------------------------
1177
1178// Use the full trait path to avoid Group::identity overlapping Identity::identity in the
1179// rest of the module (e.g. tests).
1180#[cfg(feature = "group")]
1181impl group::Group for RistrettoPoint {
1182    type Scalar = Scalar;
1183
1184    fn random(mut rng: impl RngCore) -> Self {
1185        // NOTE: this is duplicated due to different `rng` bounds
1186        let mut uniform_bytes = [0u8; 64];
1187        rng.fill_bytes(&mut uniform_bytes);
1188        RistrettoPoint::from_uniform_bytes(&uniform_bytes)
1189    }
1190
1191    fn identity() -> Self {
1192        Identity::identity()
1193    }
1194
1195    fn generator() -> Self {
1196        constants::RISTRETTO_BASEPOINT_POINT
1197    }
1198
1199    fn is_identity(&self) -> Choice {
1200        self.ct_eq(&Identity::identity())
1201    }
1202
1203    fn double(&self) -> Self {
1204        self + self
1205    }
1206}
1207
1208#[cfg(feature = "group")]
1209impl GroupEncoding for RistrettoPoint {
1210    type Repr = [u8; 32];
1211
1212    fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
1213        let (s_encoding_is_canonical, s_is_negative, s) =
1214            decompress::step_1(&CompressedRistretto(*bytes));
1215
1216        let s_is_valid = s_encoding_is_canonical & !s_is_negative;
1217
1218        let (ok, t_is_negative, y_is_zero, res) = decompress::step_2(s);
1219
1220        CtOption::new(res, s_is_valid & ok & !t_is_negative & !y_is_zero)
1221    }
1222
1223    fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
1224        // Just use the checked API; the checks we could skip aren't expensive.
1225        Self::from_bytes(bytes)
1226    }
1227
1228    fn to_bytes(&self) -> Self::Repr {
1229        self.compress().to_bytes()
1230    }
1231}
1232
1233#[cfg(feature = "group")]
1234impl PrimeGroup for RistrettoPoint {}
1235
1236/// Ristretto has a cofactor of 1.
1237#[cfg(feature = "group")]
1238impl CofactorGroup for RistrettoPoint {
1239    type Subgroup = Self;
1240
1241    fn clear_cofactor(&self) -> Self::Subgroup {
1242        *self
1243    }
1244
1245    fn into_subgroup(self) -> CtOption<Self::Subgroup> {
1246        CtOption::new(self, Choice::from(1))
1247    }
1248
1249    fn is_torsion_free(&self) -> Choice {
1250        Choice::from(1)
1251    }
1252}
1253
1254// ------------------------------------------------------------------------
1255// Zeroize traits
1256// ------------------------------------------------------------------------
1257
1258#[cfg(feature = "zeroize")]
1259impl Zeroize for CompressedRistretto {
1260    fn zeroize(&mut self) {
1261        self.0.zeroize();
1262    }
1263}
1264
1265#[cfg(feature = "zeroize")]
1266impl Zeroize for RistrettoPoint {
1267    fn zeroize(&mut self) {
1268        self.0.zeroize();
1269    }
1270}
1271
1272// ------------------------------------------------------------------------
1273// Tests
1274// ------------------------------------------------------------------------
1275
1276#[cfg(test)]
1277mod test {
1278    use super::*;
1279    use crate::edwards::CompressedEdwardsY;
1280
1281    use rand_core::OsRng;
1282
1283    #[test]
1284    #[cfg(feature = "serde")]
1285    fn serde_bincode_basepoint_roundtrip() {
1286        use bincode;
1287
1288        let encoded = bincode::serialize(&constants::RISTRETTO_BASEPOINT_POINT).unwrap();
1289        let enc_compressed =
1290            bincode::serialize(&constants::RISTRETTO_BASEPOINT_COMPRESSED).unwrap();
1291        assert_eq!(encoded, enc_compressed);
1292
1293        // Check that the encoding is 32 bytes exactly
1294        assert_eq!(encoded.len(), 32);
1295
1296        let dec_uncompressed: RistrettoPoint = bincode::deserialize(&encoded).unwrap();
1297        let dec_compressed: CompressedRistretto = bincode::deserialize(&encoded).unwrap();
1298
1299        assert_eq!(dec_uncompressed, constants::RISTRETTO_BASEPOINT_POINT);
1300        assert_eq!(dec_compressed, constants::RISTRETTO_BASEPOINT_COMPRESSED);
1301
1302        // Check that the encoding itself matches the usual one
1303        let raw_bytes = constants::RISTRETTO_BASEPOINT_COMPRESSED.as_bytes();
1304        let bp: RistrettoPoint = bincode::deserialize(raw_bytes).unwrap();
1305        assert_eq!(bp, constants::RISTRETTO_BASEPOINT_POINT);
1306    }
1307
1308    #[test]
1309    fn scalarmult_ristrettopoint_works_both_ways() {
1310        let P = constants::RISTRETTO_BASEPOINT_POINT;
1311        let s = Scalar::from(999u64);
1312
1313        let P1 = P * s;
1314        let P2 = s * P;
1315
1316        assert!(P1.compress().as_bytes() == P2.compress().as_bytes());
1317    }
1318
1319    #[test]
1320    #[cfg(feature = "alloc")]
1321    fn impl_sum() {
1322        // Test that sum works for non-empty iterators
1323        let BASE = constants::RISTRETTO_BASEPOINT_POINT;
1324
1325        let s1 = Scalar::from(999u64);
1326        let P1 = BASE * s1;
1327
1328        let s2 = Scalar::from(333u64);
1329        let P2 = BASE * s2;
1330
1331        let vec = vec![P1, P2];
1332        let sum: RistrettoPoint = vec.iter().sum();
1333
1334        assert_eq!(sum, P1 + P2);
1335
1336        // Test that sum works for the empty iterator
1337        let empty_vector: Vec<RistrettoPoint> = vec![];
1338        let sum: RistrettoPoint = empty_vector.iter().sum();
1339
1340        assert_eq!(sum, RistrettoPoint::identity());
1341
1342        // Test that sum works on owning iterators
1343        let s = Scalar::from(2u64);
1344        let mapped = vec.iter().map(|x| x * s);
1345        let sum: RistrettoPoint = mapped.sum();
1346
1347        assert_eq!(sum, P1 * s + P2 * s);
1348    }
1349
1350    #[test]
1351    fn decompress_negative_s_fails() {
1352        // constants::d is neg, so decompression should fail as |d| != d.
1353        let bad_compressed = CompressedRistretto(constants::EDWARDS_D.as_bytes());
1354        assert!(bad_compressed.decompress().is_none());
1355    }
1356
1357    #[test]
1358    fn decompress_id() {
1359        let compressed_id = CompressedRistretto::identity();
1360        let id = compressed_id.decompress().unwrap();
1361        let mut identity_in_coset = false;
1362        for P in &id.coset4() {
1363            if P.compress() == CompressedEdwardsY::identity() {
1364                identity_in_coset = true;
1365            }
1366        }
1367        assert!(identity_in_coset);
1368    }
1369
1370    #[test]
1371    fn compress_id() {
1372        let id = RistrettoPoint::identity();
1373        assert_eq!(id.compress(), CompressedRistretto::identity());
1374    }
1375
1376    #[test]
1377    fn basepoint_roundtrip() {
1378        let bp_compressed_ristretto = constants::RISTRETTO_BASEPOINT_POINT.compress();
1379        let bp_recaf = bp_compressed_ristretto.decompress().unwrap().0;
1380        // Check that bp_recaf differs from bp by a point of order 4
1381        let diff = constants::RISTRETTO_BASEPOINT_POINT.0 - bp_recaf;
1382        let diff4 = diff.mul_by_pow_2(2);
1383        assert_eq!(diff4.compress(), CompressedEdwardsY::identity());
1384    }
1385
1386    #[test]
1387    fn encodings_of_small_multiples_of_basepoint() {
1388        // Table of encodings of i*basepoint
1389        // Generated using ristretto.sage
1390        let compressed = [
1391            CompressedRistretto([
1392                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,
1393                0, 0, 0, 0,
1394            ]),
1395            CompressedRistretto([
1396                226, 242, 174, 10, 106, 188, 78, 113, 168, 132, 169, 97, 197, 0, 81, 95, 88, 227,
1397                11, 106, 165, 130, 221, 141, 182, 166, 89, 69, 224, 141, 45, 118,
1398            ]),
1399            CompressedRistretto([
1400                106, 73, 50, 16, 247, 73, 156, 209, 127, 236, 181, 16, 174, 12, 234, 35, 161, 16,
1401                232, 213, 185, 1, 248, 172, 173, 211, 9, 92, 115, 163, 185, 25,
1402            ]),
1403            CompressedRistretto([
1404                148, 116, 31, 93, 93, 82, 117, 94, 206, 79, 35, 240, 68, 238, 39, 213, 209, 234,
1405                30, 43, 209, 150, 180, 98, 22, 107, 22, 21, 42, 157, 2, 89,
1406            ]),
1407            CompressedRistretto([
1408                218, 128, 134, 39, 115, 53, 139, 70, 111, 250, 223, 224, 179, 41, 58, 179, 217,
1409                253, 83, 197, 234, 108, 149, 83, 88, 245, 104, 50, 45, 175, 106, 87,
1410            ]),
1411            CompressedRistretto([
1412                232, 130, 177, 49, 1, 107, 82, 193, 211, 51, 112, 128, 24, 124, 247, 104, 66, 62,
1413                252, 203, 181, 23, 187, 73, 90, 184, 18, 196, 22, 15, 244, 78,
1414            ]),
1415            CompressedRistretto([
1416                246, 71, 70, 211, 201, 43, 19, 5, 14, 216, 216, 2, 54, 167, 240, 0, 124, 59, 63,
1417                150, 47, 91, 167, 147, 209, 154, 96, 30, 187, 29, 244, 3,
1418            ]),
1419            CompressedRistretto([
1420                68, 245, 53, 32, 146, 110, 200, 31, 189, 90, 56, 120, 69, 190, 183, 223, 133, 169,
1421                106, 36, 236, 225, 135, 56, 189, 207, 166, 167, 130, 42, 23, 109,
1422            ]),
1423            CompressedRistretto([
1424                144, 50, 147, 216, 242, 40, 126, 190, 16, 226, 55, 77, 193, 165, 62, 11, 200, 135,
1425                229, 146, 105, 159, 2, 208, 119, 213, 38, 60, 221, 85, 96, 28,
1426            ]),
1427            CompressedRistretto([
1428                2, 98, 42, 206, 143, 115, 3, 163, 28, 175, 198, 63, 143, 196, 143, 220, 22, 225,
1429                200, 200, 210, 52, 178, 240, 214, 104, 82, 130, 169, 7, 96, 49,
1430            ]),
1431            CompressedRistretto([
1432                32, 112, 111, 215, 136, 178, 114, 10, 30, 210, 165, 218, 212, 149, 43, 1, 244, 19,
1433                188, 240, 231, 86, 77, 232, 205, 200, 22, 104, 158, 45, 185, 95,
1434            ]),
1435            CompressedRistretto([
1436                188, 232, 63, 139, 165, 221, 47, 165, 114, 134, 76, 36, 186, 24, 16, 249, 82, 43,
1437                198, 0, 74, 254, 149, 135, 122, 199, 50, 65, 202, 253, 171, 66,
1438            ]),
1439            CompressedRistretto([
1440                228, 84, 158, 225, 107, 154, 160, 48, 153, 202, 32, 140, 103, 173, 175, 202, 250,
1441                76, 63, 62, 78, 83, 3, 222, 96, 38, 227, 202, 143, 248, 68, 96,
1442            ]),
1443            CompressedRistretto([
1444                170, 82, 224, 0, 223, 46, 22, 245, 95, 177, 3, 47, 195, 59, 196, 39, 66, 218, 214,
1445                189, 90, 143, 192, 190, 1, 103, 67, 108, 89, 72, 80, 31,
1446            ]),
1447            CompressedRistretto([
1448                70, 55, 107, 128, 244, 9, 178, 157, 194, 181, 246, 240, 197, 37, 145, 153, 8, 150,
1449                229, 113, 111, 65, 71, 124, 211, 0, 133, 171, 127, 16, 48, 30,
1450            ]),
1451            CompressedRistretto([
1452                224, 196, 24, 247, 200, 217, 196, 205, 215, 57, 91, 147, 234, 18, 79, 58, 217, 144,
1453                33, 187, 104, 29, 252, 51, 2, 169, 217, 154, 46, 83, 230, 78,
1454            ]),
1455        ];
1456        let mut bp = RistrettoPoint::identity();
1457        for point in compressed {
1458            assert_eq!(bp.compress(), point);
1459            bp += constants::RISTRETTO_BASEPOINT_POINT;
1460        }
1461    }
1462
1463    #[test]
1464    fn four_torsion_basepoint() {
1465        let bp = constants::RISTRETTO_BASEPOINT_POINT;
1466        let bp_coset = bp.coset4();
1467        for point in bp_coset {
1468            assert_eq!(bp, RistrettoPoint(point));
1469        }
1470    }
1471
1472    #[test]
1473    fn four_torsion_random() {
1474        let mut rng = OsRng;
1475        let P = RistrettoPoint::mul_base(&Scalar::random(&mut rng));
1476        let P_coset = P.coset4();
1477        for point in P_coset {
1478            assert_eq!(P, RistrettoPoint(point));
1479        }
1480    }
1481
1482    #[test]
1483    fn elligator_vs_ristretto_sage() {
1484        // Test vectors extracted from ristretto.sage.
1485        //
1486        // Notice that all of the byte sequences have bit 255 set to 0; this is because
1487        // ristretto.sage does not mask the high bit of a field element.  When the high bit is set,
1488        // the ristretto.sage elligator implementation gives different results, since it takes a
1489        // different field element as input.
1490        let bytes: [[u8; 32]; 16] = [
1491            [
1492                184, 249, 135, 49, 253, 123, 89, 113, 67, 160, 6, 239, 7, 105, 211, 41, 192, 249,
1493                185, 57, 9, 102, 70, 198, 15, 127, 7, 26, 160, 102, 134, 71,
1494            ],
1495            [
1496                229, 14, 241, 227, 75, 9, 118, 60, 128, 153, 226, 21, 183, 217, 91, 136, 98, 0,
1497                231, 156, 124, 77, 82, 139, 142, 134, 164, 169, 169, 62, 250, 52,
1498            ],
1499            [
1500                115, 109, 36, 220, 180, 223, 99, 6, 204, 169, 19, 29, 169, 68, 84, 23, 21, 109,
1501                189, 149, 127, 205, 91, 102, 172, 35, 112, 35, 134, 69, 186, 34,
1502            ],
1503            [
1504                16, 49, 96, 107, 171, 199, 164, 9, 129, 16, 64, 62, 241, 63, 132, 173, 209, 160,
1505                112, 215, 105, 50, 157, 81, 253, 105, 1, 154, 229, 25, 120, 83,
1506            ],
1507            [
1508                156, 131, 161, 162, 236, 251, 5, 187, 167, 171, 17, 178, 148, 210, 90, 207, 86, 21,
1509                79, 161, 167, 215, 234, 1, 136, 242, 182, 248, 38, 85, 79, 86,
1510            ],
1511            [
1512                251, 177, 124, 54, 18, 101, 75, 235, 245, 186, 19, 46, 133, 157, 229, 64, 10, 136,
1513                181, 185, 78, 144, 254, 167, 137, 49, 107, 10, 61, 10, 21, 25,
1514            ],
1515            [
1516                232, 193, 20, 68, 240, 77, 186, 77, 183, 40, 44, 86, 150, 31, 198, 212, 76, 81, 3,
1517                217, 197, 8, 126, 128, 126, 152, 164, 208, 153, 44, 189, 77,
1518            ],
1519            [
1520                173, 229, 149, 177, 37, 230, 30, 69, 61, 56, 172, 190, 219, 115, 167, 194, 71, 134,
1521                59, 75, 28, 244, 118, 26, 162, 97, 64, 16, 15, 189, 30, 64,
1522            ],
1523            [
1524                106, 71, 61, 107, 250, 117, 42, 151, 91, 202, 212, 100, 52, 188, 190, 21, 125, 218,
1525                31, 18, 253, 241, 160, 133, 57, 242, 3, 164, 189, 68, 111, 75,
1526            ],
1527            [
1528                112, 204, 182, 90, 220, 198, 120, 73, 173, 107, 193, 17, 227, 40, 162, 36, 150,
1529                141, 235, 55, 172, 183, 12, 39, 194, 136, 43, 153, 244, 118, 91, 89,
1530            ],
1531            [
1532                111, 24, 203, 123, 254, 189, 11, 162, 51, 196, 163, 136, 204, 143, 10, 222, 33,
1533                112, 81, 205, 34, 35, 8, 66, 90, 6, 164, 58, 170, 177, 34, 25,
1534            ],
1535            [
1536                225, 183, 30, 52, 236, 82, 6, 183, 109, 25, 227, 181, 25, 82, 41, 193, 80, 77, 161,
1537                80, 242, 203, 79, 204, 136, 245, 131, 110, 237, 106, 3, 58,
1538            ],
1539            [
1540                207, 246, 38, 56, 30, 86, 176, 90, 27, 200, 61, 42, 221, 27, 56, 210, 79, 178, 189,
1541                120, 68, 193, 120, 167, 77, 185, 53, 197, 124, 128, 191, 126,
1542            ],
1543            [
1544                1, 136, 215, 80, 240, 46, 63, 147, 16, 244, 230, 207, 82, 189, 74, 50, 106, 169,
1545                138, 86, 30, 131, 214, 202, 166, 125, 251, 228, 98, 24, 36, 21,
1546            ],
1547            [
1548                210, 207, 228, 56, 155, 116, 207, 54, 84, 195, 251, 215, 249, 199, 116, 75, 109,
1549                239, 196, 251, 194, 246, 252, 228, 70, 146, 156, 35, 25, 39, 241, 4,
1550            ],
1551            [
1552                34, 116, 123, 9, 8, 40, 93, 189, 9, 103, 57, 103, 66, 227, 3, 2, 157, 107, 134,
1553                219, 202, 74, 230, 154, 78, 107, 219, 195, 214, 14, 84, 80,
1554            ],
1555        ];
1556        let encoded_images: [CompressedRistretto; 16] = [
1557            CompressedRistretto([
1558                176, 157, 237, 97, 66, 29, 140, 166, 168, 94, 26, 157, 212, 216, 229, 160, 195,
1559                246, 232, 239, 169, 112, 63, 193, 64, 32, 152, 69, 11, 190, 246, 86,
1560            ]),
1561            CompressedRistretto([
1562                234, 141, 77, 203, 181, 225, 250, 74, 171, 62, 15, 118, 78, 212, 150, 19, 131, 14,
1563                188, 238, 194, 244, 141, 138, 166, 162, 83, 122, 228, 201, 19, 26,
1564            ]),
1565            CompressedRistretto([
1566                232, 231, 51, 92, 5, 168, 80, 36, 173, 179, 104, 68, 186, 149, 68, 40, 140, 170,
1567                27, 103, 99, 140, 21, 242, 43, 62, 250, 134, 208, 255, 61, 89,
1568            ]),
1569            CompressedRistretto([
1570                208, 120, 140, 129, 177, 179, 237, 159, 252, 160, 28, 13, 206, 5, 211, 241, 192,
1571                218, 1, 97, 130, 241, 20, 169, 119, 46, 246, 29, 79, 80, 77, 84,
1572            ]),
1573            CompressedRistretto([
1574                202, 11, 236, 145, 58, 12, 181, 157, 209, 6, 213, 88, 75, 147, 11, 119, 191, 139,
1575                47, 142, 33, 36, 153, 193, 223, 183, 178, 8, 205, 120, 248, 110,
1576            ]),
1577            CompressedRistretto([
1578                26, 66, 231, 67, 203, 175, 116, 130, 32, 136, 62, 253, 215, 46, 5, 214, 166, 248,
1579                108, 237, 216, 71, 244, 173, 72, 133, 82, 6, 143, 240, 104, 41,
1580            ]),
1581            CompressedRistretto([
1582                40, 157, 102, 96, 201, 223, 200, 197, 150, 181, 106, 83, 103, 126, 143, 33, 145,
1583                230, 78, 6, 171, 146, 210, 143, 112, 5, 245, 23, 183, 138, 18, 120,
1584            ]),
1585            CompressedRistretto([
1586                220, 37, 27, 203, 239, 196, 176, 131, 37, 66, 188, 243, 185, 250, 113, 23, 167,
1587                211, 154, 243, 168, 215, 54, 171, 159, 36, 195, 81, 13, 150, 43, 43,
1588            ]),
1589            CompressedRistretto([
1590                232, 121, 176, 222, 183, 196, 159, 90, 238, 193, 105, 52, 101, 167, 244, 170, 121,
1591                114, 196, 6, 67, 152, 80, 185, 221, 7, 83, 105, 176, 208, 224, 121,
1592            ]),
1593            CompressedRistretto([
1594                226, 181, 183, 52, 241, 163, 61, 179, 221, 207, 220, 73, 245, 242, 25, 236, 67, 84,
1595                179, 222, 167, 62, 167, 182, 32, 9, 92, 30, 165, 127, 204, 68,
1596            ]),
1597            CompressedRistretto([
1598                226, 119, 16, 242, 200, 139, 240, 87, 11, 222, 92, 146, 156, 243, 46, 119, 65, 59,
1599                1, 248, 92, 183, 50, 175, 87, 40, 206, 53, 208, 220, 148, 13,
1600            ]),
1601            CompressedRistretto([
1602                70, 240, 79, 112, 54, 157, 228, 146, 74, 122, 216, 88, 232, 62, 158, 13, 14, 146,
1603                115, 117, 176, 222, 90, 225, 244, 23, 94, 190, 150, 7, 136, 96,
1604            ]),
1605            CompressedRistretto([
1606                22, 71, 241, 103, 45, 193, 195, 144, 183, 101, 154, 50, 39, 68, 49, 110, 51, 44,
1607                62, 0, 229, 113, 72, 81, 168, 29, 73, 106, 102, 40, 132, 24,
1608            ]),
1609            CompressedRistretto([
1610                196, 133, 107, 11, 130, 105, 74, 33, 204, 171, 133, 221, 174, 193, 241, 36, 38,
1611                179, 196, 107, 219, 185, 181, 253, 228, 47, 155, 42, 231, 73, 41, 78,
1612            ]),
1613            CompressedRistretto([
1614                58, 255, 225, 197, 115, 208, 160, 143, 39, 197, 82, 69, 143, 235, 92, 170, 74, 40,
1615                57, 11, 171, 227, 26, 185, 217, 207, 90, 185, 197, 190, 35, 60,
1616            ]),
1617            CompressedRistretto([
1618                88, 43, 92, 118, 223, 136, 105, 145, 238, 186, 115, 8, 214, 112, 153, 253, 38, 108,
1619                205, 230, 157, 130, 11, 66, 101, 85, 253, 110, 110, 14, 148, 112,
1620            ]),
1621        ];
1622        for i in 0..16 {
1623            let r_0 = FieldElement::from_bytes(&bytes[i]);
1624            let Q = RistrettoPoint::elligator_ristretto_flavor(&r_0);
1625            assert_eq!(Q.compress(), encoded_images[i]);
1626        }
1627    }
1628
1629    // Known answer tests for the one-way mapping function in the Ristretto RFC
1630    #[test]
1631    fn one_way_map() {
1632        // These inputs are from
1633        // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-ristretto255-decaf448-04#appendix-A.3
1634        let test_vectors: &[([u8; 64], CompressedRistretto)] = &[
1635            (
1636                [
1637                    0x5d, 0x1b, 0xe0, 0x9e, 0x3d, 0x0c, 0x82, 0xfc, 0x53, 0x81, 0x12, 0x49, 0x0e,
1638                    0x35, 0x70, 0x19, 0x79, 0xd9, 0x9e, 0x06, 0xca, 0x3e, 0x2b, 0x5b, 0x54, 0xbf,
1639                    0xfe, 0x8b, 0x4d, 0xc7, 0x72, 0xc1, 0x4d, 0x98, 0xb6, 0x96, 0xa1, 0xbb, 0xfb,
1640                    0x5c, 0xa3, 0x2c, 0x43, 0x6c, 0xc6, 0x1c, 0x16, 0x56, 0x37, 0x90, 0x30, 0x6c,
1641                    0x79, 0xea, 0xca, 0x77, 0x05, 0x66, 0x8b, 0x47, 0xdf, 0xfe, 0x5b, 0xb6,
1642                ],
1643                CompressedRistretto([
1644                    0x30, 0x66, 0xf8, 0x2a, 0x1a, 0x74, 0x7d, 0x45, 0x12, 0x0d, 0x17, 0x40, 0xf1,
1645                    0x43, 0x58, 0x53, 0x1a, 0x8f, 0x04, 0xbb, 0xff, 0xe6, 0xa8, 0x19, 0xf8, 0x6d,
1646                    0xfe, 0x50, 0xf4, 0x4a, 0x0a, 0x46,
1647                ]),
1648            ),
1649            (
1650                [
1651                    0xf1, 0x16, 0xb3, 0x4b, 0x8f, 0x17, 0xce, 0xb5, 0x6e, 0x87, 0x32, 0xa6, 0x0d,
1652                    0x91, 0x3d, 0xd1, 0x0c, 0xce, 0x47, 0xa6, 0xd5, 0x3b, 0xee, 0x92, 0x04, 0xbe,
1653                    0x8b, 0x44, 0xf6, 0x67, 0x8b, 0x27, 0x01, 0x02, 0xa5, 0x69, 0x02, 0xe2, 0x48,
1654                    0x8c, 0x46, 0x12, 0x0e, 0x92, 0x76, 0xcf, 0xe5, 0x46, 0x38, 0x28, 0x6b, 0x9e,
1655                    0x4b, 0x3c, 0xdb, 0x47, 0x0b, 0x54, 0x2d, 0x46, 0xc2, 0x06, 0x8d, 0x38,
1656                ],
1657                CompressedRistretto([
1658                    0xf2, 0x6e, 0x5b, 0x6f, 0x7d, 0x36, 0x2d, 0x2d, 0x2a, 0x94, 0xc5, 0xd0, 0xe7,
1659                    0x60, 0x2c, 0xb4, 0x77, 0x3c, 0x95, 0xa2, 0xe5, 0xc3, 0x1a, 0x64, 0xf1, 0x33,
1660                    0x18, 0x9f, 0xa7, 0x6e, 0xd6, 0x1b,
1661                ]),
1662            ),
1663            (
1664                [
1665                    0x84, 0x22, 0xe1, 0xbb, 0xda, 0xab, 0x52, 0x93, 0x8b, 0x81, 0xfd, 0x60, 0x2e,
1666                    0xff, 0xb6, 0xf8, 0x91, 0x10, 0xe1, 0xe5, 0x72, 0x08, 0xad, 0x12, 0xd9, 0xad,
1667                    0x76, 0x7e, 0x2e, 0x25, 0x51, 0x0c, 0x27, 0x14, 0x07, 0x75, 0xf9, 0x33, 0x70,
1668                    0x88, 0xb9, 0x82, 0xd8, 0x3d, 0x7f, 0xcf, 0x0b, 0x2f, 0xa1, 0xed, 0xff, 0xe5,
1669                    0x19, 0x52, 0xcb, 0xe7, 0x36, 0x5e, 0x95, 0xc8, 0x6e, 0xaf, 0x32, 0x5c,
1670                ],
1671                CompressedRistretto([
1672                    0x00, 0x6c, 0xcd, 0x2a, 0x9e, 0x68, 0x67, 0xe6, 0xa2, 0xc5, 0xce, 0xa8, 0x3d,
1673                    0x33, 0x02, 0xcc, 0x9d, 0xe1, 0x28, 0xdd, 0x2a, 0x9a, 0x57, 0xdd, 0x8e, 0xe7,
1674                    0xb9, 0xd7, 0xff, 0xe0, 0x28, 0x26,
1675                ]),
1676            ),
1677            (
1678                [
1679                    0xac, 0x22, 0x41, 0x51, 0x29, 0xb6, 0x14, 0x27, 0xbf, 0x46, 0x4e, 0x17, 0xba,
1680                    0xee, 0x8d, 0xb6, 0x59, 0x40, 0xc2, 0x33, 0xb9, 0x8a, 0xfc, 0xe8, 0xd1, 0x7c,
1681                    0x57, 0xbe, 0xeb, 0x78, 0x76, 0xc2, 0x15, 0x0d, 0x15, 0xaf, 0x1c, 0xb1, 0xfb,
1682                    0x82, 0x4b, 0xbd, 0x14, 0x95, 0x5f, 0x2b, 0x57, 0xd0, 0x8d, 0x38, 0x8a, 0xab,
1683                    0x43, 0x1a, 0x39, 0x1c, 0xfc, 0x33, 0xd5, 0xba, 0xfb, 0x5d, 0xbb, 0xaf,
1684                ],
1685                CompressedRistretto([
1686                    0xf8, 0xf0, 0xc8, 0x7c, 0xf2, 0x37, 0x95, 0x3c, 0x58, 0x90, 0xae, 0xc3, 0x99,
1687                    0x81, 0x69, 0x00, 0x5d, 0xae, 0x3e, 0xca, 0x1f, 0xbb, 0x04, 0x54, 0x8c, 0x63,
1688                    0x59, 0x53, 0xc8, 0x17, 0xf9, 0x2a,
1689                ]),
1690            ),
1691            (
1692                [
1693                    0x16, 0x5d, 0x69, 0x7a, 0x1e, 0xf3, 0xd5, 0xcf, 0x3c, 0x38, 0x56, 0x5b, 0xee,
1694                    0xfc, 0xf8, 0x8c, 0x0f, 0x28, 0x2b, 0x8e, 0x7d, 0xbd, 0x28, 0x54, 0x4c, 0x48,
1695                    0x34, 0x32, 0xf1, 0xce, 0xc7, 0x67, 0x5d, 0xeb, 0xea, 0x8e, 0xbb, 0x4e, 0x5f,
1696                    0xe7, 0xd6, 0xf6, 0xe5, 0xdb, 0x15, 0xf1, 0x55, 0x87, 0xac, 0x4d, 0x4d, 0x4a,
1697                    0x1d, 0xe7, 0x19, 0x1e, 0x0c, 0x1c, 0xa6, 0x66, 0x4a, 0xbc, 0xc4, 0x13,
1698                ],
1699                CompressedRistretto([
1700                    0xae, 0x81, 0xe7, 0xde, 0xdf, 0x20, 0xa4, 0x97, 0xe1, 0x0c, 0x30, 0x4a, 0x76,
1701                    0x5c, 0x17, 0x67, 0xa4, 0x2d, 0x6e, 0x06, 0x02, 0x97, 0x58, 0xd2, 0xd7, 0xe8,
1702                    0xef, 0x7c, 0xc4, 0xc4, 0x11, 0x79,
1703                ]),
1704            ),
1705            (
1706                [
1707                    0xa8, 0x36, 0xe6, 0xc9, 0xa9, 0xca, 0x9f, 0x1e, 0x8d, 0x48, 0x62, 0x73, 0xad,
1708                    0x56, 0xa7, 0x8c, 0x70, 0xcf, 0x18, 0xf0, 0xce, 0x10, 0xab, 0xb1, 0xc7, 0x17,
1709                    0x2d, 0xdd, 0x60, 0x5d, 0x7f, 0xd2, 0x97, 0x98, 0x54, 0xf4, 0x7a, 0xe1, 0xcc,
1710                    0xf2, 0x04, 0xa3, 0x31, 0x02, 0x09, 0x5b, 0x42, 0x00, 0xe5, 0xbe, 0xfc, 0x04,
1711                    0x65, 0xac, 0xcc, 0x26, 0x31, 0x75, 0x48, 0x5f, 0x0e, 0x17, 0xea, 0x5c,
1712                ],
1713                CompressedRistretto([
1714                    0xe2, 0x70, 0x56, 0x52, 0xff, 0x9f, 0x5e, 0x44, 0xd3, 0xe8, 0x41, 0xbf, 0x1c,
1715                    0x25, 0x1c, 0xf7, 0xdd, 0xdb, 0x77, 0xd1, 0x40, 0x87, 0x0d, 0x1a, 0xb2, 0xed,
1716                    0x64, 0xf1, 0xa9, 0xce, 0x86, 0x28,
1717                ]),
1718            ),
1719            (
1720                [
1721                    0x2c, 0xdc, 0x11, 0xea, 0xeb, 0x95, 0xda, 0xf0, 0x11, 0x89, 0x41, 0x7c, 0xdd,
1722                    0xdb, 0xf9, 0x59, 0x52, 0x99, 0x3a, 0xa9, 0xcb, 0x9c, 0x64, 0x0e, 0xb5, 0x05,
1723                    0x8d, 0x09, 0x70, 0x2c, 0x74, 0x62, 0x2c, 0x99, 0x65, 0xa6, 0x97, 0xa3, 0xb3,
1724                    0x45, 0xec, 0x24, 0xee, 0x56, 0x33, 0x5b, 0x55, 0x6e, 0x67, 0x7b, 0x30, 0xe6,
1725                    0xf9, 0x0a, 0xc7, 0x7d, 0x78, 0x10, 0x64, 0xf8, 0x66, 0xa3, 0xc9, 0x82,
1726                ],
1727                CompressedRistretto([
1728                    0x80, 0xbd, 0x07, 0x26, 0x25, 0x11, 0xcd, 0xde, 0x48, 0x63, 0xf8, 0xa7, 0x43,
1729                    0x4c, 0xef, 0x69, 0x67, 0x50, 0x68, 0x1c, 0xb9, 0x51, 0x0e, 0xea, 0x55, 0x70,
1730                    0x88, 0xf7, 0x6d, 0x9e, 0x50, 0x65,
1731                ]),
1732            ),
1733            (
1734                [
1735                    0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1736                    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1737                    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1738                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1739                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1740                ],
1741                CompressedRistretto([
1742                    0x30, 0x42, 0x82, 0x79, 0x10, 0x23, 0xb7, 0x31, 0x28, 0xd2, 0x77, 0xbd, 0xcb,
1743                    0x5c, 0x77, 0x46, 0xef, 0x2e, 0xac, 0x08, 0xdd, 0xe9, 0xf2, 0x98, 0x33, 0x79,
1744                    0xcb, 0x8e, 0x5e, 0xf0, 0x51, 0x7f,
1745                ]),
1746            ),
1747            (
1748                [
1749                    0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1750                    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1751                    0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1752                    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1753                    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1754                ],
1755                CompressedRistretto([
1756                    0x30, 0x42, 0x82, 0x79, 0x10, 0x23, 0xb7, 0x31, 0x28, 0xd2, 0x77, 0xbd, 0xcb,
1757                    0x5c, 0x77, 0x46, 0xef, 0x2e, 0xac, 0x08, 0xdd, 0xe9, 0xf2, 0x98, 0x33, 0x79,
1758                    0xcb, 0x8e, 0x5e, 0xf0, 0x51, 0x7f,
1759                ]),
1760            ),
1761            (
1762                [
1763                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1764                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1765                    0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1766                    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1767                    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
1768                ],
1769                CompressedRistretto([
1770                    0x30, 0x42, 0x82, 0x79, 0x10, 0x23, 0xb7, 0x31, 0x28, 0xd2, 0x77, 0xbd, 0xcb,
1771                    0x5c, 0x77, 0x46, 0xef, 0x2e, 0xac, 0x08, 0xdd, 0xe9, 0xf2, 0x98, 0x33, 0x79,
1772                    0xcb, 0x8e, 0x5e, 0xf0, 0x51, 0x7f,
1773                ]),
1774            ),
1775            (
1776                [
1777                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1778                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1779                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1780                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1781                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
1782                ],
1783                CompressedRistretto([
1784                    0x30, 0x42, 0x82, 0x79, 0x10, 0x23, 0xb7, 0x31, 0x28, 0xd2, 0x77, 0xbd, 0xcb,
1785                    0x5c, 0x77, 0x46, 0xef, 0x2e, 0xac, 0x08, 0xdd, 0xe9, 0xf2, 0x98, 0x33, 0x79,
1786                    0xcb, 0x8e, 0x5e, 0xf0, 0x51, 0x7f,
1787                ]),
1788            ),
1789        ];
1790        // Check that onewaymap(input) == output for all the above vectors
1791        for (input, output) in test_vectors {
1792            let Q = RistrettoPoint::from_uniform_bytes(input);
1793            assert_eq!(&Q.compress(), output);
1794        }
1795    }
1796
1797    #[test]
1798    fn random_roundtrip() {
1799        let mut rng = OsRng;
1800        for _ in 0..100 {
1801            let P = RistrettoPoint::mul_base(&Scalar::random(&mut rng));
1802            let compressed_P = P.compress();
1803            let Q = compressed_P.decompress().unwrap();
1804            assert_eq!(P, Q);
1805        }
1806    }
1807
1808    #[test]
1809    #[cfg(all(feature = "alloc", feature = "rand_core"))]
1810    fn double_and_compress_1024_random_points() {
1811        let mut rng = OsRng;
1812
1813        let mut points: Vec<RistrettoPoint> = (0..1024)
1814            .map(|_| RistrettoPoint::random(&mut rng))
1815            .collect();
1816        points[500] = RistrettoPoint::identity();
1817
1818        let compressed = RistrettoPoint::double_and_compress_batch(&points);
1819
1820        for (P, P2_compressed) in points.iter().zip(compressed.iter()) {
1821            assert_eq!(*P2_compressed, (P + P).compress());
1822        }
1823    }
1824
1825    #[test]
1826    #[cfg(feature = "alloc")]
1827    fn vartime_precomputed_vs_nonprecomputed_multiscalar() {
1828        let mut rng = rand::thread_rng();
1829
1830        let static_scalars = (0..128)
1831            .map(|_| Scalar::random(&mut rng))
1832            .collect::<Vec<_>>();
1833
1834        let dynamic_scalars = (0..128)
1835            .map(|_| Scalar::random(&mut rng))
1836            .collect::<Vec<_>>();
1837
1838        let check_scalar: Scalar = static_scalars
1839            .iter()
1840            .chain(dynamic_scalars.iter())
1841            .map(|s| s * s)
1842            .sum();
1843
1844        let static_points = static_scalars
1845            .iter()
1846            .map(RistrettoPoint::mul_base)
1847            .collect::<Vec<_>>();
1848        let dynamic_points = dynamic_scalars
1849            .iter()
1850            .map(RistrettoPoint::mul_base)
1851            .collect::<Vec<_>>();
1852
1853        let precomputation = VartimeRistrettoPrecomputation::new(static_points.iter());
1854
1855        let P = precomputation.vartime_mixed_multiscalar_mul(
1856            &static_scalars,
1857            &dynamic_scalars,
1858            &dynamic_points,
1859        );
1860
1861        use crate::traits::VartimeMultiscalarMul;
1862        let Q = RistrettoPoint::vartime_multiscalar_mul(
1863            static_scalars.iter().chain(dynamic_scalars.iter()),
1864            static_points.iter().chain(dynamic_points.iter()),
1865        );
1866
1867        let R = RistrettoPoint::mul_base(&check_scalar);
1868
1869        assert_eq!(P.compress(), R.compress());
1870        assert_eq!(Q.compress(), R.compress());
1871    }
1872}