Skip to content

Commit 6212ecb

Browse files
committed
ec/suite_b: Thread CPU features through functions using Modulus.
Follow the same pattern that is used in arithmetic/bigint.rs: Since we have to construct a `Modulus` at roughly the same place we have to get the proof we've done CPU feature detection, just have `Modulus` contain the `cpu::Features`, so that any function that takes a `Modulus` no longer needs a `cpu::Features` argument. Then, make a step towards threading `cpu::Features` all the way down to to the callers of the lowest-level C/assembly functions. This will facilitate a future refactoring where all dispatching based on CPU features is moved out of the assembly code, from upstream.
1 parent 3518d05 commit 6212ecb

15 files changed

+283
-209
lines changed

mk/generate_curves.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,13 @@
7777
// %(q_minus_3)s
7878
7979
#[inline]
80-
fn sqr_mul(a: &Elem<R>, squarings: LeakyWord, b: &Elem<R>) -> Elem<R> {
81-
elem_sqr_mul(&COMMON_OPS, a, squarings, b)
80+
fn sqr_mul(q: &Modulus<Q>, a: &Elem<R>, squarings: LeakyWord, b: &Elem<R>) -> Elem<R> {
81+
elem_sqr_mul(&COMMON_OPS, a, squarings, b, q.cpu())
8282
}
8383
8484
#[inline]
85-
fn sqr_mul_acc(a: &mut Elem<R>, squarings: LeakyWord, b: &Elem<R>) {
86-
elem_sqr_mul_acc(&COMMON_OPS, a, squarings, b)
85+
fn sqr_mul_acc(q: &Modulus<Q>, a: &mut Elem<R>, squarings: LeakyWord, b: &Elem<R>) {
86+
elem_sqr_mul_acc(&COMMON_OPS, a, squarings, b, q.cpu())
8787
}
8888
8989
let b_1 = &a;

src/ec.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,13 @@ pub struct Curve {
2323
pub id: CurveID,
2424

2525
// Precondition: `bytes` is the correct length.
26-
check_private_key_bytes: fn(bytes: &[u8]) -> Result<(), error::Unspecified>,
26+
check_private_key_bytes: fn(bytes: &[u8], cpu: cpu::Features) -> Result<(), error::Unspecified>,
2727

28-
generate_private_key:
29-
fn(rng: &dyn rand::SecureRandom, &mut [u8]) -> Result<(), error::Unspecified>,
28+
generate_private_key: fn(
29+
rng: &dyn rand::SecureRandom,
30+
&mut [u8],
31+
cpu: cpu::Features,
32+
) -> Result<(), error::Unspecified>,
3033

3134
public_from_private: fn(
3235
public_out: &mut [u8],

src/ec/curve25519/x25519.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,18 @@ pub static X25519: agreement::Algorithm = agreement::Algorithm {
4040
};
4141

4242
#[allow(clippy::unnecessary_wraps)]
43-
fn x25519_check_private_key_bytes(bytes: &[u8]) -> Result<(), error::Unspecified> {
43+
fn x25519_check_private_key_bytes(
44+
bytes: &[u8],
45+
_: cpu::Features,
46+
) -> Result<(), error::Unspecified> {
4447
debug_assert_eq!(bytes.len(), PRIVATE_KEY_LEN);
4548
Ok(())
4649
}
4750

4851
fn x25519_generate_private_key(
4952
rng: &dyn rand::SecureRandom,
5053
out: &mut [u8],
54+
_: cpu::Features,
5155
) -> Result<(), error::Unspecified> {
5256
rng.fill(out)
5357
}

src/ec/keys.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -32,26 +32,26 @@ impl Seed {
3232
pub(crate) fn generate(
3333
curve: &'static Curve,
3434
rng: &dyn rand::SecureRandom,
35-
_cpu_features: cpu::Features,
35+
cpu: cpu::Features,
3636
) -> Result<Self, error::Unspecified> {
3737
let mut r = Self {
3838
bytes: [0u8; SEED_MAX_BYTES],
3939
curve,
4040
};
41-
(curve.generate_private_key)(rng, &mut r.bytes[..curve.elem_scalar_seed_len])?;
41+
(curve.generate_private_key)(rng, &mut r.bytes[..curve.elem_scalar_seed_len], cpu)?;
4242
Ok(r)
4343
}
4444

4545
pub(crate) fn from_bytes(
4646
curve: &'static Curve,
4747
bytes: untrusted::Input,
48-
_cpu_features: cpu::Features,
48+
cpu: cpu::Features,
4949
) -> Result<Self, error::Unspecified> {
5050
let bytes = bytes.as_slice_less_safe();
5151
if curve.elem_scalar_seed_len != bytes.len() {
5252
return Err(error::Unspecified);
5353
}
54-
(curve.check_private_key_bytes)(bytes)?;
54+
(curve.check_private_key_bytes)(bytes, cpu)?;
5555
let mut r = Self {
5656
bytes: [0; SEED_MAX_BYTES],
5757
curve,

src/ec/suite_b.rs

+17-26
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,10 @@ use crate::{arithmetic::montgomery::*, cpu, ec, error, io::der, pkcs8};
3030
// y**2 == (x**2 + a)*x + b (mod q)
3131
//
3232
fn verify_affine_point_is_on_the_curve(
33-
ops: &CommonOps,
3433
q: &Modulus<Q>,
3534
(x, y): (&Elem<R>, &Elem<R>),
3635
) -> Result<(), error::Unspecified> {
37-
verify_affine_point_is_on_the_curve_scaled(
38-
ops,
39-
q,
40-
(x, y),
41-
&Elem::from(&ops.a),
42-
&Elem::from(&ops.b),
43-
)
36+
verify_affine_point_is_on_the_curve_scaled(q, (x, y), &Elem::from(q.a()), &Elem::from(q.b()))
4437
}
4538

4639
// Use `verify_affine_point_is_on_the_curve` instead of this function whenever
@@ -53,17 +46,16 @@ fn verify_affine_point_is_on_the_curve(
5346
//
5447
// This function also verifies that the point is not at infinity.
5548
fn verify_jacobian_point_is_on_the_curve(
56-
ops: &CommonOps,
5749
q: &Modulus<Q>,
5850
p: &Point,
5951
) -> Result<Elem<R>, error::Unspecified> {
60-
let z = ops.point_z(p);
52+
let z = q.point_z(p);
6153

6254
// Verify that the point is not at infinity.
63-
ops.elem_verify_is_not_zero(&z)?;
55+
q.elem_verify_is_not_zero(&z)?;
6456

65-
let x = ops.point_x(p);
66-
let y = ops.point_y(p);
57+
let x = q.point_x(p);
58+
let y = q.point_y(p);
6759

6860
// We are given Jacobian coordinates (x, y, z). So, we have:
6961
//
@@ -107,12 +99,12 @@ fn verify_jacobian_point_is_on_the_curve(
10799
//
108100
// y**2 == (x**2 + z**4 * a) * x + (z**6) * b
109101
//
110-
let z2 = ops.elem_squared(&z);
111-
let z4 = ops.elem_squared(&z2);
112-
let z4_a = ops.elem_product(&z4, &Elem::from(&ops.a));
113-
let z6 = ops.elem_product(&z4, &z2);
114-
let z6_b = ops.elem_product(&z6, &Elem::from(&ops.b));
115-
verify_affine_point_is_on_the_curve_scaled(ops, q, (&x, &y), &z4_a, &z6_b)?;
102+
let z2 = q.elem_squared(&z);
103+
let z4 = q.elem_squared(&z2);
104+
let z4_a = q.elem_product(&z4, &Elem::from(q.a()));
105+
let z6 = q.elem_product(&z4, &z2);
106+
let z6_b = q.elem_product(&z6, &Elem::from(q.b()));
107+
verify_affine_point_is_on_the_curve_scaled(q, (&x, &y), &z4_a, &z6_b)?;
116108
Ok(z2)
117109
}
118110

@@ -142,20 +134,19 @@ fn verify_jacobian_point_is_on_the_curve(
142134
// Elliptic Curve Cryptosystems" by Johannes Blömer, Martin Otto, and
143135
// Jean-Pierre Seifert.
144136
fn verify_affine_point_is_on_the_curve_scaled(
145-
ops: &CommonOps,
146137
q: &Modulus<Q>,
147138
(x, y): (&Elem<R>, &Elem<R>),
148139
a_scaled: &Elem<R>,
149140
b_scaled: &Elem<R>,
150141
) -> Result<(), error::Unspecified> {
151-
let lhs = ops.elem_squared(y);
142+
let lhs = q.elem_squared(y);
152143

153-
let mut rhs = ops.elem_squared(x);
154-
q.elem_add(&mut rhs, a_scaled);
155-
ops.elem_mul(&mut rhs, x);
156-
q.elem_add(&mut rhs, b_scaled);
144+
let mut rhs = q.elem_squared(x);
145+
q.add_assign(&mut rhs, a_scaled);
146+
q.elem_mul(&mut rhs, x);
147+
q.add_assign(&mut rhs, b_scaled);
157148

158-
if !ops.elems_are_equal(&lhs, &rhs).leak() {
149+
if !q.elems_are_equal(&lhs, &rhs).leak() {
159150
return Err(error::Unspecified);
160151
}
161152

src/ec/suite_b/curve.rs

+9-5
Original file line numberDiff line numberDiff line change
@@ -41,28 +41,32 @@ macro_rules! suite_b_curve {
4141
public_from_private: $public_from_private,
4242
};
4343

44-
fn $check_private_key_bytes(bytes: &[u8]) -> Result<(), error::Unspecified> {
44+
fn $check_private_key_bytes(
45+
bytes: &[u8],
46+
cpu: cpu::Features,
47+
) -> Result<(), error::Unspecified> {
4548
debug_assert_eq!(bytes.len(), $bits / 8);
46-
ec::suite_b::private_key::check_scalar_big_endian_bytes($private_key_ops, bytes)
49+
ec::suite_b::private_key::check_scalar_big_endian_bytes($private_key_ops, bytes, cpu)
4750
}
4851

4952
fn $generate_private_key(
5053
rng: &dyn rand::SecureRandom,
5154
out: &mut [u8],
55+
cpu: cpu::Features,
5256
) -> Result<(), error::Unspecified> {
53-
ec::suite_b::private_key::generate_private_scalar_bytes($private_key_ops, rng, out)
57+
ec::suite_b::private_key::generate_private_scalar_bytes($private_key_ops, rng, out, cpu)
5458
}
5559

5660
fn $public_from_private(
5761
public_out: &mut [u8],
5862
private_key: &ec::Seed,
59-
cpu_features: cpu::Features,
63+
cpu: cpu::Features,
6064
) -> Result<(), error::Unspecified> {
6165
ec::suite_b::private_key::public_from_private(
6266
$private_key_ops,
6367
public_out,
6468
private_key,
65-
cpu_features,
69+
cpu,
6670
)
6771
}
6872
};

src/ec/suite_b/ecdh.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ fn ecdh(
9393
// The "NSA Guide" steps are from section 3.1 of the NSA guide, "Ephemeral
9494
// Unified Model."
9595

96-
let q = &public_key_ops.common.elem_modulus();
96+
let q = &public_key_ops.common.elem_modulus(cpu);
9797

9898
// NSA Guide Step 1 is handled separately.
9999

@@ -103,7 +103,7 @@ fn ecdh(
103103
// `parse_uncompressed_point` verifies that the point is not at infinity
104104
// and that it is on the curve, using the Partial Public-Key Validation
105105
// Routine.
106-
let peer_public_key = parse_uncompressed_point(public_key_ops, q, peer_public_key, cpu)?;
106+
let peer_public_key = parse_uncompressed_point(public_key_ops, q, peer_public_key)?;
107107

108108
// NIST SP 800-56Ar2 Step 1.
109109
// NSA Guide Step 3 (except point at infinity check).
@@ -125,7 +125,7 @@ fn ecdh(
125125
// information about their values can be recovered. This doesn't meet the
126126
// NSA guide's explicit requirement to "zeroize" them though.
127127
// TODO: this only needs common scalar ops
128-
let n = &private_key_ops.common.scalar_modulus();
128+
let n = &private_key_ops.common.scalar_modulus(cpu);
129129
let my_private_key = private_key_as_scalar(n, my_private_key);
130130
let product = private_key_ops.point_mul(&my_private_key, &peer_public_key, cpu);
131131

@@ -137,7 +137,7 @@ fn ecdh(
137137
// `big_endian_affine_from_jacobian` verifies that the result is not at
138138
// infinity and also does an extra check to verify that the point is on
139139
// the curve.
140-
big_endian_affine_from_jacobian(private_key_ops, q, out, None, &product, cpu)
140+
big_endian_affine_from_jacobian(private_key_ops, q, out, None, &product)
141141

142142
// NSA Guide Step 5 & 6 are deferred to the caller. Again, we have a
143143
// pretty liberal interpretation of the NIST's spec's "Destroy" that

src/ec/suite_b/ecdsa/digest_scalar.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,11 @@ fn digest_scalar_(n: &Modulus<N>, digest: &[u8]) -> Scalar {
6868
#[cfg(test)]
6969
mod tests {
7070
use super::digest_bytes_scalar;
71-
use crate::{digest, ec::suite_b::ops::*, limb, test};
71+
use crate::{cpu, digest, ec::suite_b::ops::*, limb, test};
7272

7373
#[test]
7474
fn test() {
75+
let cpu = cpu::features();
7576
test::run(
7677
test_file!("ecdsa_digest_scalar_tests.txt"),
7778
|section, test_case| {
@@ -91,7 +92,7 @@ mod tests {
9192
panic!("Unsupported curve+digest: {}+{}", curve_name, digest_name);
9293
}
9394
};
94-
let n = &ops.scalar_ops.scalar_modulus();
95+
let n = &ops.scalar_ops.scalar_modulus(cpu);
9596

9697
assert_eq!(input.len(), digest_alg.output_len());
9798
assert_eq!(output.len(), ops.scalar_ops.scalar_bytes_len());

src/ec/suite_b/ecdsa/signing.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ impl EcdsaKeyPair {
156156
let cpu = cpu::features();
157157

158158
let (seed, public_key) = key_pair.split();
159-
let n = &alg.private_scalar_ops.scalar_ops.scalar_modulus();
159+
let n = &alg.private_scalar_ops.scalar_ops.scalar_modulus(cpu);
160160
let d = private_key::private_key_as_scalar(n, &seed);
161161
let d = alg.private_scalar_ops.to_mont(&d, cpu);
162162

@@ -240,8 +240,8 @@ impl EcdsaKeyPair {
240240
let scalar_ops = ops.scalar_ops;
241241
let cops = scalar_ops.common;
242242
let private_key_ops = self.alg.private_key_ops;
243-
let q = &cops.elem_modulus();
244-
let n = &scalar_ops.scalar_modulus();
243+
let q = &cops.elem_modulus(cpu);
244+
let n = &scalar_ops.scalar_modulus(cpu);
245245

246246
for _ in 0..100 {
247247
// XXX: iteration conut?
@@ -254,11 +254,11 @@ impl EcdsaKeyPair {
254254

255255
// Step 3.
256256
let r = {
257-
let (x, _) = private_key::affine_from_jacobian(private_key_ops, q, &r, cpu)?;
258-
let x = cops.elem_unencoded(&x);
257+
let (x, _) = private_key::affine_from_jacobian(private_key_ops, q, &r)?;
258+
let x = q.elem_unencoded(&x);
259259
n.elem_reduced_to_scalar(&x)
260260
};
261-
if cops.is_zero(&r) {
261+
if n.is_zero(&r) {
262262
continue;
263263
}
264264

@@ -270,7 +270,7 @@ impl EcdsaKeyPair {
270270
// Step 6.
271271
let s = {
272272
let mut e_plus_dr = scalar_ops.scalar_product(&self.d, &r, cpu);
273-
n.elem_add(&mut e_plus_dr, &e);
273+
n.add_assign(&mut e_plus_dr, &e);
274274
scalar_ops.scalar_product(&k_inv, &e_plus_dr, cpu)
275275
};
276276
if cops.is_zero(&s) {

0 commit comments

Comments
 (0)