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