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