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::test;
617 use alloc::{format, vec, vec::Vec};
618
619 const ZERO_SCALAR: Scalar = Scalar {
620 limbs: [0; elem::NumLimbs::MAX],
621 m: PhantomData,
622 encoding: PhantomData,
623 };
624
625 trait Convert<E: Encoding> {
626 fn convert(self, q: &Modulus<Q>) -> Elem<E>;
627 }
628
629 impl Convert<R> for Elem<R> {
630 fn convert(self, _q: &Modulus<Q>) -> Elem<R> {
631 self
632 }
633 }
634
635 impl Convert<Unencoded> for Elem<R> {
636 fn convert(self, q: &Modulus<Q>) -> Elem<Unencoded> {
637 q.elem_unencoded(&self)
638 }
639 }
640
641 fn q_minus_n_plus_n_equals_0_test(ops: &PublicScalarOps) {
642 let cops = ops.scalar_ops.common;
643 let q = &cops.elem_modulus(cpu::features());
644 let mut x = Elem::from(&ops.q_minus_n);
645 q.add_assign(&mut x, &Elem::from(&cops.n));
646 assert!(q.is_zero(&x));
647 }
648
649 #[test]
650 fn p256_q_minus_n_plus_n_equals_0_test() {
651 q_minus_n_plus_n_equals_0_test(&p256::PUBLIC_SCALAR_OPS);
652 }
653
654 #[test]
655 fn p384_q_minus_n_plus_n_equals_0_test() {
656 q_minus_n_plus_n_equals_0_test(&p384::PUBLIC_SCALAR_OPS);
657 }
658
659 #[test]
660 fn p256_elem_add_test() {
661 elem_add_test(
662 &p256::PUBLIC_SCALAR_OPS,
663 test_file!("ops/p256_elem_sum_tests.txt"),
664 );
665 }
666
667 #[test]
668 fn p384_elem_add_test() {
669 elem_add_test(
670 &p384::PUBLIC_SCALAR_OPS,
671 test_file!("ops/p384_elem_sum_tests.txt"),
672 );
673 }
674
675 fn elem_add_test(ops: &PublicScalarOps, test_file: test::File) {
676 let cops = ops.public_key_ops.common;
677 let q = &cops.elem_modulus(cpu::features());
678 test::run(test_file, |section, test_case| {
679 assert_eq!(section, "");
680
681 let a = consume_elem(q, test_case, "a");
682 let b = consume_elem(q, test_case, "b");
683 let expected_sum = consume_elem(q, test_case, "r");
684
685 let mut actual_sum = a;
686 q.add_assign(&mut actual_sum, &b);
687 assert_limbs_are_equal(cops, &actual_sum.limbs, &expected_sum.limbs);
688
689 let mut actual_sum = b;
690 q.add_assign(&mut actual_sum, &a);
691 assert_limbs_are_equal(cops, &actual_sum.limbs, &expected_sum.limbs);
692
693 Ok(())
694 })
695 }
696
697 #[test]
701 fn p384_elem_sub_test() {
702 prefixed_extern! {
703 fn p384_elem_sub(r: *mut Limb, a: *const Limb, b: *const Limb);
704 }
705 elem_sub_test(
706 &p384::COMMON_OPS,
707 p384_elem_sub,
708 test_file!("ops/p384_elem_sum_tests.txt"),
709 );
710 }
711
712 fn elem_sub_test(
713 ops: &'static CommonOps,
714 elem_sub: unsafe extern "C" fn(r: *mut Limb, a: *const Limb, b: *const Limb),
715 test_file: test::File,
716 ) {
717 let q = &ops.elem_modulus(cpu::features());
718 test::run(test_file, |section, test_case| {
719 assert_eq!(section, "");
720
721 let a = consume_elem(q, test_case, "a");
722 let b = consume_elem(q, test_case, "b");
723 let r = consume_elem(q, test_case, "r");
724
725 let mut actual_difference = Elem::<R>::zero();
726 unsafe {
727 elem_sub(
728 actual_difference.limbs.as_mut_ptr(),
729 r.limbs.as_ptr(),
730 b.limbs.as_ptr(),
731 );
732 }
733 assert_limbs_are_equal(ops, &actual_difference.limbs, &a.limbs);
734
735 let mut actual_difference = Elem::<R>::zero();
736 unsafe {
737 elem_sub(
738 actual_difference.limbs.as_mut_ptr(),
739 r.limbs.as_ptr(),
740 a.limbs.as_ptr(),
741 );
742 }
743 assert_limbs_are_equal(ops, &actual_difference.limbs, &b.limbs);
744
745 Ok(())
746 })
747 }
748
749 #[test]
753 fn p384_elem_div_by_2_test() {
754 prefixed_extern! {
755 fn p384_elem_div_by_2(r: *mut Limb, a: *const Limb);
756 }
757 elem_div_by_2_test(
758 &p384::COMMON_OPS,
759 p384_elem_div_by_2,
760 test_file!("ops/p384_elem_div_by_2_tests.txt"),
761 );
762 }
763
764 fn elem_div_by_2_test(
765 ops: &'static CommonOps,
766 elem_div_by_2: unsafe extern "C" fn(r: *mut Limb, a: *const Limb),
767 test_file: test::File,
768 ) {
769 let q = &ops.elem_modulus(cpu::features());
770 test::run(test_file, |section, test_case| {
771 assert_eq!(section, "");
772
773 let a = consume_elem(q, test_case, "a");
774 let r = consume_elem(q, test_case, "r");
775
776 let mut actual_result = Elem::<R>::zero();
777 unsafe {
778 elem_div_by_2(actual_result.limbs.as_mut_ptr(), a.limbs.as_ptr());
779 }
780 assert_limbs_are_equal(ops, &actual_result.limbs, &r.limbs);
781
782 Ok(())
783 })
784 }
785
786 #[cfg(target_arch = "x86_64")]
788 #[test]
789 fn p256_elem_neg_test() {
790 prefixed_extern! {
791 fn ecp_nistz256_neg(r: *mut Limb, a: *const Limb);
792 }
793 elem_neg_test(
794 &p256::COMMON_OPS,
795 ecp_nistz256_neg,
796 test_file!("ops/p256_elem_neg_tests.txt"),
797 );
798 }
799
800 #[test]
801 fn p384_elem_neg_test() {
802 prefixed_extern! {
803 fn p384_elem_neg(r: *mut Limb, a: *const Limb);
804 }
805 elem_neg_test(
806 &p384::COMMON_OPS,
807 p384_elem_neg,
808 test_file!("ops/p384_elem_neg_tests.txt"),
809 );
810 }
811
812 fn elem_neg_test(
813 ops: &'static CommonOps,
814 elem_neg: unsafe extern "C" fn(r: *mut Limb, a: *const Limb),
815 test_file: test::File,
816 ) {
817 let q = &ops.elem_modulus(cpu::features());
818 test::run(test_file, |section, test_case| {
819 assert_eq!(section, "");
820
821 let a = consume_elem(q, test_case, "a");
822 let b = consume_elem(q, test_case, "b");
823
824 {
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(&p256::COMMON_OPS, test_file!("ops/p256_elem_mul_tests.txt"));
849 }
850
851 #[test]
852 fn p384_elem_mul_test() {
853 elem_mul_test(&p384::COMMON_OPS, test_file!("ops/p384_elem_mul_tests.txt"));
854 }
855
856 fn elem_mul_test(ops: &'static CommonOps, test_file: test::File) {
857 let q = &ops.elem_modulus(cpu::features());
858 test::run(test_file, |section, test_case| {
859 assert_eq!(section, "");
860
861 let mut a = consume_elem(q, test_case, "a");
862 let b = consume_elem(q, test_case, "b");
863 let r = consume_elem(q, test_case, "r");
864 q.elem_mul(&mut a, &b);
865 assert_limbs_are_equal(ops, &a.limbs, &r.limbs);
866
867 Ok(())
868 })
869 }
870
871 #[test]
872 fn p256_scalar_mul_test() {
873 scalar_mul_test(
874 &p256::SCALAR_OPS,
875 test_file!("ops/p256_scalar_mul_tests.txt"),
876 );
877 }
878
879 #[test]
880 fn p384_scalar_mul_test() {
881 scalar_mul_test(
882 &p384::SCALAR_OPS,
883 test_file!("ops/p384_scalar_mul_tests.txt"),
884 );
885 }
886
887 fn scalar_mul_test(ops: &ScalarOps, test_file: test::File) {
888 let cpu = cpu::features();
889 let cops = ops.common;
890 let n = &cops.scalar_modulus(cpu);
891 test::run(test_file, |section, test_case| {
892 assert_eq!(section, "");
893 let a = consume_scalar(n, test_case, "a");
894 let b = consume_scalar_mont(n, test_case, "b");
895 let expected_result = consume_scalar(n, test_case, "r");
896 let actual_result = ops.scalar_product(&a, &b, cpu);
897 assert_limbs_are_equal(cops, &actual_result.limbs, &expected_result.limbs);
898
899 Ok(())
900 })
901 }
902
903 #[test]
904 fn p256_scalar_square_test() {
905 prefixed_extern! {
906 fn p256_scalar_sqr_rep_mont(r: *mut Limb, a: *const Limb, rep: LeakyWord);
907 }
908 scalar_square_test(
909 &p256::SCALAR_OPS,
910 p256_scalar_sqr_rep_mont,
911 test_file!("ops/p256_scalar_square_tests.txt"),
912 );
913 }
914
915 fn scalar_square_test(
919 ops: &ScalarOps,
920 sqr_rep: unsafe extern "C" fn(r: *mut Limb, a: *const Limb, rep: LeakyWord),
921 test_file: test::File,
922 ) {
923 let cpu = cpu::features();
924 let cops = ops.common;
925 let n = &cops.scalar_modulus(cpu);
926 test::run(test_file, |section, test_case| {
927 assert_eq!(section, "");
928 let cpu = cpu::features();
929 let a = consume_scalar(n, test_case, "a");
930 let expected_result = consume_scalar(n, test_case, "r");
931
932 {
933 let mut actual_result: Scalar<R> = Scalar {
934 limbs: [0; elem::NumLimbs::MAX],
935 m: PhantomData,
936 encoding: PhantomData,
937 };
938 unsafe {
939 sqr_rep(actual_result.limbs.as_mut_ptr(), a.limbs.as_ptr(), 1);
940 }
941 assert_limbs_are_equal(cops, &actual_result.limbs, &expected_result.limbs);
942 }
943
944 {
945 let actual_result = ops.scalar_product(&a, &a, cpu);
946 assert_limbs_are_equal(cops, &actual_result.limbs, &expected_result.limbs);
947 }
948
949 Ok(())
950 })
951 }
952
953 #[test]
954 #[should_panic(expected = "!self.scalar_ops.common.is_zero(a)")]
955 fn p256_scalar_inv_to_mont_zero_panic_test() {
956 let _ = p256::PRIVATE_SCALAR_OPS.scalar_inv_to_mont(&ZERO_SCALAR, cpu::features());
957 }
958
959 #[test]
960 #[should_panic(expected = "!self.scalar_ops.common.is_zero(a)")]
961 fn p384_scalar_inv_to_mont_zero_panic_test() {
962 let _ = p384::PRIVATE_SCALAR_OPS.scalar_inv_to_mont(&ZERO_SCALAR, cpu::features());
963 }
964
965 #[test]
966 fn p256_point_sum_test() {
967 point_sum_test(
968 &p256::PRIVATE_KEY_OPS,
969 test_file!("ops/p256_point_sum_tests.txt"),
970 );
971 }
972
973 #[test]
974 fn p384_point_sum_test() {
975 point_sum_test(
976 &p384::PRIVATE_KEY_OPS,
977 test_file!("ops/p384_point_sum_tests.txt"),
978 );
979 }
980
981 fn point_sum_test(ops: &PrivateKeyOps, test_file: test::File) {
982 let cpu = cpu::features();
983
984 test::run(test_file, |section, test_case| {
985 assert_eq!(section, "");
986
987 let a = consume_jacobian_point(ops, test_case, "a");
988 let b = consume_jacobian_point(ops, test_case, "b");
989 let r_expected: TestPoint<R> = consume_point(ops, test_case, "r");
990
991 let r_actual = ops.point_sum(&a, &b, cpu);
992 assert_point_actual_equals_expected(ops, &r_actual, &r_expected);
993
994 Ok(())
995 });
996 }
997
998 #[test]
999 fn p256_point_sum_mixed_test() {
1000 prefixed_extern! {
1001 fn p256_point_add_affine(
1002 r: *mut Limb, a: *const Limb, b: *const Limb, );
1006 }
1007 point_sum_mixed_test(
1008 &p256::PRIVATE_KEY_OPS,
1009 p256_point_add_affine,
1010 test_file!("ops/p256_point_sum_mixed_tests.txt"),
1011 );
1012 }
1013
1014 fn point_sum_mixed_test(
1017 ops: &PrivateKeyOps,
1018 point_add_affine: unsafe extern "C" fn(
1019 r: *mut Limb, a: *const Limb, b: *const Limb, ),
1023 test_file: test::File,
1024 ) {
1025 test::run(test_file, |section, test_case| {
1026 assert_eq!(section, "");
1027
1028 let a = consume_jacobian_point(ops, test_case, "a");
1029 let b = consume_affine_point(ops, test_case, "b");
1030 let r_expected: TestPoint<R> = consume_point(ops, test_case, "r");
1031
1032 let mut r_actual = Point::new_at_infinity();
1033 unsafe {
1034 point_add_affine(r_actual.xyz.as_mut_ptr(), a.xyz.as_ptr(), b.xy.as_ptr());
1035 }
1036
1037 assert_point_actual_equals_expected(ops, &r_actual, &r_expected);
1038
1039 Ok(())
1040 });
1041 }
1042
1043 #[test]
1044 fn p256_point_double_test() {
1045 prefixed_extern! {
1046 fn p256_point_double(
1047 r: *mut Limb, a: *const Limb, );
1050 }
1051 point_double_test(
1052 &p256::PRIVATE_KEY_OPS,
1053 p256_point_double,
1054 test_file!("ops/p256_point_double_tests.txt"),
1055 );
1056 }
1057
1058 #[test]
1059 fn p384_point_double_test() {
1060 prefixed_extern! {
1061 fn p384_point_double(
1062 r: *mut Limb, a: *const Limb, );
1065 }
1066 point_double_test(
1067 &p384::PRIVATE_KEY_OPS,
1068 p384_point_double,
1069 test_file!("ops/p384_point_double_tests.txt"),
1070 );
1071 }
1072
1073 fn point_double_test(
1074 ops: &PrivateKeyOps,
1075 point_double: unsafe extern "C" fn(
1076 r: *mut Limb, a: *const Limb, ),
1079 test_file: test::File,
1080 ) {
1081 test::run(test_file, |section, test_case| {
1082 assert_eq!(section, "");
1083
1084 let a = consume_jacobian_point(ops, test_case, "a");
1085 let r_expected: TestPoint<R> = consume_point(ops, test_case, "r");
1086
1087 let mut r_actual = Point::new_at_infinity();
1088 unsafe {
1089 point_double(r_actual.xyz.as_mut_ptr(), a.xyz.as_ptr());
1090 }
1091
1092 assert_point_actual_equals_expected(ops, &r_actual, &r_expected);
1093
1094 Ok(())
1095 });
1096 }
1097
1098 #[test]
1100 fn p256_point_mul_test() {
1101 let generator = (
1102 Elem::from(&p256::GENERATOR.0),
1103 Elem::from(&p256::GENERATOR.1),
1104 );
1105 point_mul_base_tests(
1106 &p256::PRIVATE_KEY_OPS,
1107 |s, cpu| p256::PRIVATE_KEY_OPS.point_mul(s, &generator, cpu),
1108 test_file!("ops/p256_point_mul_base_tests.txt"),
1109 );
1110 }
1111
1112 #[test]
1114 fn p384_point_mul_test() {
1115 let generator = (
1116 Elem::from(&p384::GENERATOR.0),
1117 Elem::from(&p384::GENERATOR.1),
1118 );
1119
1120 point_mul_base_tests(
1121 &p384::PRIVATE_KEY_OPS,
1122 |s, cpu| p384::PRIVATE_KEY_OPS.point_mul(s, &generator, cpu),
1123 test_file!("ops/p384_point_mul_base_tests.txt"),
1124 );
1125 }
1126
1127 #[test]
1128 fn p256_point_mul_serialized_test() {
1129 point_mul_serialized_test(
1130 &p256::PRIVATE_KEY_OPS,
1131 &p256::PUBLIC_KEY_OPS,
1132 test_file!("ops/p256_point_mul_serialized_tests.txt"),
1133 );
1134 }
1135
1136 fn point_mul_serialized_test(
1137 priv_ops: &PrivateKeyOps,
1138 pub_ops: &PublicKeyOps,
1139 test_file: test::File,
1140 ) {
1141 let cpu = cpu::features();
1142 let cops = pub_ops.common;
1143 let q = &cops.elem_modulus(cpu);
1144 let n = &cops.scalar_modulus(cpu);
1145 test::run(test_file, |section, test_case| {
1146 assert_eq!(section, "");
1147 let p_scalar = consume_scalar(n, test_case, "p_scalar");
1148
1149 let p = test_case.consume_bytes("p");
1150 let p = super::super::public_key::parse_uncompressed_point(
1151 pub_ops,
1152 q,
1153 untrusted::Input::from(&p),
1154 )
1155 .expect("valid point");
1156
1157 let expected_result = test_case.consume_bytes("r");
1158
1159 let product = priv_ops.point_mul(&p_scalar, &p, cpu::features());
1160
1161 let mut actual_result = vec![4u8; 1 + (2 * cops.len())];
1162 {
1163 let (x, y) = actual_result[1..].split_at_mut(cops.len());
1164 super::super::private_key::big_endian_affine_from_jacobian(
1165 priv_ops,
1166 q,
1167 x,
1168 Some(y),
1169 &product,
1170 )
1171 .expect("successful encoding");
1172 }
1173
1174 assert_eq!(expected_result, actual_result);
1175
1176 Ok(())
1177 })
1178 }
1179
1180 #[test]
1181 fn p256_point_mul_base_test() {
1182 point_mul_base_tests(
1183 &p256::PRIVATE_KEY_OPS,
1184 |s, cpu| p256::PRIVATE_KEY_OPS.point_mul_base(s, cpu),
1185 test_file!("ops/p256_point_mul_base_tests.txt"),
1186 );
1187 }
1188
1189 #[test]
1190 fn p384_point_mul_base_test() {
1191 point_mul_base_tests(
1192 &p384::PRIVATE_KEY_OPS,
1193 |s, cpu| p384::PRIVATE_KEY_OPS.point_mul_base(s, cpu),
1194 test_file!("ops/p384_point_mul_base_tests.txt"),
1195 );
1196 }
1197
1198 pub(super) fn point_mul_base_tests(
1199 ops: &PrivateKeyOps,
1200 f: impl Fn(&Scalar, cpu::Features) -> Point,
1201 test_file: test::File,
1202 ) {
1203 let cpu = cpu::features();
1204 let n = &ops.common.scalar_modulus(cpu);
1205 test::run(test_file, |section, test_case| {
1206 assert_eq!(section, "");
1207 let g_scalar = consume_scalar(n, test_case, "g_scalar");
1208 let expected_result: TestPoint<Unencoded> = consume_point(ops, test_case, "r");
1209 let actual_result = f(&g_scalar, cpu);
1210 assert_point_actual_equals_expected(ops, &actual_result, &expected_result);
1211 Ok(())
1212 })
1213 }
1214
1215 fn assert_point_actual_equals_expected<E: Encoding>(
1216 ops: &PrivateKeyOps,
1217 actual_point: &Point,
1218 expected_point: &TestPoint<E>,
1219 ) where
1220 Elem<R>: Convert<E>,
1221 {
1222 let cpu = cpu::features();
1223
1224 let cops = ops.common;
1225 let q = &cops.elem_modulus(cpu);
1226 let actual_x = &q.point_x(actual_point);
1227 let actual_y = &q.point_y(actual_point);
1228 let actual_z = &q.point_z(actual_point);
1229 match expected_point {
1230 TestPoint::Infinity => {
1231 let zero = Elem::zero();
1232 assert_elems_are_equal(q, actual_z, &zero);
1233 }
1234 TestPoint::Affine(expected_x, expected_y) => {
1235 let zz_inv = ops.elem_inverse_squared(q, actual_z);
1236 let x_aff = q.elem_product(actual_x, &zz_inv);
1237 let y_aff = {
1238 let zzzz_inv = q.elem_squared(&zz_inv);
1239 let zzz_inv = q.elem_product(actual_z, &zzzz_inv);
1240 q.elem_product(actual_y, &zzz_inv)
1241 };
1242
1243 let x_aff = x_aff.convert(q);
1244 let y_aff = y_aff.convert(q);
1245
1246 assert_elems_are_equal(q, &x_aff, expected_x);
1247 assert_elems_are_equal(q, &y_aff, expected_y);
1248 }
1249 }
1250 }
1251
1252 fn consume_jacobian_point(
1253 ops: &PrivateKeyOps,
1254 test_case: &mut test::TestCase,
1255 name: &str,
1256 ) -> Point {
1257 let q = &ops.common.elem_modulus(cpu::features());
1258 let input = test_case.consume_string(name);
1259 let elems = input.split(", ").collect::<Vec<&str>>();
1260 assert_eq!(elems.len(), 3);
1261 let mut p = Point::new_at_infinity();
1262 consume_point_elem(q, &mut p.xyz, &elems, 0);
1263 consume_point_elem(q, &mut p.xyz, &elems, 1);
1264 consume_point_elem(q, &mut p.xyz, &elems, 2);
1265 p
1266 }
1267
1268 struct AffinePoint {
1269 xy: [Limb; 2 * elem::NumLimbs::MAX],
1270 }
1271
1272 fn consume_affine_point(
1273 ops: &PrivateKeyOps,
1274 test_case: &mut test::TestCase,
1275 name: &str,
1276 ) -> AffinePoint {
1277 let q = &ops.common.elem_modulus(cpu::features());
1278 let input = test_case.consume_string(name);
1279 let elems = input.split(", ").collect::<Vec<&str>>();
1280 assert_eq!(elems.len(), 2);
1281 let mut p = AffinePoint {
1282 xy: [0; 2 * elem::NumLimbs::MAX],
1283 };
1284 consume_point_elem(q, &mut p.xy, &elems, 0);
1285 consume_point_elem(q, &mut p.xy, &elems, 1);
1286 p
1287 }
1288
1289 fn consume_point_elem(q: &Modulus<Q>, limbs_out: &mut [Limb], elems: &[&str], i: usize) {
1290 let num_limbs = q.num_limbs.into();
1291 let bytes = test::from_hex(elems[i]).unwrap();
1292 let bytes = untrusted::Input::from(&bytes);
1293 let r: Elem<Unencoded> = elem_parse_big_endian_fixed_consttime(q, bytes).unwrap();
1294 limbs_out[(i * num_limbs)..((i + 1) * num_limbs)].copy_from_slice(&r.limbs[..num_limbs]);
1296 }
1297
1298 enum TestPoint<E: Encoding> {
1299 Infinity,
1300 Affine(Elem<E>, Elem<E>),
1301 }
1302
1303 fn consume_point<E: Encoding>(
1304 ops: &PrivateKeyOps,
1305 test_case: &mut test::TestCase,
1306 name: &str,
1307 ) -> TestPoint<E> {
1308 let q = &ops.common.elem_modulus(cpu::features());
1309 fn consume_point_elem<E: Encoding>(q: &Modulus<Q>, elems: &[&str], i: usize) -> Elem<E> {
1310 let bytes = test::from_hex(elems[i]).unwrap();
1311 let bytes = untrusted::Input::from(&bytes);
1312 let unencoded: Elem<Unencoded> =
1313 elem_parse_big_endian_fixed_consttime(q, bytes).unwrap();
1314 Elem {
1316 limbs: unencoded.limbs,
1317 m: PhantomData,
1318 encoding: PhantomData,
1319 }
1320 }
1321
1322 let input = test_case.consume_string(name);
1323 if input == "inf" {
1324 return TestPoint::Infinity;
1325 }
1326 let elems = input.split(", ").collect::<Vec<&str>>();
1327 assert_eq!(elems.len(), 2);
1328 let x = consume_point_elem(q, &elems, 0);
1329 let y = consume_point_elem(q, &elems, 1);
1330 TestPoint::Affine(x, y)
1331 }
1332
1333 fn assert_elems_are_equal<E: Encoding>(q: &Modulus<Q>, a: &Elem<E>, b: &Elem<E>) {
1334 assert_limbs_are_equal(q.cops, &a.limbs, &b.limbs)
1335 }
1336
1337 fn assert_limbs_are_equal(
1338 ops: &CommonOps,
1339 actual: &[Limb; elem::NumLimbs::MAX],
1340 expected: &[Limb; elem::NumLimbs::MAX],
1341 ) {
1342 let num_limbs = ops.num_limbs.into();
1343 if actual[..num_limbs] != expected[..num_limbs] {
1344 let mut actual_s = alloc::string::String::new();
1345 let mut expected_s = alloc::string::String::new();
1346 for j in 0..num_limbs {
1347 let width = LIMB_BITS / 4;
1348 let formatted = format!("{:0width$x}", actual[num_limbs - j - 1]);
1349 actual_s.push_str(&formatted);
1350 let formatted = format!("{:0width$x}", expected[num_limbs - j - 1]);
1351 expected_s.push_str(&formatted);
1352 }
1353 panic!(
1354 "Actual != Expected,\nActual = {}, Expected = {}",
1355 actual_s, expected_s
1356 );
1357 }
1358 }
1359
1360 fn consume_elem(q: &Modulus<Q>, test_case: &mut test::TestCase, name: &str) -> Elem<R> {
1361 let unpadded_bytes = test_case.consume_bytes(name);
1362 let mut bytes = vec![0; q.bytes_len() - unpadded_bytes.len()];
1363 bytes.extend(&unpadded_bytes);
1364
1365 let bytes = untrusted::Input::from(&bytes);
1366 let r: Elem<Unencoded> = elem_parse_big_endian_fixed_consttime(q, bytes).unwrap();
1367 Elem {
1369 limbs: r.limbs,
1370 m: PhantomData,
1371 encoding: PhantomData,
1372 }
1373 }
1374
1375 fn consume_scalar(n: &Modulus<N>, test_case: &mut test::TestCase, name: &str) -> Scalar {
1376 let bytes = test_case.consume_bytes(name);
1377 let bytes = untrusted::Input::from(&bytes);
1378 scalar_parse_big_endian_variable(n, AllowZero::Yes, bytes).unwrap()
1379 }
1380
1381 fn consume_scalar_mont(
1382 n: &Modulus<N>,
1383 test_case: &mut test::TestCase,
1384 name: &str,
1385 ) -> Scalar<R> {
1386 let bytes = test_case.consume_bytes(name);
1387 let bytes = untrusted::Input::from(&bytes);
1388 let s = scalar_parse_big_endian_variable(n, AllowZero::Yes, bytes).unwrap();
1389 Scalar {
1391 limbs: s.limbs,
1392 m: PhantomData,
1393 encoding: PhantomData,
1394 }
1395 }
1396}
1397
1398mod elem;
1399pub mod p256;
1400pub mod p384;