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