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}