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