ring/ec/suite_b/ops/
p256.rs

1// Copyright 2016-2023 Brian Smith.
2//
3// Permission to use, copy, modify, and/or distribute this software for any
4// purpose with or without fee is hereby granted, provided that the above
5// copyright notice and this permission notice appear in all copies.
6//
7// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
8// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
10// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14
15use super::{
16    elem::{binary_op, binary_op_assign},
17    elem_sqr_mul, elem_sqr_mul_acc, Modulus, *,
18};
19
20pub static COMMON_OPS: CommonOps = CommonOps {
21    num_limbs: 256 / LIMB_BITS,
22
23    q: Modulus {
24        p: limbs_from_hex("ffffffff00000001000000000000000000000000ffffffffffffffffffffffff"),
25        rr: limbs_from_hex("4fffffffdfffffffffffffffefffffffbffffffff0000000000000003"),
26    },
27    n: Elem::from_hex("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551"),
28
29    a: Elem::from_hex("fffffffc00000004000000000000000000000003fffffffffffffffffffffffc"),
30    b: Elem::from_hex("dc30061d04874834e5a220abf7212ed6acf005cd78843090d89cdf6229c4bddf"),
31
32    elem_mul_mont: p256_mul_mont,
33    elem_sqr_mont: p256_sqr_mont,
34
35    point_add_jacobian_impl: p256_point_add,
36};
37
38#[cfg(test)]
39pub(super) static GENERATOR: (Elem<R>, Elem<R>) = (
40    Elem::from_hex("18905f76a53755c679fb732b7762251075ba95fc5fedb60179e730d418a9143c"),
41    Elem::from_hex("8571ff1825885d85d2e88688dd21f3258b4ab8e4ba19e45cddf25357ce95560a"),
42);
43
44pub static PRIVATE_KEY_OPS: PrivateKeyOps = PrivateKeyOps {
45    common: &COMMON_OPS,
46    elem_inv_squared: p256_elem_inv_squared,
47    point_mul_base_impl: p256_point_mul_base_impl,
48    point_mul_impl: p256_point_mul,
49};
50
51fn p256_elem_inv_squared(a: &Elem<R>) -> Elem<R> {
52    // Calculate a**-2 (mod q) == a**(q - 3) (mod q)
53    //
54    // The exponent (q - 3) is:
55    //
56    //    0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc
57
58    #[inline]
59    fn sqr_mul(a: &Elem<R>, squarings: usize, b: &Elem<R>) -> Elem<R> {
60        elem_sqr_mul(&COMMON_OPS, a, squarings, b)
61    }
62
63    #[inline]
64    fn sqr_mul_acc(a: &mut Elem<R>, squarings: usize, b: &Elem<R>) {
65        elem_sqr_mul_acc(&COMMON_OPS, a, squarings, b)
66    }
67
68    let b_1 = &a;
69    let b_11 = sqr_mul(b_1, 1, b_1);
70    let b_111 = sqr_mul(&b_11, 1, b_1);
71    let f_11 = sqr_mul(&b_111, 3, &b_111);
72    let fff = sqr_mul(&f_11, 6, &f_11);
73    let fff_111 = sqr_mul(&fff, 3, &b_111);
74    let fffffff_11 = sqr_mul(&fff_111, 15, &fff_111);
75    let ffffffff = sqr_mul(&fffffff_11, 2, &b_11);
76
77    // ffffffff00000001
78    let mut acc = sqr_mul(&ffffffff, 31 + 1, b_1);
79
80    // ffffffff00000001000000000000000000000000ffffffff
81    sqr_mul_acc(&mut acc, 96 + 32, &ffffffff);
82
83    // ffffffff00000001000000000000000000000000ffffffffffffffff
84    sqr_mul_acc(&mut acc, 32, &ffffffff);
85
86    // ffffffff00000001000000000000000000000000fffffffffffffffffffffff_11
87    sqr_mul_acc(&mut acc, 30, &fffffff_11);
88
89    // ffffffff00000001000000000000000000000000fffffffffffffffffffffffc
90    COMMON_OPS.elem_square(&mut acc);
91    COMMON_OPS.elem_square(&mut acc);
92
93    acc
94}
95
96fn p256_point_mul_base_impl(g_scalar: &Scalar) -> Point {
97    prefixed_extern! {
98        fn p256_point_mul_base(
99            r: *mut Limb,          // [3][COMMON_OPS.num_limbs]
100            g_scalar: *const Limb, // [COMMON_OPS.num_limbs]
101        );
102    }
103
104    let mut r = Point::new_at_infinity();
105    unsafe {
106        p256_point_mul_base(r.xyz.as_mut_ptr(), g_scalar.limbs.as_ptr());
107    }
108    r
109}
110
111pub static PUBLIC_KEY_OPS: PublicKeyOps = PublicKeyOps {
112    common: &COMMON_OPS,
113};
114
115pub static SCALAR_OPS: ScalarOps = ScalarOps {
116    common: &COMMON_OPS,
117    scalar_mul_mont: p256_scalar_mul_mont,
118};
119
120pub static PUBLIC_SCALAR_OPS: PublicScalarOps = PublicScalarOps {
121    scalar_ops: &SCALAR_OPS,
122    public_key_ops: &PUBLIC_KEY_OPS,
123
124    #[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))]
125    twin_mul: twin_mul_nistz256,
126
127    #[cfg(not(any(target_arch = "aarch64", target_arch = "x86_64")))]
128    twin_mul: |g_scalar, p_scalar, p_xy| {
129        twin_mul_inefficient(&PRIVATE_KEY_OPS, g_scalar, p_scalar, p_xy)
130    },
131
132    q_minus_n: Elem::from_hex("4319055358e8617b0c46353d039cdaae"),
133
134    // TODO: Use an optimized variable-time implementation.
135    scalar_inv_to_mont_vartime: |s| PRIVATE_SCALAR_OPS.scalar_inv_to_mont(s),
136};
137
138#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))]
139fn twin_mul_nistz256(g_scalar: &Scalar, p_scalar: &Scalar, p_xy: &(Elem<R>, Elem<R>)) -> Point {
140    let scaled_g = point_mul_base_vartime(g_scalar);
141    let scaled_p = PRIVATE_KEY_OPS.point_mul(p_scalar, p_xy);
142    PRIVATE_KEY_OPS.common.point_sum(&scaled_g, &scaled_p)
143}
144
145#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))]
146fn point_mul_base_vartime(g_scalar: &Scalar) -> Point {
147    prefixed_extern! {
148        fn p256_point_mul_base_vartime(r: *mut Limb,          // [3][COMMON_OPS.num_limbs]
149                                       g_scalar: *const Limb, // [COMMON_OPS.num_limbs]
150        );
151    }
152    let mut scaled_g = Point::new_at_infinity();
153    unsafe {
154        p256_point_mul_base_vartime(scaled_g.xyz.as_mut_ptr(), g_scalar.limbs.as_ptr());
155    }
156    scaled_g
157}
158
159pub static PRIVATE_SCALAR_OPS: PrivateScalarOps = PrivateScalarOps {
160    scalar_ops: &SCALAR_OPS,
161
162    oneRR_mod_n: Scalar::from_hex(
163        "66e12d94f3d956202845b2392b6bec594699799c49bd6fa683244c95be79eea2",
164    ),
165    scalar_inv_to_mont: p256_scalar_inv_to_mont,
166};
167
168fn p256_scalar_inv_to_mont(a: Scalar<R>) -> Scalar<R> {
169    // Calculate the modular inverse of scalar |a| using Fermat's Little
170    // Theorem:
171    //
172    //    a**-1 (mod n) == a**(n - 2) (mod n)
173    //
174    // The exponent (n - 2) is:
175    //
176    //    0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254f
177
178    #[inline]
179    fn mul(a: &Scalar<R>, b: &Scalar<R>) -> Scalar<R> {
180        binary_op(p256_scalar_mul_mont, a, b)
181    }
182
183    #[inline]
184    fn sqr(a: &Scalar<R>) -> Scalar<R> {
185        let mut tmp = Scalar::zero();
186        unsafe { p256_scalar_sqr_rep_mont(tmp.limbs.as_mut_ptr(), a.limbs.as_ptr(), 1) }
187        tmp
188    }
189
190    // Returns (`a` squared `squarings` times) * `b`.
191    fn sqr_mul(a: &Scalar<R>, squarings: Limb, b: &Scalar<R>) -> Scalar<R> {
192        debug_assert!(squarings >= 1);
193        let mut tmp = Scalar::zero();
194        unsafe { p256_scalar_sqr_rep_mont(tmp.limbs.as_mut_ptr(), a.limbs.as_ptr(), squarings) }
195        mul(&tmp, b)
196    }
197
198    // Sets `acc` = (`acc` squared `squarings` times) * `b`.
199    fn sqr_mul_acc(acc: &mut Scalar<R>, squarings: Limb, b: &Scalar<R>) {
200        debug_assert!(squarings >= 1);
201        unsafe { p256_scalar_sqr_rep_mont(acc.limbs.as_mut_ptr(), acc.limbs.as_ptr(), squarings) }
202        binary_op_assign(p256_scalar_mul_mont, acc, b);
203    }
204
205    // Indexes into `d`.
206    const B_1: usize = 0;
207    const B_10: usize = 1;
208    const B_11: usize = 2;
209    const B_101: usize = 3;
210    const B_111: usize = 4;
211    const B_1111: usize = 5;
212    const B_10101: usize = 6;
213    const B_101111: usize = 7;
214    const DIGIT_COUNT: usize = 8;
215
216    let mut d = [Scalar::zero(); DIGIT_COUNT];
217
218    d[B_1] = a;
219    d[B_10] = sqr(&d[B_1]);
220    d[B_11] = mul(&d[B_10], &d[B_1]);
221    d[B_101] = mul(&d[B_10], &d[B_11]);
222    d[B_111] = mul(&d[B_101], &d[B_10]);
223    let b_1010 = sqr(&d[B_101]);
224    d[B_1111] = mul(&b_1010, &d[B_101]);
225    d[B_10101] = sqr_mul(&b_1010, 0 + 1, &d[B_1]);
226    let b_101010 = sqr(&d[B_10101]);
227    d[B_101111] = mul(&b_101010, &d[B_101]);
228    let b_111111 = mul(&b_101010, &d[B_10101]);
229
230    let ff = sqr_mul(&b_111111, 0 + 2, &d[B_11]);
231    let ffff = sqr_mul(&ff, 0 + 8, &ff);
232    let ffffffff = sqr_mul(&ffff, 0 + 16, &ffff);
233
234    // ffffffff00000000ffffffff
235    let mut acc = sqr_mul(&ffffffff, 32 + 32, &ffffffff);
236
237    // ffffffff00000000ffffffffffffffff
238    sqr_mul_acc(&mut acc, 0 + 32, &ffffffff);
239
240    // The rest of the exponent, in binary, is:
241    //
242    //    1011110011100110111110101010110110100111000101111001111010000100
243    //    1111001110111001110010101100001011111100011000110010010101001111
244
245    #[allow(clippy::cast_possible_truncation)]
246    static REMAINING_WINDOWS: [(u8, u8); 26] = [
247        (6, B_101111 as u8),
248        (2 + 3, B_111 as u8),
249        (2 + 2, B_11 as u8),
250        (1 + 4, B_1111 as u8),
251        (5, B_10101 as u8),
252        (1 + 3, B_101 as u8),
253        (3, B_101 as u8),
254        (3, B_101 as u8),
255        (2 + 3, B_111 as u8),
256        (3 + 6, B_101111 as u8),
257        (2 + 4, B_1111 as u8),
258        (1 + 1, B_1 as u8),
259        (4 + 1, B_1 as u8),
260        (2 + 4, B_1111 as u8),
261        (2 + 3, B_111 as u8),
262        (1 + 3, B_111 as u8),
263        (2 + 3, B_111 as u8),
264        (2 + 3, B_101 as u8),
265        (1 + 2, B_11 as u8),
266        (4 + 6, B_101111 as u8),
267        (2, B_11 as u8),
268        (3 + 2, B_11 as u8),
269        (3 + 2, B_11 as u8),
270        (2 + 1, B_1 as u8),
271        (2 + 5, B_10101 as u8),
272        (2 + 4, B_1111 as u8),
273    ];
274
275    for &(squarings, digit) in &REMAINING_WINDOWS {
276        sqr_mul_acc(&mut acc, Limb::from(squarings), &d[usize::from(digit)]);
277    }
278
279    acc
280}
281
282prefixed_extern! {
283    pub(super) fn p256_mul_mont(
284        r: *mut Limb,   // [COMMON_OPS.num_limbs]
285        a: *const Limb, // [COMMON_OPS.num_limbs]
286        b: *const Limb, // [COMMON_OPS.num_limbs]
287    );
288    pub(super) fn p256_sqr_mont(
289        r: *mut Limb,   // [COMMON_OPS.num_limbs]
290        a: *const Limb, // [COMMON_OPS.num_limbs]
291    );
292
293    fn p256_point_add(
294        r: *mut Limb,   // [3][COMMON_OPS.num_limbs]
295        a: *const Limb, // [3][COMMON_OPS.num_limbs]
296        b: *const Limb, // [3][COMMON_OPS.num_limbs]
297    );
298    fn p256_point_mul(
299        r: *mut Limb,          // [3][COMMON_OPS.num_limbs]
300        p_scalar: *const Limb, // [COMMON_OPS.num_limbs]
301        p_x: *const Limb,      // [COMMON_OPS.num_limbs]
302        p_y: *const Limb,      // [COMMON_OPS.num_limbs]
303    );
304
305    fn p256_scalar_mul_mont(
306        r: *mut Limb,   // [COMMON_OPS.num_limbs]
307        a: *const Limb, // [COMMON_OPS.num_limbs]
308        b: *const Limb, // [COMMON_OPS.num_limbs]
309    );
310    fn p256_scalar_sqr_rep_mont(
311        r: *mut Limb,   // [COMMON_OPS.num_limbs]
312        a: *const Limb, // [COMMON_OPS.num_limbs]
313        rep: Limb,
314    );
315}
316
317#[cfg(test)]
318mod tests {
319    #[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))]
320    #[test]
321    fn p256_point_mul_base_vartime_test() {
322        use super::{super::tests::point_mul_base_tests, *};
323        point_mul_base_tests(
324            &PRIVATE_KEY_OPS,
325            point_mul_base_vartime,
326            test_file!("p256_point_mul_base_tests.txt"),
327        );
328    }
329}