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