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