curve25519_dalek/
traits.rs

1// -*- mode: rust; -*-
2//
3// This file is part of curve25519-dalek.
4// Copyright (c) 2016-2021 isis lovecruft
5// Copyright (c) 2016-2019 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//! Module for common traits.
13
14#![allow(non_snake_case)]
15
16use core::borrow::Borrow;
17
18use crate::scalar::{clamp_integer, Scalar};
19use subtle::ConstantTimeEq;
20
21// ------------------------------------------------------------------------
22// Public Traits
23// ------------------------------------------------------------------------
24
25/// Trait for getting the identity element of a point type.
26pub trait Identity {
27    /// Returns the identity element of the curve.
28    /// Can be used as a constructor.
29    fn identity() -> Self;
30}
31
32/// Trait for testing if a curve point is equivalent to the identity point.
33pub trait IsIdentity {
34    /// Return true if this element is the identity element of the curve.
35    fn is_identity(&self) -> bool;
36}
37
38/// Implement generic identity equality testing for a point representations
39/// which have constant-time equality testing and a defined identity
40/// constructor.
41impl<T> IsIdentity for T
42where
43    T: ConstantTimeEq + Identity,
44{
45    fn is_identity(&self) -> bool {
46        self.ct_eq(&T::identity()).into()
47    }
48}
49
50/// A precomputed table of basepoints, for optimising scalar multiplications.
51pub trait BasepointTable {
52    /// The type of point contained within this table.
53    type Point;
54
55    /// Generate a new precomputed basepoint table from the given basepoint.
56    fn create(basepoint: &Self::Point) -> Self;
57
58    /// Retrieve the original basepoint from this table.
59    fn basepoint(&self) -> Self::Point;
60
61    /// Multiply a `scalar` by this precomputed basepoint table, in constant time.
62    fn mul_base(&self, scalar: &Scalar) -> Self::Point;
63
64    /// Multiply `clamp_integer(bytes)` by this precomputed basepoint table, in constant time. For
65    /// a description of clamping, see [`clamp_integer`].
66    fn mul_base_clamped(&self, bytes: [u8; 32]) -> Self::Point {
67        // Basepoint multiplication is defined for all values of `bytes` up to and including
68        // 2^255 - 1. The limit comes from the fact that scalar.as_radix_16() doesn't work for
69        // most scalars larger than 2^255.
70        let s = Scalar {
71            bytes: clamp_integer(bytes),
72        };
73        self.mul_base(&s)
74    }
75}
76
77/// A trait for constant-time multiscalar multiplication without precomputation.
78pub trait MultiscalarMul {
79    /// The type of point being multiplied, e.g., `RistrettoPoint`.
80    type Point;
81
82    /// Given an iterator of (possibly secret) scalars and an iterator of
83    /// public points, compute
84    /// $$
85    /// Q = c\_1 P\_1 + \cdots + c\_n P\_n.
86    /// $$
87    ///
88    /// It is an error to call this function with two iterators of different lengths.
89    ///
90    /// # Examples
91    ///
92    /// The trait bound aims for maximum flexibility: the inputs must be
93    /// convertable to iterators (`I: IntoIter`), and the iterator's items
94    /// must be `Borrow<Scalar>` (or `Borrow<Point>`), to allow
95    /// iterators returning either `Scalar`s or `&Scalar`s.
96    ///
97    /// ```
98    /// # #[cfg(feature = "alloc")]
99    /// # {
100    /// use curve25519_dalek::constants;
101    /// use curve25519_dalek::traits::MultiscalarMul;
102    /// use curve25519_dalek::ristretto::RistrettoPoint;
103    /// use curve25519_dalek::scalar::Scalar;
104    ///
105    /// // Some scalars
106    /// let a = Scalar::from(87329482u64);
107    /// let b = Scalar::from(37264829u64);
108    /// let c = Scalar::from(98098098u64);
109    ///
110    /// // Some points
111    /// let P = constants::RISTRETTO_BASEPOINT_POINT;
112    /// let Q = P + P;
113    /// let R = P + Q;
114    ///
115    /// // A1 = a*P + b*Q + c*R
116    /// let abc = [a,b,c];
117    /// let A1 = RistrettoPoint::multiscalar_mul(&abc, &[P,Q,R]);
118    /// // Note: (&abc).into_iter(): Iterator<Item=&Scalar>
119    ///
120    /// // A2 = (-a)*P + (-b)*Q + (-c)*R
121    /// let minus_abc = abc.iter().map(|x| -x);
122    /// let A2 = RistrettoPoint::multiscalar_mul(minus_abc, &[P,Q,R]);
123    /// // Note: minus_abc.into_iter(): Iterator<Item=Scalar>
124    ///
125    /// assert_eq!(A1.compress(), (-A2).compress());
126    /// # }
127    /// ```
128    fn multiscalar_mul<I, J>(scalars: I, points: J) -> Self::Point
129    where
130        I: IntoIterator,
131        I::Item: Borrow<Scalar>,
132        J: IntoIterator,
133        J::Item: Borrow<Self::Point>;
134}
135
136/// A trait for variable-time multiscalar multiplication without precomputation.
137pub trait VartimeMultiscalarMul {
138    /// The type of point being multiplied, e.g., `RistrettoPoint`.
139    type Point;
140
141    /// Given an iterator of public scalars and an iterator of
142    /// `Option`s of points, compute either `Some(Q)`, where
143    /// $$
144    /// Q = c\_1 P\_1 + \cdots + c\_n P\_n,
145    /// $$
146    /// if all points were `Some(P_i)`, or else return `None`.
147    ///
148    /// This function is particularly useful when verifying statements
149    /// involving compressed points.  Accepting `Option<Point>` allows
150    /// inlining point decompression into the multiscalar call,
151    /// avoiding the need for temporary buffers.
152    /// ```
153    /// #[cfg(feature = "alloc")]
154    /// # {
155    /// use curve25519_dalek::constants;
156    /// use curve25519_dalek::traits::VartimeMultiscalarMul;
157    /// use curve25519_dalek::ristretto::RistrettoPoint;
158    /// use curve25519_dalek::scalar::Scalar;
159    ///
160    /// // Some scalars
161    /// let a = Scalar::from(87329482u64);
162    /// let b = Scalar::from(37264829u64);
163    /// let c = Scalar::from(98098098u64);
164    /// let abc = [a,b,c];
165    ///
166    /// // Some points
167    /// let P = constants::RISTRETTO_BASEPOINT_POINT;
168    /// let Q = P + P;
169    /// let R = P + Q;
170    /// let PQR = [P, Q, R];
171    ///
172    /// let compressed = [P.compress(), Q.compress(), R.compress()];
173    ///
174    /// // Now we can compute A1 = a*P + b*Q + c*R using P, Q, R:
175    /// let A1 = RistrettoPoint::vartime_multiscalar_mul(&abc, &PQR);
176    ///
177    /// // Or using the compressed points:
178    /// let A2 = RistrettoPoint::optional_multiscalar_mul(
179    ///     &abc,
180    ///     compressed.iter().map(|pt| pt.decompress()),
181    /// );
182    ///
183    /// assert_eq!(A2, Some(A1));
184    ///
185    /// // It's also possible to mix compressed and uncompressed points:
186    /// let A3 = RistrettoPoint::optional_multiscalar_mul(
187    ///     abc.iter()
188    ///         .chain(abc.iter()),
189    ///     compressed.iter().map(|pt| pt.decompress())
190    ///         .chain(PQR.iter().map(|&pt| Some(pt))),
191    /// );
192    ///
193    /// assert_eq!(A3, Some(A1+A1));
194    /// # }
195    /// ```
196    fn optional_multiscalar_mul<I, J>(scalars: I, points: J) -> Option<Self::Point>
197    where
198        I: IntoIterator,
199        I::Item: Borrow<Scalar>,
200        J: IntoIterator<Item = Option<Self::Point>>;
201
202    /// Given an iterator of public scalars and an iterator of
203    /// public points, compute
204    /// $$
205    /// Q = c\_1 P\_1 + \cdots + c\_n P\_n,
206    /// $$
207    /// using variable-time operations.
208    ///
209    /// It is an error to call this function with two iterators of different lengths.
210    ///
211    /// # Examples
212    ///
213    /// The trait bound aims for maximum flexibility: the inputs must be
214    /// convertable to iterators (`I: IntoIter`), and the iterator's items
215    /// must be `Borrow<Scalar>` (or `Borrow<Point>`), to allow
216    /// iterators returning either `Scalar`s or `&Scalar`s.
217    ///
218    /// ```
219    /// #[cfg(feature = "alloc")]
220    /// # {
221    /// use curve25519_dalek::constants;
222    /// use curve25519_dalek::traits::VartimeMultiscalarMul;
223    /// use curve25519_dalek::ristretto::RistrettoPoint;
224    /// use curve25519_dalek::scalar::Scalar;
225    ///
226    /// // Some scalars
227    /// let a = Scalar::from(87329482u64);
228    /// let b = Scalar::from(37264829u64);
229    /// let c = Scalar::from(98098098u64);
230    ///
231    /// // Some points
232    /// let P = constants::RISTRETTO_BASEPOINT_POINT;
233    /// let Q = P + P;
234    /// let R = P + Q;
235    ///
236    /// // A1 = a*P + b*Q + c*R
237    /// let abc = [a,b,c];
238    /// let A1 = RistrettoPoint::vartime_multiscalar_mul(&abc, &[P,Q,R]);
239    /// // Note: (&abc).into_iter(): Iterator<Item=&Scalar>
240    ///
241    /// // A2 = (-a)*P + (-b)*Q + (-c)*R
242    /// let minus_abc = abc.iter().map(|x| -x);
243    /// let A2 = RistrettoPoint::vartime_multiscalar_mul(minus_abc, &[P,Q,R]);
244    /// // Note: minus_abc.into_iter(): Iterator<Item=Scalar>
245    ///
246    /// assert_eq!(A1.compress(), (-A2).compress());
247    /// # }
248    /// ```
249    fn vartime_multiscalar_mul<I, J>(scalars: I, points: J) -> Self::Point
250    where
251        I: IntoIterator,
252        I::Item: Borrow<Scalar>,
253        J: IntoIterator,
254        J::Item: Borrow<Self::Point>,
255        Self::Point: Clone,
256    {
257        Self::optional_multiscalar_mul(
258            scalars,
259            points.into_iter().map(|P| Some(P.borrow().clone())),
260        )
261        .expect("should return some point")
262    }
263}
264
265/// A trait for variable-time multiscalar multiplication with precomputation.
266///
267/// A general multiscalar multiplication with precomputation can be written as
268/// $$
269/// Q = a_1 A_1 + \cdots + a_n A_n + b_1 B_1 + \cdots + b_m B_m,
270/// $$
271/// where the \\(B_i\\) are *static* points, for which precomputation
272/// is possible, and the \\(A_j\\) are *dynamic* points, for which
273/// precomputation is not possible.
274///
275/// This trait has three methods for performing this computation:
276///
277/// * [`Self::vartime_multiscalar_mul`], which handles the special case where
278///   \\(n = 0\\) and there are no dynamic points;
279///
280/// * [`Self::vartime_mixed_multiscalar_mul`], which takes the dynamic points as
281///   already-validated `Point`s and is infallible;
282///
283/// * [`Self::optional_mixed_multiscalar_mul`], which takes the dynamic points
284///   as `Option<Point>`s and returns an `Option<Point>`, allowing decompression
285///   to be composed into the input iterators.
286///
287/// All methods require that the lengths of the input iterators be
288/// known and matching, as if they were `ExactSizeIterator`s.  (It
289/// does not require `ExactSizeIterator` only because that trait is
290/// broken).
291pub trait VartimePrecomputedMultiscalarMul: Sized {
292    /// The type of point to be multiplied, e.g., `RistrettoPoint`.
293    type Point: Clone;
294
295    /// Given the static points \\( B_i \\), perform precomputation
296    /// and return the precomputation data.
297    fn new<I>(static_points: I) -> Self
298    where
299        I: IntoIterator,
300        I::Item: Borrow<Self::Point>;
301
302    /// Given `static_scalars`, an iterator of public scalars
303    /// \\(b_i\\), compute
304    /// $$
305    /// Q = b_1 B_1 + \cdots + b_m B_m,
306    /// $$
307    /// where the \\(B_j\\) are the points that were supplied to `new`.
308    ///
309    /// It is an error to call this function with iterators of
310    /// inconsistent lengths.
311    ///
312    /// The trait bound aims for maximum flexibility: the input must
313    /// be convertable to iterators (`I: IntoIter`), and the
314    /// iterator's items must be `Borrow<Scalar>`, to allow iterators
315    /// returning either `Scalar`s or `&Scalar`s.
316    fn vartime_multiscalar_mul<I>(&self, static_scalars: I) -> Self::Point
317    where
318        I: IntoIterator,
319        I::Item: Borrow<Scalar>,
320    {
321        use core::iter;
322
323        Self::vartime_mixed_multiscalar_mul(
324            self,
325            static_scalars,
326            iter::empty::<Scalar>(),
327            iter::empty::<Self::Point>(),
328        )
329    }
330
331    /// Given `static_scalars`, an iterator of public scalars
332    /// \\(b_i\\), `dynamic_scalars`, an iterator of public scalars
333    /// \\(a_i\\), and `dynamic_points`, an iterator of points
334    /// \\(A_i\\), compute
335    /// $$
336    /// Q = a_1 A_1 + \cdots + a_n A_n + b_1 B_1 + \cdots + b_m B_m,
337    /// $$
338    /// where the \\(B_j\\) are the points that were supplied to `new`.
339    ///
340    /// It is an error to call this function with iterators of
341    /// inconsistent lengths.
342    ///
343    /// The trait bound aims for maximum flexibility: the inputs must be
344    /// convertable to iterators (`I: IntoIter`), and the iterator's items
345    /// must be `Borrow<Scalar>` (or `Borrow<Point>`), to allow
346    /// iterators returning either `Scalar`s or `&Scalar`s.
347    fn vartime_mixed_multiscalar_mul<I, J, K>(
348        &self,
349        static_scalars: I,
350        dynamic_scalars: J,
351        dynamic_points: K,
352    ) -> Self::Point
353    where
354        I: IntoIterator,
355        I::Item: Borrow<Scalar>,
356        J: IntoIterator,
357        J::Item: Borrow<Scalar>,
358        K: IntoIterator,
359        K::Item: Borrow<Self::Point>,
360    {
361        Self::optional_mixed_multiscalar_mul(
362            self,
363            static_scalars,
364            dynamic_scalars,
365            dynamic_points.into_iter().map(|P| Some(P.borrow().clone())),
366        )
367        .expect("should return some point")
368    }
369
370    /// Given `static_scalars`, an iterator of public scalars
371    /// \\(b_i\\), `dynamic_scalars`, an iterator of public scalars
372    /// \\(a_i\\), and `dynamic_points`, an iterator of points
373    /// \\(A_i\\), compute
374    /// $$
375    /// Q = a_1 A_1 + \cdots + a_n A_n + b_1 B_1 + \cdots + b_m B_m,
376    /// $$
377    /// where the \\(B_j\\) are the points that were supplied to `new`.
378    ///
379    /// If any of the dynamic points were `None`, return `None`.
380    ///
381    /// It is an error to call this function with iterators of
382    /// inconsistent lengths.
383    ///
384    /// This function is particularly useful when verifying statements
385    /// involving compressed points.  Accepting `Option<Point>` allows
386    /// inlining point decompression into the multiscalar call,
387    /// avoiding the need for temporary buffers.
388    fn optional_mixed_multiscalar_mul<I, J, K>(
389        &self,
390        static_scalars: I,
391        dynamic_scalars: J,
392        dynamic_points: K,
393    ) -> Option<Self::Point>
394    where
395        I: IntoIterator,
396        I::Item: Borrow<Scalar>,
397        J: IntoIterator,
398        J::Item: Borrow<Scalar>,
399        K: IntoIterator<Item = Option<Self::Point>>;
400}
401
402// ------------------------------------------------------------------------
403// Private Traits
404// ------------------------------------------------------------------------
405
406/// Trait for checking whether a point is on the curve.
407///
408/// This trait is only for debugging/testing, since it should be
409/// impossible for a `curve25519-dalek` user to construct an invalid
410/// point.
411#[allow(dead_code)]
412pub(crate) trait ValidityCheck {
413    /// Checks whether the point is on the curve. Not CT.
414    fn is_valid(&self) -> bool;
415}