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
15use crate::{arithmetic::limbs_from_hex, arithmetic::montgomery::*, error, limb::*};
16use core::marker::PhantomData;
17
18pub use self::elem::*;
19
20/// A field element, i.e. an element of ℤ/qℤ for the curve's field modulus
21/// *q*.
22pub type Elem<E> = elem::Elem<Q, E>;
23
24/// Represents the (prime) order *q* of the curve's prime field.
25#[derive(Clone, Copy)]
26pub enum Q {}
27
28/// A scalar. Its value is in [0, n). Zero-valued scalars are forbidden in most
29/// contexts.
30pub type Scalar<E = Unencoded> = elem::Elem<N, E>;
31
32/// Represents the prime order *n* of the curve's group.
33#[derive(Clone, Copy)]
34pub enum N {}
35
36pub 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
45impl 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.
54pub 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
69impl 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
170struct Modulus {
171 p: [Limb; MAX_LIMBS],
172 rr: [Limb; MAX_LIMBS],
173}
174
175/// Operations on private keys, for ECDH and ECDSA signing.
176pub 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
188impl 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).
220pub struct PublicKeyOps {
221 pub common: &'static CommonOps,
222}
223
224impl 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.
249pub 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
255impl 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.
279pub 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
288impl 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)]
318pub 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
325impl 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.
340fn 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.
352pub 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
363pub 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`.
373fn 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`.
383fn 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]
392pub 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]
400pub 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]
408pub 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
423pub 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
438fn 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)]
458mod 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
1216mod elem;
1217pub mod p256;
1218pub mod p384;
1219