162306a36Sopenharmony_ci/* ec.c - Elliptic Curve functions 262306a36Sopenharmony_ci * Copyright (C) 2007 Free Software Foundation, Inc. 362306a36Sopenharmony_ci * Copyright (C) 2013 g10 Code GmbH 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * This file is part of Libgcrypt. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Libgcrypt is free software; you can redistribute it and/or modify 862306a36Sopenharmony_ci * it under the terms of the GNU Lesser General Public License as 962306a36Sopenharmony_ci * published by the Free Software Foundation; either version 2.1 of 1062306a36Sopenharmony_ci * the License, or (at your option) any later version. 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Libgcrypt is distributed in the hope that it will be useful, 1362306a36Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 1462306a36Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1562306a36Sopenharmony_ci * GNU Lesser General Public License for more details. 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * You should have received a copy of the GNU Lesser General Public 1862306a36Sopenharmony_ci * License along with this program; if not, see <http://www.gnu.org/licenses/>. 1962306a36Sopenharmony_ci */ 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include "mpi-internal.h" 2262306a36Sopenharmony_ci#include "longlong.h" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define point_init(a) mpi_point_init((a)) 2562306a36Sopenharmony_ci#define point_free(a) mpi_point_free_parts((a)) 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define log_error(fmt, ...) pr_err(fmt, ##__VA_ARGS__) 2862306a36Sopenharmony_ci#define log_fatal(fmt, ...) pr_err(fmt, ##__VA_ARGS__) 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#define DIM(v) (sizeof(v)/sizeof((v)[0])) 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/* Create a new point option. NBITS gives the size in bits of one 3462306a36Sopenharmony_ci * coordinate; it is only used to pre-allocate some resources and 3562306a36Sopenharmony_ci * might also be passed as 0 to use a default value. 3662306a36Sopenharmony_ci */ 3762306a36Sopenharmony_ciMPI_POINT mpi_point_new(unsigned int nbits) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci MPI_POINT p; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci (void)nbits; /* Currently not used. */ 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci p = kmalloc(sizeof(*p), GFP_KERNEL); 4462306a36Sopenharmony_ci if (p) 4562306a36Sopenharmony_ci mpi_point_init(p); 4662306a36Sopenharmony_ci return p; 4762306a36Sopenharmony_ci} 4862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mpi_point_new); 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci/* Release the point object P. P may be NULL. */ 5162306a36Sopenharmony_civoid mpi_point_release(MPI_POINT p) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci if (p) { 5462306a36Sopenharmony_ci mpi_point_free_parts(p); 5562306a36Sopenharmony_ci kfree(p); 5662306a36Sopenharmony_ci } 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mpi_point_release); 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci/* Initialize the fields of a point object. gcry_mpi_point_free_parts 6162306a36Sopenharmony_ci * may be used to release the fields. 6262306a36Sopenharmony_ci */ 6362306a36Sopenharmony_civoid mpi_point_init(MPI_POINT p) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci p->x = mpi_new(0); 6662306a36Sopenharmony_ci p->y = mpi_new(0); 6762306a36Sopenharmony_ci p->z = mpi_new(0); 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mpi_point_init); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci/* Release the parts of a point object. */ 7262306a36Sopenharmony_civoid mpi_point_free_parts(MPI_POINT p) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci mpi_free(p->x); p->x = NULL; 7562306a36Sopenharmony_ci mpi_free(p->y); p->y = NULL; 7662306a36Sopenharmony_ci mpi_free(p->z); p->z = NULL; 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mpi_point_free_parts); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci/* Set the value from S into D. */ 8162306a36Sopenharmony_cistatic void point_set(MPI_POINT d, MPI_POINT s) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci mpi_set(d->x, s->x); 8462306a36Sopenharmony_ci mpi_set(d->y, s->y); 8562306a36Sopenharmony_ci mpi_set(d->z, s->z); 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic void point_resize(MPI_POINT p, struct mpi_ec_ctx *ctx) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci size_t nlimbs = ctx->p->nlimbs; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci mpi_resize(p->x, nlimbs); 9362306a36Sopenharmony_ci p->x->nlimbs = nlimbs; 9462306a36Sopenharmony_ci mpi_resize(p->z, nlimbs); 9562306a36Sopenharmony_ci p->z->nlimbs = nlimbs; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci if (ctx->model != MPI_EC_MONTGOMERY) { 9862306a36Sopenharmony_ci mpi_resize(p->y, nlimbs); 9962306a36Sopenharmony_ci p->y->nlimbs = nlimbs; 10062306a36Sopenharmony_ci } 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic void point_swap_cond(MPI_POINT d, MPI_POINT s, unsigned long swap, 10462306a36Sopenharmony_ci struct mpi_ec_ctx *ctx) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci mpi_swap_cond(d->x, s->x, swap); 10762306a36Sopenharmony_ci if (ctx->model != MPI_EC_MONTGOMERY) 10862306a36Sopenharmony_ci mpi_swap_cond(d->y, s->y, swap); 10962306a36Sopenharmony_ci mpi_swap_cond(d->z, s->z, swap); 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci/* W = W mod P. */ 11462306a36Sopenharmony_cistatic void ec_mod(MPI w, struct mpi_ec_ctx *ec) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci if (ec->t.p_barrett) 11762306a36Sopenharmony_ci mpi_mod_barrett(w, w, ec->t.p_barrett); 11862306a36Sopenharmony_ci else 11962306a36Sopenharmony_ci mpi_mod(w, w, ec->p); 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic void ec_addm(MPI w, MPI u, MPI v, struct mpi_ec_ctx *ctx) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci mpi_add(w, u, v); 12562306a36Sopenharmony_ci ec_mod(w, ctx); 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic void ec_subm(MPI w, MPI u, MPI v, struct mpi_ec_ctx *ec) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci mpi_sub(w, u, v); 13162306a36Sopenharmony_ci while (w->sign) 13262306a36Sopenharmony_ci mpi_add(w, w, ec->p); 13362306a36Sopenharmony_ci /*ec_mod(w, ec);*/ 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic void ec_mulm(MPI w, MPI u, MPI v, struct mpi_ec_ctx *ctx) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci mpi_mul(w, u, v); 13962306a36Sopenharmony_ci ec_mod(w, ctx); 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci/* W = 2 * U mod P. */ 14362306a36Sopenharmony_cistatic void ec_mul2(MPI w, MPI u, struct mpi_ec_ctx *ctx) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci mpi_lshift(w, u, 1); 14662306a36Sopenharmony_ci ec_mod(w, ctx); 14762306a36Sopenharmony_ci} 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_cistatic void ec_powm(MPI w, const MPI b, const MPI e, 15062306a36Sopenharmony_ci struct mpi_ec_ctx *ctx) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci mpi_powm(w, b, e, ctx->p); 15362306a36Sopenharmony_ci /* mpi_abs(w); */ 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci/* Shortcut for 15762306a36Sopenharmony_ci * ec_powm(B, B, mpi_const(MPI_C_TWO), ctx); 15862306a36Sopenharmony_ci * for easier optimization. 15962306a36Sopenharmony_ci */ 16062306a36Sopenharmony_cistatic void ec_pow2(MPI w, const MPI b, struct mpi_ec_ctx *ctx) 16162306a36Sopenharmony_ci{ 16262306a36Sopenharmony_ci /* Using mpi_mul is slightly faster (at least on amd64). */ 16362306a36Sopenharmony_ci /* mpi_powm(w, b, mpi_const(MPI_C_TWO), ctx->p); */ 16462306a36Sopenharmony_ci ec_mulm(w, b, b, ctx); 16562306a36Sopenharmony_ci} 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci/* Shortcut for 16862306a36Sopenharmony_ci * ec_powm(B, B, mpi_const(MPI_C_THREE), ctx); 16962306a36Sopenharmony_ci * for easier optimization. 17062306a36Sopenharmony_ci */ 17162306a36Sopenharmony_cistatic void ec_pow3(MPI w, const MPI b, struct mpi_ec_ctx *ctx) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci mpi_powm(w, b, mpi_const(MPI_C_THREE), ctx->p); 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cistatic void ec_invm(MPI x, MPI a, struct mpi_ec_ctx *ctx) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci if (!mpi_invm(x, a, ctx->p)) 17962306a36Sopenharmony_ci log_error("ec_invm: inverse does not exist:\n"); 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cistatic void mpih_set_cond(mpi_ptr_t wp, mpi_ptr_t up, 18362306a36Sopenharmony_ci mpi_size_t usize, unsigned long set) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci mpi_size_t i; 18662306a36Sopenharmony_ci mpi_limb_t mask = ((mpi_limb_t)0) - set; 18762306a36Sopenharmony_ci mpi_limb_t x; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci for (i = 0; i < usize; i++) { 19062306a36Sopenharmony_ci x = mask & (wp[i] ^ up[i]); 19162306a36Sopenharmony_ci wp[i] = wp[i] ^ x; 19262306a36Sopenharmony_ci } 19362306a36Sopenharmony_ci} 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci/* Routines for 2^255 - 19. */ 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci#define LIMB_SIZE_25519 ((256+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB) 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cistatic void ec_addm_25519(MPI w, MPI u, MPI v, struct mpi_ec_ctx *ctx) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci mpi_ptr_t wp, up, vp; 20262306a36Sopenharmony_ci mpi_size_t wsize = LIMB_SIZE_25519; 20362306a36Sopenharmony_ci mpi_limb_t n[LIMB_SIZE_25519]; 20462306a36Sopenharmony_ci mpi_limb_t borrow; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci if (w->nlimbs != wsize || u->nlimbs != wsize || v->nlimbs != wsize) 20762306a36Sopenharmony_ci log_bug("addm_25519: different sizes\n"); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci memset(n, 0, sizeof(n)); 21062306a36Sopenharmony_ci up = u->d; 21162306a36Sopenharmony_ci vp = v->d; 21262306a36Sopenharmony_ci wp = w->d; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci mpihelp_add_n(wp, up, vp, wsize); 21562306a36Sopenharmony_ci borrow = mpihelp_sub_n(wp, wp, ctx->p->d, wsize); 21662306a36Sopenharmony_ci mpih_set_cond(n, ctx->p->d, wsize, (borrow != 0UL)); 21762306a36Sopenharmony_ci mpihelp_add_n(wp, wp, n, wsize); 21862306a36Sopenharmony_ci wp[LIMB_SIZE_25519-1] &= ~((mpi_limb_t)1 << (255 % BITS_PER_MPI_LIMB)); 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic void ec_subm_25519(MPI w, MPI u, MPI v, struct mpi_ec_ctx *ctx) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci mpi_ptr_t wp, up, vp; 22462306a36Sopenharmony_ci mpi_size_t wsize = LIMB_SIZE_25519; 22562306a36Sopenharmony_ci mpi_limb_t n[LIMB_SIZE_25519]; 22662306a36Sopenharmony_ci mpi_limb_t borrow; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci if (w->nlimbs != wsize || u->nlimbs != wsize || v->nlimbs != wsize) 22962306a36Sopenharmony_ci log_bug("subm_25519: different sizes\n"); 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci memset(n, 0, sizeof(n)); 23262306a36Sopenharmony_ci up = u->d; 23362306a36Sopenharmony_ci vp = v->d; 23462306a36Sopenharmony_ci wp = w->d; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci borrow = mpihelp_sub_n(wp, up, vp, wsize); 23762306a36Sopenharmony_ci mpih_set_cond(n, ctx->p->d, wsize, (borrow != 0UL)); 23862306a36Sopenharmony_ci mpihelp_add_n(wp, wp, n, wsize); 23962306a36Sopenharmony_ci wp[LIMB_SIZE_25519-1] &= ~((mpi_limb_t)1 << (255 % BITS_PER_MPI_LIMB)); 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cistatic void ec_mulm_25519(MPI w, MPI u, MPI v, struct mpi_ec_ctx *ctx) 24362306a36Sopenharmony_ci{ 24462306a36Sopenharmony_ci mpi_ptr_t wp, up, vp; 24562306a36Sopenharmony_ci mpi_size_t wsize = LIMB_SIZE_25519; 24662306a36Sopenharmony_ci mpi_limb_t n[LIMB_SIZE_25519*2]; 24762306a36Sopenharmony_ci mpi_limb_t m[LIMB_SIZE_25519+1]; 24862306a36Sopenharmony_ci mpi_limb_t cy; 24962306a36Sopenharmony_ci int msb; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci (void)ctx; 25262306a36Sopenharmony_ci if (w->nlimbs != wsize || u->nlimbs != wsize || v->nlimbs != wsize) 25362306a36Sopenharmony_ci log_bug("mulm_25519: different sizes\n"); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci up = u->d; 25662306a36Sopenharmony_ci vp = v->d; 25762306a36Sopenharmony_ci wp = w->d; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci mpihelp_mul_n(n, up, vp, wsize); 26062306a36Sopenharmony_ci memcpy(wp, n, wsize * BYTES_PER_MPI_LIMB); 26162306a36Sopenharmony_ci wp[LIMB_SIZE_25519-1] &= ~((mpi_limb_t)1 << (255 % BITS_PER_MPI_LIMB)); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci memcpy(m, n+LIMB_SIZE_25519-1, (wsize+1) * BYTES_PER_MPI_LIMB); 26462306a36Sopenharmony_ci mpihelp_rshift(m, m, LIMB_SIZE_25519+1, (255 % BITS_PER_MPI_LIMB)); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci memcpy(n, m, wsize * BYTES_PER_MPI_LIMB); 26762306a36Sopenharmony_ci cy = mpihelp_lshift(m, m, LIMB_SIZE_25519, 4); 26862306a36Sopenharmony_ci m[LIMB_SIZE_25519] = cy; 26962306a36Sopenharmony_ci cy = mpihelp_add_n(m, m, n, wsize); 27062306a36Sopenharmony_ci m[LIMB_SIZE_25519] += cy; 27162306a36Sopenharmony_ci cy = mpihelp_add_n(m, m, n, wsize); 27262306a36Sopenharmony_ci m[LIMB_SIZE_25519] += cy; 27362306a36Sopenharmony_ci cy = mpihelp_add_n(m, m, n, wsize); 27462306a36Sopenharmony_ci m[LIMB_SIZE_25519] += cy; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci cy = mpihelp_add_n(wp, wp, m, wsize); 27762306a36Sopenharmony_ci m[LIMB_SIZE_25519] += cy; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci memset(m, 0, wsize * BYTES_PER_MPI_LIMB); 28062306a36Sopenharmony_ci msb = (wp[LIMB_SIZE_25519-1] >> (255 % BITS_PER_MPI_LIMB)); 28162306a36Sopenharmony_ci m[0] = (m[LIMB_SIZE_25519] * 2 + msb) * 19; 28262306a36Sopenharmony_ci wp[LIMB_SIZE_25519-1] &= ~((mpi_limb_t)1 << (255 % BITS_PER_MPI_LIMB)); 28362306a36Sopenharmony_ci mpihelp_add_n(wp, wp, m, wsize); 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci m[0] = 0; 28662306a36Sopenharmony_ci cy = mpihelp_sub_n(wp, wp, ctx->p->d, wsize); 28762306a36Sopenharmony_ci mpih_set_cond(m, ctx->p->d, wsize, (cy != 0UL)); 28862306a36Sopenharmony_ci mpihelp_add_n(wp, wp, m, wsize); 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_cistatic void ec_mul2_25519(MPI w, MPI u, struct mpi_ec_ctx *ctx) 29262306a36Sopenharmony_ci{ 29362306a36Sopenharmony_ci ec_addm_25519(w, u, u, ctx); 29462306a36Sopenharmony_ci} 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_cistatic void ec_pow2_25519(MPI w, const MPI b, struct mpi_ec_ctx *ctx) 29762306a36Sopenharmony_ci{ 29862306a36Sopenharmony_ci ec_mulm_25519(w, b, b, ctx); 29962306a36Sopenharmony_ci} 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci/* Routines for 2^448 - 2^224 - 1. */ 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci#define LIMB_SIZE_448 ((448+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB) 30462306a36Sopenharmony_ci#define LIMB_SIZE_HALF_448 ((LIMB_SIZE_448+1)/2) 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_cistatic void ec_addm_448(MPI w, MPI u, MPI v, struct mpi_ec_ctx *ctx) 30762306a36Sopenharmony_ci{ 30862306a36Sopenharmony_ci mpi_ptr_t wp, up, vp; 30962306a36Sopenharmony_ci mpi_size_t wsize = LIMB_SIZE_448; 31062306a36Sopenharmony_ci mpi_limb_t n[LIMB_SIZE_448]; 31162306a36Sopenharmony_ci mpi_limb_t cy; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci if (w->nlimbs != wsize || u->nlimbs != wsize || v->nlimbs != wsize) 31462306a36Sopenharmony_ci log_bug("addm_448: different sizes\n"); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci memset(n, 0, sizeof(n)); 31762306a36Sopenharmony_ci up = u->d; 31862306a36Sopenharmony_ci vp = v->d; 31962306a36Sopenharmony_ci wp = w->d; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci cy = mpihelp_add_n(wp, up, vp, wsize); 32262306a36Sopenharmony_ci mpih_set_cond(n, ctx->p->d, wsize, (cy != 0UL)); 32362306a36Sopenharmony_ci mpihelp_sub_n(wp, wp, n, wsize); 32462306a36Sopenharmony_ci} 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_cistatic void ec_subm_448(MPI w, MPI u, MPI v, struct mpi_ec_ctx *ctx) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci mpi_ptr_t wp, up, vp; 32962306a36Sopenharmony_ci mpi_size_t wsize = LIMB_SIZE_448; 33062306a36Sopenharmony_ci mpi_limb_t n[LIMB_SIZE_448]; 33162306a36Sopenharmony_ci mpi_limb_t borrow; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci if (w->nlimbs != wsize || u->nlimbs != wsize || v->nlimbs != wsize) 33462306a36Sopenharmony_ci log_bug("subm_448: different sizes\n"); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci memset(n, 0, sizeof(n)); 33762306a36Sopenharmony_ci up = u->d; 33862306a36Sopenharmony_ci vp = v->d; 33962306a36Sopenharmony_ci wp = w->d; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci borrow = mpihelp_sub_n(wp, up, vp, wsize); 34262306a36Sopenharmony_ci mpih_set_cond(n, ctx->p->d, wsize, (borrow != 0UL)); 34362306a36Sopenharmony_ci mpihelp_add_n(wp, wp, n, wsize); 34462306a36Sopenharmony_ci} 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_cistatic void ec_mulm_448(MPI w, MPI u, MPI v, struct mpi_ec_ctx *ctx) 34762306a36Sopenharmony_ci{ 34862306a36Sopenharmony_ci mpi_ptr_t wp, up, vp; 34962306a36Sopenharmony_ci mpi_size_t wsize = LIMB_SIZE_448; 35062306a36Sopenharmony_ci mpi_limb_t n[LIMB_SIZE_448*2]; 35162306a36Sopenharmony_ci mpi_limb_t a2[LIMB_SIZE_HALF_448]; 35262306a36Sopenharmony_ci mpi_limb_t a3[LIMB_SIZE_HALF_448]; 35362306a36Sopenharmony_ci mpi_limb_t b0[LIMB_SIZE_HALF_448]; 35462306a36Sopenharmony_ci mpi_limb_t b1[LIMB_SIZE_HALF_448]; 35562306a36Sopenharmony_ci mpi_limb_t cy; 35662306a36Sopenharmony_ci int i; 35762306a36Sopenharmony_ci#if (LIMB_SIZE_HALF_448 > LIMB_SIZE_448/2) 35862306a36Sopenharmony_ci mpi_limb_t b1_rest, a3_rest; 35962306a36Sopenharmony_ci#endif 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci if (w->nlimbs != wsize || u->nlimbs != wsize || v->nlimbs != wsize) 36262306a36Sopenharmony_ci log_bug("mulm_448: different sizes\n"); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci up = u->d; 36562306a36Sopenharmony_ci vp = v->d; 36662306a36Sopenharmony_ci wp = w->d; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci mpihelp_mul_n(n, up, vp, wsize); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci for (i = 0; i < (wsize + 1) / 2; i++) { 37162306a36Sopenharmony_ci b0[i] = n[i]; 37262306a36Sopenharmony_ci b1[i] = n[i+wsize/2]; 37362306a36Sopenharmony_ci a2[i] = n[i+wsize]; 37462306a36Sopenharmony_ci a3[i] = n[i+wsize+wsize/2]; 37562306a36Sopenharmony_ci } 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci#if (LIMB_SIZE_HALF_448 > LIMB_SIZE_448/2) 37862306a36Sopenharmony_ci b0[LIMB_SIZE_HALF_448-1] &= ((mpi_limb_t)1UL << 32)-1; 37962306a36Sopenharmony_ci a2[LIMB_SIZE_HALF_448-1] &= ((mpi_limb_t)1UL << 32)-1; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci b1_rest = 0; 38262306a36Sopenharmony_ci a3_rest = 0; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci for (i = (wsize + 1) / 2 - 1; i >= 0; i--) { 38562306a36Sopenharmony_ci mpi_limb_t b1v, a3v; 38662306a36Sopenharmony_ci b1v = b1[i]; 38762306a36Sopenharmony_ci a3v = a3[i]; 38862306a36Sopenharmony_ci b1[i] = (b1_rest << 32) | (b1v >> 32); 38962306a36Sopenharmony_ci a3[i] = (a3_rest << 32) | (a3v >> 32); 39062306a36Sopenharmony_ci b1_rest = b1v & (((mpi_limb_t)1UL << 32)-1); 39162306a36Sopenharmony_ci a3_rest = a3v & (((mpi_limb_t)1UL << 32)-1); 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci#endif 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci cy = mpihelp_add_n(b0, b0, a2, LIMB_SIZE_HALF_448); 39662306a36Sopenharmony_ci cy += mpihelp_add_n(b0, b0, a3, LIMB_SIZE_HALF_448); 39762306a36Sopenharmony_ci for (i = 0; i < (wsize + 1) / 2; i++) 39862306a36Sopenharmony_ci wp[i] = b0[i]; 39962306a36Sopenharmony_ci#if (LIMB_SIZE_HALF_448 > LIMB_SIZE_448/2) 40062306a36Sopenharmony_ci wp[LIMB_SIZE_HALF_448-1] &= (((mpi_limb_t)1UL << 32)-1); 40162306a36Sopenharmony_ci#endif 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci#if (LIMB_SIZE_HALF_448 > LIMB_SIZE_448/2) 40462306a36Sopenharmony_ci cy = b0[LIMB_SIZE_HALF_448-1] >> 32; 40562306a36Sopenharmony_ci#endif 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci cy = mpihelp_add_1(b1, b1, LIMB_SIZE_HALF_448, cy); 40862306a36Sopenharmony_ci cy += mpihelp_add_n(b1, b1, a2, LIMB_SIZE_HALF_448); 40962306a36Sopenharmony_ci cy += mpihelp_add_n(b1, b1, a3, LIMB_SIZE_HALF_448); 41062306a36Sopenharmony_ci cy += mpihelp_add_n(b1, b1, a3, LIMB_SIZE_HALF_448); 41162306a36Sopenharmony_ci#if (LIMB_SIZE_HALF_448 > LIMB_SIZE_448/2) 41262306a36Sopenharmony_ci b1_rest = 0; 41362306a36Sopenharmony_ci for (i = (wsize + 1) / 2 - 1; i >= 0; i--) { 41462306a36Sopenharmony_ci mpi_limb_t b1v = b1[i]; 41562306a36Sopenharmony_ci b1[i] = (b1_rest << 32) | (b1v >> 32); 41662306a36Sopenharmony_ci b1_rest = b1v & (((mpi_limb_t)1UL << 32)-1); 41762306a36Sopenharmony_ci } 41862306a36Sopenharmony_ci wp[LIMB_SIZE_HALF_448-1] |= (b1_rest << 32); 41962306a36Sopenharmony_ci#endif 42062306a36Sopenharmony_ci for (i = 0; i < wsize / 2; i++) 42162306a36Sopenharmony_ci wp[i+(wsize + 1) / 2] = b1[i]; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci#if (LIMB_SIZE_HALF_448 > LIMB_SIZE_448/2) 42462306a36Sopenharmony_ci cy = b1[LIMB_SIZE_HALF_448-1]; 42562306a36Sopenharmony_ci#endif 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci memset(n, 0, wsize * BYTES_PER_MPI_LIMB); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci#if (LIMB_SIZE_HALF_448 > LIMB_SIZE_448/2) 43062306a36Sopenharmony_ci n[LIMB_SIZE_HALF_448-1] = cy << 32; 43162306a36Sopenharmony_ci#else 43262306a36Sopenharmony_ci n[LIMB_SIZE_HALF_448] = cy; 43362306a36Sopenharmony_ci#endif 43462306a36Sopenharmony_ci n[0] = cy; 43562306a36Sopenharmony_ci mpihelp_add_n(wp, wp, n, wsize); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci memset(n, 0, wsize * BYTES_PER_MPI_LIMB); 43862306a36Sopenharmony_ci cy = mpihelp_sub_n(wp, wp, ctx->p->d, wsize); 43962306a36Sopenharmony_ci mpih_set_cond(n, ctx->p->d, wsize, (cy != 0UL)); 44062306a36Sopenharmony_ci mpihelp_add_n(wp, wp, n, wsize); 44162306a36Sopenharmony_ci} 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_cistatic void ec_mul2_448(MPI w, MPI u, struct mpi_ec_ctx *ctx) 44462306a36Sopenharmony_ci{ 44562306a36Sopenharmony_ci ec_addm_448(w, u, u, ctx); 44662306a36Sopenharmony_ci} 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_cistatic void ec_pow2_448(MPI w, const MPI b, struct mpi_ec_ctx *ctx) 44962306a36Sopenharmony_ci{ 45062306a36Sopenharmony_ci ec_mulm_448(w, b, b, ctx); 45162306a36Sopenharmony_ci} 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_cistruct field_table { 45462306a36Sopenharmony_ci const char *p; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci /* computation routines for the field. */ 45762306a36Sopenharmony_ci void (*addm)(MPI w, MPI u, MPI v, struct mpi_ec_ctx *ctx); 45862306a36Sopenharmony_ci void (*subm)(MPI w, MPI u, MPI v, struct mpi_ec_ctx *ctx); 45962306a36Sopenharmony_ci void (*mulm)(MPI w, MPI u, MPI v, struct mpi_ec_ctx *ctx); 46062306a36Sopenharmony_ci void (*mul2)(MPI w, MPI u, struct mpi_ec_ctx *ctx); 46162306a36Sopenharmony_ci void (*pow2)(MPI w, const MPI b, struct mpi_ec_ctx *ctx); 46262306a36Sopenharmony_ci}; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_cistatic const struct field_table field_table[] = { 46562306a36Sopenharmony_ci { 46662306a36Sopenharmony_ci "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED", 46762306a36Sopenharmony_ci ec_addm_25519, 46862306a36Sopenharmony_ci ec_subm_25519, 46962306a36Sopenharmony_ci ec_mulm_25519, 47062306a36Sopenharmony_ci ec_mul2_25519, 47162306a36Sopenharmony_ci ec_pow2_25519 47262306a36Sopenharmony_ci }, 47362306a36Sopenharmony_ci { 47462306a36Sopenharmony_ci "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" 47562306a36Sopenharmony_ci "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 47662306a36Sopenharmony_ci ec_addm_448, 47762306a36Sopenharmony_ci ec_subm_448, 47862306a36Sopenharmony_ci ec_mulm_448, 47962306a36Sopenharmony_ci ec_mul2_448, 48062306a36Sopenharmony_ci ec_pow2_448 48162306a36Sopenharmony_ci }, 48262306a36Sopenharmony_ci { NULL, NULL, NULL, NULL, NULL, NULL }, 48362306a36Sopenharmony_ci}; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci/* Force recomputation of all helper variables. */ 48662306a36Sopenharmony_cistatic void mpi_ec_get_reset(struct mpi_ec_ctx *ec) 48762306a36Sopenharmony_ci{ 48862306a36Sopenharmony_ci ec->t.valid.a_is_pminus3 = 0; 48962306a36Sopenharmony_ci ec->t.valid.two_inv_p = 0; 49062306a36Sopenharmony_ci} 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci/* Accessor for helper variable. */ 49362306a36Sopenharmony_cistatic int ec_get_a_is_pminus3(struct mpi_ec_ctx *ec) 49462306a36Sopenharmony_ci{ 49562306a36Sopenharmony_ci MPI tmp; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci if (!ec->t.valid.a_is_pminus3) { 49862306a36Sopenharmony_ci ec->t.valid.a_is_pminus3 = 1; 49962306a36Sopenharmony_ci tmp = mpi_alloc_like(ec->p); 50062306a36Sopenharmony_ci mpi_sub_ui(tmp, ec->p, 3); 50162306a36Sopenharmony_ci ec->t.a_is_pminus3 = !mpi_cmp(ec->a, tmp); 50262306a36Sopenharmony_ci mpi_free(tmp); 50362306a36Sopenharmony_ci } 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci return ec->t.a_is_pminus3; 50662306a36Sopenharmony_ci} 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci/* Accessor for helper variable. */ 50962306a36Sopenharmony_cistatic MPI ec_get_two_inv_p(struct mpi_ec_ctx *ec) 51062306a36Sopenharmony_ci{ 51162306a36Sopenharmony_ci if (!ec->t.valid.two_inv_p) { 51262306a36Sopenharmony_ci ec->t.valid.two_inv_p = 1; 51362306a36Sopenharmony_ci if (!ec->t.two_inv_p) 51462306a36Sopenharmony_ci ec->t.two_inv_p = mpi_alloc(0); 51562306a36Sopenharmony_ci ec_invm(ec->t.two_inv_p, mpi_const(MPI_C_TWO), ec); 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ci return ec->t.two_inv_p; 51862306a36Sopenharmony_ci} 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_cistatic const char *const curve25519_bad_points[] = { 52162306a36Sopenharmony_ci "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed", 52262306a36Sopenharmony_ci "0x0000000000000000000000000000000000000000000000000000000000000000", 52362306a36Sopenharmony_ci "0x0000000000000000000000000000000000000000000000000000000000000001", 52462306a36Sopenharmony_ci "0x00b8495f16056286fdb1329ceb8d09da6ac49ff1fae35616aeb8413b7c7aebe0", 52562306a36Sopenharmony_ci "0x57119fd0dd4e22d8868e1c58c45c44045bef839c55b1d0b1248c50a3bc959c5f", 52662306a36Sopenharmony_ci "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec", 52762306a36Sopenharmony_ci "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee", 52862306a36Sopenharmony_ci NULL 52962306a36Sopenharmony_ci}; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_cistatic const char *const curve448_bad_points[] = { 53262306a36Sopenharmony_ci "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffe" 53362306a36Sopenharmony_ci "ffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 53462306a36Sopenharmony_ci "0x00000000000000000000000000000000000000000000000000000000" 53562306a36Sopenharmony_ci "00000000000000000000000000000000000000000000000000000000", 53662306a36Sopenharmony_ci "0x00000000000000000000000000000000000000000000000000000000" 53762306a36Sopenharmony_ci "00000000000000000000000000000000000000000000000000000001", 53862306a36Sopenharmony_ci "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffe" 53962306a36Sopenharmony_ci "fffffffffffffffffffffffffffffffffffffffffffffffffffffffe", 54062306a36Sopenharmony_ci "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff" 54162306a36Sopenharmony_ci "00000000000000000000000000000000000000000000000000000000", 54262306a36Sopenharmony_ci NULL 54362306a36Sopenharmony_ci}; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_cistatic const char *const *bad_points_table[] = { 54662306a36Sopenharmony_ci curve25519_bad_points, 54762306a36Sopenharmony_ci curve448_bad_points, 54862306a36Sopenharmony_ci}; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_cistatic void mpi_ec_coefficient_normalize(MPI a, MPI p) 55162306a36Sopenharmony_ci{ 55262306a36Sopenharmony_ci if (a->sign) { 55362306a36Sopenharmony_ci mpi_resize(a, p->nlimbs); 55462306a36Sopenharmony_ci mpihelp_sub_n(a->d, p->d, a->d, p->nlimbs); 55562306a36Sopenharmony_ci a->nlimbs = p->nlimbs; 55662306a36Sopenharmony_ci a->sign = 0; 55762306a36Sopenharmony_ci } 55862306a36Sopenharmony_ci} 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci/* This function initialized a context for elliptic curve based on the 56162306a36Sopenharmony_ci * field GF(p). P is the prime specifying this field, A is the first 56262306a36Sopenharmony_ci * coefficient. CTX is expected to be zeroized. 56362306a36Sopenharmony_ci */ 56462306a36Sopenharmony_civoid mpi_ec_init(struct mpi_ec_ctx *ctx, enum gcry_mpi_ec_models model, 56562306a36Sopenharmony_ci enum ecc_dialects dialect, 56662306a36Sopenharmony_ci int flags, MPI p, MPI a, MPI b) 56762306a36Sopenharmony_ci{ 56862306a36Sopenharmony_ci int i; 56962306a36Sopenharmony_ci static int use_barrett = -1 /* TODO: 1 or -1 */; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci mpi_ec_coefficient_normalize(a, p); 57262306a36Sopenharmony_ci mpi_ec_coefficient_normalize(b, p); 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci /* Fixme: Do we want to check some constraints? e.g. a < p */ 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci ctx->model = model; 57762306a36Sopenharmony_ci ctx->dialect = dialect; 57862306a36Sopenharmony_ci ctx->flags = flags; 57962306a36Sopenharmony_ci if (dialect == ECC_DIALECT_ED25519) 58062306a36Sopenharmony_ci ctx->nbits = 256; 58162306a36Sopenharmony_ci else 58262306a36Sopenharmony_ci ctx->nbits = mpi_get_nbits(p); 58362306a36Sopenharmony_ci ctx->p = mpi_copy(p); 58462306a36Sopenharmony_ci ctx->a = mpi_copy(a); 58562306a36Sopenharmony_ci ctx->b = mpi_copy(b); 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci ctx->d = NULL; 58862306a36Sopenharmony_ci ctx->t.two_inv_p = NULL; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci ctx->t.p_barrett = use_barrett > 0 ? mpi_barrett_init(ctx->p, 0) : NULL; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci mpi_ec_get_reset(ctx); 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci if (model == MPI_EC_MONTGOMERY) { 59562306a36Sopenharmony_ci for (i = 0; i < DIM(bad_points_table); i++) { 59662306a36Sopenharmony_ci MPI p_candidate = mpi_scanval(bad_points_table[i][0]); 59762306a36Sopenharmony_ci int match_p = !mpi_cmp(ctx->p, p_candidate); 59862306a36Sopenharmony_ci int j; 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci mpi_free(p_candidate); 60162306a36Sopenharmony_ci if (!match_p) 60262306a36Sopenharmony_ci continue; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci for (j = 0; i < DIM(ctx->t.scratch) && bad_points_table[i][j]; j++) 60562306a36Sopenharmony_ci ctx->t.scratch[j] = mpi_scanval(bad_points_table[i][j]); 60662306a36Sopenharmony_ci } 60762306a36Sopenharmony_ci } else { 60862306a36Sopenharmony_ci /* Allocate scratch variables. */ 60962306a36Sopenharmony_ci for (i = 0; i < DIM(ctx->t.scratch); i++) 61062306a36Sopenharmony_ci ctx->t.scratch[i] = mpi_alloc_like(ctx->p); 61162306a36Sopenharmony_ci } 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci ctx->addm = ec_addm; 61462306a36Sopenharmony_ci ctx->subm = ec_subm; 61562306a36Sopenharmony_ci ctx->mulm = ec_mulm; 61662306a36Sopenharmony_ci ctx->mul2 = ec_mul2; 61762306a36Sopenharmony_ci ctx->pow2 = ec_pow2; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci for (i = 0; field_table[i].p; i++) { 62062306a36Sopenharmony_ci MPI f_p; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci f_p = mpi_scanval(field_table[i].p); 62362306a36Sopenharmony_ci if (!f_p) 62462306a36Sopenharmony_ci break; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci if (!mpi_cmp(p, f_p)) { 62762306a36Sopenharmony_ci ctx->addm = field_table[i].addm; 62862306a36Sopenharmony_ci ctx->subm = field_table[i].subm; 62962306a36Sopenharmony_ci ctx->mulm = field_table[i].mulm; 63062306a36Sopenharmony_ci ctx->mul2 = field_table[i].mul2; 63162306a36Sopenharmony_ci ctx->pow2 = field_table[i].pow2; 63262306a36Sopenharmony_ci mpi_free(f_p); 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci mpi_resize(ctx->a, ctx->p->nlimbs); 63562306a36Sopenharmony_ci ctx->a->nlimbs = ctx->p->nlimbs; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci mpi_resize(ctx->b, ctx->p->nlimbs); 63862306a36Sopenharmony_ci ctx->b->nlimbs = ctx->p->nlimbs; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci for (i = 0; i < DIM(ctx->t.scratch) && ctx->t.scratch[i]; i++) 64162306a36Sopenharmony_ci ctx->t.scratch[i]->nlimbs = ctx->p->nlimbs; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci break; 64462306a36Sopenharmony_ci } 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci mpi_free(f_p); 64762306a36Sopenharmony_ci } 64862306a36Sopenharmony_ci} 64962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mpi_ec_init); 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_civoid mpi_ec_deinit(struct mpi_ec_ctx *ctx) 65262306a36Sopenharmony_ci{ 65362306a36Sopenharmony_ci int i; 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci mpi_barrett_free(ctx->t.p_barrett); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci /* Domain parameter. */ 65862306a36Sopenharmony_ci mpi_free(ctx->p); 65962306a36Sopenharmony_ci mpi_free(ctx->a); 66062306a36Sopenharmony_ci mpi_free(ctx->b); 66162306a36Sopenharmony_ci mpi_point_release(ctx->G); 66262306a36Sopenharmony_ci mpi_free(ctx->n); 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci /* The key. */ 66562306a36Sopenharmony_ci mpi_point_release(ctx->Q); 66662306a36Sopenharmony_ci mpi_free(ctx->d); 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci /* Private data of ec.c. */ 66962306a36Sopenharmony_ci mpi_free(ctx->t.two_inv_p); 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci for (i = 0; i < DIM(ctx->t.scratch); i++) 67262306a36Sopenharmony_ci mpi_free(ctx->t.scratch[i]); 67362306a36Sopenharmony_ci} 67462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mpi_ec_deinit); 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci/* Compute the affine coordinates from the projective coordinates in 67762306a36Sopenharmony_ci * POINT. Set them into X and Y. If one coordinate is not required, 67862306a36Sopenharmony_ci * X or Y may be passed as NULL. CTX is the usual context. Returns: 0 67962306a36Sopenharmony_ci * on success or !0 if POINT is at infinity. 68062306a36Sopenharmony_ci */ 68162306a36Sopenharmony_ciint mpi_ec_get_affine(MPI x, MPI y, MPI_POINT point, struct mpi_ec_ctx *ctx) 68262306a36Sopenharmony_ci{ 68362306a36Sopenharmony_ci if (!mpi_cmp_ui(point->z, 0)) 68462306a36Sopenharmony_ci return -1; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci switch (ctx->model) { 68762306a36Sopenharmony_ci case MPI_EC_WEIERSTRASS: /* Using Jacobian coordinates. */ 68862306a36Sopenharmony_ci { 68962306a36Sopenharmony_ci MPI z1, z2, z3; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci z1 = mpi_new(0); 69262306a36Sopenharmony_ci z2 = mpi_new(0); 69362306a36Sopenharmony_ci ec_invm(z1, point->z, ctx); /* z1 = z^(-1) mod p */ 69462306a36Sopenharmony_ci ec_mulm(z2, z1, z1, ctx); /* z2 = z^(-2) mod p */ 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci if (x) 69762306a36Sopenharmony_ci ec_mulm(x, point->x, z2, ctx); 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci if (y) { 70062306a36Sopenharmony_ci z3 = mpi_new(0); 70162306a36Sopenharmony_ci ec_mulm(z3, z2, z1, ctx); /* z3 = z^(-3) mod p */ 70262306a36Sopenharmony_ci ec_mulm(y, point->y, z3, ctx); 70362306a36Sopenharmony_ci mpi_free(z3); 70462306a36Sopenharmony_ci } 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci mpi_free(z2); 70762306a36Sopenharmony_ci mpi_free(z1); 70862306a36Sopenharmony_ci } 70962306a36Sopenharmony_ci return 0; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci case MPI_EC_MONTGOMERY: 71262306a36Sopenharmony_ci { 71362306a36Sopenharmony_ci if (x) 71462306a36Sopenharmony_ci mpi_set(x, point->x); 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci if (y) { 71762306a36Sopenharmony_ci log_fatal("%s: Getting Y-coordinate on %s is not supported\n", 71862306a36Sopenharmony_ci "mpi_ec_get_affine", "Montgomery"); 71962306a36Sopenharmony_ci return -1; 72062306a36Sopenharmony_ci } 72162306a36Sopenharmony_ci } 72262306a36Sopenharmony_ci return 0; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci case MPI_EC_EDWARDS: 72562306a36Sopenharmony_ci { 72662306a36Sopenharmony_ci MPI z; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci z = mpi_new(0); 72962306a36Sopenharmony_ci ec_invm(z, point->z, ctx); 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci mpi_resize(z, ctx->p->nlimbs); 73262306a36Sopenharmony_ci z->nlimbs = ctx->p->nlimbs; 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci if (x) { 73562306a36Sopenharmony_ci mpi_resize(x, ctx->p->nlimbs); 73662306a36Sopenharmony_ci x->nlimbs = ctx->p->nlimbs; 73762306a36Sopenharmony_ci ctx->mulm(x, point->x, z, ctx); 73862306a36Sopenharmony_ci } 73962306a36Sopenharmony_ci if (y) { 74062306a36Sopenharmony_ci mpi_resize(y, ctx->p->nlimbs); 74162306a36Sopenharmony_ci y->nlimbs = ctx->p->nlimbs; 74262306a36Sopenharmony_ci ctx->mulm(y, point->y, z, ctx); 74362306a36Sopenharmony_ci } 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci mpi_free(z); 74662306a36Sopenharmony_ci } 74762306a36Sopenharmony_ci return 0; 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci default: 75062306a36Sopenharmony_ci return -1; 75162306a36Sopenharmony_ci } 75262306a36Sopenharmony_ci} 75362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mpi_ec_get_affine); 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci/* RESULT = 2 * POINT (Weierstrass version). */ 75662306a36Sopenharmony_cistatic void dup_point_weierstrass(MPI_POINT result, 75762306a36Sopenharmony_ci MPI_POINT point, struct mpi_ec_ctx *ctx) 75862306a36Sopenharmony_ci{ 75962306a36Sopenharmony_ci#define x3 (result->x) 76062306a36Sopenharmony_ci#define y3 (result->y) 76162306a36Sopenharmony_ci#define z3 (result->z) 76262306a36Sopenharmony_ci#define t1 (ctx->t.scratch[0]) 76362306a36Sopenharmony_ci#define t2 (ctx->t.scratch[1]) 76462306a36Sopenharmony_ci#define t3 (ctx->t.scratch[2]) 76562306a36Sopenharmony_ci#define l1 (ctx->t.scratch[3]) 76662306a36Sopenharmony_ci#define l2 (ctx->t.scratch[4]) 76762306a36Sopenharmony_ci#define l3 (ctx->t.scratch[5]) 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci if (!mpi_cmp_ui(point->y, 0) || !mpi_cmp_ui(point->z, 0)) { 77062306a36Sopenharmony_ci /* P_y == 0 || P_z == 0 => [1:1:0] */ 77162306a36Sopenharmony_ci mpi_set_ui(x3, 1); 77262306a36Sopenharmony_ci mpi_set_ui(y3, 1); 77362306a36Sopenharmony_ci mpi_set_ui(z3, 0); 77462306a36Sopenharmony_ci } else { 77562306a36Sopenharmony_ci if (ec_get_a_is_pminus3(ctx)) { 77662306a36Sopenharmony_ci /* Use the faster case. */ 77762306a36Sopenharmony_ci /* L1 = 3(X - Z^2)(X + Z^2) */ 77862306a36Sopenharmony_ci /* T1: used for Z^2. */ 77962306a36Sopenharmony_ci /* T2: used for the right term. */ 78062306a36Sopenharmony_ci ec_pow2(t1, point->z, ctx); 78162306a36Sopenharmony_ci ec_subm(l1, point->x, t1, ctx); 78262306a36Sopenharmony_ci ec_mulm(l1, l1, mpi_const(MPI_C_THREE), ctx); 78362306a36Sopenharmony_ci ec_addm(t2, point->x, t1, ctx); 78462306a36Sopenharmony_ci ec_mulm(l1, l1, t2, ctx); 78562306a36Sopenharmony_ci } else { 78662306a36Sopenharmony_ci /* Standard case. */ 78762306a36Sopenharmony_ci /* L1 = 3X^2 + aZ^4 */ 78862306a36Sopenharmony_ci /* T1: used for aZ^4. */ 78962306a36Sopenharmony_ci ec_pow2(l1, point->x, ctx); 79062306a36Sopenharmony_ci ec_mulm(l1, l1, mpi_const(MPI_C_THREE), ctx); 79162306a36Sopenharmony_ci ec_powm(t1, point->z, mpi_const(MPI_C_FOUR), ctx); 79262306a36Sopenharmony_ci ec_mulm(t1, t1, ctx->a, ctx); 79362306a36Sopenharmony_ci ec_addm(l1, l1, t1, ctx); 79462306a36Sopenharmony_ci } 79562306a36Sopenharmony_ci /* Z3 = 2YZ */ 79662306a36Sopenharmony_ci ec_mulm(z3, point->y, point->z, ctx); 79762306a36Sopenharmony_ci ec_mul2(z3, z3, ctx); 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci /* L2 = 4XY^2 */ 80062306a36Sopenharmony_ci /* T2: used for Y2; required later. */ 80162306a36Sopenharmony_ci ec_pow2(t2, point->y, ctx); 80262306a36Sopenharmony_ci ec_mulm(l2, t2, point->x, ctx); 80362306a36Sopenharmony_ci ec_mulm(l2, l2, mpi_const(MPI_C_FOUR), ctx); 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci /* X3 = L1^2 - 2L2 */ 80662306a36Sopenharmony_ci /* T1: used for L2^2. */ 80762306a36Sopenharmony_ci ec_pow2(x3, l1, ctx); 80862306a36Sopenharmony_ci ec_mul2(t1, l2, ctx); 80962306a36Sopenharmony_ci ec_subm(x3, x3, t1, ctx); 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci /* L3 = 8Y^4 */ 81262306a36Sopenharmony_ci /* T2: taken from above. */ 81362306a36Sopenharmony_ci ec_pow2(t2, t2, ctx); 81462306a36Sopenharmony_ci ec_mulm(l3, t2, mpi_const(MPI_C_EIGHT), ctx); 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci /* Y3 = L1(L2 - X3) - L3 */ 81762306a36Sopenharmony_ci ec_subm(y3, l2, x3, ctx); 81862306a36Sopenharmony_ci ec_mulm(y3, y3, l1, ctx); 81962306a36Sopenharmony_ci ec_subm(y3, y3, l3, ctx); 82062306a36Sopenharmony_ci } 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci#undef x3 82362306a36Sopenharmony_ci#undef y3 82462306a36Sopenharmony_ci#undef z3 82562306a36Sopenharmony_ci#undef t1 82662306a36Sopenharmony_ci#undef t2 82762306a36Sopenharmony_ci#undef t3 82862306a36Sopenharmony_ci#undef l1 82962306a36Sopenharmony_ci#undef l2 83062306a36Sopenharmony_ci#undef l3 83162306a36Sopenharmony_ci} 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci/* RESULT = 2 * POINT (Montgomery version). */ 83462306a36Sopenharmony_cistatic void dup_point_montgomery(MPI_POINT result, 83562306a36Sopenharmony_ci MPI_POINT point, struct mpi_ec_ctx *ctx) 83662306a36Sopenharmony_ci{ 83762306a36Sopenharmony_ci (void)result; 83862306a36Sopenharmony_ci (void)point; 83962306a36Sopenharmony_ci (void)ctx; 84062306a36Sopenharmony_ci log_fatal("%s: %s not yet supported\n", 84162306a36Sopenharmony_ci "mpi_ec_dup_point", "Montgomery"); 84262306a36Sopenharmony_ci} 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci/* RESULT = 2 * POINT (Twisted Edwards version). */ 84562306a36Sopenharmony_cistatic void dup_point_edwards(MPI_POINT result, 84662306a36Sopenharmony_ci MPI_POINT point, struct mpi_ec_ctx *ctx) 84762306a36Sopenharmony_ci{ 84862306a36Sopenharmony_ci#define X1 (point->x) 84962306a36Sopenharmony_ci#define Y1 (point->y) 85062306a36Sopenharmony_ci#define Z1 (point->z) 85162306a36Sopenharmony_ci#define X3 (result->x) 85262306a36Sopenharmony_ci#define Y3 (result->y) 85362306a36Sopenharmony_ci#define Z3 (result->z) 85462306a36Sopenharmony_ci#define B (ctx->t.scratch[0]) 85562306a36Sopenharmony_ci#define C (ctx->t.scratch[1]) 85662306a36Sopenharmony_ci#define D (ctx->t.scratch[2]) 85762306a36Sopenharmony_ci#define E (ctx->t.scratch[3]) 85862306a36Sopenharmony_ci#define F (ctx->t.scratch[4]) 85962306a36Sopenharmony_ci#define H (ctx->t.scratch[5]) 86062306a36Sopenharmony_ci#define J (ctx->t.scratch[6]) 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci /* Compute: (X_3 : Y_3 : Z_3) = 2( X_1 : Y_1 : Z_1 ) */ 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci /* B = (X_1 + Y_1)^2 */ 86562306a36Sopenharmony_ci ctx->addm(B, X1, Y1, ctx); 86662306a36Sopenharmony_ci ctx->pow2(B, B, ctx); 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci /* C = X_1^2 */ 86962306a36Sopenharmony_ci /* D = Y_1^2 */ 87062306a36Sopenharmony_ci ctx->pow2(C, X1, ctx); 87162306a36Sopenharmony_ci ctx->pow2(D, Y1, ctx); 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci /* E = aC */ 87462306a36Sopenharmony_ci if (ctx->dialect == ECC_DIALECT_ED25519) 87562306a36Sopenharmony_ci ctx->subm(E, ctx->p, C, ctx); 87662306a36Sopenharmony_ci else 87762306a36Sopenharmony_ci ctx->mulm(E, ctx->a, C, ctx); 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci /* F = E + D */ 88062306a36Sopenharmony_ci ctx->addm(F, E, D, ctx); 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci /* H = Z_1^2 */ 88362306a36Sopenharmony_ci ctx->pow2(H, Z1, ctx); 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci /* J = F - 2H */ 88662306a36Sopenharmony_ci ctx->mul2(J, H, ctx); 88762306a36Sopenharmony_ci ctx->subm(J, F, J, ctx); 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci /* X_3 = (B - C - D) · J */ 89062306a36Sopenharmony_ci ctx->subm(X3, B, C, ctx); 89162306a36Sopenharmony_ci ctx->subm(X3, X3, D, ctx); 89262306a36Sopenharmony_ci ctx->mulm(X3, X3, J, ctx); 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci /* Y_3 = F · (E - D) */ 89562306a36Sopenharmony_ci ctx->subm(Y3, E, D, ctx); 89662306a36Sopenharmony_ci ctx->mulm(Y3, Y3, F, ctx); 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci /* Z_3 = F · J */ 89962306a36Sopenharmony_ci ctx->mulm(Z3, F, J, ctx); 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci#undef X1 90262306a36Sopenharmony_ci#undef Y1 90362306a36Sopenharmony_ci#undef Z1 90462306a36Sopenharmony_ci#undef X3 90562306a36Sopenharmony_ci#undef Y3 90662306a36Sopenharmony_ci#undef Z3 90762306a36Sopenharmony_ci#undef B 90862306a36Sopenharmony_ci#undef C 90962306a36Sopenharmony_ci#undef D 91062306a36Sopenharmony_ci#undef E 91162306a36Sopenharmony_ci#undef F 91262306a36Sopenharmony_ci#undef H 91362306a36Sopenharmony_ci#undef J 91462306a36Sopenharmony_ci} 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci/* RESULT = 2 * POINT */ 91762306a36Sopenharmony_cistatic void 91862306a36Sopenharmony_cimpi_ec_dup_point(MPI_POINT result, MPI_POINT point, struct mpi_ec_ctx *ctx) 91962306a36Sopenharmony_ci{ 92062306a36Sopenharmony_ci switch (ctx->model) { 92162306a36Sopenharmony_ci case MPI_EC_WEIERSTRASS: 92262306a36Sopenharmony_ci dup_point_weierstrass(result, point, ctx); 92362306a36Sopenharmony_ci break; 92462306a36Sopenharmony_ci case MPI_EC_MONTGOMERY: 92562306a36Sopenharmony_ci dup_point_montgomery(result, point, ctx); 92662306a36Sopenharmony_ci break; 92762306a36Sopenharmony_ci case MPI_EC_EDWARDS: 92862306a36Sopenharmony_ci dup_point_edwards(result, point, ctx); 92962306a36Sopenharmony_ci break; 93062306a36Sopenharmony_ci } 93162306a36Sopenharmony_ci} 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci/* RESULT = P1 + P2 (Weierstrass version).*/ 93462306a36Sopenharmony_cistatic void add_points_weierstrass(MPI_POINT result, 93562306a36Sopenharmony_ci MPI_POINT p1, MPI_POINT p2, 93662306a36Sopenharmony_ci struct mpi_ec_ctx *ctx) 93762306a36Sopenharmony_ci{ 93862306a36Sopenharmony_ci#define x1 (p1->x) 93962306a36Sopenharmony_ci#define y1 (p1->y) 94062306a36Sopenharmony_ci#define z1 (p1->z) 94162306a36Sopenharmony_ci#define x2 (p2->x) 94262306a36Sopenharmony_ci#define y2 (p2->y) 94362306a36Sopenharmony_ci#define z2 (p2->z) 94462306a36Sopenharmony_ci#define x3 (result->x) 94562306a36Sopenharmony_ci#define y3 (result->y) 94662306a36Sopenharmony_ci#define z3 (result->z) 94762306a36Sopenharmony_ci#define l1 (ctx->t.scratch[0]) 94862306a36Sopenharmony_ci#define l2 (ctx->t.scratch[1]) 94962306a36Sopenharmony_ci#define l3 (ctx->t.scratch[2]) 95062306a36Sopenharmony_ci#define l4 (ctx->t.scratch[3]) 95162306a36Sopenharmony_ci#define l5 (ctx->t.scratch[4]) 95262306a36Sopenharmony_ci#define l6 (ctx->t.scratch[5]) 95362306a36Sopenharmony_ci#define l7 (ctx->t.scratch[6]) 95462306a36Sopenharmony_ci#define l8 (ctx->t.scratch[7]) 95562306a36Sopenharmony_ci#define l9 (ctx->t.scratch[8]) 95662306a36Sopenharmony_ci#define t1 (ctx->t.scratch[9]) 95762306a36Sopenharmony_ci#define t2 (ctx->t.scratch[10]) 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci if ((!mpi_cmp(x1, x2)) && (!mpi_cmp(y1, y2)) && (!mpi_cmp(z1, z2))) { 96062306a36Sopenharmony_ci /* Same point; need to call the duplicate function. */ 96162306a36Sopenharmony_ci mpi_ec_dup_point(result, p1, ctx); 96262306a36Sopenharmony_ci } else if (!mpi_cmp_ui(z1, 0)) { 96362306a36Sopenharmony_ci /* P1 is at infinity. */ 96462306a36Sopenharmony_ci mpi_set(x3, p2->x); 96562306a36Sopenharmony_ci mpi_set(y3, p2->y); 96662306a36Sopenharmony_ci mpi_set(z3, p2->z); 96762306a36Sopenharmony_ci } else if (!mpi_cmp_ui(z2, 0)) { 96862306a36Sopenharmony_ci /* P2 is at infinity. */ 96962306a36Sopenharmony_ci mpi_set(x3, p1->x); 97062306a36Sopenharmony_ci mpi_set(y3, p1->y); 97162306a36Sopenharmony_ci mpi_set(z3, p1->z); 97262306a36Sopenharmony_ci } else { 97362306a36Sopenharmony_ci int z1_is_one = !mpi_cmp_ui(z1, 1); 97462306a36Sopenharmony_ci int z2_is_one = !mpi_cmp_ui(z2, 1); 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci /* l1 = x1 z2^2 */ 97762306a36Sopenharmony_ci /* l2 = x2 z1^2 */ 97862306a36Sopenharmony_ci if (z2_is_one) 97962306a36Sopenharmony_ci mpi_set(l1, x1); 98062306a36Sopenharmony_ci else { 98162306a36Sopenharmony_ci ec_pow2(l1, z2, ctx); 98262306a36Sopenharmony_ci ec_mulm(l1, l1, x1, ctx); 98362306a36Sopenharmony_ci } 98462306a36Sopenharmony_ci if (z1_is_one) 98562306a36Sopenharmony_ci mpi_set(l2, x2); 98662306a36Sopenharmony_ci else { 98762306a36Sopenharmony_ci ec_pow2(l2, z1, ctx); 98862306a36Sopenharmony_ci ec_mulm(l2, l2, x2, ctx); 98962306a36Sopenharmony_ci } 99062306a36Sopenharmony_ci /* l3 = l1 - l2 */ 99162306a36Sopenharmony_ci ec_subm(l3, l1, l2, ctx); 99262306a36Sopenharmony_ci /* l4 = y1 z2^3 */ 99362306a36Sopenharmony_ci ec_powm(l4, z2, mpi_const(MPI_C_THREE), ctx); 99462306a36Sopenharmony_ci ec_mulm(l4, l4, y1, ctx); 99562306a36Sopenharmony_ci /* l5 = y2 z1^3 */ 99662306a36Sopenharmony_ci ec_powm(l5, z1, mpi_const(MPI_C_THREE), ctx); 99762306a36Sopenharmony_ci ec_mulm(l5, l5, y2, ctx); 99862306a36Sopenharmony_ci /* l6 = l4 - l5 */ 99962306a36Sopenharmony_ci ec_subm(l6, l4, l5, ctx); 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci if (!mpi_cmp_ui(l3, 0)) { 100262306a36Sopenharmony_ci if (!mpi_cmp_ui(l6, 0)) { 100362306a36Sopenharmony_ci /* P1 and P2 are the same - use duplicate function. */ 100462306a36Sopenharmony_ci mpi_ec_dup_point(result, p1, ctx); 100562306a36Sopenharmony_ci } else { 100662306a36Sopenharmony_ci /* P1 is the inverse of P2. */ 100762306a36Sopenharmony_ci mpi_set_ui(x3, 1); 100862306a36Sopenharmony_ci mpi_set_ui(y3, 1); 100962306a36Sopenharmony_ci mpi_set_ui(z3, 0); 101062306a36Sopenharmony_ci } 101162306a36Sopenharmony_ci } else { 101262306a36Sopenharmony_ci /* l7 = l1 + l2 */ 101362306a36Sopenharmony_ci ec_addm(l7, l1, l2, ctx); 101462306a36Sopenharmony_ci /* l8 = l4 + l5 */ 101562306a36Sopenharmony_ci ec_addm(l8, l4, l5, ctx); 101662306a36Sopenharmony_ci /* z3 = z1 z2 l3 */ 101762306a36Sopenharmony_ci ec_mulm(z3, z1, z2, ctx); 101862306a36Sopenharmony_ci ec_mulm(z3, z3, l3, ctx); 101962306a36Sopenharmony_ci /* x3 = l6^2 - l7 l3^2 */ 102062306a36Sopenharmony_ci ec_pow2(t1, l6, ctx); 102162306a36Sopenharmony_ci ec_pow2(t2, l3, ctx); 102262306a36Sopenharmony_ci ec_mulm(t2, t2, l7, ctx); 102362306a36Sopenharmony_ci ec_subm(x3, t1, t2, ctx); 102462306a36Sopenharmony_ci /* l9 = l7 l3^2 - 2 x3 */ 102562306a36Sopenharmony_ci ec_mul2(t1, x3, ctx); 102662306a36Sopenharmony_ci ec_subm(l9, t2, t1, ctx); 102762306a36Sopenharmony_ci /* y3 = (l9 l6 - l8 l3^3)/2 */ 102862306a36Sopenharmony_ci ec_mulm(l9, l9, l6, ctx); 102962306a36Sopenharmony_ci ec_powm(t1, l3, mpi_const(MPI_C_THREE), ctx); /* fixme: Use saved value*/ 103062306a36Sopenharmony_ci ec_mulm(t1, t1, l8, ctx); 103162306a36Sopenharmony_ci ec_subm(y3, l9, t1, ctx); 103262306a36Sopenharmony_ci ec_mulm(y3, y3, ec_get_two_inv_p(ctx), ctx); 103362306a36Sopenharmony_ci } 103462306a36Sopenharmony_ci } 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci#undef x1 103762306a36Sopenharmony_ci#undef y1 103862306a36Sopenharmony_ci#undef z1 103962306a36Sopenharmony_ci#undef x2 104062306a36Sopenharmony_ci#undef y2 104162306a36Sopenharmony_ci#undef z2 104262306a36Sopenharmony_ci#undef x3 104362306a36Sopenharmony_ci#undef y3 104462306a36Sopenharmony_ci#undef z3 104562306a36Sopenharmony_ci#undef l1 104662306a36Sopenharmony_ci#undef l2 104762306a36Sopenharmony_ci#undef l3 104862306a36Sopenharmony_ci#undef l4 104962306a36Sopenharmony_ci#undef l5 105062306a36Sopenharmony_ci#undef l6 105162306a36Sopenharmony_ci#undef l7 105262306a36Sopenharmony_ci#undef l8 105362306a36Sopenharmony_ci#undef l9 105462306a36Sopenharmony_ci#undef t1 105562306a36Sopenharmony_ci#undef t2 105662306a36Sopenharmony_ci} 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci/* RESULT = P1 + P2 (Montgomery version).*/ 105962306a36Sopenharmony_cistatic void add_points_montgomery(MPI_POINT result, 106062306a36Sopenharmony_ci MPI_POINT p1, MPI_POINT p2, 106162306a36Sopenharmony_ci struct mpi_ec_ctx *ctx) 106262306a36Sopenharmony_ci{ 106362306a36Sopenharmony_ci (void)result; 106462306a36Sopenharmony_ci (void)p1; 106562306a36Sopenharmony_ci (void)p2; 106662306a36Sopenharmony_ci (void)ctx; 106762306a36Sopenharmony_ci log_fatal("%s: %s not yet supported\n", 106862306a36Sopenharmony_ci "mpi_ec_add_points", "Montgomery"); 106962306a36Sopenharmony_ci} 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci/* RESULT = P1 + P2 (Twisted Edwards version).*/ 107262306a36Sopenharmony_cistatic void add_points_edwards(MPI_POINT result, 107362306a36Sopenharmony_ci MPI_POINT p1, MPI_POINT p2, 107462306a36Sopenharmony_ci struct mpi_ec_ctx *ctx) 107562306a36Sopenharmony_ci{ 107662306a36Sopenharmony_ci#define X1 (p1->x) 107762306a36Sopenharmony_ci#define Y1 (p1->y) 107862306a36Sopenharmony_ci#define Z1 (p1->z) 107962306a36Sopenharmony_ci#define X2 (p2->x) 108062306a36Sopenharmony_ci#define Y2 (p2->y) 108162306a36Sopenharmony_ci#define Z2 (p2->z) 108262306a36Sopenharmony_ci#define X3 (result->x) 108362306a36Sopenharmony_ci#define Y3 (result->y) 108462306a36Sopenharmony_ci#define Z3 (result->z) 108562306a36Sopenharmony_ci#define A (ctx->t.scratch[0]) 108662306a36Sopenharmony_ci#define B (ctx->t.scratch[1]) 108762306a36Sopenharmony_ci#define C (ctx->t.scratch[2]) 108862306a36Sopenharmony_ci#define D (ctx->t.scratch[3]) 108962306a36Sopenharmony_ci#define E (ctx->t.scratch[4]) 109062306a36Sopenharmony_ci#define F (ctx->t.scratch[5]) 109162306a36Sopenharmony_ci#define G (ctx->t.scratch[6]) 109262306a36Sopenharmony_ci#define tmp (ctx->t.scratch[7]) 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci point_resize(result, ctx); 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci /* Compute: (X_3 : Y_3 : Z_3) = (X_1 : Y_1 : Z_1) + (X_2 : Y_2 : Z_3) */ 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci /* A = Z1 · Z2 */ 109962306a36Sopenharmony_ci ctx->mulm(A, Z1, Z2, ctx); 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci /* B = A^2 */ 110262306a36Sopenharmony_ci ctx->pow2(B, A, ctx); 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci /* C = X1 · X2 */ 110562306a36Sopenharmony_ci ctx->mulm(C, X1, X2, ctx); 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci /* D = Y1 · Y2 */ 110862306a36Sopenharmony_ci ctx->mulm(D, Y1, Y2, ctx); 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci /* E = d · C · D */ 111162306a36Sopenharmony_ci ctx->mulm(E, ctx->b, C, ctx); 111262306a36Sopenharmony_ci ctx->mulm(E, E, D, ctx); 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci /* F = B - E */ 111562306a36Sopenharmony_ci ctx->subm(F, B, E, ctx); 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci /* G = B + E */ 111862306a36Sopenharmony_ci ctx->addm(G, B, E, ctx); 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci /* X_3 = A · F · ((X_1 + Y_1) · (X_2 + Y_2) - C - D) */ 112162306a36Sopenharmony_ci ctx->addm(tmp, X1, Y1, ctx); 112262306a36Sopenharmony_ci ctx->addm(X3, X2, Y2, ctx); 112362306a36Sopenharmony_ci ctx->mulm(X3, X3, tmp, ctx); 112462306a36Sopenharmony_ci ctx->subm(X3, X3, C, ctx); 112562306a36Sopenharmony_ci ctx->subm(X3, X3, D, ctx); 112662306a36Sopenharmony_ci ctx->mulm(X3, X3, F, ctx); 112762306a36Sopenharmony_ci ctx->mulm(X3, X3, A, ctx); 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci /* Y_3 = A · G · (D - aC) */ 113062306a36Sopenharmony_ci if (ctx->dialect == ECC_DIALECT_ED25519) { 113162306a36Sopenharmony_ci ctx->addm(Y3, D, C, ctx); 113262306a36Sopenharmony_ci } else { 113362306a36Sopenharmony_ci ctx->mulm(Y3, ctx->a, C, ctx); 113462306a36Sopenharmony_ci ctx->subm(Y3, D, Y3, ctx); 113562306a36Sopenharmony_ci } 113662306a36Sopenharmony_ci ctx->mulm(Y3, Y3, G, ctx); 113762306a36Sopenharmony_ci ctx->mulm(Y3, Y3, A, ctx); 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci /* Z_3 = F · G */ 114062306a36Sopenharmony_ci ctx->mulm(Z3, F, G, ctx); 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci#undef X1 114462306a36Sopenharmony_ci#undef Y1 114562306a36Sopenharmony_ci#undef Z1 114662306a36Sopenharmony_ci#undef X2 114762306a36Sopenharmony_ci#undef Y2 114862306a36Sopenharmony_ci#undef Z2 114962306a36Sopenharmony_ci#undef X3 115062306a36Sopenharmony_ci#undef Y3 115162306a36Sopenharmony_ci#undef Z3 115262306a36Sopenharmony_ci#undef A 115362306a36Sopenharmony_ci#undef B 115462306a36Sopenharmony_ci#undef C 115562306a36Sopenharmony_ci#undef D 115662306a36Sopenharmony_ci#undef E 115762306a36Sopenharmony_ci#undef F 115862306a36Sopenharmony_ci#undef G 115962306a36Sopenharmony_ci#undef tmp 116062306a36Sopenharmony_ci} 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci/* Compute a step of Montgomery Ladder (only use X and Z in the point). 116362306a36Sopenharmony_ci * Inputs: P1, P2, and x-coordinate of DIF = P1 - P1. 116462306a36Sopenharmony_ci * Outputs: PRD = 2 * P1 and SUM = P1 + P2. 116562306a36Sopenharmony_ci */ 116662306a36Sopenharmony_cistatic void montgomery_ladder(MPI_POINT prd, MPI_POINT sum, 116762306a36Sopenharmony_ci MPI_POINT p1, MPI_POINT p2, MPI dif_x, 116862306a36Sopenharmony_ci struct mpi_ec_ctx *ctx) 116962306a36Sopenharmony_ci{ 117062306a36Sopenharmony_ci ctx->addm(sum->x, p2->x, p2->z, ctx); 117162306a36Sopenharmony_ci ctx->subm(p2->z, p2->x, p2->z, ctx); 117262306a36Sopenharmony_ci ctx->addm(prd->x, p1->x, p1->z, ctx); 117362306a36Sopenharmony_ci ctx->subm(p1->z, p1->x, p1->z, ctx); 117462306a36Sopenharmony_ci ctx->mulm(p2->x, p1->z, sum->x, ctx); 117562306a36Sopenharmony_ci ctx->mulm(p2->z, prd->x, p2->z, ctx); 117662306a36Sopenharmony_ci ctx->pow2(p1->x, prd->x, ctx); 117762306a36Sopenharmony_ci ctx->pow2(p1->z, p1->z, ctx); 117862306a36Sopenharmony_ci ctx->addm(sum->x, p2->x, p2->z, ctx); 117962306a36Sopenharmony_ci ctx->subm(p2->z, p2->x, p2->z, ctx); 118062306a36Sopenharmony_ci ctx->mulm(prd->x, p1->x, p1->z, ctx); 118162306a36Sopenharmony_ci ctx->subm(p1->z, p1->x, p1->z, ctx); 118262306a36Sopenharmony_ci ctx->pow2(sum->x, sum->x, ctx); 118362306a36Sopenharmony_ci ctx->pow2(sum->z, p2->z, ctx); 118462306a36Sopenharmony_ci ctx->mulm(prd->z, p1->z, ctx->a, ctx); /* CTX->A: (a-2)/4 */ 118562306a36Sopenharmony_ci ctx->mulm(sum->z, sum->z, dif_x, ctx); 118662306a36Sopenharmony_ci ctx->addm(prd->z, p1->x, prd->z, ctx); 118762306a36Sopenharmony_ci ctx->mulm(prd->z, prd->z, p1->z, ctx); 118862306a36Sopenharmony_ci} 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci/* RESULT = P1 + P2 */ 119162306a36Sopenharmony_civoid mpi_ec_add_points(MPI_POINT result, 119262306a36Sopenharmony_ci MPI_POINT p1, MPI_POINT p2, 119362306a36Sopenharmony_ci struct mpi_ec_ctx *ctx) 119462306a36Sopenharmony_ci{ 119562306a36Sopenharmony_ci switch (ctx->model) { 119662306a36Sopenharmony_ci case MPI_EC_WEIERSTRASS: 119762306a36Sopenharmony_ci add_points_weierstrass(result, p1, p2, ctx); 119862306a36Sopenharmony_ci break; 119962306a36Sopenharmony_ci case MPI_EC_MONTGOMERY: 120062306a36Sopenharmony_ci add_points_montgomery(result, p1, p2, ctx); 120162306a36Sopenharmony_ci break; 120262306a36Sopenharmony_ci case MPI_EC_EDWARDS: 120362306a36Sopenharmony_ci add_points_edwards(result, p1, p2, ctx); 120462306a36Sopenharmony_ci break; 120562306a36Sopenharmony_ci } 120662306a36Sopenharmony_ci} 120762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mpi_ec_add_points); 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci/* Scalar point multiplication - the main function for ECC. If takes 121062306a36Sopenharmony_ci * an integer SCALAR and a POINT as well as the usual context CTX. 121162306a36Sopenharmony_ci * RESULT will be set to the resulting point. 121262306a36Sopenharmony_ci */ 121362306a36Sopenharmony_civoid mpi_ec_mul_point(MPI_POINT result, 121462306a36Sopenharmony_ci MPI scalar, MPI_POINT point, 121562306a36Sopenharmony_ci struct mpi_ec_ctx *ctx) 121662306a36Sopenharmony_ci{ 121762306a36Sopenharmony_ci MPI x1, y1, z1, k, h, yy; 121862306a36Sopenharmony_ci unsigned int i, loops; 121962306a36Sopenharmony_ci struct gcry_mpi_point p1, p2, p1inv; 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci if (ctx->model == MPI_EC_EDWARDS) { 122262306a36Sopenharmony_ci /* Simple left to right binary method. Algorithm 3.27 from 122362306a36Sopenharmony_ci * {author={Hankerson, Darrel and Menezes, Alfred J. and Vanstone, Scott}, 122462306a36Sopenharmony_ci * title = {Guide to Elliptic Curve Cryptography}, 122562306a36Sopenharmony_ci * year = {2003}, isbn = {038795273X}, 122662306a36Sopenharmony_ci * url = {http://www.cacr.math.uwaterloo.ca/ecc/}, 122762306a36Sopenharmony_ci * publisher = {Springer-Verlag New York, Inc.}} 122862306a36Sopenharmony_ci */ 122962306a36Sopenharmony_ci unsigned int nbits; 123062306a36Sopenharmony_ci int j; 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci if (mpi_cmp(scalar, ctx->p) >= 0) 123362306a36Sopenharmony_ci nbits = mpi_get_nbits(scalar); 123462306a36Sopenharmony_ci else 123562306a36Sopenharmony_ci nbits = mpi_get_nbits(ctx->p); 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci mpi_set_ui(result->x, 0); 123862306a36Sopenharmony_ci mpi_set_ui(result->y, 1); 123962306a36Sopenharmony_ci mpi_set_ui(result->z, 1); 124062306a36Sopenharmony_ci point_resize(point, ctx); 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci point_resize(result, ctx); 124362306a36Sopenharmony_ci point_resize(point, ctx); 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci for (j = nbits-1; j >= 0; j--) { 124662306a36Sopenharmony_ci mpi_ec_dup_point(result, result, ctx); 124762306a36Sopenharmony_ci if (mpi_test_bit(scalar, j)) 124862306a36Sopenharmony_ci mpi_ec_add_points(result, result, point, ctx); 124962306a36Sopenharmony_ci } 125062306a36Sopenharmony_ci return; 125162306a36Sopenharmony_ci } else if (ctx->model == MPI_EC_MONTGOMERY) { 125262306a36Sopenharmony_ci unsigned int nbits; 125362306a36Sopenharmony_ci int j; 125462306a36Sopenharmony_ci struct gcry_mpi_point p1_, p2_; 125562306a36Sopenharmony_ci MPI_POINT q1, q2, prd, sum; 125662306a36Sopenharmony_ci unsigned long sw; 125762306a36Sopenharmony_ci mpi_size_t rsize; 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci /* Compute scalar point multiplication with Montgomery Ladder. 126062306a36Sopenharmony_ci * Note that we don't use Y-coordinate in the points at all. 126162306a36Sopenharmony_ci * RESULT->Y will be filled by zero. 126262306a36Sopenharmony_ci */ 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci nbits = mpi_get_nbits(scalar); 126562306a36Sopenharmony_ci point_init(&p1); 126662306a36Sopenharmony_ci point_init(&p2); 126762306a36Sopenharmony_ci point_init(&p1_); 126862306a36Sopenharmony_ci point_init(&p2_); 126962306a36Sopenharmony_ci mpi_set_ui(p1.x, 1); 127062306a36Sopenharmony_ci mpi_free(p2.x); 127162306a36Sopenharmony_ci p2.x = mpi_copy(point->x); 127262306a36Sopenharmony_ci mpi_set_ui(p2.z, 1); 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci point_resize(&p1, ctx); 127562306a36Sopenharmony_ci point_resize(&p2, ctx); 127662306a36Sopenharmony_ci point_resize(&p1_, ctx); 127762306a36Sopenharmony_ci point_resize(&p2_, ctx); 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci mpi_resize(point->x, ctx->p->nlimbs); 128062306a36Sopenharmony_ci point->x->nlimbs = ctx->p->nlimbs; 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci q1 = &p1; 128362306a36Sopenharmony_ci q2 = &p2; 128462306a36Sopenharmony_ci prd = &p1_; 128562306a36Sopenharmony_ci sum = &p2_; 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci for (j = nbits-1; j >= 0; j--) { 128862306a36Sopenharmony_ci MPI_POINT t; 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci sw = mpi_test_bit(scalar, j); 129162306a36Sopenharmony_ci point_swap_cond(q1, q2, sw, ctx); 129262306a36Sopenharmony_ci montgomery_ladder(prd, sum, q1, q2, point->x, ctx); 129362306a36Sopenharmony_ci point_swap_cond(prd, sum, sw, ctx); 129462306a36Sopenharmony_ci t = q1; q1 = prd; prd = t; 129562306a36Sopenharmony_ci t = q2; q2 = sum; sum = t; 129662306a36Sopenharmony_ci } 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci mpi_clear(result->y); 129962306a36Sopenharmony_ci sw = (nbits & 1); 130062306a36Sopenharmony_ci point_swap_cond(&p1, &p1_, sw, ctx); 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci rsize = p1.z->nlimbs; 130362306a36Sopenharmony_ci MPN_NORMALIZE(p1.z->d, rsize); 130462306a36Sopenharmony_ci if (rsize == 0) { 130562306a36Sopenharmony_ci mpi_set_ui(result->x, 1); 130662306a36Sopenharmony_ci mpi_set_ui(result->z, 0); 130762306a36Sopenharmony_ci } else { 130862306a36Sopenharmony_ci z1 = mpi_new(0); 130962306a36Sopenharmony_ci ec_invm(z1, p1.z, ctx); 131062306a36Sopenharmony_ci ec_mulm(result->x, p1.x, z1, ctx); 131162306a36Sopenharmony_ci mpi_set_ui(result->z, 1); 131262306a36Sopenharmony_ci mpi_free(z1); 131362306a36Sopenharmony_ci } 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci point_free(&p1); 131662306a36Sopenharmony_ci point_free(&p2); 131762306a36Sopenharmony_ci point_free(&p1_); 131862306a36Sopenharmony_ci point_free(&p2_); 131962306a36Sopenharmony_ci return; 132062306a36Sopenharmony_ci } 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci x1 = mpi_alloc_like(ctx->p); 132362306a36Sopenharmony_ci y1 = mpi_alloc_like(ctx->p); 132462306a36Sopenharmony_ci h = mpi_alloc_like(ctx->p); 132562306a36Sopenharmony_ci k = mpi_copy(scalar); 132662306a36Sopenharmony_ci yy = mpi_copy(point->y); 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ci if (mpi_has_sign(k)) { 132962306a36Sopenharmony_ci k->sign = 0; 133062306a36Sopenharmony_ci ec_invm(yy, yy, ctx); 133162306a36Sopenharmony_ci } 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci if (!mpi_cmp_ui(point->z, 1)) { 133462306a36Sopenharmony_ci mpi_set(x1, point->x); 133562306a36Sopenharmony_ci mpi_set(y1, yy); 133662306a36Sopenharmony_ci } else { 133762306a36Sopenharmony_ci MPI z2, z3; 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci z2 = mpi_alloc_like(ctx->p); 134062306a36Sopenharmony_ci z3 = mpi_alloc_like(ctx->p); 134162306a36Sopenharmony_ci ec_mulm(z2, point->z, point->z, ctx); 134262306a36Sopenharmony_ci ec_mulm(z3, point->z, z2, ctx); 134362306a36Sopenharmony_ci ec_invm(z2, z2, ctx); 134462306a36Sopenharmony_ci ec_mulm(x1, point->x, z2, ctx); 134562306a36Sopenharmony_ci ec_invm(z3, z3, ctx); 134662306a36Sopenharmony_ci ec_mulm(y1, yy, z3, ctx); 134762306a36Sopenharmony_ci mpi_free(z2); 134862306a36Sopenharmony_ci mpi_free(z3); 134962306a36Sopenharmony_ci } 135062306a36Sopenharmony_ci z1 = mpi_copy(mpi_const(MPI_C_ONE)); 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci mpi_mul(h, k, mpi_const(MPI_C_THREE)); /* h = 3k */ 135362306a36Sopenharmony_ci loops = mpi_get_nbits(h); 135462306a36Sopenharmony_ci if (loops < 2) { 135562306a36Sopenharmony_ci /* If SCALAR is zero, the above mpi_mul sets H to zero and thus 135662306a36Sopenharmony_ci * LOOPs will be zero. To avoid an underflow of I in the main 135762306a36Sopenharmony_ci * loop we set LOOP to 2 and the result to (0,0,0). 135862306a36Sopenharmony_ci */ 135962306a36Sopenharmony_ci loops = 2; 136062306a36Sopenharmony_ci mpi_clear(result->x); 136162306a36Sopenharmony_ci mpi_clear(result->y); 136262306a36Sopenharmony_ci mpi_clear(result->z); 136362306a36Sopenharmony_ci } else { 136462306a36Sopenharmony_ci mpi_set(result->x, point->x); 136562306a36Sopenharmony_ci mpi_set(result->y, yy); 136662306a36Sopenharmony_ci mpi_set(result->z, point->z); 136762306a36Sopenharmony_ci } 136862306a36Sopenharmony_ci mpi_free(yy); yy = NULL; 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci p1.x = x1; x1 = NULL; 137162306a36Sopenharmony_ci p1.y = y1; y1 = NULL; 137262306a36Sopenharmony_ci p1.z = z1; z1 = NULL; 137362306a36Sopenharmony_ci point_init(&p2); 137462306a36Sopenharmony_ci point_init(&p1inv); 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci /* Invert point: y = p - y mod p */ 137762306a36Sopenharmony_ci point_set(&p1inv, &p1); 137862306a36Sopenharmony_ci ec_subm(p1inv.y, ctx->p, p1inv.y, ctx); 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci for (i = loops-2; i > 0; i--) { 138162306a36Sopenharmony_ci mpi_ec_dup_point(result, result, ctx); 138262306a36Sopenharmony_ci if (mpi_test_bit(h, i) == 1 && mpi_test_bit(k, i) == 0) { 138362306a36Sopenharmony_ci point_set(&p2, result); 138462306a36Sopenharmony_ci mpi_ec_add_points(result, &p2, &p1, ctx); 138562306a36Sopenharmony_ci } 138662306a36Sopenharmony_ci if (mpi_test_bit(h, i) == 0 && mpi_test_bit(k, i) == 1) { 138762306a36Sopenharmony_ci point_set(&p2, result); 138862306a36Sopenharmony_ci mpi_ec_add_points(result, &p2, &p1inv, ctx); 138962306a36Sopenharmony_ci } 139062306a36Sopenharmony_ci } 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci point_free(&p1); 139362306a36Sopenharmony_ci point_free(&p2); 139462306a36Sopenharmony_ci point_free(&p1inv); 139562306a36Sopenharmony_ci mpi_free(h); 139662306a36Sopenharmony_ci mpi_free(k); 139762306a36Sopenharmony_ci} 139862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mpi_ec_mul_point); 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci/* Return true if POINT is on the curve described by CTX. */ 140162306a36Sopenharmony_ciint mpi_ec_curve_point(MPI_POINT point, struct mpi_ec_ctx *ctx) 140262306a36Sopenharmony_ci{ 140362306a36Sopenharmony_ci int res = 0; 140462306a36Sopenharmony_ci MPI x, y, w; 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci x = mpi_new(0); 140762306a36Sopenharmony_ci y = mpi_new(0); 140862306a36Sopenharmony_ci w = mpi_new(0); 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_ci /* Check that the point is in range. This needs to be done here and 141162306a36Sopenharmony_ci * not after conversion to affine coordinates. 141262306a36Sopenharmony_ci */ 141362306a36Sopenharmony_ci if (mpi_cmpabs(point->x, ctx->p) >= 0) 141462306a36Sopenharmony_ci goto leave; 141562306a36Sopenharmony_ci if (mpi_cmpabs(point->y, ctx->p) >= 0) 141662306a36Sopenharmony_ci goto leave; 141762306a36Sopenharmony_ci if (mpi_cmpabs(point->z, ctx->p) >= 0) 141862306a36Sopenharmony_ci goto leave; 141962306a36Sopenharmony_ci 142062306a36Sopenharmony_ci switch (ctx->model) { 142162306a36Sopenharmony_ci case MPI_EC_WEIERSTRASS: 142262306a36Sopenharmony_ci { 142362306a36Sopenharmony_ci MPI xxx; 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci if (mpi_ec_get_affine(x, y, point, ctx)) 142662306a36Sopenharmony_ci goto leave; 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci xxx = mpi_new(0); 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci /* y^2 == x^3 + a·x + b */ 143162306a36Sopenharmony_ci ec_pow2(y, y, ctx); 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci ec_pow3(xxx, x, ctx); 143462306a36Sopenharmony_ci ec_mulm(w, ctx->a, x, ctx); 143562306a36Sopenharmony_ci ec_addm(w, w, ctx->b, ctx); 143662306a36Sopenharmony_ci ec_addm(w, w, xxx, ctx); 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_ci if (!mpi_cmp(y, w)) 143962306a36Sopenharmony_ci res = 1; 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_ci mpi_free(xxx); 144262306a36Sopenharmony_ci } 144362306a36Sopenharmony_ci break; 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ci case MPI_EC_MONTGOMERY: 144662306a36Sopenharmony_ci { 144762306a36Sopenharmony_ci#define xx y 144862306a36Sopenharmony_ci /* With Montgomery curve, only X-coordinate is valid. */ 144962306a36Sopenharmony_ci if (mpi_ec_get_affine(x, NULL, point, ctx)) 145062306a36Sopenharmony_ci goto leave; 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_ci /* The equation is: b * y^2 == x^3 + a · x^2 + x */ 145362306a36Sopenharmony_ci /* We check if right hand is quadratic residue or not by 145462306a36Sopenharmony_ci * Euler's criterion. 145562306a36Sopenharmony_ci */ 145662306a36Sopenharmony_ci /* CTX->A has (a-2)/4 and CTX->B has b^-1 */ 145762306a36Sopenharmony_ci ec_mulm(w, ctx->a, mpi_const(MPI_C_FOUR), ctx); 145862306a36Sopenharmony_ci ec_addm(w, w, mpi_const(MPI_C_TWO), ctx); 145962306a36Sopenharmony_ci ec_mulm(w, w, x, ctx); 146062306a36Sopenharmony_ci ec_pow2(xx, x, ctx); 146162306a36Sopenharmony_ci ec_addm(w, w, xx, ctx); 146262306a36Sopenharmony_ci ec_addm(w, w, mpi_const(MPI_C_ONE), ctx); 146362306a36Sopenharmony_ci ec_mulm(w, w, x, ctx); 146462306a36Sopenharmony_ci ec_mulm(w, w, ctx->b, ctx); 146562306a36Sopenharmony_ci#undef xx 146662306a36Sopenharmony_ci /* Compute Euler's criterion: w^(p-1)/2 */ 146762306a36Sopenharmony_ci#define p_minus1 y 146862306a36Sopenharmony_ci ec_subm(p_minus1, ctx->p, mpi_const(MPI_C_ONE), ctx); 146962306a36Sopenharmony_ci mpi_rshift(p_minus1, p_minus1, 1); 147062306a36Sopenharmony_ci ec_powm(w, w, p_minus1, ctx); 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci res = !mpi_cmp_ui(w, 1); 147362306a36Sopenharmony_ci#undef p_minus1 147462306a36Sopenharmony_ci } 147562306a36Sopenharmony_ci break; 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_ci case MPI_EC_EDWARDS: 147862306a36Sopenharmony_ci { 147962306a36Sopenharmony_ci if (mpi_ec_get_affine(x, y, point, ctx)) 148062306a36Sopenharmony_ci goto leave; 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci mpi_resize(w, ctx->p->nlimbs); 148362306a36Sopenharmony_ci w->nlimbs = ctx->p->nlimbs; 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_ci /* a · x^2 + y^2 - 1 - b · x^2 · y^2 == 0 */ 148662306a36Sopenharmony_ci ctx->pow2(x, x, ctx); 148762306a36Sopenharmony_ci ctx->pow2(y, y, ctx); 148862306a36Sopenharmony_ci if (ctx->dialect == ECC_DIALECT_ED25519) 148962306a36Sopenharmony_ci ctx->subm(w, ctx->p, x, ctx); 149062306a36Sopenharmony_ci else 149162306a36Sopenharmony_ci ctx->mulm(w, ctx->a, x, ctx); 149262306a36Sopenharmony_ci ctx->addm(w, w, y, ctx); 149362306a36Sopenharmony_ci ctx->mulm(x, x, y, ctx); 149462306a36Sopenharmony_ci ctx->mulm(x, x, ctx->b, ctx); 149562306a36Sopenharmony_ci ctx->subm(w, w, x, ctx); 149662306a36Sopenharmony_ci if (!mpi_cmp_ui(w, 1)) 149762306a36Sopenharmony_ci res = 1; 149862306a36Sopenharmony_ci } 149962306a36Sopenharmony_ci break; 150062306a36Sopenharmony_ci } 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_cileave: 150362306a36Sopenharmony_ci mpi_free(w); 150462306a36Sopenharmony_ci mpi_free(x); 150562306a36Sopenharmony_ci mpi_free(y); 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci return res; 150862306a36Sopenharmony_ci} 150962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mpi_ec_curve_point); 1510