ring/ec/suite_b/ops/
p256.rs

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
15use super::{
16    elem::{binary_op, binary_op_assign},
17    elem_sqr_mul, elem_sqr_mul_acc, Modulus, *,
18};
19use core::marker::PhantomData;
20
21macro_rules! p256_limbs {
22    [ $($limb:expr),+ ] => {
23        limbs![$($limb),+, 0, 0, 0, 0]
24    };
25}
26
27pub static COMMON_OPS: CommonOps = CommonOps {
28    num_limbs: 256 / LIMB_BITS,
29
30    q: Modulus {
31        p: p256_limbs![
32            0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000001,
33            0xffffffff
34        ],
35        rr: p256_limbs![
36            0x00000003, 0x00000000, 0xffffffff, 0xfffffffb, 0xfffffffe, 0xffffffff, 0xfffffffd,
37            0x00000004
38        ],
39    },
40
41    n: Elem {
42        limbs: p256_limbs![
43            0xfc632551, 0xf3b9cac2, 0xa7179e84, 0xbce6faad, 0xffffffff, 0xffffffff, 0x00000000,
44            0xffffffff
45        ],
46        m: PhantomData,
47        encoding: PhantomData, // Unencoded
48    },
49
50    a: Elem {
51        limbs: p256_limbs![
52            0xfffffffc, 0xffffffff, 0xffffffff, 0x00000003, 0x00000000, 0x00000000, 0x00000004,
53            0xfffffffc
54        ],
55        m: PhantomData,
56        encoding: PhantomData, // R
57    },
58    b: Elem {
59        limbs: p256_limbs![
60            0x29c4bddf, 0xd89cdf62, 0x78843090, 0xacf005cd, 0xf7212ed6, 0xe5a220ab, 0x04874834,
61            0xdc30061d
62        ],
63        m: PhantomData,
64        encoding: PhantomData, // R
65    },
66
67    elem_add_impl: GFp_nistz256_add,
68    elem_mul_mont: GFp_nistz256_mul_mont,
69    elem_sqr_mont: GFp_nistz256_sqr_mont,
70
71    point_add_jacobian_impl: GFp_nistz256_point_add,
72};
73
74pub static PRIVATE_KEY_OPS: PrivateKeyOps = PrivateKeyOps {
75    common: &COMMON_OPS,
76    elem_inv_squared: p256_elem_inv_squared,
77    point_mul_base_impl: p256_point_mul_base_impl,
78    point_mul_impl: GFp_nistz256_point_mul,
79};
80
81fn p256_elem_inv_squared(a: &Elem<R>) -> Elem<R> {
82    // Calculate a**-2 (mod q) == a**(q - 3) (mod q)
83    //
84    // The exponent (q - 3) is:
85    //
86    //    0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc
87
88    #[inline]
89    fn sqr_mul(a: &Elem<R>, squarings: usize, b: &Elem<R>) -> Elem<R> {
90        elem_sqr_mul(&COMMON_OPS, a, squarings, b)
91    }
92
93    #[inline]
94    fn sqr_mul_acc(a: &mut Elem<R>, squarings: usize, b: &Elem<R>) {
95        elem_sqr_mul_acc(&COMMON_OPS, a, squarings, b)
96    }
97
98    let b_1 = &a;
99    let b_11 = sqr_mul(b_1, 1, b_1);
100    let b_111 = sqr_mul(&b_11, 1, b_1);
101    let f_11 = sqr_mul(&b_111, 3, &b_111);
102    let fff = sqr_mul(&f_11, 6, &f_11);
103    let fff_111 = sqr_mul(&fff, 3, &b_111);
104    let fffffff_11 = sqr_mul(&fff_111, 15, &fff_111);
105    let ffffffff = sqr_mul(&fffffff_11, 2, &b_11);
106
107    // ffffffff00000001
108    let mut acc = sqr_mul(&ffffffff, 31 + 1, b_1);
109
110    // ffffffff00000001000000000000000000000000ffffffff
111    sqr_mul_acc(&mut acc, 96 + 32, &ffffffff);
112
113    // ffffffff00000001000000000000000000000000ffffffffffffffff
114    sqr_mul_acc(&mut acc, 32, &ffffffff);
115
116    // ffffffff00000001000000000000000000000000fffffffffffffffffffffff_11
117    sqr_mul_acc(&mut acc, 30, &fffffff_11);
118
119    // ffffffff00000001000000000000000000000000fffffffffffffffffffffffc
120    COMMON_OPS.elem_square(&mut acc);
121    COMMON_OPS.elem_square(&mut acc);
122
123    acc
124}
125
126fn p256_point_mul_base_impl(g_scalar: &Scalar) -> Point {
127    let mut r = Point::new_at_infinity();
128
129    // Keep this in sync with the logic for defining `GFp_USE_LARGE_TABLE` and
130    // with the logic for deciding whether to test `GFp_nistz256_point_add_affine`
131    // in suite_b/ops.rs.
132
133    #[cfg(any(target_arch = "aarch64", target_arch = "x86", target_arch = "x86_64"))]
134    {
135        extern "C" {
136            fn GFp_nistz256_point_mul_base(
137                r: *mut Limb,          // [3][COMMON_OPS.num_limbs]
138                g_scalar: *const Limb, // [COMMON_OPS.num_limbs]
139            );
140        }
141        unsafe {
142            GFp_nistz256_point_mul_base(r.xyz.as_mut_ptr(), g_scalar.limbs.as_ptr());
143        }
144    }
145
146    #[cfg(not(any(target_arch = "aarch64", target_arch = "x86", target_arch = "x86_64")))]
147    {
148        static GENERATOR: (Elem<R>, Elem<R>) = (
149            Elem {
150                limbs: p256_limbs![
151                    0x18a9143c, 0x79e730d4, 0x5fedb601, 0x75ba95fc, 0x77622510, 0x79fb732b,
152                    0xa53755c6, 0x18905f76
153                ],
154                m: PhantomData,
155                encoding: PhantomData,
156            },
157            Elem {
158                limbs: p256_limbs![
159                    0xce95560a, 0xddf25357, 0xba19e45c, 0x8b4ab8e4, 0xdd21f325, 0xd2e88688,
160                    0x25885d85, 0x8571ff18
161                ],
162                m: PhantomData,
163                encoding: PhantomData,
164            },
165        );
166
167        unsafe {
168            GFp_nistz256_point_mul(
169                r.xyz.as_mut_ptr(),
170                g_scalar.limbs.as_ptr(),
171                GENERATOR.0.limbs.as_ptr(),
172                GENERATOR.1.limbs.as_ptr(),
173            );
174        }
175    }
176
177    r
178}
179
180pub static PUBLIC_KEY_OPS: PublicKeyOps = PublicKeyOps {
181    common: &COMMON_OPS,
182};
183
184pub static SCALAR_OPS: ScalarOps = ScalarOps {
185    common: &COMMON_OPS,
186    scalar_inv_to_mont_impl: p256_scalar_inv_to_mont,
187    scalar_mul_mont: GFp_p256_scalar_mul_mont,
188};
189
190pub static PUBLIC_SCALAR_OPS: PublicScalarOps = PublicScalarOps {
191    scalar_ops: &SCALAR_OPS,
192    public_key_ops: &PUBLIC_KEY_OPS,
193    private_key_ops: &PRIVATE_KEY_OPS,
194
195    q_minus_n: Elem {
196        limbs: p256_limbs![0x039cdaae, 0x0c46353d, 0x58e8617b, 0x43190553, 0, 0, 0, 0],
197        m: PhantomData,
198        encoding: PhantomData, // Unencoded
199    },
200};
201
202pub static PRIVATE_SCALAR_OPS: PrivateScalarOps = PrivateScalarOps {
203    scalar_ops: &SCALAR_OPS,
204
205    oneRR_mod_n: Scalar {
206        limbs: p256_limbs![
207            0xbe79eea2, 0x83244c95, 0x49bd6fa6, 0x4699799c, 0x2b6bec59, 0x2845b239, 0xf3d95620,
208            0x66e12d94
209        ],
210        m: PhantomData,
211        encoding: PhantomData, // R
212    },
213};
214
215fn p256_scalar_inv_to_mont(a: &Scalar<Unencoded>) -> Scalar<R> {
216    // Calculate the modular inverse of scalar |a| using Fermat's Little
217    // Theorem:
218    //
219    //    a**-1 (mod n) == a**(n - 2) (mod n)
220    //
221    // The exponent (n - 2) is:
222    //
223    //    0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254f
224
225    #[inline]
226    fn mul(a: &Scalar<R>, b: &Scalar<R>) -> Scalar<R> {
227        binary_op(GFp_p256_scalar_mul_mont, a, b)
228    }
229
230    #[inline]
231    fn sqr(a: &Scalar<R>) -> Scalar<R> {
232        unary_op(GFp_p256_scalar_sqr_mont, a)
233    }
234
235    // Returns (`a` squared `squarings` times) * `b`.
236    fn sqr_mul(a: &Scalar<R>, squarings: Limb, b: &Scalar<R>) -> Scalar<R> {
237        debug_assert!(squarings >= 1);
238        let mut tmp = Scalar::zero();
239        unsafe { GFp_p256_scalar_sqr_rep_mont(tmp.limbs.as_mut_ptr(), a.limbs.as_ptr(), squarings) }
240        mul(&tmp, b)
241    }
242
243    // Sets `acc` = (`acc` squared `squarings` times) * `b`.
244    fn sqr_mul_acc(acc: &mut Scalar<R>, squarings: Limb, b: &Scalar<R>) {
245        debug_assert!(squarings >= 1);
246        unsafe {
247            GFp_p256_scalar_sqr_rep_mont(acc.limbs.as_mut_ptr(), acc.limbs.as_ptr(), squarings)
248        }
249        binary_op_assign(GFp_p256_scalar_mul_mont, acc, b);
250    }
251
252    fn to_mont(a: &Scalar) -> Scalar<R> {
253        static N_RR: Scalar<Unencoded> = Scalar {
254            limbs: p256_limbs![
255                0xbe79eea2, 0x83244c95, 0x49bd6fa6, 0x4699799c, 0x2b6bec59, 0x2845b239, 0xf3d95620,
256                0x66e12d94
257            ],
258            m: PhantomData,
259            encoding: PhantomData,
260        };
261        binary_op(GFp_p256_scalar_mul_mont, a, &N_RR)
262    }
263
264    // Indexes into `d`.
265    const B_1: usize = 0;
266    const B_10: usize = 1;
267    const B_11: usize = 2;
268    const B_101: usize = 3;
269    const B_111: usize = 4;
270    const B_1111: usize = 5;
271    const B_10101: usize = 6;
272    const B_101111: usize = 7;
273    const DIGIT_COUNT: usize = 8;
274
275    let mut d = [Scalar::zero(); DIGIT_COUNT];
276
277    d[B_1] = to_mont(a);
278    d[B_10] = sqr(&d[B_1]);
279    d[B_11] = mul(&d[B_10], &d[B_1]);
280    d[B_101] = mul(&d[B_10], &d[B_11]);
281    d[B_111] = mul(&d[B_101], &d[B_10]);
282    let b_1010 = sqr(&d[B_101]);
283    d[B_1111] = mul(&b_1010, &d[B_101]);
284    d[B_10101] = sqr_mul(&b_1010, 0 + 1, &d[B_1]);
285    let b_101010 = sqr(&d[B_10101]);
286    d[B_101111] = mul(&b_101010, &d[B_101]);
287    let b_111111 = mul(&b_101010, &d[B_10101]);
288
289    let ff = sqr_mul(&b_111111, 0 + 2, &d[B_11]);
290    let ffff = sqr_mul(&ff, 0 + 8, &ff);
291    let ffffffff = sqr_mul(&ffff, 0 + 16, &ffff);
292
293    // ffffffff00000000ffffffff
294    let mut acc = sqr_mul(&ffffffff, 32 + 32, &ffffffff);
295
296    // ffffffff00000000ffffffffffffffff
297    sqr_mul_acc(&mut acc, 0 + 32, &ffffffff);
298
299    // The rest of the exponent, in binary, is:
300    //
301    //    1011110011100110111110101010110110100111000101111001111010000100
302    //    1111001110111001110010101100001011111100011000110010010101001111
303
304    static REMAINING_WINDOWS: [(u8, u8); 26] = [
305        (6, B_101111 as u8),
306        (2 + 3, B_111 as u8),
307        (2 + 2, B_11 as u8),
308        (1 + 4, B_1111 as u8),
309        (5, B_10101 as u8),
310        (1 + 3, B_101 as u8),
311        (3, B_101 as u8),
312        (3, B_101 as u8),
313        (2 + 3, B_111 as u8),
314        (3 + 6, B_101111 as u8),
315        (2 + 4, B_1111 as u8),
316        (1 + 1, B_1 as u8),
317        (4 + 1, B_1 as u8),
318        (2 + 4, B_1111 as u8),
319        (2 + 3, B_111 as u8),
320        (1 + 3, B_111 as u8),
321        (2 + 3, B_111 as u8),
322        (2 + 3, B_101 as u8),
323        (1 + 2, B_11 as u8),
324        (4 + 6, B_101111 as u8),
325        (2, B_11 as u8),
326        (3 + 2, B_11 as u8),
327        (3 + 2, B_11 as u8),
328        (2 + 1, B_1 as u8),
329        (2 + 5, B_10101 as u8),
330        (2 + 4, B_1111 as u8),
331    ];
332
333    for &(squarings, digit) in &REMAINING_WINDOWS {
334        sqr_mul_acc(&mut acc, Limb::from(squarings), &d[usize::from(digit)]);
335    }
336
337    acc
338}
339
340extern "C" {
341    fn GFp_nistz256_add(
342        r: *mut Limb,   // [COMMON_OPS.num_limbs]
343        a: *const Limb, // [COMMON_OPS.num_limbs]
344        b: *const Limb, // [COMMON_OPS.num_limbs]
345    );
346    fn GFp_nistz256_mul_mont(
347        r: *mut Limb,   // [COMMON_OPS.num_limbs]
348        a: *const Limb, // [COMMON_OPS.num_limbs]
349        b: *const Limb, // [COMMON_OPS.num_limbs]
350    );
351    fn GFp_nistz256_sqr_mont(
352        r: *mut Limb,   // [COMMON_OPS.num_limbs]
353        a: *const Limb, // [COMMON_OPS.num_limbs]
354    );
355
356    fn GFp_nistz256_point_add(
357        r: *mut Limb,   // [3][COMMON_OPS.num_limbs]
358        a: *const Limb, // [3][COMMON_OPS.num_limbs]
359        b: *const Limb, // [3][COMMON_OPS.num_limbs]
360    );
361    fn GFp_nistz256_point_mul(
362        r: *mut Limb,          // [3][COMMON_OPS.num_limbs]
363        p_scalar: *const Limb, // [COMMON_OPS.num_limbs]
364        p_x: *const Limb,      // [COMMON_OPS.num_limbs]
365        p_y: *const Limb,      // [COMMON_OPS.num_limbs]
366    );
367
368    fn GFp_p256_scalar_mul_mont(
369        r: *mut Limb,   // [COMMON_OPS.num_limbs]
370        a: *const Limb, // [COMMON_OPS.num_limbs]
371        b: *const Limb, // [COMMON_OPS.num_limbs]
372    );
373    fn GFp_p256_scalar_sqr_mont(
374        r: *mut Limb,   // [COMMON_OPS.num_limbs]
375        a: *const Limb, // [COMMON_OPS.num_limbs]
376    );
377    fn GFp_p256_scalar_sqr_rep_mont(
378        r: *mut Limb,   // [COMMON_OPS.num_limbs]
379        a: *const Limb, // [COMMON_OPS.num_limbs]
380        rep: Limb,
381    );
382}