xref: /openssl/crypto/ec/curve448/curve448.c (revision 7ed6de99)
1 /*
2  * Copyright 2017-2024 The OpenSSL Project Authors. All Rights Reserved.
3  * Copyright 2015-2016 Cryptography Research, Inc.
4  *
5  * Licensed under the Apache License 2.0 (the "License").  You may not use
6  * this file except in compliance with the License.  You can obtain a copy
7  * in the file LICENSE in the source distribution or at
8  * https://www.openssl.org/source/license.html
9  *
10  * Originally written by Mike Hamburg
11  */
12 #include <openssl/crypto.h>
13 #include "word.h"
14 #include "field.h"
15 
16 #include "point_448.h"
17 #include "ed448.h"
18 #include "crypto/ecx.h"
19 #include "curve448_local.h"
20 
21 #define COFACTOR 4
22 
23 #define C448_WNAF_FIXED_TABLE_BITS 5
24 #define C448_WNAF_VAR_TABLE_BITS 3
25 
26 #define EDWARDS_D       (-39081)
27 
28 static const curve448_scalar_t precomputed_scalarmul_adjustment = {
29     {
30         {
31             SC_LIMB(0xc873d6d54a7bb0cfULL), SC_LIMB(0xe933d8d723a70aadULL),
32             SC_LIMB(0xbb124b65129c96fdULL), SC_LIMB(0x00000008335dc163ULL)
33         }
34     }
35 };
36 
37 #define TWISTED_D (EDWARDS_D - 1)
38 
39 #define WBITS C448_WORD_BITS   /* NB this may be different from ARCH_WORD_BITS */
40 
41 /* Inverse. */
gf_invert(gf y,const gf x,int assert_nonzero)42 static void gf_invert(gf y, const gf x, int assert_nonzero)
43 {
44     mask_t ret;
45     gf t1, t2;
46 
47     ossl_gf_sqr(t1, x);              /* o^2 */
48     ret = gf_isr(t2, t1);       /* +-1/sqrt(o^2) = +-1/o */
49     (void)ret;
50     if (assert_nonzero)
51         assert(ret);
52     ossl_gf_sqr(t1, t2);
53     ossl_gf_mul(t2, t1, x);          /* not direct to y in case of alias. */
54     gf_copy(y, t2);
55 }
56 
57 /** identity = (0,1) */
58 const curve448_point_t ossl_curve448_point_identity = {
59     {{{{0}}}, {{{1}}}, {{{1}}}, {{{0}}}}
60 };
61 
point_double_internal(curve448_point_t p,const curve448_point_t q,int before_double)62 static void point_double_internal(curve448_point_t p, const curve448_point_t q,
63                                   int before_double)
64 {
65     gf a, b, c, d;
66 
67     ossl_gf_sqr(c, q->x);
68     ossl_gf_sqr(a, q->y);
69     gf_add_nr(d, c, a);         /* 2+e */
70     gf_add_nr(p->t, q->y, q->x); /* 2+e */
71     ossl_gf_sqr(b, p->t);
72     gf_subx_nr(b, b, d, 3);     /* 4+e */
73     gf_sub_nr(p->t, a, c);      /* 3+e */
74     ossl_gf_sqr(p->x, q->z);
75     gf_add_nr(p->z, p->x, p->x); /* 2+e */
76     gf_subx_nr(a, p->z, p->t, 4); /* 6+e */
77     if (GF_HEADROOM == 5)
78         gf_weak_reduce(a);      /* or 1+e */
79     ossl_gf_mul(p->x, a, b);
80     ossl_gf_mul(p->z, p->t, a);
81     ossl_gf_mul(p->y, p->t, d);
82     if (!before_double)
83         ossl_gf_mul(p->t, b, d);
84 }
85 
ossl_curve448_point_double(curve448_point_t p,const curve448_point_t q)86 void ossl_curve448_point_double(curve448_point_t p, const curve448_point_t q)
87 {
88     point_double_internal(p, q, 0);
89 }
90 
91 /* Operations on [p]niels */
cond_neg_niels(niels_t n,mask_t neg)92 static ossl_inline void cond_neg_niels(niels_t n, mask_t neg)
93 {
94     gf_cond_swap(n->a, n->b, neg);
95     gf_cond_neg(n->c, neg);
96 }
97 
pt_to_pniels(pniels_t b,const curve448_point_t a)98 static void pt_to_pniels(pniels_t b, const curve448_point_t a)
99 {
100     gf_sub(b->n->a, a->y, a->x);
101     gf_add(b->n->b, a->x, a->y);
102     gf_mulw(b->n->c, a->t, 2 * TWISTED_D);
103     gf_add(b->z, a->z, a->z);
104 }
105 
pniels_to_pt(curve448_point_t e,const pniels_t d)106 static void pniels_to_pt(curve448_point_t e, const pniels_t d)
107 {
108     gf eu;
109 
110     gf_add(eu, d->n->b, d->n->a);
111     gf_sub(e->y, d->n->b, d->n->a);
112     ossl_gf_mul(e->t, e->y, eu);
113     ossl_gf_mul(e->x, d->z, e->y);
114     ossl_gf_mul(e->y, d->z, eu);
115     ossl_gf_sqr(e->z, d->z);
116 }
117 
niels_to_pt(curve448_point_t e,const niels_t n)118 static void niels_to_pt(curve448_point_t e, const niels_t n)
119 {
120     gf_add(e->y, n->b, n->a);
121     gf_sub(e->x, n->b, n->a);
122     ossl_gf_mul(e->t, e->y, e->x);
123     gf_copy(e->z, ONE);
124 }
125 
add_niels_to_pt(curve448_point_t d,const niels_t e,int before_double)126 static void add_niels_to_pt(curve448_point_t d, const niels_t e,
127                             int before_double)
128 {
129     gf a, b, c;
130 
131     gf_sub_nr(b, d->y, d->x);   /* 3+e */
132     ossl_gf_mul(a, e->a, b);
133     gf_add_nr(b, d->x, d->y);   /* 2+e */
134     ossl_gf_mul(d->y, e->b, b);
135     ossl_gf_mul(d->x, e->c, d->t);
136     gf_add_nr(c, a, d->y);      /* 2+e */
137     gf_sub_nr(b, d->y, a);      /* 3+e */
138     gf_sub_nr(d->y, d->z, d->x); /* 3+e */
139     gf_add_nr(a, d->x, d->z);   /* 2+e */
140     ossl_gf_mul(d->z, a, d->y);
141     ossl_gf_mul(d->x, d->y, b);
142     ossl_gf_mul(d->y, a, c);
143     if (!before_double)
144         ossl_gf_mul(d->t, b, c);
145 }
146 
sub_niels_from_pt(curve448_point_t d,const niels_t e,int before_double)147 static void sub_niels_from_pt(curve448_point_t d, const niels_t e,
148                               int before_double)
149 {
150     gf a, b, c;
151 
152     gf_sub_nr(b, d->y, d->x);   /* 3+e */
153     ossl_gf_mul(a, e->b, b);
154     gf_add_nr(b, d->x, d->y);   /* 2+e */
155     ossl_gf_mul(d->y, e->a, b);
156     ossl_gf_mul(d->x, e->c, d->t);
157     gf_add_nr(c, a, d->y);      /* 2+e */
158     gf_sub_nr(b, d->y, a);      /* 3+e */
159     gf_add_nr(d->y, d->z, d->x); /* 2+e */
160     gf_sub_nr(a, d->z, d->x);   /* 3+e */
161     ossl_gf_mul(d->z, a, d->y);
162     ossl_gf_mul(d->x, d->y, b);
163     ossl_gf_mul(d->y, a, c);
164     if (!before_double)
165         ossl_gf_mul(d->t, b, c);
166 }
167 
add_pniels_to_pt(curve448_point_t p,const pniels_t pn,int before_double)168 static void add_pniels_to_pt(curve448_point_t p, const pniels_t pn,
169                              int before_double)
170 {
171     gf L0;
172 
173     ossl_gf_mul(L0, p->z, pn->z);
174     gf_copy(p->z, L0);
175     add_niels_to_pt(p, pn->n, before_double);
176 }
177 
sub_pniels_from_pt(curve448_point_t p,const pniels_t pn,int before_double)178 static void sub_pniels_from_pt(curve448_point_t p, const pniels_t pn,
179                                int before_double)
180 {
181     gf L0;
182 
183     ossl_gf_mul(L0, p->z, pn->z);
184     gf_copy(p->z, L0);
185     sub_niels_from_pt(p, pn->n, before_double);
186 }
187 
188 c448_bool_t
ossl_curve448_point_eq(const curve448_point_t p,const curve448_point_t q)189 ossl_curve448_point_eq(const curve448_point_t p,
190                        const curve448_point_t q)
191 {
192     mask_t succ;
193     gf a, b;
194 
195     /* equality mod 2-torsion compares x/y */
196     ossl_gf_mul(a, p->y, q->x);
197     ossl_gf_mul(b, q->y, p->x);
198     succ = gf_eq(a, b);
199 
200     return mask_to_bool(succ);
201 }
202 
203 c448_bool_t
ossl_curve448_point_valid(const curve448_point_t p)204 ossl_curve448_point_valid(const curve448_point_t p)
205 {
206     mask_t out;
207     gf a, b, c;
208 
209     ossl_gf_mul(a, p->x, p->y);
210     ossl_gf_mul(b, p->z, p->t);
211     out = gf_eq(a, b);
212     ossl_gf_sqr(a, p->x);
213     ossl_gf_sqr(b, p->y);
214     gf_sub(a, b, a);
215     ossl_gf_sqr(b, p->t);
216     gf_mulw(c, b, TWISTED_D);
217     ossl_gf_sqr(b, p->z);
218     gf_add(b, b, c);
219     out &= gf_eq(a, b);
220     out &= ~gf_eq(p->z, ZERO);
221     return mask_to_bool(out);
222 }
223 
constant_time_lookup_niels(niels_s * RESTRICT ni,const niels_t * table,int nelts,int idx)224 static ossl_inline void constant_time_lookup_niels(niels_s * RESTRICT ni,
225                                                    const niels_t *table,
226                                                    int nelts, int idx)
227 {
228     constant_time_lookup(ni, table, sizeof(niels_s), nelts, idx);
229 }
230 
231 void
ossl_curve448_precomputed_scalarmul(curve448_point_t out,const curve448_precomputed_s * table,const curve448_scalar_t scalar)232 ossl_curve448_precomputed_scalarmul(curve448_point_t out,
233                                     const curve448_precomputed_s *table,
234                                     const curve448_scalar_t scalar)
235 {
236     unsigned int i, j, k;
237     const unsigned int n = COMBS_N, t = COMBS_T, s = COMBS_S;
238     niels_t ni;
239     curve448_scalar_t scalar1x;
240 
241     ossl_curve448_scalar_add(scalar1x, scalar, precomputed_scalarmul_adjustment);
242     ossl_curve448_scalar_halve(scalar1x, scalar1x);
243 
244     for (i = s; i > 0; i--) {
245         if (i != s)
246             point_double_internal(out, out, 0);
247 
248         for (j = 0; j < n; j++) {
249             int tab = 0;
250             mask_t invert;
251 
252             for (k = 0; k < t; k++) {
253                 unsigned int bit = (i - 1) + s * (k + j * t);
254 
255                 if (bit < C448_SCALAR_BITS)
256                     tab |=
257                         (scalar1x->limb[bit / WBITS] >> (bit % WBITS) & 1) << k;
258             }
259 
260             invert = (tab >> (t - 1)) - 1;
261             tab ^= invert;
262             tab &= (1 << (t - 1)) - 1;
263 
264             constant_time_lookup_niels(ni, &table->table[j << (t - 1)],
265                                        1 << (t - 1), tab);
266 
267             cond_neg_niels(ni, invert);
268             if ((i != s) || j != 0)
269                 add_niels_to_pt(out, ni, j == n - 1 && i != 1);
270             else
271                 niels_to_pt(out, ni);
272         }
273     }
274 
275     OPENSSL_cleanse(ni, sizeof(ni));
276     OPENSSL_cleanse(scalar1x, sizeof(scalar1x));
277 }
278 
279 void
ossl_curve448_point_mul_by_ratio_and_encode_like_eddsa(uint8_t enc[EDDSA_448_PUBLIC_BYTES],const curve448_point_t p)280 ossl_curve448_point_mul_by_ratio_and_encode_like_eddsa(
281                                     uint8_t enc[EDDSA_448_PUBLIC_BYTES],
282                                     const curve448_point_t p)
283 {
284     gf x, y, z, t;
285     curve448_point_t q;
286 
287     /* The point is now on the twisted curve.  Move it to untwisted. */
288     curve448_point_copy(q, p);
289 
290     {
291         /* 4-isogeny: 2xy/(y^+x^2), (y^2-x^2)/(2z^2-y^2+x^2) */
292         gf u;
293 
294         ossl_gf_sqr(x, q->x);
295         ossl_gf_sqr(t, q->y);
296         gf_add(u, x, t);
297         gf_add(z, q->y, q->x);
298         ossl_gf_sqr(y, z);
299         gf_sub(y, y, u);
300         gf_sub(z, t, x);
301         ossl_gf_sqr(x, q->z);
302         gf_add(t, x, x);
303         gf_sub(t, t, z);
304         ossl_gf_mul(x, t, y);
305         ossl_gf_mul(y, z, u);
306         ossl_gf_mul(z, u, t);
307         OPENSSL_cleanse(u, sizeof(u));
308     }
309 
310     /* Affinize */
311     gf_invert(z, z, 1);
312     ossl_gf_mul(t, x, z);
313     ossl_gf_mul(x, y, z);
314 
315     /* Encode */
316     enc[EDDSA_448_PRIVATE_BYTES - 1] = 0;
317     gf_serialize(enc, x, 1);
318     enc[EDDSA_448_PRIVATE_BYTES - 1] |= 0x80 & gf_lobit(t);
319 
320     OPENSSL_cleanse(x, sizeof(x));
321     OPENSSL_cleanse(y, sizeof(y));
322     OPENSSL_cleanse(z, sizeof(z));
323     OPENSSL_cleanse(t, sizeof(t));
324     ossl_curve448_point_destroy(q);
325 }
326 
327 c448_error_t
ossl_curve448_point_decode_like_eddsa_and_mul_by_ratio(curve448_point_t p,const uint8_t enc[EDDSA_448_PUBLIC_BYTES])328 ossl_curve448_point_decode_like_eddsa_and_mul_by_ratio(
329                                 curve448_point_t p,
330                                 const uint8_t enc[EDDSA_448_PUBLIC_BYTES])
331 {
332     uint8_t enc2[EDDSA_448_PUBLIC_BYTES];
333     mask_t low;
334     mask_t succ;
335 
336     memcpy(enc2, enc, sizeof(enc2));
337 
338     low = ~word_is_zero(enc2[EDDSA_448_PRIVATE_BYTES - 1] & 0x80);
339     enc2[EDDSA_448_PRIVATE_BYTES - 1] &= ~0x80;
340 
341     succ = gf_deserialize(p->y, enc2, 1, 0);
342     succ &= word_is_zero(enc2[EDDSA_448_PRIVATE_BYTES - 1]);
343 
344     ossl_gf_sqr(p->x, p->y);
345     gf_sub(p->z, ONE, p->x);    /* num = 1-y^2 */
346     gf_mulw(p->t, p->x, EDWARDS_D); /* dy^2 */
347     gf_sub(p->t, ONE, p->t);    /* denom = 1-dy^2 or 1-d + dy^2 */
348 
349     ossl_gf_mul(p->x, p->z, p->t);
350     succ &= gf_isr(p->t, p->x); /* 1/sqrt(num * denom) */
351 
352     ossl_gf_mul(p->x, p->t, p->z);   /* sqrt(num / denom) */
353     gf_cond_neg(p->x, gf_lobit(p->x) ^ low);
354     gf_copy(p->z, ONE);
355 
356     {
357         gf a, b, c, d;
358 
359         /* 4-isogeny 2xy/(y^2-ax^2), (y^2+ax^2)/(2-y^2-ax^2) */
360         ossl_gf_sqr(c, p->x);
361         ossl_gf_sqr(a, p->y);
362         gf_add(d, c, a);
363         gf_add(p->t, p->y, p->x);
364         ossl_gf_sqr(b, p->t);
365         gf_sub(b, b, d);
366         gf_sub(p->t, a, c);
367         ossl_gf_sqr(p->x, p->z);
368         gf_add(p->z, p->x, p->x);
369         gf_sub(a, p->z, d);
370         ossl_gf_mul(p->x, a, b);
371         ossl_gf_mul(p->z, p->t, a);
372         ossl_gf_mul(p->y, p->t, d);
373         ossl_gf_mul(p->t, b, d);
374         OPENSSL_cleanse(a, sizeof(a));
375         OPENSSL_cleanse(b, sizeof(b));
376         OPENSSL_cleanse(c, sizeof(c));
377         OPENSSL_cleanse(d, sizeof(d));
378     }
379 
380     OPENSSL_cleanse(enc2, sizeof(enc2));
381     assert(ossl_curve448_point_valid(p) || ~succ);
382 
383     return c448_succeed_if(mask_to_bool(succ));
384 }
385 
386 c448_error_t
ossl_x448_int(uint8_t out[X_PUBLIC_BYTES],const uint8_t base[X_PUBLIC_BYTES],const uint8_t scalar[X_PRIVATE_BYTES])387 ossl_x448_int(uint8_t out[X_PUBLIC_BYTES],
388               const uint8_t base[X_PUBLIC_BYTES],
389               const uint8_t scalar[X_PRIVATE_BYTES])
390 {
391     gf x1, x2, z2, x3, z3, t1, t2;
392     int t;
393     mask_t swap = 0;
394     mask_t nz;
395 
396     (void)gf_deserialize(x1, base, 1, 0);
397     gf_copy(x2, ONE);
398     gf_copy(z2, ZERO);
399     gf_copy(x3, x1);
400     gf_copy(z3, ONE);
401 
402     for (t = X_PRIVATE_BITS - 1; t >= 0; t--) {
403         uint8_t sb = scalar[t / 8];
404         mask_t k_t;
405 
406         /* Scalar conditioning */
407         if (t / 8 == 0)
408             sb &= -(uint8_t)COFACTOR;
409         else if (t == X_PRIVATE_BITS - 1)
410             sb = -1;
411 
412         k_t = (sb >> (t % 8)) & 1;
413         k_t = 0 - k_t;             /* set to all 0s or all 1s */
414 
415         swap ^= k_t;
416         gf_cond_swap(x2, x3, swap);
417         gf_cond_swap(z2, z3, swap);
418         swap = k_t;
419 
420         /*
421          * The "_nr" below skips coefficient reduction. In the following
422          * comments, "2+e" is saying that the coefficients are at most 2+epsilon
423          * times the reduction limit.
424          */
425         gf_add_nr(t1, x2, z2);  /* A = x2 + z2 */ /* 2+e */
426         gf_sub_nr(t2, x2, z2);  /* B = x2 - z2 */ /* 3+e */
427         gf_sub_nr(z2, x3, z3);  /* D = x3 - z3 */ /* 3+e */
428         ossl_gf_mul(x2, t1, z2);     /* DA */
429         gf_add_nr(z2, z3, x3);  /* C = x3 + z3 */ /* 2+e */
430         ossl_gf_mul(x3, t2, z2);     /* CB */
431         gf_sub_nr(z3, x2, x3);  /* DA-CB */ /* 3+e */
432         ossl_gf_sqr(z2, z3);         /* (DA-CB)^2 */
433         ossl_gf_mul(z3, x1, z2);     /* z3 = x1(DA-CB)^2 */
434         gf_add_nr(z2, x2, x3);  /* (DA+CB) */ /* 2+e */
435         ossl_gf_sqr(x3, z2);         /* x3 = (DA+CB)^2 */
436 
437         ossl_gf_sqr(z2, t1);         /* AA = A^2 */
438         ossl_gf_sqr(t1, t2);         /* BB = B^2 */
439         ossl_gf_mul(x2, z2, t1);     /* x2 = AA*BB */
440         gf_sub_nr(t2, z2, t1);  /* E = AA-BB */ /* 3+e */
441 
442         gf_mulw(t1, t2, -EDWARDS_D); /* E*-d = a24*E */
443         gf_add_nr(t1, t1, z2);  /* AA + a24*E */ /* 2+e */
444         ossl_gf_mul(z2, t2, t1);     /* z2 = E(AA+a24*E) */
445     }
446 
447     /* Finish */
448     gf_cond_swap(x2, x3, swap);
449     gf_cond_swap(z2, z3, swap);
450     gf_invert(z2, z2, 0);
451     ossl_gf_mul(x1, x2, z2);
452     gf_serialize(out, x1, 1);
453     nz = ~gf_eq(x1, ZERO);
454 
455     OPENSSL_cleanse(x1, sizeof(x1));
456     OPENSSL_cleanse(x2, sizeof(x2));
457     OPENSSL_cleanse(z2, sizeof(z2));
458     OPENSSL_cleanse(x3, sizeof(x3));
459     OPENSSL_cleanse(z3, sizeof(z3));
460     OPENSSL_cleanse(t1, sizeof(t1));
461     OPENSSL_cleanse(t2, sizeof(t2));
462 
463     return c448_succeed_if(mask_to_bool(nz));
464 }
465 
466 void
ossl_curve448_point_mul_by_ratio_and_encode_like_x448(uint8_t out[X_PUBLIC_BYTES],const curve448_point_t p)467 ossl_curve448_point_mul_by_ratio_and_encode_like_x448(uint8_t
468                                                       out[X_PUBLIC_BYTES],
469                                                       const curve448_point_t p)
470 {
471     curve448_point_t q;
472 
473     curve448_point_copy(q, p);
474     gf_invert(q->t, q->x, 0);   /* 1/x */
475     ossl_gf_mul(q->z, q->t, q->y);   /* y/x */
476     ossl_gf_sqr(q->y, q->z);         /* (y/x)^2 */
477     gf_serialize(out, q->y, 1);
478     ossl_curve448_point_destroy(q);
479 }
480 
ossl_x448_derive_public_key(uint8_t out[X_PUBLIC_BYTES],const uint8_t scalar[X_PRIVATE_BYTES])481 void ossl_x448_derive_public_key(uint8_t out[X_PUBLIC_BYTES],
482                                  const uint8_t scalar[X_PRIVATE_BYTES])
483 {
484     /* Scalar conditioning */
485     uint8_t scalar2[X_PRIVATE_BYTES];
486     curve448_scalar_t the_scalar;
487     curve448_point_t p;
488     unsigned int i;
489 
490     memcpy(scalar2, scalar, sizeof(scalar2));
491     scalar2[0] &= -(uint8_t)COFACTOR;
492 
493     scalar2[X_PRIVATE_BYTES - 1] &= ~((0u - 1u) << ((X_PRIVATE_BITS + 7) % 8));
494     scalar2[X_PRIVATE_BYTES - 1] |= 1 << ((X_PRIVATE_BITS + 7) % 8);
495 
496     ossl_curve448_scalar_decode_long(the_scalar, scalar2, sizeof(scalar2));
497 
498     /* Compensate for the encoding ratio */
499     for (i = 1; i < X448_ENCODE_RATIO; i <<= 1)
500         ossl_curve448_scalar_halve(the_scalar, the_scalar);
501 
502     ossl_curve448_precomputed_scalarmul(p, ossl_curve448_precomputed_base,
503                                         the_scalar);
504     ossl_curve448_point_mul_by_ratio_and_encode_like_x448(out, p);
505     ossl_curve448_point_destroy(p);
506 }
507 
508 /* Control for variable-time scalar multiply algorithms. */
509 struct smvt_control {
510     int power, addend;
511 };
512 
513 #if defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 3))
514 # define NUMTRAILINGZEROS       __builtin_ctz
515 #else
516 # define NUMTRAILINGZEROS       numtrailingzeros
numtrailingzeros(uint32_t i)517 static uint32_t numtrailingzeros(uint32_t i)
518 {
519     uint32_t tmp;
520     uint32_t num = 31;
521 
522     if (i == 0)
523         return 32;
524 
525     tmp = i << 16;
526     if (tmp != 0) {
527         i = tmp;
528         num -= 16;
529     }
530     tmp = i << 8;
531     if (tmp != 0) {
532         i = tmp;
533         num -= 8;
534     }
535     tmp = i << 4;
536     if (tmp != 0) {
537         i = tmp;
538         num -= 4;
539     }
540     tmp = i << 2;
541     if (tmp != 0) {
542         i = tmp;
543         num -= 2;
544     }
545     tmp = i << 1;
546     if (tmp != 0)
547         num--;
548 
549     return num;
550 }
551 #endif
552 
recode_wnaf(struct smvt_control * control,const curve448_scalar_t scalar,unsigned int table_bits)553 static int recode_wnaf(struct smvt_control *control,
554                        /* [nbits/(table_bits + 1) + 3] */
555                        const curve448_scalar_t scalar,
556                        unsigned int table_bits)
557 {
558     unsigned int table_size = C448_SCALAR_BITS / (table_bits + 1) + 3;
559     int position = table_size - 1; /* at the end */
560     uint64_t current = scalar->limb[0] & 0xFFFF;
561     uint32_t mask = (1 << (table_bits + 1)) - 1;
562     unsigned int w;
563     const unsigned int B_OVER_16 = sizeof(scalar->limb[0]) / 2;
564     unsigned int n, i;
565 
566     /* place the end marker */
567     control[position].power = -1;
568     control[position].addend = 0;
569     position--;
570 
571     /*
572      * PERF: Could negate scalar if it's large.  But then would need more cases
573      * in the actual code that uses it, all for an expected reduction of like
574      * 1/5 op. Probably not worth it.
575      */
576 
577     for (w = 1; w < (C448_SCALAR_BITS - 1) / 16 + 3; w++) {
578         if (w < (C448_SCALAR_BITS - 1) / 16 + 1) {
579             /* Refill the 16 high bits of current */
580             current += (uint32_t)((scalar->limb[w / B_OVER_16]
581                        >> (16 * (w % B_OVER_16))) << 16);
582         }
583 
584         while (current & 0xFFFF) {
585             uint32_t pos = NUMTRAILINGZEROS((uint32_t)current);
586             uint32_t odd = (uint32_t)current >> pos;
587             int32_t delta = odd & mask;
588 
589             assert(position >= 0);
590             if (odd & (1 << (table_bits + 1)))
591                 delta -= (1 << (table_bits + 1));
592             /*
593              * Coverity gets confused by the value of pos, thinking it might be
594              * 32.  This would require current & 0xFFFF to be zero which isn't
595              * possible.  Suppress this false positive, since adding a check
596              * isn't desirable.
597              */
598             /* coverity[overflow_before_widen] */
599             current -= delta * (1 << pos);
600             control[position].power = pos + 16 * (w - 1);
601             control[position].addend = delta;
602             position--;
603         }
604         current >>= 16;
605     }
606     assert(current == 0);
607 
608     position++;
609     n = table_size - position;
610     for (i = 0; i < n; i++)
611         control[i] = control[i + position];
612 
613     return n - 1;
614 }
615 
prepare_wnaf_table(pniels_t * output,const curve448_point_t working,unsigned int tbits)616 static void prepare_wnaf_table(pniels_t *output,
617                                const curve448_point_t working,
618                                unsigned int tbits)
619 {
620     curve448_point_t tmp;
621     int i;
622     pniels_t twop;
623 
624     pt_to_pniels(output[0], working);
625 
626     if (tbits == 0)
627         return;
628 
629     ossl_curve448_point_double(tmp, working);
630     pt_to_pniels(twop, tmp);
631 
632     add_pniels_to_pt(tmp, output[0], 0);
633     pt_to_pniels(output[1], tmp);
634 
635     for (i = 2; i < 1 << tbits; i++) {
636         add_pniels_to_pt(tmp, twop, 0);
637         pt_to_pniels(output[i], tmp);
638     }
639 
640     ossl_curve448_point_destroy(tmp);
641     OPENSSL_cleanse(twop, sizeof(twop));
642 }
643 
644 void
ossl_curve448_base_double_scalarmul_non_secret(curve448_point_t combo,const curve448_scalar_t scalar1,const curve448_point_t base2,const curve448_scalar_t scalar2)645 ossl_curve448_base_double_scalarmul_non_secret(curve448_point_t combo,
646                                                const curve448_scalar_t scalar1,
647                                                const curve448_point_t base2,
648                                                const curve448_scalar_t scalar2)
649 {
650     const int table_bits_var = C448_WNAF_VAR_TABLE_BITS;
651     const int table_bits_pre = C448_WNAF_FIXED_TABLE_BITS;
652     struct smvt_control control_var[C448_SCALAR_BITS /
653                                     (C448_WNAF_VAR_TABLE_BITS + 1) + 3];
654     struct smvt_control control_pre[C448_SCALAR_BITS /
655                                     (C448_WNAF_FIXED_TABLE_BITS + 1) + 3];
656     int ncb_pre = recode_wnaf(control_pre, scalar1, table_bits_pre);
657     int ncb_var = recode_wnaf(control_var, scalar2, table_bits_var);
658     pniels_t precmp_var[1 << C448_WNAF_VAR_TABLE_BITS];
659     int contp = 0, contv = 0, i;
660 
661     prepare_wnaf_table(precmp_var, base2, table_bits_var);
662     i = control_var[0].power;
663 
664     if (i < 0) {
665         curve448_point_copy(combo, ossl_curve448_point_identity);
666         return;
667     }
668     if (i > control_pre[0].power) {
669         pniels_to_pt(combo, precmp_var[control_var[0].addend >> 1]);
670         contv++;
671     } else if (i == control_pre[0].power && i >= 0) {
672         pniels_to_pt(combo, precmp_var[control_var[0].addend >> 1]);
673         add_niels_to_pt(combo,
674                         ossl_curve448_wnaf_base[control_pre[0].addend >> 1],
675                         i);
676         contv++;
677         contp++;
678     } else {
679         i = control_pre[0].power;
680         niels_to_pt(combo, ossl_curve448_wnaf_base[control_pre[0].addend >> 1]);
681         contp++;
682     }
683 
684     for (i--; i >= 0; i--) {
685         int cv = (i == control_var[contv].power);
686         int cp = (i == control_pre[contp].power);
687 
688         point_double_internal(combo, combo, i && !(cv || cp));
689 
690         if (cv) {
691             assert(control_var[contv].addend);
692 
693             if (control_var[contv].addend > 0)
694                 add_pniels_to_pt(combo,
695                                  precmp_var[control_var[contv].addend >> 1],
696                                  i && !cp);
697             else
698                 sub_pniels_from_pt(combo,
699                                    precmp_var[(-control_var[contv].addend)
700                                               >> 1], i && !cp);
701             contv++;
702         }
703 
704         if (cp) {
705             assert(control_pre[contp].addend);
706 
707             if (control_pre[contp].addend > 0)
708                 add_niels_to_pt(combo,
709                                 ossl_curve448_wnaf_base[control_pre[contp].addend
710                                                    >> 1], i);
711             else
712                 sub_niels_from_pt(combo,
713                                   ossl_curve448_wnaf_base[(-control_pre
714                                                       [contp].addend) >> 1], i);
715             contp++;
716         }
717     }
718 
719     /* This function is non-secret, but whatever this is cheap. */
720     OPENSSL_cleanse(control_var, sizeof(control_var));
721     OPENSSL_cleanse(control_pre, sizeof(control_pre));
722     OPENSSL_cleanse(precmp_var, sizeof(precmp_var));
723 
724     assert(contv == ncb_var);
725     (void)ncb_var;
726     assert(contp == ncb_pre);
727     (void)ncb_pre;
728 }
729 
ossl_curve448_point_destroy(curve448_point_t point)730 void ossl_curve448_point_destroy(curve448_point_t point)
731 {
732     OPENSSL_cleanse(point, sizeof(curve448_point_t));
733 }
734 
ossl_x448(uint8_t out_shared_key[56],const uint8_t private_key[56],const uint8_t peer_public_value[56])735 int ossl_x448(uint8_t out_shared_key[56], const uint8_t private_key[56],
736               const uint8_t peer_public_value[56])
737 {
738     return ossl_x448_int(out_shared_key, peer_public_value, private_key)
739            == C448_SUCCESS;
740 }
741 
ossl_x448_public_from_private(uint8_t out_public_value[56],const uint8_t private_key[56])742 void ossl_x448_public_from_private(uint8_t out_public_value[56],
743                                    const uint8_t private_key[56])
744 {
745     ossl_x448_derive_public_key(out_public_value, private_key);
746 }
747