1 | // Copyright 2016 Brian Smith. |
2 | // |
3 | // Permission to use, copy, modify, and/or distribute this software for any |
4 | // purpose with or without fee is hereby granted, provided that the above |
5 | // copyright notice and this permission notice appear in all copies. |
6 | // |
7 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES |
8 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
9 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY |
10 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
11 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
12 | // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
13 | // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
14 | |
15 | use crate::{ |
16 | arithmetic::limbs_from_hex, |
17 | arithmetic::montgomery::*, |
18 | constant_time::LeakyWord, |
19 | cpu, |
20 | error::{self, LenMismatchError}, |
21 | limb::*, |
22 | }; |
23 | use core::marker::PhantomData; |
24 | |
25 | use elem::{mul_mont, unary_op, unary_op_assign, unary_op_from_binary_op_assign}; |
26 | |
27 | /// A field element, i.e. an element of ℤ/qℤ for the curve's field modulus |
28 | /// *q*. |
29 | pub type Elem<E> = elem::Elem<Q, E>; |
30 | type PublicElem<E> = elem::PublicElem<Q, E>; |
31 | |
32 | /// Represents the (prime) order *q* of the curve's prime field. |
33 | #[derive (Clone, Copy)] |
34 | pub enum Q {} |
35 | |
36 | /// A scalar. Its value is in [0, n). Zero-valued scalars are forbidden in most |
37 | /// contexts. |
38 | pub type Scalar<E = Unencoded> = elem::Elem<N, E>; |
39 | type PublicScalar<E> = elem::PublicElem<N, E>; |
40 | |
41 | /// Represents the prime order *n* of the curve's group. |
42 | #[derive (Clone, Copy)] |
43 | pub enum N {} |
44 | |
45 | pub(super) struct Modulus<M> { |
46 | // TODO: [Limb; elem::NumLimbs::MAX] |
47 | limbs: &'static [Limb; elem::NumLimbs::MAX], |
48 | num_limbs: elem::NumLimbs, |
49 | cops: &'static CommonOps, |
50 | m: PhantomData<M>, |
51 | cpu: cpu::Features, |
52 | } |
53 | |
54 | pub struct Point { |
55 | // The coordinates are stored in a contiguous array, where the first |
56 | // `ops.num_limbs` elements are the X coordinate, the next |
57 | // `ops.num_limbs` elements are the Y coordinate, and the next |
58 | // `ops.num_limbs` elements are the Z coordinate. This layout is dictated |
59 | // by the requirements of the nistz256 code. |
60 | xyz: [Limb; 3 * elem::NumLimbs::MAX], |
61 | } |
62 | |
63 | impl Point { |
64 | pub fn new_at_infinity() -> Self { |
65 | Self { |
66 | xyz: [0; 3 * elem::NumLimbs::MAX], |
67 | } |
68 | } |
69 | } |
70 | |
71 | /// Operations and values needed by all curve operations. |
72 | pub struct CommonOps { |
73 | num_limbs: elem::NumLimbs, |
74 | q: PublicModulus, |
75 | n: PublicElem<Unencoded>, |
76 | |
77 | pub a: PublicElem<R>, // Must be -3 mod q |
78 | pub b: PublicElem<R>, |
79 | |
80 | // In all cases, `r`, `a`, and `b` may all alias each other. |
81 | elem_mul_mont: unsafe extern "C" fn(r: *mut Limb, a: *const Limb, b: *const Limb), |
82 | elem_sqr_mont: unsafe extern "C" fn(r: *mut Limb, a: *const Limb), |
83 | } |
84 | |
85 | impl CommonOps { |
86 | pub(super) fn elem_modulus(&'static self, cpu_features: cpu::Features) -> Modulus<Q> { |
87 | Modulus { |
88 | // TODO: limbs: self.q.p.map(Limb::from), |
89 | limbs: &self.q.p, |
90 | num_limbs: self.num_limbs, |
91 | cops: self, |
92 | m: PhantomData, |
93 | cpu: cpu_features, |
94 | } |
95 | } |
96 | |
97 | pub(super) fn scalar_modulus(&'static self, cpu_features: cpu::Features) -> Modulus<N> { |
98 | Modulus { |
99 | // TODO: limbs: self.n.limbs.map(Limb::from), |
100 | limbs: &self.n.limbs, |
101 | num_limbs: self.num_limbs, |
102 | cops: self, |
103 | m: PhantomData, |
104 | cpu: cpu_features, |
105 | } |
106 | } |
107 | |
108 | // The length of a field element, which is the same as the length of a |
109 | // scalar, in bytes. |
110 | pub fn len(&self) -> usize { |
111 | // Keep in sync with `Modulus<M>::len()` |
112 | self.num_limbs.into() * LIMB_BYTES |
113 | } |
114 | |
115 | #[cfg (test)] |
116 | pub(super) fn n_limbs(&self) -> &[Limb] { |
117 | &self.n.limbs[..self.num_limbs.into()] |
118 | } |
119 | } |
120 | |
121 | impl<M> Modulus<M> { |
122 | pub fn cpu(&self) -> cpu::Features { |
123 | self.cpu |
124 | } |
125 | |
126 | // Keep in sync with `CommonOps::len()`. |
127 | pub fn bytes_len(&self) -> usize { |
128 | self.num_limbs.into() * LIMB_BYTES |
129 | } |
130 | } |
131 | |
132 | impl<M> Modulus<M> { |
133 | #[inline ] |
134 | pub fn add_assign<E: Encoding>(&self, a: &mut elem::Elem<M, E>, b: &elem::Elem<M, E>) { |
135 | let num_limbs: usize = self.num_limbs.into(); |
136 | limbs_add_assign_mod( |
137 | &mut a.limbs[..num_limbs], |
138 | &b.limbs[..num_limbs], |
139 | &self.limbs[..num_limbs], |
140 | ) |
141 | .unwrap_or_else(op:unwrap_impossible_len_mismatch_error) |
142 | } |
143 | } |
144 | |
145 | impl Modulus<Q> { |
146 | #[inline ] |
147 | pub fn elems_are_equal<E: Encoding>(&self, a: &Elem<E>, b: &Elem<E>) -> LimbMask { |
148 | let num_limbs: usize = self.num_limbs.into(); |
149 | limbs_equal_limbs_consttime(&a.limbs[..num_limbs], &b.limbs[..num_limbs]) |
150 | .unwrap_or_else(op:unwrap_impossible_len_mismatch_error) |
151 | } |
152 | |
153 | #[inline ] |
154 | pub fn elem_unencoded(&self, a: &Elem<R>) -> Elem<Unencoded> { |
155 | self.elem_product(a, &Elem::one()) |
156 | } |
157 | } |
158 | |
159 | impl CommonOps { |
160 | #[inline ] |
161 | fn is_zero<M, E: Encoding>(&self, a: &elem::Elem<M, E>) -> bool { |
162 | let num_limbs = self.num_limbs.into(); |
163 | limbs_are_zero_constant_time(&a.limbs[..num_limbs]).leak() |
164 | } |
165 | |
166 | #[inline ] |
167 | fn elem_mul(&self, a: &mut Elem<R>, b: &Elem<R>, _cpu: cpu::Features) { |
168 | elem::binary_op_assign(self.elem_mul_mont, a, b) |
169 | } |
170 | |
171 | #[inline ] |
172 | fn elem_product<EA: Encoding, EB: Encoding>( |
173 | &self, |
174 | a: &Elem<EA>, |
175 | b: &Elem<EB>, |
176 | _cpu: cpu::Features, |
177 | ) -> Elem<<(EA, EB) as ProductEncoding>::Output> |
178 | where |
179 | (EA, EB): ProductEncoding, |
180 | { |
181 | mul_mont(self.elem_mul_mont, a, b) |
182 | } |
183 | |
184 | #[inline ] |
185 | fn elem_square(&self, a: &mut Elem<R>, _cpu: cpu::Features) { |
186 | unary_op_assign(self.elem_sqr_mont, a); |
187 | } |
188 | |
189 | #[inline ] |
190 | fn elem_squared(&self, a: &Elem<R>, _cpu: cpu::Features) -> Elem<R> { |
191 | unary_op(self.elem_sqr_mont, a) |
192 | } |
193 | } |
194 | |
195 | impl Modulus<Q> { |
196 | #[inline ] |
197 | pub fn elem_mul(&self, a: &mut Elem<R>, b: &Elem<R>) { |
198 | self.cops.elem_mul(a, b, self.cpu) |
199 | } |
200 | |
201 | #[inline ] |
202 | pub fn elem_product<EA: Encoding, EB: Encoding>( |
203 | &self, |
204 | a: &Elem<EA>, |
205 | b: &Elem<EB>, |
206 | ) -> Elem<<(EA, EB) as ProductEncoding>::Output> |
207 | where |
208 | (EA, EB): ProductEncoding, |
209 | { |
210 | self.cops.elem_product(a, b, self.cpu) |
211 | } |
212 | |
213 | #[inline ] |
214 | pub fn elem_square(&self, a: &mut Elem<R>) { |
215 | self.cops.elem_square(a, self.cpu) |
216 | } |
217 | |
218 | #[inline ] |
219 | pub fn elem_squared(&self, a: &Elem<R>) -> Elem<R> { |
220 | self.cops.elem_squared(a, self.cpu) |
221 | } |
222 | } |
223 | |
224 | impl<M> Modulus<M> { |
225 | #[inline ] |
226 | pub fn is_zero<E: Encoding>(&self, a: &elem::Elem<M, E>) -> bool { |
227 | self.cops.is_zero(a) |
228 | } |
229 | } |
230 | |
231 | impl Modulus<Q> { |
232 | pub fn elem_verify_is_not_zero(&self, a: &Elem<R>) -> Result<(), error::Unspecified> { |
233 | if self.is_zero(a) { |
234 | Err(error::Unspecified) |
235 | } else { |
236 | Ok(()) |
237 | } |
238 | } |
239 | |
240 | pub(super) fn a(&self) -> &'static PublicElem<R> { |
241 | &self.cops.a |
242 | } |
243 | pub(super) fn b(&self) -> &'static PublicElem<R> { |
244 | &self.cops.b |
245 | } |
246 | } |
247 | |
248 | impl PrivateKeyOps { |
249 | pub(super) fn point_sum(&self, a: &Point, b: &Point, _cpu: cpu::Features) -> Point { |
250 | let mut r: Point = Point::new_at_infinity(); |
251 | unsafe { |
252 | (self.point_add_jacobian_impl)(r.xyz.as_mut_ptr(), a.xyz.as_ptr(), b.xyz.as_ptr()) |
253 | } |
254 | r |
255 | } |
256 | } |
257 | |
258 | impl Modulus<Q> { |
259 | pub fn point_x(&self, p: &Point) -> Elem<R> { |
260 | let num_limbs: usize = self.num_limbs.into(); |
261 | let mut r: Elem = Elem::zero(); |
262 | r.limbs[..num_limbs].copy_from_slice(&p.xyz[0..num_limbs]); |
263 | r |
264 | } |
265 | |
266 | pub fn point_y(&self, p: &Point) -> Elem<R> { |
267 | let num_limbs: usize = self.num_limbs.into(); |
268 | let mut r: Elem = Elem::zero(); |
269 | r.limbs[..num_limbs].copy_from_slice(&p.xyz[num_limbs..(2 * num_limbs)]); |
270 | r |
271 | } |
272 | |
273 | pub fn point_z(&self, p: &Point) -> Elem<R> { |
274 | let num_limbs: usize = self.num_limbs.into(); |
275 | let mut r: Elem = Elem::zero(); |
276 | r.limbs[..num_limbs].copy_from_slice(&p.xyz[(2 * num_limbs)..(3 * num_limbs)]); |
277 | r |
278 | } |
279 | } |
280 | |
281 | struct PublicModulus { |
282 | p: [LeakyLimb; elem::NumLimbs::MAX], |
283 | rr: PublicElem<RR>, |
284 | } |
285 | |
286 | /// Operations on private keys, for ECDH and ECDSA signing. |
287 | pub struct PrivateKeyOps { |
288 | pub common: &'static CommonOps, |
289 | elem_inv_squared: fn(q: &Modulus<Q>, a: &Elem<R>) -> Elem<R>, |
290 | point_mul_base_impl: fn(a: &Scalar, cpu: cpu::Features) -> Point, |
291 | point_mul_impl: unsafe extern "C" fn( |
292 | r: *mut Limb, // [3][num_limbs] |
293 | p_scalar: *const Limb, // [num_limbs] |
294 | p_x: *const Limb, // [num_limbs] |
295 | p_y: *const Limb, // [num_limbs] |
296 | ), |
297 | point_add_jacobian_impl: unsafe extern "C" fn(r: *mut Limb, a: *const Limb, b: *const Limb), |
298 | } |
299 | |
300 | impl PrivateKeyOps { |
301 | pub fn leak_limbs<'a>(&self, a: &'a Elem<Unencoded>) -> &'a [Limb] { |
302 | &a.limbs[..self.common.num_limbs.into()] |
303 | } |
304 | |
305 | #[inline (always)] |
306 | pub(super) fn point_mul_base(&self, a: &Scalar, cpu: cpu::Features) -> Point { |
307 | (self.point_mul_base_impl)(a, cpu) |
308 | } |
309 | |
310 | #[inline (always)] |
311 | pub(super) fn point_mul( |
312 | &self, |
313 | p_scalar: &Scalar, |
314 | (p_x, p_y): &(Elem<R>, Elem<R>), |
315 | _cpu: cpu::Features, |
316 | ) -> Point { |
317 | let mut r = Point::new_at_infinity(); |
318 | unsafe { |
319 | (self.point_mul_impl)( |
320 | r.xyz.as_mut_ptr(), |
321 | p_scalar.limbs.as_ptr(), |
322 | p_x.limbs.as_ptr(), |
323 | p_y.limbs.as_ptr(), |
324 | ); |
325 | } |
326 | r |
327 | } |
328 | |
329 | #[inline ] |
330 | pub(super) fn elem_inverse_squared(&self, q: &Modulus<Q>, a: &Elem<R>) -> Elem<R> { |
331 | (self.elem_inv_squared)(q, a) |
332 | } |
333 | } |
334 | |
335 | /// Operations and values needed by all operations on public keys (ECDH |
336 | /// agreement and ECDSA verification). |
337 | pub struct PublicKeyOps { |
338 | pub common: &'static CommonOps, |
339 | } |
340 | |
341 | impl PublicKeyOps { |
342 | // The serialized bytes are in big-endian order, zero-padded. The limbs |
343 | // of `Elem` are in the native endianness, least significant limb to |
344 | // most significant limb. Besides the parsing, conversion, this also |
345 | // implements NIST SP 800-56A Step 2: "Verify that xQ and yQ are integers |
346 | // in the interval [0, p-1] in the case that q is an odd prime p[.]" |
347 | pub(super) fn elem_parse( |
348 | &self, |
349 | q: &Modulus<Q>, |
350 | input: &mut untrusted::Reader, |
351 | ) -> Result<Elem<R>, error::Unspecified> { |
352 | let _cpu = cpu::features(); |
353 | let encoded_value = input.read_bytes(self.common.len())?; |
354 | let parsed = elem_parse_big_endian_fixed_consttime(q, encoded_value)?; |
355 | let mut r = Elem::zero(); |
356 | let rr = Elem::from(&self.common.q.rr); |
357 | // Montgomery encode (elem_to_mont). |
358 | // TODO: do something about this. |
359 | unsafe { |
360 | (self.common.elem_mul_mont)( |
361 | r.limbs.as_mut_ptr(), |
362 | parsed.limbs.as_ptr(), |
363 | rr.limbs.as_ptr(), |
364 | ) |
365 | } |
366 | Ok(r) |
367 | } |
368 | } |
369 | |
370 | // Operations used by both ECDSA signing and ECDSA verification. In general |
371 | // these must be side-channel resistant. |
372 | pub struct ScalarOps { |
373 | pub common: &'static CommonOps, |
374 | |
375 | scalar_mul_mont: unsafe extern "C" fn(r: *mut Limb, a: *const Limb, b: *const Limb), |
376 | } |
377 | |
378 | impl ScalarOps { |
379 | pub(super) fn scalar_modulus(&'static self, cpu_features: cpu::Features) -> Modulus<N> { |
380 | self.common.scalar_modulus(cpu_features) |
381 | } |
382 | |
383 | // The (maximum) length of a scalar, not including any padding. |
384 | pub fn scalar_bytes_len(&self) -> usize { |
385 | self.common.len() |
386 | } |
387 | } |
388 | |
389 | impl ScalarOps { |
390 | pub fn leak_limbs<'s>(&self, s: &'s Scalar) -> &'s [Limb] { |
391 | &s.limbs[..self.common.num_limbs.into()] |
392 | } |
393 | |
394 | #[inline ] |
395 | pub(super) fn scalar_product<EA: Encoding, EB: Encoding>( |
396 | &self, |
397 | a: &Scalar<EA>, |
398 | b: &Scalar<EB>, |
399 | _cpu: cpu::Features, |
400 | ) -> Scalar<<(EA, EB) as ProductEncoding>::Output> |
401 | where |
402 | (EA, EB): ProductEncoding, |
403 | { |
404 | mul_mont(self.scalar_mul_mont, a, b) |
405 | } |
406 | } |
407 | |
408 | /// Operations on public scalars needed by ECDSA signature verification. |
409 | pub struct PublicScalarOps { |
410 | pub scalar_ops: &'static ScalarOps, |
411 | pub public_key_ops: &'static PublicKeyOps, |
412 | |
413 | pub(super) twin_mul: fn( |
414 | g_scalar: &Scalar, |
415 | p_scalar: &Scalar, |
416 | p_xy: &(Elem<R>, Elem<R>), |
417 | cpu: cpu::Features, |
418 | ) -> Point, |
419 | scalar_inv_to_mont_vartime: fn(s: &Scalar<Unencoded>, cpu: cpu::Features) -> Scalar<R>, |
420 | pub(super) q_minus_n: PublicElem<Unencoded>, |
421 | } |
422 | |
423 | impl PublicScalarOps { |
424 | pub fn n(&self) -> &PublicElem<Unencoded> { |
425 | &self.scalar_ops.common.n |
426 | } |
427 | |
428 | #[inline ] |
429 | pub fn scalar_as_elem(&self, a: &Scalar) -> Elem<Unencoded> { |
430 | Elem { |
431 | limbs: a.limbs, |
432 | m: PhantomData, |
433 | encoding: PhantomData, |
434 | } |
435 | } |
436 | } |
437 | |
438 | impl Modulus<Q> { |
439 | pub fn elem_less_than_vartime(&self, a: &Elem<Unencoded>, b: &PublicElem<Unencoded>) -> bool { |
440 | let num_limbs: usize = self.num_limbs.into(); |
441 | limbs_less_than_limbs_vartime(&a.limbs[..num_limbs], &b.limbs[..num_limbs]) |
442 | .unwrap_or_else(|LenMismatchError { .. }| unreachable!()) |
443 | } |
444 | } |
445 | |
446 | impl PublicScalarOps { |
447 | pub(super) fn scalar_inv_to_mont_vartime( |
448 | &self, |
449 | s: &Scalar<Unencoded>, |
450 | cpu: cpu::Features, |
451 | ) -> Scalar<R> { |
452 | (self.scalar_inv_to_mont_vartime)(s, cpu) |
453 | } |
454 | } |
455 | |
456 | #[allow (non_snake_case)] |
457 | pub struct PrivateScalarOps { |
458 | pub scalar_ops: &'static ScalarOps, |
459 | |
460 | oneRR_mod_n: PublicScalar<RR>, // 1 * R**2 (mod n). TOOD: Use One<RR>. |
461 | scalar_inv_to_mont: fn(a: Scalar<R>, cpu: cpu::Features) -> Scalar<R>, |
462 | } |
463 | |
464 | impl PrivateScalarOps { |
465 | pub(super) fn to_mont(&self, s: &Scalar<Unencoded>, cpu: cpu::Features) -> Scalar<R> { |
466 | self.scalar_ops |
467 | .scalar_product(a:s, &Scalar::from(&self.oneRR_mod_n), cpu) |
468 | } |
469 | |
470 | /// Returns the modular inverse of `a` (mod `n`). Panics if `a` is zero. |
471 | pub(super) fn scalar_inv_to_mont(&self, a: &Scalar, cpu: cpu::Features) -> Scalar<R> { |
472 | assert!(!self.scalar_ops.common.is_zero(a)); |
473 | let a: Elem = self.to_mont(s:a, cpu); |
474 | (self.scalar_inv_to_mont)(a, cpu) |
475 | } |
476 | } |
477 | |
478 | // XXX: Inefficient and unnecessarily depends on `PrivateKeyOps`. TODO: implement interleaved wNAF |
479 | // multiplication. |
480 | fn twin_mul_inefficient( |
481 | ops: &PrivateKeyOps, |
482 | g_scalar: &Scalar, |
483 | p_scalar: &Scalar, |
484 | p_xy: &(Elem<R>, Elem<R>), |
485 | cpu: cpu::Features, |
486 | ) -> Point { |
487 | let scaled_g: Point = ops.point_mul_base(a:g_scalar, cpu); |
488 | let scaled_p: Point = ops.point_mul(p_scalar, p_xy, cpu); |
489 | ops.point_sum(&scaled_g, &scaled_p, cpu) |
490 | } |
491 | |
492 | // This assumes n < q < 2*n. |
493 | impl Modulus<N> { |
494 | pub fn elem_reduced_to_scalar(&self, elem: &Elem<Unencoded>) -> Scalar<Unencoded> { |
495 | let num_limbs: usize = self.num_limbs.into(); |
496 | let mut r_limbs: [u64; _] = elem.limbs; |
497 | limbs_reduce_once_constant_time(&mut r_limbs[..num_limbs], &self.limbs[..num_limbs]) |
498 | .unwrap_or_else(op:unwrap_impossible_len_mismatch_error); |
499 | Scalar { |
500 | limbs: r_limbs, |
501 | m: PhantomData, |
502 | encoding: PhantomData, |
503 | } |
504 | } |
505 | } |
506 | |
507 | // Returns (`a` squared `squarings` times) * `b`. |
508 | fn elem_sqr_mul( |
509 | ops: &CommonOps, |
510 | a: &Elem<R>, |
511 | squarings: LeakyWord, |
512 | b: &Elem<R>, |
513 | cpu: cpu::Features, |
514 | ) -> Elem<R> { |
515 | debug_assert!(squarings >= 1); |
516 | let mut tmp: Elem = ops.elem_squared(a, cpu); |
517 | for _ in 1..squarings { |
518 | ops.elem_square(&mut tmp, cpu); |
519 | } |
520 | ops.elem_product(&tmp, b, cpu) |
521 | } |
522 | |
523 | // Sets `acc` = (`acc` squared `squarings` times) * `b`. |
524 | fn elem_sqr_mul_acc( |
525 | ops: &CommonOps, |
526 | acc: &mut Elem<R>, |
527 | squarings: LeakyWord, |
528 | b: &Elem<R>, |
529 | cpu: cpu::Features, |
530 | ) { |
531 | debug_assert!(squarings >= 1); |
532 | for _ in 0..squarings { |
533 | ops.elem_square(a:acc, cpu); |
534 | } |
535 | ops.elem_mul(a:acc, b, cpu) |
536 | } |
537 | |
538 | #[inline ] |
539 | pub(super) fn elem_parse_big_endian_fixed_consttime( |
540 | q: &Modulus<Q>, |
541 | bytes: untrusted::Input, |
542 | ) -> Result<Elem<Unencoded>, error::Unspecified> { |
543 | parse_big_endian_fixed_consttime(m:q, bytes, AllowZero::Yes) |
544 | } |
545 | |
546 | #[inline ] |
547 | pub(super) fn scalar_parse_big_endian_fixed_consttime( |
548 | n: &Modulus<N>, |
549 | bytes: untrusted::Input, |
550 | ) -> Result<Scalar, error::Unspecified> { |
551 | parse_big_endian_fixed_consttime(m:n, bytes, AllowZero::No) |
552 | } |
553 | |
554 | #[inline ] |
555 | pub(super) fn scalar_parse_big_endian_variable( |
556 | n: &Modulus<N>, |
557 | allow_zero: AllowZero, |
558 | bytes: untrusted::Input, |
559 | ) -> Result<Scalar, error::Unspecified> { |
560 | let num_limbs: usize = n.num_limbs.into(); |
561 | let mut r: Elem = Scalar::zero(); |
562 | parse_big_endian_in_range_and_pad_consttime( |
563 | input:bytes, |
564 | allow_zero, |
565 | &n.limbs[..num_limbs], |
566 | &mut r.limbs[..num_limbs], |
567 | )?; |
568 | Ok(r) |
569 | } |
570 | |
571 | pub(super) fn scalar_parse_big_endian_partially_reduced_variable_consttime( |
572 | n: &Modulus<N>, |
573 | bytes: untrusted::Input, |
574 | ) -> Result<Scalar, error::Unspecified> { |
575 | let num_limbs: usize = n.num_limbs.into(); |
576 | let mut r: Elem = Scalar::zero(); |
577 | { |
578 | let r: &mut [u64] = &mut r.limbs[..num_limbs]; |
579 | parse_big_endian_and_pad_consttime(input:bytes, result:r)?; |
580 | limbs_reduce_once_constant_time(r, &n.limbs[..num_limbs]) |
581 | .unwrap_or_else(op:unwrap_impossible_len_mismatch_error); |
582 | } |
583 | |
584 | Ok(r) |
585 | } |
586 | |
587 | fn parse_big_endian_fixed_consttime<M>( |
588 | m: &Modulus<M>, |
589 | bytes: untrusted::Input, |
590 | allow_zero: AllowZero, |
591 | ) -> Result<elem::Elem<M, Unencoded>, error::Unspecified> { |
592 | let num_limbs: usize = m.num_limbs.into(); |
593 | if bytes.len() != m.bytes_len() { |
594 | return Err(error::Unspecified); |
595 | } |
596 | let mut r: Elem = elem::Elem::zero(); |
597 | parse_big_endian_in_range_and_pad_consttime( |
598 | input:bytes, |
599 | allow_zero, |
600 | &m.limbs[..num_limbs], |
601 | &mut r.limbs[..num_limbs], |
602 | )?; |
603 | Ok(r) |
604 | } |
605 | |
606 | #[cold ] |
607 | #[inline (never)] |
608 | fn unwrap_impossible_len_mismatch_error<T>(LenMismatchError { .. }: LenMismatchError) -> T { |
609 | unreachable!() |
610 | } |
611 | |
612 | #[cfg (test)] |
613 | mod tests { |
614 | extern crate alloc; |
615 | use super::*; |
616 | use crate::test; |
617 | use alloc::{format, vec, vec::Vec}; |
618 | |
619 | const ZERO_SCALAR: Scalar = Scalar { |
620 | limbs: [0; elem::NumLimbs::MAX], |
621 | m: PhantomData, |
622 | encoding: PhantomData, |
623 | }; |
624 | |
625 | trait Convert<E: Encoding> { |
626 | fn convert(self, q: &Modulus<Q>) -> Elem<E>; |
627 | } |
628 | |
629 | impl Convert<R> for Elem<R> { |
630 | fn convert(self, _q: &Modulus<Q>) -> Elem<R> { |
631 | self |
632 | } |
633 | } |
634 | |
635 | impl Convert<Unencoded> for Elem<R> { |
636 | fn convert(self, q: &Modulus<Q>) -> Elem<Unencoded> { |
637 | q.elem_unencoded(&self) |
638 | } |
639 | } |
640 | |
641 | fn q_minus_n_plus_n_equals_0_test(ops: &PublicScalarOps) { |
642 | let cops = ops.scalar_ops.common; |
643 | let q = &cops.elem_modulus(cpu::features()); |
644 | let mut x = Elem::from(&ops.q_minus_n); |
645 | q.add_assign(&mut x, &Elem::from(&cops.n)); |
646 | assert!(q.is_zero(&x)); |
647 | } |
648 | |
649 | #[test ] |
650 | fn p256_q_minus_n_plus_n_equals_0_test() { |
651 | q_minus_n_plus_n_equals_0_test(&p256::PUBLIC_SCALAR_OPS); |
652 | } |
653 | |
654 | #[test ] |
655 | fn p384_q_minus_n_plus_n_equals_0_test() { |
656 | q_minus_n_plus_n_equals_0_test(&p384::PUBLIC_SCALAR_OPS); |
657 | } |
658 | |
659 | #[test ] |
660 | fn p256_elem_add_test() { |
661 | elem_add_test( |
662 | &p256::PUBLIC_SCALAR_OPS, |
663 | test_file!("ops/p256_elem_sum_tests.txt" ), |
664 | ); |
665 | } |
666 | |
667 | #[test ] |
668 | fn p384_elem_add_test() { |
669 | elem_add_test( |
670 | &p384::PUBLIC_SCALAR_OPS, |
671 | test_file!("ops/p384_elem_sum_tests.txt" ), |
672 | ); |
673 | } |
674 | |
675 | fn elem_add_test(ops: &PublicScalarOps, test_file: test::File) { |
676 | let cops = ops.public_key_ops.common; |
677 | let q = &cops.elem_modulus(cpu::features()); |
678 | test::run(test_file, |section, test_case| { |
679 | assert_eq!(section, "" ); |
680 | |
681 | let a = consume_elem(q, test_case , "a" ); |
682 | let b = consume_elem(q, test_case , "b" ); |
683 | let expected_sum = consume_elem(q, test_case , "r" ); |
684 | |
685 | let mut actual_sum = a; |
686 | q.add_assign(&mut actual_sum, &b); |
687 | assert_limbs_are_equal(cops, &actual_sum.limbs, &expected_sum.limbs); |
688 | |
689 | let mut actual_sum = b; |
690 | q.add_assign(&mut actual_sum, &a); |
691 | assert_limbs_are_equal(cops, &actual_sum.limbs, &expected_sum.limbs); |
692 | |
693 | Ok(()) |
694 | }) |
695 | } |
696 | |
697 | // XXX: There's no `p256_sub` in *ring*; it's logic is inlined into |
698 | // the point arithmetic functions. Thus, we can't test it. |
699 | |
700 | #[test ] |
701 | fn p384_elem_sub_test() { |
702 | prefixed_extern! { |
703 | fn p384_elem_sub(r: *mut Limb, a: *const Limb, b: *const Limb); |
704 | } |
705 | elem_sub_test( |
706 | &p384::COMMON_OPS, |
707 | p384_elem_sub, |
708 | test_file!("ops/p384_elem_sum_tests.txt" ), |
709 | ); |
710 | } |
711 | |
712 | fn elem_sub_test( |
713 | ops: &'static CommonOps, |
714 | elem_sub: unsafe extern "C" fn(r: *mut Limb, a: *const Limb, b: *const Limb), |
715 | test_file: test::File, |
716 | ) { |
717 | let q = &ops.elem_modulus(cpu::features()); |
718 | test::run(test_file, |section, test_case| { |
719 | assert_eq!(section, "" ); |
720 | |
721 | let a = consume_elem(q, test_case , "a" ); |
722 | let b = consume_elem(q, test_case , "b" ); |
723 | let r = consume_elem(q, test_case , "r" ); |
724 | |
725 | let mut actual_difference = Elem::<R>::zero(); |
726 | unsafe { |
727 | elem_sub( |
728 | actual_difference.limbs.as_mut_ptr(), |
729 | r.limbs.as_ptr(), |
730 | b.limbs.as_ptr(), |
731 | ); |
732 | } |
733 | assert_limbs_are_equal(ops, &actual_difference.limbs, &a.limbs); |
734 | |
735 | let mut actual_difference = Elem::<R>::zero(); |
736 | unsafe { |
737 | elem_sub( |
738 | actual_difference.limbs.as_mut_ptr(), |
739 | r.limbs.as_ptr(), |
740 | a.limbs.as_ptr(), |
741 | ); |
742 | } |
743 | assert_limbs_are_equal(ops, &actual_difference.limbs, &b.limbs); |
744 | |
745 | Ok(()) |
746 | }) |
747 | } |
748 | |
749 | // XXX: There's no `p256_div_by_2` in *ring*; it's logic is inlined |
750 | // into the point arithmetic functions. Thus, we can't test it. |
751 | |
752 | #[test ] |
753 | fn p384_elem_div_by_2_test() { |
754 | prefixed_extern! { |
755 | fn p384_elem_div_by_2(r: *mut Limb, a: *const Limb); |
756 | } |
757 | elem_div_by_2_test( |
758 | &p384::COMMON_OPS, |
759 | p384_elem_div_by_2, |
760 | test_file!("ops/p384_elem_div_by_2_tests.txt" ), |
761 | ); |
762 | } |
763 | |
764 | fn elem_div_by_2_test( |
765 | ops: &'static CommonOps, |
766 | elem_div_by_2: unsafe extern "C" fn(r: *mut Limb, a: *const Limb), |
767 | test_file: test::File, |
768 | ) { |
769 | let q = &ops.elem_modulus(cpu::features()); |
770 | test::run(test_file, |section, test_case| { |
771 | assert_eq!(section, "" ); |
772 | |
773 | let a = consume_elem(q, test_case , "a" ); |
774 | let r = consume_elem(q, test_case , "r" ); |
775 | |
776 | let mut actual_result = Elem::<R>::zero(); |
777 | unsafe { |
778 | elem_div_by_2(actual_result.limbs.as_mut_ptr(), a.limbs.as_ptr()); |
779 | } |
780 | assert_limbs_are_equal(ops, &actual_result.limbs, &r.limbs); |
781 | |
782 | Ok(()) |
783 | }) |
784 | } |
785 | |
786 | // There is no `ecp_nistz256_neg` on other targets. |
787 | #[cfg (target_arch = "x86_64" )] |
788 | #[test ] |
789 | fn p256_elem_neg_test() { |
790 | prefixed_extern! { |
791 | fn ecp_nistz256_neg(r: *mut Limb, a: *const Limb); |
792 | } |
793 | elem_neg_test( |
794 | &p256::COMMON_OPS, |
795 | ecp_nistz256_neg, |
796 | test_file!("ops/p256_elem_neg_tests.txt" ), |
797 | ); |
798 | } |
799 | |
800 | #[test ] |
801 | fn p384_elem_neg_test() { |
802 | prefixed_extern! { |
803 | fn p384_elem_neg(r: *mut Limb, a: *const Limb); |
804 | } |
805 | elem_neg_test( |
806 | &p384::COMMON_OPS, |
807 | p384_elem_neg, |
808 | test_file!("ops/p384_elem_neg_tests.txt" ), |
809 | ); |
810 | } |
811 | |
812 | fn elem_neg_test( |
813 | ops: &'static CommonOps, |
814 | elem_neg: unsafe extern "C" fn(r: *mut Limb, a: *const Limb), |
815 | test_file: test::File, |
816 | ) { |
817 | let q = &ops.elem_modulus(cpu::features()); |
818 | test::run(test_file, |section, test_case| { |
819 | assert_eq!(section, "" ); |
820 | |
821 | let a = consume_elem(q, test_case , "a" ); |
822 | let b = consume_elem(q, test_case , "b" ); |
823 | |
824 | // Verify -a == b. |
825 | { |
826 | let mut actual_result = Elem::<R>::zero(); |
827 | unsafe { |
828 | elem_neg(actual_result.limbs.as_mut_ptr(), a.limbs.as_ptr()); |
829 | } |
830 | assert_limbs_are_equal(ops, &actual_result.limbs, &b.limbs); |
831 | } |
832 | |
833 | // Verify -b == a. |
834 | { |
835 | let mut actual_result = Elem::<R>::zero(); |
836 | unsafe { |
837 | elem_neg(actual_result.limbs.as_mut_ptr(), b.limbs.as_ptr()); |
838 | } |
839 | assert_limbs_are_equal(ops, &actual_result.limbs, &a.limbs); |
840 | } |
841 | |
842 | Ok(()) |
843 | }) |
844 | } |
845 | |
846 | #[test ] |
847 | fn p256_elem_mul_test() { |
848 | elem_mul_test(&p256::COMMON_OPS, test_file!("ops/p256_elem_mul_tests.txt" )); |
849 | } |
850 | |
851 | #[test ] |
852 | fn p384_elem_mul_test() { |
853 | elem_mul_test(&p384::COMMON_OPS, test_file!("ops/p384_elem_mul_tests.txt" )); |
854 | } |
855 | |
856 | fn elem_mul_test(ops: &'static CommonOps, test_file: test::File) { |
857 | let q = &ops.elem_modulus(cpu::features()); |
858 | test::run(test_file, |section, test_case| { |
859 | assert_eq!(section, "" ); |
860 | |
861 | let mut a = consume_elem(q, test_case , "a" ); |
862 | let b = consume_elem(q, test_case , "b" ); |
863 | let r = consume_elem(q, test_case , "r" ); |
864 | q.elem_mul(&mut a, &b); |
865 | assert_limbs_are_equal(ops, &a.limbs, &r.limbs); |
866 | |
867 | Ok(()) |
868 | }) |
869 | } |
870 | |
871 | #[test ] |
872 | fn p256_scalar_mul_test() { |
873 | scalar_mul_test( |
874 | &p256::SCALAR_OPS, |
875 | test_file!("ops/p256_scalar_mul_tests.txt" ), |
876 | ); |
877 | } |
878 | |
879 | #[test ] |
880 | fn p384_scalar_mul_test() { |
881 | scalar_mul_test( |
882 | &p384::SCALAR_OPS, |
883 | test_file!("ops/p384_scalar_mul_tests.txt" ), |
884 | ); |
885 | } |
886 | |
887 | fn scalar_mul_test(ops: &ScalarOps, test_file: test::File) { |
888 | let cpu = cpu::features(); |
889 | let cops = ops.common; |
890 | let n = &cops.scalar_modulus(cpu); |
891 | test::run(test_file, |section, test_case| { |
892 | assert_eq!(section, "" ); |
893 | let a = consume_scalar(n, test_case , "a" ); |
894 | let b = consume_scalar_mont(n, test_case , "b" ); |
895 | let expected_result = consume_scalar(n, test_case , "r" ); |
896 | let actual_result = ops.scalar_product(&a, &b, cpu); |
897 | assert_limbs_are_equal(cops, &actual_result.limbs, &expected_result.limbs); |
898 | |
899 | Ok(()) |
900 | }) |
901 | } |
902 | |
903 | #[test ] |
904 | fn p256_scalar_square_test() { |
905 | prefixed_extern! { |
906 | fn p256_scalar_sqr_rep_mont(r: *mut Limb, a: *const Limb, rep: LeakyWord); |
907 | } |
908 | scalar_square_test( |
909 | &p256::SCALAR_OPS, |
910 | p256_scalar_sqr_rep_mont, |
911 | test_file!("ops/p256_scalar_square_tests.txt" ), |
912 | ); |
913 | } |
914 | |
915 | // XXX: There's no `p384_scalar_square_test()` because there's no dedicated |
916 | // `p384_scalar_sqr_rep_mont()`. |
917 | |
918 | fn scalar_square_test( |
919 | ops: &ScalarOps, |
920 | sqr_rep: unsafe extern "C" fn(r: *mut Limb, a: *const Limb, rep: LeakyWord), |
921 | test_file: test::File, |
922 | ) { |
923 | let cpu = cpu::features(); |
924 | let cops = ops.common; |
925 | let n = &cops.scalar_modulus(cpu); |
926 | test::run(test_file, |section, test_case| { |
927 | assert_eq!(section, "" ); |
928 | let cpu = cpu::features(); |
929 | let a = consume_scalar(n, test_case , "a" ); |
930 | let expected_result = consume_scalar(n, test_case , "r" ); |
931 | |
932 | { |
933 | let mut actual_result: Scalar<R> = Scalar { |
934 | limbs: [0; elem::NumLimbs::MAX], |
935 | m: PhantomData, |
936 | encoding: PhantomData, |
937 | }; |
938 | unsafe { |
939 | sqr_rep(actual_result.limbs.as_mut_ptr(), a.limbs.as_ptr(), 1); |
940 | } |
941 | assert_limbs_are_equal(cops, &actual_result.limbs, &expected_result.limbs); |
942 | } |
943 | |
944 | { |
945 | let actual_result = ops.scalar_product(&a, &a, cpu); |
946 | assert_limbs_are_equal(cops, &actual_result.limbs, &expected_result.limbs); |
947 | } |
948 | |
949 | Ok(()) |
950 | }) |
951 | } |
952 | |
953 | #[test ] |
954 | #[should_panic (expected = "!self.scalar_ops.common.is_zero(a)" )] |
955 | fn p256_scalar_inv_to_mont_zero_panic_test() { |
956 | let _ = p256::PRIVATE_SCALAR_OPS.scalar_inv_to_mont(&ZERO_SCALAR, cpu::features()); |
957 | } |
958 | |
959 | #[test ] |
960 | #[should_panic (expected = "!self.scalar_ops.common.is_zero(a)" )] |
961 | fn p384_scalar_inv_to_mont_zero_panic_test() { |
962 | let _ = p384::PRIVATE_SCALAR_OPS.scalar_inv_to_mont(&ZERO_SCALAR, cpu::features()); |
963 | } |
964 | |
965 | #[test ] |
966 | fn p256_point_sum_test() { |
967 | point_sum_test( |
968 | &p256::PRIVATE_KEY_OPS, |
969 | test_file!("ops/p256_point_sum_tests.txt" ), |
970 | ); |
971 | } |
972 | |
973 | #[test ] |
974 | fn p384_point_sum_test() { |
975 | point_sum_test( |
976 | &p384::PRIVATE_KEY_OPS, |
977 | test_file!("ops/p384_point_sum_tests.txt" ), |
978 | ); |
979 | } |
980 | |
981 | fn point_sum_test(ops: &PrivateKeyOps, test_file: test::File) { |
982 | let cpu = cpu::features(); |
983 | |
984 | test::run(test_file, |section, test_case| { |
985 | assert_eq!(section, "" ); |
986 | |
987 | let a = consume_jacobian_point(ops, test_case , "a" ); |
988 | let b = consume_jacobian_point(ops, test_case , "b" ); |
989 | let r_expected: TestPoint<R> = consume_point(ops, test_case , "r" ); |
990 | |
991 | let r_actual = ops.point_sum(&a, &b, cpu); |
992 | assert_point_actual_equals_expected(ops, &r_actual, &r_expected); |
993 | |
994 | Ok(()) |
995 | }); |
996 | } |
997 | |
998 | #[test ] |
999 | fn p256_point_sum_mixed_test() { |
1000 | prefixed_extern! { |
1001 | fn p256_point_add_affine( |
1002 | r: *mut Limb, // [p256::COMMON_OPS.num_limbs*3] |
1003 | a: *const Limb, // [p256::COMMON_OPS.num_limbs*3] |
1004 | b: *const Limb, // [p256::COMMON_OPS.num_limbs*2] |
1005 | ); |
1006 | } |
1007 | point_sum_mixed_test( |
1008 | &p256::PRIVATE_KEY_OPS, |
1009 | p256_point_add_affine, |
1010 | test_file!("ops/p256_point_sum_mixed_tests.txt" ), |
1011 | ); |
1012 | } |
1013 | |
1014 | // XXX: There is no `nistz384_point_add_affine()`. |
1015 | |
1016 | fn point_sum_mixed_test( |
1017 | ops: &PrivateKeyOps, |
1018 | point_add_affine: unsafe extern "C" fn( |
1019 | r: *mut Limb, // [ops.num_limbs*3] |
1020 | a: *const Limb, // [ops.num_limbs*3] |
1021 | b: *const Limb, // [ops.num_limbs*2] |
1022 | ), |
1023 | test_file: test::File, |
1024 | ) { |
1025 | test::run(test_file, |section, test_case| { |
1026 | assert_eq!(section, "" ); |
1027 | |
1028 | let a = consume_jacobian_point(ops, test_case , "a" ); |
1029 | let b = consume_affine_point(ops, test_case , "b" ); |
1030 | let r_expected: TestPoint<R> = consume_point(ops, test_case , "r" ); |
1031 | |
1032 | let mut r_actual = Point::new_at_infinity(); |
1033 | unsafe { |
1034 | point_add_affine(r_actual.xyz.as_mut_ptr(), a.xyz.as_ptr(), b.xy.as_ptr()); |
1035 | } |
1036 | |
1037 | assert_point_actual_equals_expected(ops, &r_actual, &r_expected); |
1038 | |
1039 | Ok(()) |
1040 | }); |
1041 | } |
1042 | |
1043 | #[test ] |
1044 | fn p256_point_double_test() { |
1045 | prefixed_extern! { |
1046 | fn p256_point_double( |
1047 | r: *mut Limb, // [p256::COMMON_OPS.num_limbs*3] |
1048 | a: *const Limb, // [p256::COMMON_OPS.num_limbs*3] |
1049 | ); |
1050 | } |
1051 | point_double_test( |
1052 | &p256::PRIVATE_KEY_OPS, |
1053 | p256_point_double, |
1054 | test_file!("ops/p256_point_double_tests.txt" ), |
1055 | ); |
1056 | } |
1057 | |
1058 | #[test ] |
1059 | fn p384_point_double_test() { |
1060 | prefixed_extern! { |
1061 | fn p384_point_double( |
1062 | r: *mut Limb, // [p384::COMMON_OPS.num_limbs*3] |
1063 | a: *const Limb, // [p384::COMMON_OPS.num_limbs*3] |
1064 | ); |
1065 | } |
1066 | point_double_test( |
1067 | &p384::PRIVATE_KEY_OPS, |
1068 | p384_point_double, |
1069 | test_file!("ops/p384_point_double_tests.txt" ), |
1070 | ); |
1071 | } |
1072 | |
1073 | fn point_double_test( |
1074 | ops: &PrivateKeyOps, |
1075 | point_double: unsafe extern "C" fn( |
1076 | r: *mut Limb, // [ops.num_limbs*3] |
1077 | a: *const Limb, // [ops.num_limbs*3] |
1078 | ), |
1079 | test_file: test::File, |
1080 | ) { |
1081 | test::run(test_file, |section, test_case| { |
1082 | assert_eq!(section, "" ); |
1083 | |
1084 | let a = consume_jacobian_point(ops, test_case , "a" ); |
1085 | let r_expected: TestPoint<R> = consume_point(ops, test_case , "r" ); |
1086 | |
1087 | let mut r_actual = Point::new_at_infinity(); |
1088 | unsafe { |
1089 | point_double(r_actual.xyz.as_mut_ptr(), a.xyz.as_ptr()); |
1090 | } |
1091 | |
1092 | assert_point_actual_equals_expected(ops, &r_actual, &r_expected); |
1093 | |
1094 | Ok(()) |
1095 | }); |
1096 | } |
1097 | |
1098 | /// TODO: We should be testing `point_mul` with points other than the generator. |
1099 | #[test ] |
1100 | fn p256_point_mul_test() { |
1101 | let generator = ( |
1102 | Elem::from(&p256::GENERATOR.0), |
1103 | Elem::from(&p256::GENERATOR.1), |
1104 | ); |
1105 | point_mul_base_tests( |
1106 | &p256::PRIVATE_KEY_OPS, |
1107 | |s, cpu| p256::PRIVATE_KEY_OPS.point_mul(s, &generator, cpu), |
1108 | test_file!("ops/p256_point_mul_base_tests.txt" ), |
1109 | ); |
1110 | } |
1111 | |
1112 | /// TODO: We should be testing `point_mul` with points other than the generator. |
1113 | #[test ] |
1114 | fn p384_point_mul_test() { |
1115 | let generator = ( |
1116 | Elem::from(&p384::GENERATOR.0), |
1117 | Elem::from(&p384::GENERATOR.1), |
1118 | ); |
1119 | |
1120 | point_mul_base_tests( |
1121 | &p384::PRIVATE_KEY_OPS, |
1122 | |s, cpu| p384::PRIVATE_KEY_OPS.point_mul(s, &generator, cpu), |
1123 | test_file!("ops/p384_point_mul_base_tests.txt" ), |
1124 | ); |
1125 | } |
1126 | |
1127 | #[test ] |
1128 | fn p256_point_mul_serialized_test() { |
1129 | point_mul_serialized_test( |
1130 | &p256::PRIVATE_KEY_OPS, |
1131 | &p256::PUBLIC_KEY_OPS, |
1132 | test_file!("ops/p256_point_mul_serialized_tests.txt" ), |
1133 | ); |
1134 | } |
1135 | |
1136 | fn point_mul_serialized_test( |
1137 | priv_ops: &PrivateKeyOps, |
1138 | pub_ops: &PublicKeyOps, |
1139 | test_file: test::File, |
1140 | ) { |
1141 | let cpu = cpu::features(); |
1142 | let cops = pub_ops.common; |
1143 | let q = &cops.elem_modulus(cpu); |
1144 | let n = &cops.scalar_modulus(cpu); |
1145 | test::run(test_file, |section, test_case| { |
1146 | assert_eq!(section, "" ); |
1147 | let p_scalar = consume_scalar(n, test_case , "p_scalar" ); |
1148 | |
1149 | let p = test_case .consume_bytes("p" ); |
1150 | let p = super::super::public_key::parse_uncompressed_point( |
1151 | pub_ops, |
1152 | q, |
1153 | untrusted::Input::from(&p), |
1154 | ) |
1155 | .expect("valid point" ); |
1156 | |
1157 | let expected_result = test_case .consume_bytes("r" ); |
1158 | |
1159 | let product = priv_ops.point_mul(&p_scalar, &p, cpu::features()); |
1160 | |
1161 | let mut actual_result = vec![4u8; 1 + (2 * cops.len())]; |
1162 | { |
1163 | let (x, y) = actual_result[1..].split_at_mut(cops.len()); |
1164 | super::super::private_key::big_endian_affine_from_jacobian( |
1165 | priv_ops, |
1166 | q, |
1167 | x, |
1168 | Some(y), |
1169 | &product, |
1170 | ) |
1171 | .expect("successful encoding" ); |
1172 | } |
1173 | |
1174 | assert_eq!(expected_result, actual_result); |
1175 | |
1176 | Ok(()) |
1177 | }) |
1178 | } |
1179 | |
1180 | #[test ] |
1181 | fn p256_point_mul_base_test() { |
1182 | point_mul_base_tests( |
1183 | &p256::PRIVATE_KEY_OPS, |
1184 | |s, cpu| p256::PRIVATE_KEY_OPS.point_mul_base(s, cpu), |
1185 | test_file!("ops/p256_point_mul_base_tests.txt" ), |
1186 | ); |
1187 | } |
1188 | |
1189 | #[test ] |
1190 | fn p384_point_mul_base_test() { |
1191 | point_mul_base_tests( |
1192 | &p384::PRIVATE_KEY_OPS, |
1193 | |s, cpu| p384::PRIVATE_KEY_OPS.point_mul_base(s, cpu), |
1194 | test_file!("ops/p384_point_mul_base_tests.txt" ), |
1195 | ); |
1196 | } |
1197 | |
1198 | pub(super) fn point_mul_base_tests( |
1199 | ops: &PrivateKeyOps, |
1200 | f: impl Fn(&Scalar, cpu::Features) -> Point, |
1201 | test_file: test::File, |
1202 | ) { |
1203 | let cpu = cpu::features(); |
1204 | let n = &ops.common.scalar_modulus(cpu); |
1205 | test::run(test_file, |section, test_case| { |
1206 | assert_eq!(section, "" ); |
1207 | let g_scalar = consume_scalar(n, test_case , "g_scalar" ); |
1208 | let expected_result: TestPoint<Unencoded> = consume_point(ops, test_case , "r" ); |
1209 | let actual_result = f(&g_scalar, cpu); |
1210 | assert_point_actual_equals_expected(ops, &actual_result, &expected_result); |
1211 | Ok(()) |
1212 | }) |
1213 | } |
1214 | |
1215 | fn assert_point_actual_equals_expected<E: Encoding>( |
1216 | ops: &PrivateKeyOps, |
1217 | actual_point: &Point, |
1218 | expected_point: &TestPoint<E>, |
1219 | ) where |
1220 | Elem<R>: Convert<E>, |
1221 | { |
1222 | let cpu = cpu::features(); |
1223 | |
1224 | let cops = ops.common; |
1225 | let q = &cops.elem_modulus(cpu); |
1226 | let actual_x = &q.point_x(actual_point); |
1227 | let actual_y = &q.point_y(actual_point); |
1228 | let actual_z = &q.point_z(actual_point); |
1229 | match expected_point { |
1230 | TestPoint::Infinity => { |
1231 | let zero = Elem::zero(); |
1232 | assert_elems_are_equal(q, actual_z, &zero); |
1233 | } |
1234 | TestPoint::Affine(expected_x, expected_y) => { |
1235 | let zz_inv = ops.elem_inverse_squared(q, actual_z); |
1236 | let x_aff = q.elem_product(actual_x, &zz_inv); |
1237 | let y_aff = { |
1238 | let zzzz_inv = q.elem_squared(&zz_inv); |
1239 | let zzz_inv = q.elem_product(actual_z, &zzzz_inv); |
1240 | q.elem_product(actual_y, &zzz_inv) |
1241 | }; |
1242 | |
1243 | let x_aff = x_aff.convert(q); |
1244 | let y_aff = y_aff.convert(q); |
1245 | |
1246 | assert_elems_are_equal(q, &x_aff, expected_x); |
1247 | assert_elems_are_equal(q, &y_aff, expected_y); |
1248 | } |
1249 | } |
1250 | } |
1251 | |
1252 | fn consume_jacobian_point( |
1253 | ops: &PrivateKeyOps, |
1254 | test_case: &mut test::TestCase, |
1255 | name: &str, |
1256 | ) -> Point { |
1257 | let q = &ops.common.elem_modulus(cpu::features()); |
1258 | let input = test_case .consume_string(name); |
1259 | let elems = input.split(", " ).collect::<Vec<&str>>(); |
1260 | assert_eq!(elems.len(), 3); |
1261 | let mut p = Point::new_at_infinity(); |
1262 | consume_point_elem(q, &mut p.xyz, &elems, 0); |
1263 | consume_point_elem(q, &mut p.xyz, &elems, 1); |
1264 | consume_point_elem(q, &mut p.xyz, &elems, 2); |
1265 | p |
1266 | } |
1267 | |
1268 | struct AffinePoint { |
1269 | xy: [Limb; 2 * elem::NumLimbs::MAX], |
1270 | } |
1271 | |
1272 | fn consume_affine_point( |
1273 | ops: &PrivateKeyOps, |
1274 | test_case: &mut test::TestCase, |
1275 | name: &str, |
1276 | ) -> AffinePoint { |
1277 | let q = &ops.common.elem_modulus(cpu::features()); |
1278 | let input = test_case .consume_string(name); |
1279 | let elems = input.split(", " ).collect::<Vec<&str>>(); |
1280 | assert_eq!(elems.len(), 2); |
1281 | let mut p = AffinePoint { |
1282 | xy: [0; 2 * elem::NumLimbs::MAX], |
1283 | }; |
1284 | consume_point_elem(q, &mut p.xy, &elems, 0); |
1285 | consume_point_elem(q, &mut p.xy, &elems, 1); |
1286 | p |
1287 | } |
1288 | |
1289 | fn consume_point_elem(q: &Modulus<Q>, limbs_out: &mut [Limb], elems: &[&str], i: usize) { |
1290 | let num_limbs = q.num_limbs.into(); |
1291 | let bytes = test::from_hex(elems[i]).unwrap(); |
1292 | let bytes = untrusted::Input::from(&bytes); |
1293 | let r: Elem<Unencoded> = elem_parse_big_endian_fixed_consttime(q, bytes).unwrap(); |
1294 | // XXX: “Transmute” this to `Elem<R>` limbs. |
1295 | limbs_out[(i * num_limbs)..((i + 1) * num_limbs)].copy_from_slice(&r.limbs[..num_limbs]); |
1296 | } |
1297 | |
1298 | enum TestPoint<E: Encoding> { |
1299 | Infinity, |
1300 | Affine(Elem<E>, Elem<E>), |
1301 | } |
1302 | |
1303 | fn consume_point<E: Encoding>( |
1304 | ops: &PrivateKeyOps, |
1305 | test_case: &mut test::TestCase, |
1306 | name: &str, |
1307 | ) -> TestPoint<E> { |
1308 | let q = &ops.common.elem_modulus(cpu::features()); |
1309 | fn consume_point_elem<E: Encoding>(q: &Modulus<Q>, elems: &[&str], i: usize) -> Elem<E> { |
1310 | let bytes = test::from_hex(elems[i]).unwrap(); |
1311 | let bytes = untrusted::Input::from(&bytes); |
1312 | let unencoded: Elem<Unencoded> = |
1313 | elem_parse_big_endian_fixed_consttime(q, bytes).unwrap(); |
1314 | // XXX: “Transmute” this to `Elem<R>` limbs. |
1315 | Elem { |
1316 | limbs: unencoded.limbs, |
1317 | m: PhantomData, |
1318 | encoding: PhantomData, |
1319 | } |
1320 | } |
1321 | |
1322 | let input = test_case .consume_string(name); |
1323 | if input == "inf" { |
1324 | return TestPoint::Infinity; |
1325 | } |
1326 | let elems = input.split(", " ).collect::<Vec<&str>>(); |
1327 | assert_eq!(elems.len(), 2); |
1328 | let x = consume_point_elem(q, &elems, 0); |
1329 | let y = consume_point_elem(q, &elems, 1); |
1330 | TestPoint::Affine(x, y) |
1331 | } |
1332 | |
1333 | fn assert_elems_are_equal<E: Encoding>(q: &Modulus<Q>, a: &Elem<E>, b: &Elem<E>) { |
1334 | assert_limbs_are_equal(q.cops, &a.limbs, &b.limbs) |
1335 | } |
1336 | |
1337 | fn assert_limbs_are_equal( |
1338 | ops: &CommonOps, |
1339 | actual: &[Limb; elem::NumLimbs::MAX], |
1340 | expected: &[Limb; elem::NumLimbs::MAX], |
1341 | ) { |
1342 | let num_limbs = ops.num_limbs.into(); |
1343 | if actual[..num_limbs] != expected[..num_limbs] { |
1344 | let mut actual_s = alloc::string::String::new(); |
1345 | let mut expected_s = alloc::string::String::new(); |
1346 | for j in 0..num_limbs { |
1347 | let width = LIMB_BITS / 4; |
1348 | let formatted = format!("{:0width$x}" , actual[num_limbs - j - 1]); |
1349 | actual_s.push_str(&formatted); |
1350 | let formatted = format!("{:0width$x}" , expected[num_limbs - j - 1]); |
1351 | expected_s.push_str(&formatted); |
1352 | } |
1353 | panic!( |
1354 | "Actual != Expected, \nActual = {}, Expected = {}" , |
1355 | actual_s, expected_s |
1356 | ); |
1357 | } |
1358 | } |
1359 | |
1360 | fn consume_elem(q: &Modulus<Q>, test_case: &mut test::TestCase, name: &str) -> Elem<R> { |
1361 | let unpadded_bytes = test_case .consume_bytes(name); |
1362 | let mut bytes = vec![0; q.bytes_len() - unpadded_bytes.len()]; |
1363 | bytes.extend(&unpadded_bytes); |
1364 | |
1365 | let bytes = untrusted::Input::from(&bytes); |
1366 | let r: Elem<Unencoded> = elem_parse_big_endian_fixed_consttime(q, bytes).unwrap(); |
1367 | // XXX: “Transmute” this to an `Elem<R>`. |
1368 | Elem { |
1369 | limbs: r.limbs, |
1370 | m: PhantomData, |
1371 | encoding: PhantomData, |
1372 | } |
1373 | } |
1374 | |
1375 | fn consume_scalar(n: &Modulus<N>, test_case: &mut test::TestCase, name: &str) -> Scalar { |
1376 | let bytes = test_case .consume_bytes(name); |
1377 | let bytes = untrusted::Input::from(&bytes); |
1378 | scalar_parse_big_endian_variable(n, AllowZero::Yes, bytes).unwrap() |
1379 | } |
1380 | |
1381 | fn consume_scalar_mont( |
1382 | n: &Modulus<N>, |
1383 | test_case: &mut test::TestCase, |
1384 | name: &str, |
1385 | ) -> Scalar<R> { |
1386 | let bytes = test_case .consume_bytes(name); |
1387 | let bytes = untrusted::Input::from(&bytes); |
1388 | let s = scalar_parse_big_endian_variable(n, AllowZero::Yes, bytes).unwrap(); |
1389 | // “Transmute” it to a `Scalar<R>`. |
1390 | Scalar { |
1391 | limbs: s.limbs, |
1392 | m: PhantomData, |
1393 | encoding: PhantomData, |
1394 | } |
1395 | } |
1396 | } |
1397 | |
1398 | mod elem; |
1399 | pub mod p256; |
1400 | pub mod p384; |
1401 | |