1use crate::{
16 arithmetic::limbs_from_hex,
17 arithmetic::montgomery::*,
18 bb::LeakyWord,
19 cpu,
20 error::{self, LenMismatchError},
21 limb::*,
22};
23use core::marker::PhantomData;
24
25use elem::{mul_mont, unary_op, unary_op_assign, unary_op_from_binary_op_assign};
26
27pub type Elem<E> = elem::Elem<Q, E>;
30type PublicElem<E> = elem::PublicElem<Q, E>;
31
32#[derive(Clone, Copy)]
34pub enum Q {}
35
36pub type Scalar<E = Unencoded> = elem::Elem<N, E>;
39type PublicScalar<E> = elem::PublicElem<N, E>;
40
41#[derive(Clone, Copy)]
43pub enum N {}
44
45pub(super) struct Modulus<M> {
46 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
54pub struct Point {
55 xyz: [Limb; 3 * elem::NumLimbs::MAX],
61}
62
63impl Point {
64 pub fn new_at_infinity() -> Self {
65 Self {
66 xyz: [0; 3 * elem::NumLimbs::MAX],
67 }
68 }
69}
70
71pub struct CommonOps {
73 num_limbs: elem::NumLimbs,
74 q: PublicModulus,
75 n: PublicElem<Unencoded>,
76
77 pub a: PublicElem<R>, pub b: PublicElem<R>,
79
80 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
85impl CommonOps {
86 pub(super) fn elem_modulus(&'static self, cpu_features: cpu::Features) -> Modulus<Q> {
87 Modulus {
88 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 limbs: &self.n.limbs,
101 num_limbs: self.num_limbs,
102 cops: self,
103 m: PhantomData,
104 cpu: cpu_features,
105 }
106 }
107
108 pub fn len(&self) -> usize {
111 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
121impl<M> Modulus<M> {
122 pub fn cpu(&self) -> cpu::Features {
123 self.cpu
124 }
125
126 pub fn bytes_len(&self) -> usize {
128 self.num_limbs.into() * LIMB_BYTES
129 }
130}
131
132impl<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 = 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(unwrap_impossible_len_mismatch_error)
142 }
143}
144
145impl Modulus<Q> {
146 #[inline]
147 pub fn elems_are_equal<E: Encoding>(&self, a: &Elem<E>, b: &Elem<E>) -> LimbMask {
148 let num_limbs = self.num_limbs.into();
149 limbs_equal_limbs_consttime(&a.limbs[..num_limbs], &b.limbs[..num_limbs])
150 .unwrap_or_else(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
159impl 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(&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
195impl 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
224impl<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
231impl 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
248impl PrivateKeyOps {
249 pub(super) fn point_sum(&self, a: &Point, b: &Point, _cpu: cpu::Features) -> Point {
250 let mut r = 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
258impl Modulus<Q> {
259 pub fn point_x(&self, p: &Point) -> Elem<R> {
260 let num_limbs = self.num_limbs.into();
261 let mut r = 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 = self.num_limbs.into();
268 let mut r = 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 = self.num_limbs.into();
275 let mut r = Elem::zero();
276 r.limbs[..num_limbs].copy_from_slice(&p.xyz[(2 * num_limbs)..(3 * num_limbs)]);
277 r
278 }
279}
280
281struct PublicModulus {
282 p: [LeakyLimb; elem::NumLimbs::MAX],
283 rr: PublicElem<RR>,
284}
285
286pub 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, p_scalar: *const Limb, p_x: *const Limb, p_y: *const Limb, ),
297 point_add_jacobian_impl: unsafe extern "C" fn(r: *mut Limb, a: *const Limb, b: *const Limb),
298}
299
300impl 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
335pub struct PublicKeyOps {
338 pub common: &'static CommonOps,
339}
340
341impl PublicKeyOps {
342 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 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
370pub 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
378impl 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 pub fn scalar_bytes_len(&self) -> usize {
385 self.common.len()
386 }
387}
388
389impl 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
408pub 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
423impl 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
438impl Modulus<Q> {
439 pub fn elem_less_than_vartime(&self, a: &Elem<Unencoded>, b: &PublicElem<Unencoded>) -> bool {
440 let num_limbs = 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
446impl 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)]
457pub struct PrivateScalarOps {
458 pub scalar_ops: &'static ScalarOps,
459
460 oneRR_mod_n: PublicScalar<RR>, scalar_inv_to_mont: fn(a: Scalar<R>, cpu: cpu::Features) -> Scalar<R>,
462}
463
464impl PrivateScalarOps {
465 pub(super) fn to_mont(&self, s: &Scalar<Unencoded>, cpu: cpu::Features) -> Scalar<R> {
466 self.scalar_ops
467 .scalar_product(s, &Scalar::from(&self.oneRR_mod_n), cpu)
468 }
469
470 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 = self.to_mont(a, cpu);
474 (self.scalar_inv_to_mont)(a, cpu)
475 }
476}
477
478fn 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 = ops.point_mul_base(g_scalar, cpu);
488 let scaled_p = ops.point_mul(p_scalar, p_xy, cpu);
489 ops.point_sum(&scaled_g, &scaled_p, cpu)
490}
491
492impl Modulus<N> {
494 pub fn elem_reduced_to_scalar(&self, elem: &Elem<Unencoded>) -> Scalar<Unencoded> {
495 let num_limbs = self.num_limbs.into();
496 let mut r_limbs = elem.limbs;
497 limbs_reduce_once(&mut r_limbs[..num_limbs], &self.limbs[..num_limbs])
498 .unwrap_or_else(unwrap_impossible_len_mismatch_error);
499 Scalar {
500 limbs: r_limbs,
501 m: PhantomData,
502 encoding: PhantomData,
503 }
504 }
505}
506
507fn 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 = 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
523fn 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(acc, cpu);
534 }
535 ops.elem_mul(acc, b, cpu)
536}
537
538#[inline]
539pub(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(q, bytes, AllowZero::Yes)
544}
545
546#[inline]
547pub(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(n, bytes, AllowZero::No)
552}
553
554#[inline]
555pub(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 = n.num_limbs.into();
561 let mut r = Scalar::zero();
562 parse_big_endian_in_range_and_pad_consttime(
563 bytes,
564 allow_zero,
565 &n.limbs[..num_limbs],
566 &mut r.limbs[..num_limbs],
567 )?;
568 Ok(r)
569}
570
571pub(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 = n.num_limbs.into();
576 let mut r = Scalar::zero();
577 {
578 let r = &mut r.limbs[..num_limbs];
579 parse_big_endian_and_pad_consttime(bytes, r)?;
580 limbs_reduce_once(r, &n.limbs[..num_limbs])
581 .unwrap_or_else(unwrap_impossible_len_mismatch_error);
582 }
583
584 Ok(r)
585}
586
587fn 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 = m.num_limbs.into();
593 if bytes.len() != m.bytes_len() {
594 return Err(error::Unspecified);
595 }
596 let mut r = elem::Elem::zero();
597 parse_big_endian_in_range_and_pad_consttime(
598 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)]
608fn unwrap_impossible_len_mismatch_error<T>(LenMismatchError { .. }: LenMismatchError) -> T {
609 unreachable!()
610}
611
612#[cfg(test)]
613mod tests {
614 extern crate alloc;
615 use super::*;
616 use crate::testutil as 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_vector_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_vector_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 #[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_vector_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 #[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_vector_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 #[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_vector_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_vector_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 {
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 {
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(
849 &p256::COMMON_OPS,
850 test_vector_file!("ops/p256_elem_mul_tests.txt"),
851 );
852 }
853
854 #[test]
855 fn p384_elem_mul_test() {
856 elem_mul_test(
857 &p384::COMMON_OPS,
858 test_vector_file!("ops/p384_elem_mul_tests.txt"),
859 );
860 }
861
862 fn elem_mul_test(ops: &'static CommonOps, test_file: test::File) {
863 let q = &ops.elem_modulus(cpu::features());
864 test::run(test_file, |section, test_case| {
865 assert_eq!(section, "");
866
867 let mut a = consume_elem(q, test_case, "a");
868 let b = consume_elem(q, test_case, "b");
869 let r = consume_elem(q, test_case, "r");
870 q.elem_mul(&mut a, &b);
871 assert_limbs_are_equal(ops, &a.limbs, &r.limbs);
872
873 Ok(())
874 })
875 }
876
877 #[test]
878 fn p256_scalar_mul_test() {
879 scalar_mul_test(
880 &p256::SCALAR_OPS,
881 test_vector_file!("ops/p256_scalar_mul_tests.txt"),
882 );
883 }
884
885 #[test]
886 fn p384_scalar_mul_test() {
887 scalar_mul_test(
888 &p384::SCALAR_OPS,
889 test_vector_file!("ops/p384_scalar_mul_tests.txt"),
890 );
891 }
892
893 fn scalar_mul_test(ops: &ScalarOps, test_file: test::File) {
894 let cpu = cpu::features();
895 let cops = ops.common;
896 let n = &cops.scalar_modulus(cpu);
897 test::run(test_file, |section, test_case| {
898 assert_eq!(section, "");
899 let a = consume_scalar(n, test_case, "a");
900 let b = consume_scalar_mont(n, test_case, "b");
901 let expected_result = consume_scalar(n, test_case, "r");
902 let actual_result = ops.scalar_product(&a, &b, cpu);
903 assert_limbs_are_equal(cops, &actual_result.limbs, &expected_result.limbs);
904
905 Ok(())
906 })
907 }
908
909 #[test]
910 fn p256_scalar_square_test() {
911 prefixed_extern! {
912 fn p256_scalar_sqr_rep_mont(r: *mut Limb, a: *const Limb, rep: LeakyWord);
913 }
914 scalar_square_test(
915 &p256::SCALAR_OPS,
916 p256_scalar_sqr_rep_mont,
917 test_vector_file!("ops/p256_scalar_square_tests.txt"),
918 );
919 }
920
921 fn scalar_square_test(
925 ops: &ScalarOps,
926 sqr_rep: unsafe extern "C" fn(r: *mut Limb, a: *const Limb, rep: LeakyWord),
927 test_file: test::File,
928 ) {
929 let cpu = cpu::features();
930 let cops = ops.common;
931 let n = &cops.scalar_modulus(cpu);
932 test::run(test_file, |section, test_case| {
933 assert_eq!(section, "");
934 let cpu = cpu::features();
935 let a = consume_scalar(n, test_case, "a");
936 let expected_result = consume_scalar(n, test_case, "r");
937
938 {
939 let mut actual_result: Scalar<R> = Scalar {
940 limbs: [0; elem::NumLimbs::MAX],
941 m: PhantomData,
942 encoding: PhantomData,
943 };
944 unsafe {
945 sqr_rep(actual_result.limbs.as_mut_ptr(), a.limbs.as_ptr(), 1);
946 }
947 assert_limbs_are_equal(cops, &actual_result.limbs, &expected_result.limbs);
948 }
949
950 {
951 let actual_result = ops.scalar_product(&a, &a, cpu);
952 assert_limbs_are_equal(cops, &actual_result.limbs, &expected_result.limbs);
953 }
954
955 Ok(())
956 })
957 }
958
959 #[test]
960 #[should_panic(expected = "!self.scalar_ops.common.is_zero(a)")]
961 fn p256_scalar_inv_to_mont_zero_panic_test() {
962 let _ = p256::PRIVATE_SCALAR_OPS.scalar_inv_to_mont(&ZERO_SCALAR, cpu::features());
963 }
964
965 #[test]
966 #[should_panic(expected = "!self.scalar_ops.common.is_zero(a)")]
967 fn p384_scalar_inv_to_mont_zero_panic_test() {
968 let _ = p384::PRIVATE_SCALAR_OPS.scalar_inv_to_mont(&ZERO_SCALAR, cpu::features());
969 }
970
971 #[test]
972 fn p256_point_sum_test() {
973 point_sum_test(
974 &p256::PRIVATE_KEY_OPS,
975 test_vector_file!("ops/p256_point_sum_tests.txt"),
976 );
977 }
978
979 #[test]
980 fn p384_point_sum_test() {
981 point_sum_test(
982 &p384::PRIVATE_KEY_OPS,
983 test_vector_file!("ops/p384_point_sum_tests.txt"),
984 );
985 }
986
987 fn point_sum_test(ops: &PrivateKeyOps, test_file: test::File) {
988 let cpu = cpu::features();
989
990 test::run(test_file, |section, test_case| {
991 assert_eq!(section, "");
992
993 let a = consume_jacobian_point(ops, test_case, "a");
994 let b = consume_jacobian_point(ops, test_case, "b");
995 let r_expected: TestPoint<R> = consume_point(ops, test_case, "r");
996
997 let r_actual = ops.point_sum(&a, &b, cpu);
998 assert_point_actual_equals_expected(ops, &r_actual, &r_expected);
999
1000 Ok(())
1001 });
1002 }
1003
1004 #[test]
1005 fn p256_point_sum_mixed_test() {
1006 prefixed_extern! {
1007 fn p256_point_add_affine(
1008 r: *mut Limb, a: *const Limb, b: *const Limb, );
1012 }
1013 point_sum_mixed_test(
1014 &p256::PRIVATE_KEY_OPS,
1015 p256_point_add_affine,
1016 test_vector_file!("ops/p256_point_sum_mixed_tests.txt"),
1017 );
1018 }
1019
1020 fn point_sum_mixed_test(
1023 ops: &PrivateKeyOps,
1024 point_add_affine: unsafe extern "C" fn(
1025 r: *mut Limb, a: *const Limb, b: *const Limb, ),
1029 test_file: test::File,
1030 ) {
1031 test::run(test_file, |section, test_case| {
1032 assert_eq!(section, "");
1033
1034 let a = consume_jacobian_point(ops, test_case, "a");
1035 let b = consume_affine_point(ops, test_case, "b");
1036 let r_expected: TestPoint<R> = consume_point(ops, test_case, "r");
1037
1038 let mut r_actual = Point::new_at_infinity();
1039 unsafe {
1040 point_add_affine(r_actual.xyz.as_mut_ptr(), a.xyz.as_ptr(), b.xy.as_ptr());
1041 }
1042
1043 assert_point_actual_equals_expected(ops, &r_actual, &r_expected);
1044
1045 Ok(())
1046 });
1047 }
1048
1049 #[test]
1050 fn p256_point_double_test() {
1051 prefixed_extern! {
1052 fn p256_point_double(
1053 r: *mut Limb, a: *const Limb, );
1056 }
1057 point_double_test(
1058 &p256::PRIVATE_KEY_OPS,
1059 p256_point_double,
1060 test_vector_file!("ops/p256_point_double_tests.txt"),
1061 );
1062 }
1063
1064 #[test]
1065 fn p384_point_double_test() {
1066 prefixed_extern! {
1067 fn p384_point_double(
1068 r: *mut Limb, a: *const Limb, );
1071 }
1072 point_double_test(
1073 &p384::PRIVATE_KEY_OPS,
1074 p384_point_double,
1075 test_vector_file!("ops/p384_point_double_tests.txt"),
1076 );
1077 }
1078
1079 fn point_double_test(
1080 ops: &PrivateKeyOps,
1081 point_double: unsafe extern "C" fn(
1082 r: *mut Limb, a: *const Limb, ),
1085 test_file: test::File,
1086 ) {
1087 test::run(test_file, |section, test_case| {
1088 assert_eq!(section, "");
1089
1090 let a = consume_jacobian_point(ops, test_case, "a");
1091 let r_expected: TestPoint<R> = consume_point(ops, test_case, "r");
1092
1093 let mut r_actual = Point::new_at_infinity();
1094 unsafe {
1095 point_double(r_actual.xyz.as_mut_ptr(), a.xyz.as_ptr());
1096 }
1097
1098 assert_point_actual_equals_expected(ops, &r_actual, &r_expected);
1099
1100 Ok(())
1101 });
1102 }
1103
1104 #[test]
1106 fn p256_point_mul_test() {
1107 let generator = (
1108 Elem::from(&p256::GENERATOR.0),
1109 Elem::from(&p256::GENERATOR.1),
1110 );
1111 point_mul_base_tests(
1112 &p256::PRIVATE_KEY_OPS,
1113 |s, cpu| p256::PRIVATE_KEY_OPS.point_mul(s, &generator, cpu),
1114 test_vector_file!("ops/p256_point_mul_base_tests.txt"),
1115 );
1116 }
1117
1118 #[test]
1120 fn p384_point_mul_test() {
1121 let generator = (
1122 Elem::from(&p384::GENERATOR.0),
1123 Elem::from(&p384::GENERATOR.1),
1124 );
1125
1126 point_mul_base_tests(
1127 &p384::PRIVATE_KEY_OPS,
1128 |s, cpu| p384::PRIVATE_KEY_OPS.point_mul(s, &generator, cpu),
1129 test_vector_file!("ops/p384_point_mul_base_tests.txt"),
1130 );
1131 }
1132
1133 #[test]
1134 fn p256_point_mul_serialized_test() {
1135 point_mul_serialized_test(
1136 &p256::PRIVATE_KEY_OPS,
1137 &p256::PUBLIC_KEY_OPS,
1138 test_vector_file!("ops/p256_point_mul_serialized_tests.txt"),
1139 );
1140 }
1141
1142 fn point_mul_serialized_test(
1143 priv_ops: &PrivateKeyOps,
1144 pub_ops: &PublicKeyOps,
1145 test_file: test::File,
1146 ) {
1147 let cpu = cpu::features();
1148 let cops = pub_ops.common;
1149 let q = &cops.elem_modulus(cpu);
1150 let n = &cops.scalar_modulus(cpu);
1151 test::run(test_file, |section, test_case| {
1152 assert_eq!(section, "");
1153 let p_scalar = consume_scalar(n, test_case, "p_scalar");
1154
1155 let p = test_case.consume_bytes("p");
1156 let p = super::super::public_key::parse_uncompressed_point(
1157 pub_ops,
1158 q,
1159 untrusted::Input::from(&p),
1160 )
1161 .expect("valid point");
1162
1163 let expected_result = test_case.consume_bytes("r");
1164
1165 let product = priv_ops.point_mul(&p_scalar, &p, cpu::features());
1166
1167 let mut actual_result = vec![4u8; 1 + (2 * cops.len())];
1168 {
1169 let (x, y) = actual_result[1..].split_at_mut(cops.len());
1170 super::super::private_key::big_endian_affine_from_jacobian(
1171 priv_ops,
1172 q,
1173 x,
1174 Some(y),
1175 &product,
1176 )
1177 .expect("successful encoding");
1178 }
1179
1180 assert_eq!(expected_result, actual_result);
1181
1182 Ok(())
1183 })
1184 }
1185
1186 #[test]
1187 fn p256_point_mul_base_test() {
1188 point_mul_base_tests(
1189 &p256::PRIVATE_KEY_OPS,
1190 |s, cpu| p256::PRIVATE_KEY_OPS.point_mul_base(s, cpu),
1191 test_vector_file!("ops/p256_point_mul_base_tests.txt"),
1192 );
1193 }
1194
1195 #[test]
1196 fn p384_point_mul_base_test() {
1197 point_mul_base_tests(
1198 &p384::PRIVATE_KEY_OPS,
1199 |s, cpu| p384::PRIVATE_KEY_OPS.point_mul_base(s, cpu),
1200 test_vector_file!("ops/p384_point_mul_base_tests.txt"),
1201 );
1202 }
1203
1204 pub(super) fn point_mul_base_tests(
1205 ops: &PrivateKeyOps,
1206 f: impl Fn(&Scalar, cpu::Features) -> Point,
1207 test_file: test::File,
1208 ) {
1209 let cpu = cpu::features();
1210 let n = &ops.common.scalar_modulus(cpu);
1211 test::run(test_file, |section, test_case| {
1212 assert_eq!(section, "");
1213 let g_scalar = consume_scalar(n, test_case, "g_scalar");
1214 let expected_result: TestPoint<Unencoded> = consume_point(ops, test_case, "r");
1215 let actual_result = f(&g_scalar, cpu);
1216 assert_point_actual_equals_expected(ops, &actual_result, &expected_result);
1217 Ok(())
1218 })
1219 }
1220
1221 fn assert_point_actual_equals_expected<E: Encoding>(
1222 ops: &PrivateKeyOps,
1223 actual_point: &Point,
1224 expected_point: &TestPoint<E>,
1225 ) where
1226 Elem<R>: Convert<E>,
1227 {
1228 let cpu = cpu::features();
1229
1230 let cops = ops.common;
1231 let q = &cops.elem_modulus(cpu);
1232 let actual_x = &q.point_x(actual_point);
1233 let actual_y = &q.point_y(actual_point);
1234 let actual_z = &q.point_z(actual_point);
1235 match expected_point {
1236 TestPoint::Infinity => {
1237 let zero = Elem::zero();
1238 assert_elems_are_equal(q, actual_z, &zero);
1239 }
1240 TestPoint::Affine(expected_x, expected_y) => {
1241 let zz_inv = ops.elem_inverse_squared(q, actual_z);
1242 let x_aff = q.elem_product(actual_x, &zz_inv);
1243 let y_aff = {
1244 let zzzz_inv = q.elem_squared(&zz_inv);
1245 let zzz_inv = q.elem_product(actual_z, &zzzz_inv);
1246 q.elem_product(actual_y, &zzz_inv)
1247 };
1248
1249 let x_aff = x_aff.convert(q);
1250 let y_aff = y_aff.convert(q);
1251
1252 assert_elems_are_equal(q, &x_aff, expected_x);
1253 assert_elems_are_equal(q, &y_aff, expected_y);
1254 }
1255 }
1256 }
1257
1258 fn consume_jacobian_point(
1259 ops: &PrivateKeyOps,
1260 test_case: &mut test::TestCase,
1261 name: &str,
1262 ) -> Point {
1263 let q = &ops.common.elem_modulus(cpu::features());
1264 let input = test_case.consume_string(name);
1265 let elems = input.split(", ").collect::<Vec<&str>>();
1266 assert_eq!(elems.len(), 3);
1267 let mut p = Point::new_at_infinity();
1268 consume_point_elem(q, &mut p.xyz, &elems, 0);
1269 consume_point_elem(q, &mut p.xyz, &elems, 1);
1270 consume_point_elem(q, &mut p.xyz, &elems, 2);
1271 p
1272 }
1273
1274 struct AffinePoint {
1275 xy: [Limb; 2 * elem::NumLimbs::MAX],
1276 }
1277
1278 fn consume_affine_point(
1279 ops: &PrivateKeyOps,
1280 test_case: &mut test::TestCase,
1281 name: &str,
1282 ) -> AffinePoint {
1283 let q = &ops.common.elem_modulus(cpu::features());
1284 let input = test_case.consume_string(name);
1285 let elems = input.split(", ").collect::<Vec<&str>>();
1286 assert_eq!(elems.len(), 2);
1287 let mut p = AffinePoint {
1288 xy: [0; 2 * elem::NumLimbs::MAX],
1289 };
1290 consume_point_elem(q, &mut p.xy, &elems, 0);
1291 consume_point_elem(q, &mut p.xy, &elems, 1);
1292 p
1293 }
1294
1295 fn consume_point_elem(q: &Modulus<Q>, limbs_out: &mut [Limb], elems: &[&str], i: usize) {
1296 let num_limbs = q.num_limbs.into();
1297 let bytes = test::from_hex(elems[i]).unwrap();
1298 let bytes = untrusted::Input::from(&bytes);
1299 let r: Elem<Unencoded> = elem_parse_big_endian_fixed_consttime(q, bytes).unwrap();
1300 limbs_out[(i * num_limbs)..((i + 1) * num_limbs)].copy_from_slice(&r.limbs[..num_limbs]);
1302 }
1303
1304 enum TestPoint<E: Encoding> {
1305 Infinity,
1306 Affine(Elem<E>, Elem<E>),
1307 }
1308
1309 fn consume_point<E: Encoding>(
1310 ops: &PrivateKeyOps,
1311 test_case: &mut test::TestCase,
1312 name: &str,
1313 ) -> TestPoint<E> {
1314 let q = &ops.common.elem_modulus(cpu::features());
1315 fn consume_point_elem<E: Encoding>(q: &Modulus<Q>, elems: &[&str], i: usize) -> Elem<E> {
1316 let bytes = test::from_hex(elems[i]).unwrap();
1317 let bytes = untrusted::Input::from(&bytes);
1318 let unencoded: Elem<Unencoded> =
1319 elem_parse_big_endian_fixed_consttime(q, bytes).unwrap();
1320 Elem {
1322 limbs: unencoded.limbs,
1323 m: PhantomData,
1324 encoding: PhantomData,
1325 }
1326 }
1327
1328 let input = test_case.consume_string(name);
1329 if input == "inf" {
1330 return TestPoint::Infinity;
1331 }
1332 let elems = input.split(", ").collect::<Vec<&str>>();
1333 assert_eq!(elems.len(), 2);
1334 let x = consume_point_elem(q, &elems, 0);
1335 let y = consume_point_elem(q, &elems, 1);
1336 TestPoint::Affine(x, y)
1337 }
1338
1339 fn assert_elems_are_equal<E: Encoding>(q: &Modulus<Q>, a: &Elem<E>, b: &Elem<E>) {
1340 assert_limbs_are_equal(q.cops, &a.limbs, &b.limbs)
1341 }
1342
1343 fn assert_limbs_are_equal(
1344 ops: &CommonOps,
1345 actual: &[Limb; elem::NumLimbs::MAX],
1346 expected: &[Limb; elem::NumLimbs::MAX],
1347 ) {
1348 let num_limbs = ops.num_limbs.into();
1349 if actual[..num_limbs] != expected[..num_limbs] {
1350 let mut actual_s = alloc::string::String::new();
1351 let mut expected_s = alloc::string::String::new();
1352 for j in 0..num_limbs {
1353 let width = LIMB_BITS / 4;
1354 let formatted = format!("{:0width$x}", actual[num_limbs - j - 1]);
1355 actual_s.push_str(&formatted);
1356 let formatted = format!("{:0width$x}", expected[num_limbs - j - 1]);
1357 expected_s.push_str(&formatted);
1358 }
1359 panic!(
1360 "Actual != Expected,\nActual = {}, Expected = {}",
1361 actual_s, expected_s
1362 );
1363 }
1364 }
1365
1366 fn consume_elem(q: &Modulus<Q>, test_case: &mut test::TestCase, name: &str) -> Elem<R> {
1367 let unpadded_bytes = test_case.consume_bytes(name);
1368 let mut bytes = vec![0; q.bytes_len() - unpadded_bytes.len()];
1369 bytes.extend(&unpadded_bytes);
1370
1371 let bytes = untrusted::Input::from(&bytes);
1372 let r: Elem<Unencoded> = elem_parse_big_endian_fixed_consttime(q, bytes).unwrap();
1373 Elem {
1375 limbs: r.limbs,
1376 m: PhantomData,
1377 encoding: PhantomData,
1378 }
1379 }
1380
1381 fn consume_scalar(n: &Modulus<N>, test_case: &mut test::TestCase, name: &str) -> Scalar {
1382 let bytes = test_case.consume_bytes(name);
1383 let bytes = untrusted::Input::from(&bytes);
1384 scalar_parse_big_endian_variable(n, AllowZero::Yes, bytes).unwrap()
1385 }
1386
1387 fn consume_scalar_mont(
1388 n: &Modulus<N>,
1389 test_case: &mut test::TestCase,
1390 name: &str,
1391 ) -> Scalar<R> {
1392 let bytes = test_case.consume_bytes(name);
1393 let bytes = untrusted::Input::from(&bytes);
1394 let s = scalar_parse_big_endian_variable(n, AllowZero::Yes, bytes).unwrap();
1395 Scalar {
1397 limbs: s.limbs,
1398 m: PhantomData,
1399 encoding: PhantomData,
1400 }
1401 }
1402}
1403
1404mod elem;
1405pub mod p256;
1406pub mod p384;