xref: /openbmc/linux/lib/crypto/mpi/ec.c (revision 7ebf812b)
12a598d0bSHerbert Xu /* ec.c -  Elliptic Curve functions
22a598d0bSHerbert Xu  * Copyright (C) 2007 Free Software Foundation, Inc.
32a598d0bSHerbert Xu  * Copyright (C) 2013 g10 Code GmbH
42a598d0bSHerbert Xu  *
52a598d0bSHerbert Xu  * This file is part of Libgcrypt.
62a598d0bSHerbert Xu  *
72a598d0bSHerbert Xu  * Libgcrypt is free software; you can redistribute it and/or modify
82a598d0bSHerbert Xu  * it under the terms of the GNU Lesser General Public License as
92a598d0bSHerbert Xu  * published by the Free Software Foundation; either version 2.1 of
102a598d0bSHerbert Xu  * the License, or (at your option) any later version.
112a598d0bSHerbert Xu  *
122a598d0bSHerbert Xu  * Libgcrypt is distributed in the hope that it will be useful,
132a598d0bSHerbert Xu  * but WITHOUT ANY WARRANTY; without even the implied warranty of
142a598d0bSHerbert Xu  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
152a598d0bSHerbert Xu  * GNU Lesser General Public License for more details.
162a598d0bSHerbert Xu  *
172a598d0bSHerbert Xu  * You should have received a copy of the GNU Lesser General Public
182a598d0bSHerbert Xu  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
192a598d0bSHerbert Xu  */
202a598d0bSHerbert Xu 
212a598d0bSHerbert Xu #include "mpi-internal.h"
222a598d0bSHerbert Xu #include "longlong.h"
232a598d0bSHerbert Xu 
242a598d0bSHerbert Xu #define point_init(a)  mpi_point_init((a))
252a598d0bSHerbert Xu #define point_free(a)  mpi_point_free_parts((a))
262a598d0bSHerbert Xu 
272a598d0bSHerbert Xu #define log_error(fmt, ...) pr_err(fmt, ##__VA_ARGS__)
282a598d0bSHerbert Xu #define log_fatal(fmt, ...) pr_err(fmt, ##__VA_ARGS__)
292a598d0bSHerbert Xu 
302a598d0bSHerbert Xu #define DIM(v) (sizeof(v)/sizeof((v)[0]))
312a598d0bSHerbert Xu 
322a598d0bSHerbert Xu 
332a598d0bSHerbert Xu /* Create a new point option.  NBITS gives the size in bits of one
342a598d0bSHerbert Xu  * coordinate; it is only used to pre-allocate some resources and
352a598d0bSHerbert Xu  * might also be passed as 0 to use a default value.
362a598d0bSHerbert Xu  */
mpi_point_new(unsigned int nbits)372a598d0bSHerbert Xu MPI_POINT mpi_point_new(unsigned int nbits)
382a598d0bSHerbert Xu {
392a598d0bSHerbert Xu 	MPI_POINT p;
402a598d0bSHerbert Xu 
412a598d0bSHerbert Xu 	(void)nbits;  /* Currently not used.  */
422a598d0bSHerbert Xu 
432a598d0bSHerbert Xu 	p = kmalloc(sizeof(*p), GFP_KERNEL);
442a598d0bSHerbert Xu 	if (p)
452a598d0bSHerbert Xu 		mpi_point_init(p);
462a598d0bSHerbert Xu 	return p;
472a598d0bSHerbert Xu }
482a598d0bSHerbert Xu EXPORT_SYMBOL_GPL(mpi_point_new);
492a598d0bSHerbert Xu 
502a598d0bSHerbert Xu /* Release the point object P.  P may be NULL. */
mpi_point_release(MPI_POINT p)512a598d0bSHerbert Xu void mpi_point_release(MPI_POINT p)
522a598d0bSHerbert Xu {
532a598d0bSHerbert Xu 	if (p) {
542a598d0bSHerbert Xu 		mpi_point_free_parts(p);
552a598d0bSHerbert Xu 		kfree(p);
562a598d0bSHerbert Xu 	}
572a598d0bSHerbert Xu }
582a598d0bSHerbert Xu EXPORT_SYMBOL_GPL(mpi_point_release);
592a598d0bSHerbert Xu 
602a598d0bSHerbert Xu /* Initialize the fields of a point object.  gcry_mpi_point_free_parts
612a598d0bSHerbert Xu  * may be used to release the fields.
622a598d0bSHerbert Xu  */
mpi_point_init(MPI_POINT p)632a598d0bSHerbert Xu void mpi_point_init(MPI_POINT p)
642a598d0bSHerbert Xu {
652a598d0bSHerbert Xu 	p->x = mpi_new(0);
662a598d0bSHerbert Xu 	p->y = mpi_new(0);
672a598d0bSHerbert Xu 	p->z = mpi_new(0);
682a598d0bSHerbert Xu }
692a598d0bSHerbert Xu EXPORT_SYMBOL_GPL(mpi_point_init);
702a598d0bSHerbert Xu 
712a598d0bSHerbert Xu /* Release the parts of a point object. */
mpi_point_free_parts(MPI_POINT p)722a598d0bSHerbert Xu void mpi_point_free_parts(MPI_POINT p)
732a598d0bSHerbert Xu {
742a598d0bSHerbert Xu 	mpi_free(p->x); p->x = NULL;
752a598d0bSHerbert Xu 	mpi_free(p->y); p->y = NULL;
762a598d0bSHerbert Xu 	mpi_free(p->z); p->z = NULL;
772a598d0bSHerbert Xu }
782a598d0bSHerbert Xu EXPORT_SYMBOL_GPL(mpi_point_free_parts);
792a598d0bSHerbert Xu 
802a598d0bSHerbert Xu /* Set the value from S into D.  */
point_set(MPI_POINT d,MPI_POINT s)812a598d0bSHerbert Xu static void point_set(MPI_POINT d, MPI_POINT s)
822a598d0bSHerbert Xu {
832a598d0bSHerbert Xu 	mpi_set(d->x, s->x);
842a598d0bSHerbert Xu 	mpi_set(d->y, s->y);
852a598d0bSHerbert Xu 	mpi_set(d->z, s->z);
862a598d0bSHerbert Xu }
872a598d0bSHerbert Xu 
point_resize(MPI_POINT p,struct mpi_ec_ctx * ctx)882a598d0bSHerbert Xu static void point_resize(MPI_POINT p, struct mpi_ec_ctx *ctx)
892a598d0bSHerbert Xu {
902a598d0bSHerbert Xu 	size_t nlimbs = ctx->p->nlimbs;
912a598d0bSHerbert Xu 
922a598d0bSHerbert Xu 	mpi_resize(p->x, nlimbs);
932a598d0bSHerbert Xu 	p->x->nlimbs = nlimbs;
942a598d0bSHerbert Xu 	mpi_resize(p->z, nlimbs);
952a598d0bSHerbert Xu 	p->z->nlimbs = nlimbs;
962a598d0bSHerbert Xu 
972a598d0bSHerbert Xu 	if (ctx->model != MPI_EC_MONTGOMERY) {
982a598d0bSHerbert Xu 		mpi_resize(p->y, nlimbs);
992a598d0bSHerbert Xu 		p->y->nlimbs = nlimbs;
1002a598d0bSHerbert Xu 	}
1012a598d0bSHerbert Xu }
1022a598d0bSHerbert Xu 
point_swap_cond(MPI_POINT d,MPI_POINT s,unsigned long swap,struct mpi_ec_ctx * ctx)1032a598d0bSHerbert Xu static void point_swap_cond(MPI_POINT d, MPI_POINT s, unsigned long swap,
1042a598d0bSHerbert Xu 		struct mpi_ec_ctx *ctx)
1052a598d0bSHerbert Xu {
1062a598d0bSHerbert Xu 	mpi_swap_cond(d->x, s->x, swap);
1072a598d0bSHerbert Xu 	if (ctx->model != MPI_EC_MONTGOMERY)
1082a598d0bSHerbert Xu 		mpi_swap_cond(d->y, s->y, swap);
1092a598d0bSHerbert Xu 	mpi_swap_cond(d->z, s->z, swap);
1102a598d0bSHerbert Xu }
1112a598d0bSHerbert Xu 
1122a598d0bSHerbert Xu 
1132a598d0bSHerbert Xu /* W = W mod P.  */
ec_mod(MPI w,struct mpi_ec_ctx * ec)1142a598d0bSHerbert Xu static void ec_mod(MPI w, struct mpi_ec_ctx *ec)
1152a598d0bSHerbert Xu {
1162a598d0bSHerbert Xu 	if (ec->t.p_barrett)
1172a598d0bSHerbert Xu 		mpi_mod_barrett(w, w, ec->t.p_barrett);
1182a598d0bSHerbert Xu 	else
1192a598d0bSHerbert Xu 		mpi_mod(w, w, ec->p);
1202a598d0bSHerbert Xu }
1212a598d0bSHerbert Xu 
ec_addm(MPI w,MPI u,MPI v,struct mpi_ec_ctx * ctx)1222a598d0bSHerbert Xu static void ec_addm(MPI w, MPI u, MPI v, struct mpi_ec_ctx *ctx)
1232a598d0bSHerbert Xu {
1242a598d0bSHerbert Xu 	mpi_add(w, u, v);
1252a598d0bSHerbert Xu 	ec_mod(w, ctx);
1262a598d0bSHerbert Xu }
1272a598d0bSHerbert Xu 
ec_subm(MPI w,MPI u,MPI v,struct mpi_ec_ctx * ec)1282a598d0bSHerbert Xu static void ec_subm(MPI w, MPI u, MPI v, struct mpi_ec_ctx *ec)
1292a598d0bSHerbert Xu {
1302a598d0bSHerbert Xu 	mpi_sub(w, u, v);
1312a598d0bSHerbert Xu 	while (w->sign)
1322a598d0bSHerbert Xu 		mpi_add(w, w, ec->p);
1332a598d0bSHerbert Xu 	/*ec_mod(w, ec);*/
1342a598d0bSHerbert Xu }
1352a598d0bSHerbert Xu 
ec_mulm(MPI w,MPI u,MPI v,struct mpi_ec_ctx * ctx)1362a598d0bSHerbert Xu static void ec_mulm(MPI w, MPI u, MPI v, struct mpi_ec_ctx *ctx)
1372a598d0bSHerbert Xu {
1382a598d0bSHerbert Xu 	mpi_mul(w, u, v);
1392a598d0bSHerbert Xu 	ec_mod(w, ctx);
1402a598d0bSHerbert Xu }
1412a598d0bSHerbert Xu 
1422a598d0bSHerbert Xu /* W = 2 * U mod P.  */
ec_mul2(MPI w,MPI u,struct mpi_ec_ctx * ctx)1432a598d0bSHerbert Xu static void ec_mul2(MPI w, MPI u, struct mpi_ec_ctx *ctx)
1442a598d0bSHerbert Xu {
1452a598d0bSHerbert Xu 	mpi_lshift(w, u, 1);
1462a598d0bSHerbert Xu 	ec_mod(w, ctx);
1472a598d0bSHerbert Xu }
1482a598d0bSHerbert Xu 
ec_powm(MPI w,const MPI b,const MPI e,struct mpi_ec_ctx * ctx)1492a598d0bSHerbert Xu static void ec_powm(MPI w, const MPI b, const MPI e,
1502a598d0bSHerbert Xu 		struct mpi_ec_ctx *ctx)
1512a598d0bSHerbert Xu {
1522a598d0bSHerbert Xu 	mpi_powm(w, b, e, ctx->p);
1532a598d0bSHerbert Xu 	/* mpi_abs(w); */
1542a598d0bSHerbert Xu }
1552a598d0bSHerbert Xu 
1562a598d0bSHerbert Xu /* Shortcut for
1572a598d0bSHerbert Xu  * ec_powm(B, B, mpi_const(MPI_C_TWO), ctx);
1582a598d0bSHerbert Xu  * for easier optimization.
1592a598d0bSHerbert Xu  */
ec_pow2(MPI w,const MPI b,struct mpi_ec_ctx * ctx)1602a598d0bSHerbert Xu static void ec_pow2(MPI w, const MPI b, struct mpi_ec_ctx *ctx)
1612a598d0bSHerbert Xu {
1622a598d0bSHerbert Xu 	/* Using mpi_mul is slightly faster (at least on amd64).  */
1632a598d0bSHerbert Xu 	/* mpi_powm(w, b, mpi_const(MPI_C_TWO), ctx->p); */
1642a598d0bSHerbert Xu 	ec_mulm(w, b, b, ctx);
1652a598d0bSHerbert Xu }
1662a598d0bSHerbert Xu 
1672a598d0bSHerbert Xu /* Shortcut for
1682a598d0bSHerbert Xu  * ec_powm(B, B, mpi_const(MPI_C_THREE), ctx);
1692a598d0bSHerbert Xu  * for easier optimization.
1702a598d0bSHerbert Xu  */
ec_pow3(MPI w,const MPI b,struct mpi_ec_ctx * ctx)1712a598d0bSHerbert Xu static void ec_pow3(MPI w, const MPI b, struct mpi_ec_ctx *ctx)
1722a598d0bSHerbert Xu {
1732a598d0bSHerbert Xu 	mpi_powm(w, b, mpi_const(MPI_C_THREE), ctx->p);
1742a598d0bSHerbert Xu }
1752a598d0bSHerbert Xu 
ec_invm(MPI x,MPI a,struct mpi_ec_ctx * ctx)1762a598d0bSHerbert Xu static void ec_invm(MPI x, MPI a, struct mpi_ec_ctx *ctx)
1772a598d0bSHerbert Xu {
1782a598d0bSHerbert Xu 	if (!mpi_invm(x, a, ctx->p))
1792a598d0bSHerbert Xu 		log_error("ec_invm: inverse does not exist:\n");
1802a598d0bSHerbert Xu }
1812a598d0bSHerbert Xu 
mpih_set_cond(mpi_ptr_t wp,mpi_ptr_t up,mpi_size_t usize,unsigned long set)1822a598d0bSHerbert Xu static void mpih_set_cond(mpi_ptr_t wp, mpi_ptr_t up,
1832a598d0bSHerbert Xu 		mpi_size_t usize, unsigned long set)
1842a598d0bSHerbert Xu {
1852a598d0bSHerbert Xu 	mpi_size_t i;
1862a598d0bSHerbert Xu 	mpi_limb_t mask = ((mpi_limb_t)0) - set;
1872a598d0bSHerbert Xu 	mpi_limb_t x;
1882a598d0bSHerbert Xu 
1892a598d0bSHerbert Xu 	for (i = 0; i < usize; i++) {
1902a598d0bSHerbert Xu 		x = mask & (wp[i] ^ up[i]);
1912a598d0bSHerbert Xu 		wp[i] = wp[i] ^ x;
1922a598d0bSHerbert Xu 	}
1932a598d0bSHerbert Xu }
1942a598d0bSHerbert Xu 
1952a598d0bSHerbert Xu /* Routines for 2^255 - 19.  */
1962a598d0bSHerbert Xu 
1972a598d0bSHerbert Xu #define LIMB_SIZE_25519 ((256+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB)
1982a598d0bSHerbert Xu 
ec_addm_25519(MPI w,MPI u,MPI v,struct mpi_ec_ctx * ctx)1992a598d0bSHerbert Xu static void ec_addm_25519(MPI w, MPI u, MPI v, struct mpi_ec_ctx *ctx)
2002a598d0bSHerbert Xu {
2012a598d0bSHerbert Xu 	mpi_ptr_t wp, up, vp;
2022a598d0bSHerbert Xu 	mpi_size_t wsize = LIMB_SIZE_25519;
2032a598d0bSHerbert Xu 	mpi_limb_t n[LIMB_SIZE_25519];
2042a598d0bSHerbert Xu 	mpi_limb_t borrow;
2052a598d0bSHerbert Xu 
2062a598d0bSHerbert Xu 	if (w->nlimbs != wsize || u->nlimbs != wsize || v->nlimbs != wsize)
2072a598d0bSHerbert Xu 		log_bug("addm_25519: different sizes\n");
2082a598d0bSHerbert Xu 
2092a598d0bSHerbert Xu 	memset(n, 0, sizeof(n));
2102a598d0bSHerbert Xu 	up = u->d;
2112a598d0bSHerbert Xu 	vp = v->d;
2122a598d0bSHerbert Xu 	wp = w->d;
2132a598d0bSHerbert Xu 
2142a598d0bSHerbert Xu 	mpihelp_add_n(wp, up, vp, wsize);
2152a598d0bSHerbert Xu 	borrow = mpihelp_sub_n(wp, wp, ctx->p->d, wsize);
2162a598d0bSHerbert Xu 	mpih_set_cond(n, ctx->p->d, wsize, (borrow != 0UL));
2172a598d0bSHerbert Xu 	mpihelp_add_n(wp, wp, n, wsize);
2182a598d0bSHerbert Xu 	wp[LIMB_SIZE_25519-1] &= ~((mpi_limb_t)1 << (255 % BITS_PER_MPI_LIMB));
2192a598d0bSHerbert Xu }
2202a598d0bSHerbert Xu 
ec_subm_25519(MPI w,MPI u,MPI v,struct mpi_ec_ctx * ctx)2212a598d0bSHerbert Xu static void ec_subm_25519(MPI w, MPI u, MPI v, struct mpi_ec_ctx *ctx)
2222a598d0bSHerbert Xu {
2232a598d0bSHerbert Xu 	mpi_ptr_t wp, up, vp;
2242a598d0bSHerbert Xu 	mpi_size_t wsize = LIMB_SIZE_25519;
2252a598d0bSHerbert Xu 	mpi_limb_t n[LIMB_SIZE_25519];
2262a598d0bSHerbert Xu 	mpi_limb_t borrow;
2272a598d0bSHerbert Xu 
2282a598d0bSHerbert Xu 	if (w->nlimbs != wsize || u->nlimbs != wsize || v->nlimbs != wsize)
2292a598d0bSHerbert Xu 		log_bug("subm_25519: different sizes\n");
2302a598d0bSHerbert Xu 
2312a598d0bSHerbert Xu 	memset(n, 0, sizeof(n));
2322a598d0bSHerbert Xu 	up = u->d;
2332a598d0bSHerbert Xu 	vp = v->d;
2342a598d0bSHerbert Xu 	wp = w->d;
2352a598d0bSHerbert Xu 
2362a598d0bSHerbert Xu 	borrow = mpihelp_sub_n(wp, up, vp, wsize);
2372a598d0bSHerbert Xu 	mpih_set_cond(n, ctx->p->d, wsize, (borrow != 0UL));
2382a598d0bSHerbert Xu 	mpihelp_add_n(wp, wp, n, wsize);
2392a598d0bSHerbert Xu 	wp[LIMB_SIZE_25519-1] &= ~((mpi_limb_t)1 << (255 % BITS_PER_MPI_LIMB));
2402a598d0bSHerbert Xu }
2412a598d0bSHerbert Xu 
ec_mulm_25519(MPI w,MPI u,MPI v,struct mpi_ec_ctx * ctx)2422a598d0bSHerbert Xu static void ec_mulm_25519(MPI w, MPI u, MPI v, struct mpi_ec_ctx *ctx)
2432a598d0bSHerbert Xu {
2442a598d0bSHerbert Xu 	mpi_ptr_t wp, up, vp;
2452a598d0bSHerbert Xu 	mpi_size_t wsize = LIMB_SIZE_25519;
2462a598d0bSHerbert Xu 	mpi_limb_t n[LIMB_SIZE_25519*2];
2472a598d0bSHerbert Xu 	mpi_limb_t m[LIMB_SIZE_25519+1];
2482a598d0bSHerbert Xu 	mpi_limb_t cy;
2492a598d0bSHerbert Xu 	int msb;
2502a598d0bSHerbert Xu 
2512a598d0bSHerbert Xu 	(void)ctx;
2522a598d0bSHerbert Xu 	if (w->nlimbs != wsize || u->nlimbs != wsize || v->nlimbs != wsize)
2532a598d0bSHerbert Xu 		log_bug("mulm_25519: different sizes\n");
2542a598d0bSHerbert Xu 
2552a598d0bSHerbert Xu 	up = u->d;
2562a598d0bSHerbert Xu 	vp = v->d;
2572a598d0bSHerbert Xu 	wp = w->d;
2582a598d0bSHerbert Xu 
2592a598d0bSHerbert Xu 	mpihelp_mul_n(n, up, vp, wsize);
2602a598d0bSHerbert Xu 	memcpy(wp, n, wsize * BYTES_PER_MPI_LIMB);
2612a598d0bSHerbert Xu 	wp[LIMB_SIZE_25519-1] &= ~((mpi_limb_t)1 << (255 % BITS_PER_MPI_LIMB));
2622a598d0bSHerbert Xu 
2632a598d0bSHerbert Xu 	memcpy(m, n+LIMB_SIZE_25519-1, (wsize+1) * BYTES_PER_MPI_LIMB);
2642a598d0bSHerbert Xu 	mpihelp_rshift(m, m, LIMB_SIZE_25519+1, (255 % BITS_PER_MPI_LIMB));
2652a598d0bSHerbert Xu 
2662a598d0bSHerbert Xu 	memcpy(n, m, wsize * BYTES_PER_MPI_LIMB);
2672a598d0bSHerbert Xu 	cy = mpihelp_lshift(m, m, LIMB_SIZE_25519, 4);
2682a598d0bSHerbert Xu 	m[LIMB_SIZE_25519] = cy;
2692a598d0bSHerbert Xu 	cy = mpihelp_add_n(m, m, n, wsize);
2702a598d0bSHerbert Xu 	m[LIMB_SIZE_25519] += cy;
2712a598d0bSHerbert Xu 	cy = mpihelp_add_n(m, m, n, wsize);
2722a598d0bSHerbert Xu 	m[LIMB_SIZE_25519] += cy;
2732a598d0bSHerbert Xu 	cy = mpihelp_add_n(m, m, n, wsize);
2742a598d0bSHerbert Xu 	m[LIMB_SIZE_25519] += cy;
2752a598d0bSHerbert Xu 
2762a598d0bSHerbert Xu 	cy = mpihelp_add_n(wp, wp, m, wsize);
2772a598d0bSHerbert Xu 	m[LIMB_SIZE_25519] += cy;
2782a598d0bSHerbert Xu 
2792a598d0bSHerbert Xu 	memset(m, 0, wsize * BYTES_PER_MPI_LIMB);
2802a598d0bSHerbert Xu 	msb = (wp[LIMB_SIZE_25519-1] >> (255 % BITS_PER_MPI_LIMB));
2812a598d0bSHerbert Xu 	m[0] = (m[LIMB_SIZE_25519] * 2 + msb) * 19;
2822a598d0bSHerbert Xu 	wp[LIMB_SIZE_25519-1] &= ~((mpi_limb_t)1 << (255 % BITS_PER_MPI_LIMB));
2832a598d0bSHerbert Xu 	mpihelp_add_n(wp, wp, m, wsize);
2842a598d0bSHerbert Xu 
2852a598d0bSHerbert Xu 	m[0] = 0;
2862a598d0bSHerbert Xu 	cy = mpihelp_sub_n(wp, wp, ctx->p->d, wsize);
2872a598d0bSHerbert Xu 	mpih_set_cond(m, ctx->p->d, wsize, (cy != 0UL));
2882a598d0bSHerbert Xu 	mpihelp_add_n(wp, wp, m, wsize);
2892a598d0bSHerbert Xu }
2902a598d0bSHerbert Xu 
ec_mul2_25519(MPI w,MPI u,struct mpi_ec_ctx * ctx)2912a598d0bSHerbert Xu static void ec_mul2_25519(MPI w, MPI u, struct mpi_ec_ctx *ctx)
2922a598d0bSHerbert Xu {
2932a598d0bSHerbert Xu 	ec_addm_25519(w, u, u, ctx);
2942a598d0bSHerbert Xu }
2952a598d0bSHerbert Xu 
ec_pow2_25519(MPI w,const MPI b,struct mpi_ec_ctx * ctx)2962a598d0bSHerbert Xu static void ec_pow2_25519(MPI w, const MPI b, struct mpi_ec_ctx *ctx)
2972a598d0bSHerbert Xu {
2982a598d0bSHerbert Xu 	ec_mulm_25519(w, b, b, ctx);
2992a598d0bSHerbert Xu }
3002a598d0bSHerbert Xu 
3012a598d0bSHerbert Xu /* Routines for 2^448 - 2^224 - 1.  */
3022a598d0bSHerbert Xu 
3032a598d0bSHerbert Xu #define LIMB_SIZE_448 ((448+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB)
3042a598d0bSHerbert Xu #define LIMB_SIZE_HALF_448 ((LIMB_SIZE_448+1)/2)
3052a598d0bSHerbert Xu 
ec_addm_448(MPI w,MPI u,MPI v,struct mpi_ec_ctx * ctx)3062a598d0bSHerbert Xu static void ec_addm_448(MPI w, MPI u, MPI v, struct mpi_ec_ctx *ctx)
3072a598d0bSHerbert Xu {
3082a598d0bSHerbert Xu 	mpi_ptr_t wp, up, vp;
3092a598d0bSHerbert Xu 	mpi_size_t wsize = LIMB_SIZE_448;
3102a598d0bSHerbert Xu 	mpi_limb_t n[LIMB_SIZE_448];
3112a598d0bSHerbert Xu 	mpi_limb_t cy;
3122a598d0bSHerbert Xu 
3132a598d0bSHerbert Xu 	if (w->nlimbs != wsize || u->nlimbs != wsize || v->nlimbs != wsize)
3142a598d0bSHerbert Xu 		log_bug("addm_448: different sizes\n");
3152a598d0bSHerbert Xu 
3162a598d0bSHerbert Xu 	memset(n, 0, sizeof(n));
3172a598d0bSHerbert Xu 	up = u->d;
3182a598d0bSHerbert Xu 	vp = v->d;
3192a598d0bSHerbert Xu 	wp = w->d;
3202a598d0bSHerbert Xu 
3212a598d0bSHerbert Xu 	cy = mpihelp_add_n(wp, up, vp, wsize);
3222a598d0bSHerbert Xu 	mpih_set_cond(n, ctx->p->d, wsize, (cy != 0UL));
3232a598d0bSHerbert Xu 	mpihelp_sub_n(wp, wp, n, wsize);
3242a598d0bSHerbert Xu }
3252a598d0bSHerbert Xu 
ec_subm_448(MPI w,MPI u,MPI v,struct mpi_ec_ctx * ctx)3262a598d0bSHerbert Xu static void ec_subm_448(MPI w, MPI u, MPI v, struct mpi_ec_ctx *ctx)
3272a598d0bSHerbert Xu {
3282a598d0bSHerbert Xu 	mpi_ptr_t wp, up, vp;
3292a598d0bSHerbert Xu 	mpi_size_t wsize = LIMB_SIZE_448;
3302a598d0bSHerbert Xu 	mpi_limb_t n[LIMB_SIZE_448];
3312a598d0bSHerbert Xu 	mpi_limb_t borrow;
3322a598d0bSHerbert Xu 
3332a598d0bSHerbert Xu 	if (w->nlimbs != wsize || u->nlimbs != wsize || v->nlimbs != wsize)
3342a598d0bSHerbert Xu 		log_bug("subm_448: different sizes\n");
3352a598d0bSHerbert Xu 
3362a598d0bSHerbert Xu 	memset(n, 0, sizeof(n));
3372a598d0bSHerbert Xu 	up = u->d;
3382a598d0bSHerbert Xu 	vp = v->d;
3392a598d0bSHerbert Xu 	wp = w->d;
3402a598d0bSHerbert Xu 
3412a598d0bSHerbert Xu 	borrow = mpihelp_sub_n(wp, up, vp, wsize);
3422a598d0bSHerbert Xu 	mpih_set_cond(n, ctx->p->d, wsize, (borrow != 0UL));
3432a598d0bSHerbert Xu 	mpihelp_add_n(wp, wp, n, wsize);
3442a598d0bSHerbert Xu }
3452a598d0bSHerbert Xu 
ec_mulm_448(MPI w,MPI u,MPI v,struct mpi_ec_ctx * ctx)3462a598d0bSHerbert Xu static void ec_mulm_448(MPI w, MPI u, MPI v, struct mpi_ec_ctx *ctx)
3472a598d0bSHerbert Xu {
3482a598d0bSHerbert Xu 	mpi_ptr_t wp, up, vp;
3492a598d0bSHerbert Xu 	mpi_size_t wsize = LIMB_SIZE_448;
3502a598d0bSHerbert Xu 	mpi_limb_t n[LIMB_SIZE_448*2];
3512a598d0bSHerbert Xu 	mpi_limb_t a2[LIMB_SIZE_HALF_448];
3522a598d0bSHerbert Xu 	mpi_limb_t a3[LIMB_SIZE_HALF_448];
3532a598d0bSHerbert Xu 	mpi_limb_t b0[LIMB_SIZE_HALF_448];
3542a598d0bSHerbert Xu 	mpi_limb_t b1[LIMB_SIZE_HALF_448];
3552a598d0bSHerbert Xu 	mpi_limb_t cy;
3562a598d0bSHerbert Xu 	int i;
3572a598d0bSHerbert Xu #if (LIMB_SIZE_HALF_448 > LIMB_SIZE_448/2)
3582a598d0bSHerbert Xu 	mpi_limb_t b1_rest, a3_rest;
3592a598d0bSHerbert Xu #endif
3602a598d0bSHerbert Xu 
3612a598d0bSHerbert Xu 	if (w->nlimbs != wsize || u->nlimbs != wsize || v->nlimbs != wsize)
3622a598d0bSHerbert Xu 		log_bug("mulm_448: different sizes\n");
3632a598d0bSHerbert Xu 
3642a598d0bSHerbert Xu 	up = u->d;
3652a598d0bSHerbert Xu 	vp = v->d;
3662a598d0bSHerbert Xu 	wp = w->d;
3672a598d0bSHerbert Xu 
3682a598d0bSHerbert Xu 	mpihelp_mul_n(n, up, vp, wsize);
3692a598d0bSHerbert Xu 
3702a598d0bSHerbert Xu 	for (i = 0; i < (wsize + 1) / 2; i++) {
3712a598d0bSHerbert Xu 		b0[i] = n[i];
3722a598d0bSHerbert Xu 		b1[i] = n[i+wsize/2];
3732a598d0bSHerbert Xu 		a2[i] = n[i+wsize];
3742a598d0bSHerbert Xu 		a3[i] = n[i+wsize+wsize/2];
3752a598d0bSHerbert Xu 	}
3762a598d0bSHerbert Xu 
3772a598d0bSHerbert Xu #if (LIMB_SIZE_HALF_448 > LIMB_SIZE_448/2)
3782a598d0bSHerbert Xu 	b0[LIMB_SIZE_HALF_448-1] &= ((mpi_limb_t)1UL << 32)-1;
3792a598d0bSHerbert Xu 	a2[LIMB_SIZE_HALF_448-1] &= ((mpi_limb_t)1UL << 32)-1;
3802a598d0bSHerbert Xu 
3812a598d0bSHerbert Xu 	b1_rest = 0;
3822a598d0bSHerbert Xu 	a3_rest = 0;
3832a598d0bSHerbert Xu 
3842a598d0bSHerbert Xu 	for (i = (wsize + 1) / 2 - 1; i >= 0; i--) {
3852a598d0bSHerbert Xu 		mpi_limb_t b1v, a3v;
3862a598d0bSHerbert Xu 		b1v = b1[i];
3872a598d0bSHerbert Xu 		a3v = a3[i];
3882a598d0bSHerbert Xu 		b1[i] = (b1_rest << 32) | (b1v >> 32);
3892a598d0bSHerbert Xu 		a3[i] = (a3_rest << 32) | (a3v >> 32);
3902a598d0bSHerbert Xu 		b1_rest = b1v & (((mpi_limb_t)1UL << 32)-1);
3912a598d0bSHerbert Xu 		a3_rest = a3v & (((mpi_limb_t)1UL << 32)-1);
3922a598d0bSHerbert Xu 	}
3932a598d0bSHerbert Xu #endif
3942a598d0bSHerbert Xu 
3952a598d0bSHerbert Xu 	cy = mpihelp_add_n(b0, b0, a2, LIMB_SIZE_HALF_448);
3962a598d0bSHerbert Xu 	cy += mpihelp_add_n(b0, b0, a3, LIMB_SIZE_HALF_448);
3972a598d0bSHerbert Xu 	for (i = 0; i < (wsize + 1) / 2; i++)
3982a598d0bSHerbert Xu 		wp[i] = b0[i];
3992a598d0bSHerbert Xu #if (LIMB_SIZE_HALF_448 > LIMB_SIZE_448/2)
4002a598d0bSHerbert Xu 	wp[LIMB_SIZE_HALF_448-1] &= (((mpi_limb_t)1UL << 32)-1);
4012a598d0bSHerbert Xu #endif
4022a598d0bSHerbert Xu 
4032a598d0bSHerbert Xu #if (LIMB_SIZE_HALF_448 > LIMB_SIZE_448/2)
4042a598d0bSHerbert Xu 	cy = b0[LIMB_SIZE_HALF_448-1] >> 32;
4052a598d0bSHerbert Xu #endif
4062a598d0bSHerbert Xu 
4072a598d0bSHerbert Xu 	cy = mpihelp_add_1(b1, b1, LIMB_SIZE_HALF_448, cy);
4082a598d0bSHerbert Xu 	cy += mpihelp_add_n(b1, b1, a2, LIMB_SIZE_HALF_448);
4092a598d0bSHerbert Xu 	cy += mpihelp_add_n(b1, b1, a3, LIMB_SIZE_HALF_448);
4102a598d0bSHerbert Xu 	cy += mpihelp_add_n(b1, b1, a3, LIMB_SIZE_HALF_448);
4112a598d0bSHerbert Xu #if (LIMB_SIZE_HALF_448 > LIMB_SIZE_448/2)
4122a598d0bSHerbert Xu 	b1_rest = 0;
4132a598d0bSHerbert Xu 	for (i = (wsize + 1) / 2 - 1; i >= 0; i--) {
4142a598d0bSHerbert Xu 		mpi_limb_t b1v = b1[i];
4152a598d0bSHerbert Xu 		b1[i] = (b1_rest << 32) | (b1v >> 32);
4162a598d0bSHerbert Xu 		b1_rest = b1v & (((mpi_limb_t)1UL << 32)-1);
4172a598d0bSHerbert Xu 	}
4182a598d0bSHerbert Xu 	wp[LIMB_SIZE_HALF_448-1] |= (b1_rest << 32);
4192a598d0bSHerbert Xu #endif
4202a598d0bSHerbert Xu 	for (i = 0; i < wsize / 2; i++)
4212a598d0bSHerbert Xu 		wp[i+(wsize + 1) / 2] = b1[i];
4222a598d0bSHerbert Xu 
4232a598d0bSHerbert Xu #if (LIMB_SIZE_HALF_448 > LIMB_SIZE_448/2)
4242a598d0bSHerbert Xu 	cy = b1[LIMB_SIZE_HALF_448-1];
4252a598d0bSHerbert Xu #endif
4262a598d0bSHerbert Xu 
4272a598d0bSHerbert Xu 	memset(n, 0, wsize * BYTES_PER_MPI_LIMB);
4282a598d0bSHerbert Xu 
4292a598d0bSHerbert Xu #if (LIMB_SIZE_HALF_448 > LIMB_SIZE_448/2)
4302a598d0bSHerbert Xu 	n[LIMB_SIZE_HALF_448-1] = cy << 32;
4312a598d0bSHerbert Xu #else
4322a598d0bSHerbert Xu 	n[LIMB_SIZE_HALF_448] = cy;
4332a598d0bSHerbert Xu #endif
4342a598d0bSHerbert Xu 	n[0] = cy;
4352a598d0bSHerbert Xu 	mpihelp_add_n(wp, wp, n, wsize);
4362a598d0bSHerbert Xu 
4372a598d0bSHerbert Xu 	memset(n, 0, wsize * BYTES_PER_MPI_LIMB);
4382a598d0bSHerbert Xu 	cy = mpihelp_sub_n(wp, wp, ctx->p->d, wsize);
4392a598d0bSHerbert Xu 	mpih_set_cond(n, ctx->p->d, wsize, (cy != 0UL));
4402a598d0bSHerbert Xu 	mpihelp_add_n(wp, wp, n, wsize);
4412a598d0bSHerbert Xu }
4422a598d0bSHerbert Xu 
ec_mul2_448(MPI w,MPI u,struct mpi_ec_ctx * ctx)4432a598d0bSHerbert Xu static void ec_mul2_448(MPI w, MPI u, struct mpi_ec_ctx *ctx)
4442a598d0bSHerbert Xu {
4452a598d0bSHerbert Xu 	ec_addm_448(w, u, u, ctx);
4462a598d0bSHerbert Xu }
4472a598d0bSHerbert Xu 
ec_pow2_448(MPI w,const MPI b,struct mpi_ec_ctx * ctx)4482a598d0bSHerbert Xu static void ec_pow2_448(MPI w, const MPI b, struct mpi_ec_ctx *ctx)
4492a598d0bSHerbert Xu {
4502a598d0bSHerbert Xu 	ec_mulm_448(w, b, b, ctx);
4512a598d0bSHerbert Xu }
4522a598d0bSHerbert Xu 
4532a598d0bSHerbert Xu struct field_table {
4542a598d0bSHerbert Xu 	const char *p;
4552a598d0bSHerbert Xu 
4562a598d0bSHerbert Xu 	/* computation routines for the field.  */
4572a598d0bSHerbert Xu 	void (*addm)(MPI w, MPI u, MPI v, struct mpi_ec_ctx *ctx);
4582a598d0bSHerbert Xu 	void (*subm)(MPI w, MPI u, MPI v, struct mpi_ec_ctx *ctx);
4592a598d0bSHerbert Xu 	void (*mulm)(MPI w, MPI u, MPI v, struct mpi_ec_ctx *ctx);
4602a598d0bSHerbert Xu 	void (*mul2)(MPI w, MPI u, struct mpi_ec_ctx *ctx);
4612a598d0bSHerbert Xu 	void (*pow2)(MPI w, const MPI b, struct mpi_ec_ctx *ctx);
4622a598d0bSHerbert Xu };
4632a598d0bSHerbert Xu 
4642a598d0bSHerbert Xu static const struct field_table field_table[] = {
4652a598d0bSHerbert Xu 	{
4662a598d0bSHerbert Xu 		"0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED",
4672a598d0bSHerbert Xu 		ec_addm_25519,
4682a598d0bSHerbert Xu 		ec_subm_25519,
4692a598d0bSHerbert Xu 		ec_mulm_25519,
4702a598d0bSHerbert Xu 		ec_mul2_25519,
4712a598d0bSHerbert Xu 		ec_pow2_25519
4722a598d0bSHerbert Xu 	},
4732a598d0bSHerbert Xu 	{
4742a598d0bSHerbert Xu 		"0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE"
4752a598d0bSHerbert Xu 		"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
4762a598d0bSHerbert Xu 		ec_addm_448,
4772a598d0bSHerbert Xu 		ec_subm_448,
4782a598d0bSHerbert Xu 		ec_mulm_448,
4792a598d0bSHerbert Xu 		ec_mul2_448,
4802a598d0bSHerbert Xu 		ec_pow2_448
4812a598d0bSHerbert Xu 	},
4822a598d0bSHerbert Xu 	{ NULL, NULL, NULL, NULL, NULL, NULL },
4832a598d0bSHerbert Xu };
4842a598d0bSHerbert Xu 
4852a598d0bSHerbert Xu /* Force recomputation of all helper variables.  */
mpi_ec_get_reset(struct mpi_ec_ctx * ec)4862a598d0bSHerbert Xu static void mpi_ec_get_reset(struct mpi_ec_ctx *ec)
4872a598d0bSHerbert Xu {
4882a598d0bSHerbert Xu 	ec->t.valid.a_is_pminus3 = 0;
4892a598d0bSHerbert Xu 	ec->t.valid.two_inv_p = 0;
4902a598d0bSHerbert Xu }
4912a598d0bSHerbert Xu 
4922a598d0bSHerbert Xu /* Accessor for helper variable.  */
ec_get_a_is_pminus3(struct mpi_ec_ctx * ec)4932a598d0bSHerbert Xu static int ec_get_a_is_pminus3(struct mpi_ec_ctx *ec)
4942a598d0bSHerbert Xu {
4952a598d0bSHerbert Xu 	MPI tmp;
4962a598d0bSHerbert Xu 
4972a598d0bSHerbert Xu 	if (!ec->t.valid.a_is_pminus3) {
4982a598d0bSHerbert Xu 		ec->t.valid.a_is_pminus3 = 1;
4992a598d0bSHerbert Xu 		tmp = mpi_alloc_like(ec->p);
5002a598d0bSHerbert Xu 		mpi_sub_ui(tmp, ec->p, 3);
5012a598d0bSHerbert Xu 		ec->t.a_is_pminus3 = !mpi_cmp(ec->a, tmp);
5022a598d0bSHerbert Xu 		mpi_free(tmp);
5032a598d0bSHerbert Xu 	}
5042a598d0bSHerbert Xu 
5052a598d0bSHerbert Xu 	return ec->t.a_is_pminus3;
5062a598d0bSHerbert Xu }
5072a598d0bSHerbert Xu 
5082a598d0bSHerbert Xu /* Accessor for helper variable.  */
ec_get_two_inv_p(struct mpi_ec_ctx * ec)5092a598d0bSHerbert Xu static MPI ec_get_two_inv_p(struct mpi_ec_ctx *ec)
5102a598d0bSHerbert Xu {
5112a598d0bSHerbert Xu 	if (!ec->t.valid.two_inv_p) {
5122a598d0bSHerbert Xu 		ec->t.valid.two_inv_p = 1;
5132a598d0bSHerbert Xu 		if (!ec->t.two_inv_p)
5142a598d0bSHerbert Xu 			ec->t.two_inv_p = mpi_alloc(0);
5152a598d0bSHerbert Xu 		ec_invm(ec->t.two_inv_p, mpi_const(MPI_C_TWO), ec);
5162a598d0bSHerbert Xu 	}
5172a598d0bSHerbert Xu 	return ec->t.two_inv_p;
5182a598d0bSHerbert Xu }
5192a598d0bSHerbert Xu 
5202a598d0bSHerbert Xu static const char *const curve25519_bad_points[] = {
5212a598d0bSHerbert Xu 	"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed",
5222a598d0bSHerbert Xu 	"0x0000000000000000000000000000000000000000000000000000000000000000",
5232a598d0bSHerbert Xu 	"0x0000000000000000000000000000000000000000000000000000000000000001",
5242a598d0bSHerbert Xu 	"0x00b8495f16056286fdb1329ceb8d09da6ac49ff1fae35616aeb8413b7c7aebe0",
5252a598d0bSHerbert Xu 	"0x57119fd0dd4e22d8868e1c58c45c44045bef839c55b1d0b1248c50a3bc959c5f",
5262a598d0bSHerbert Xu 	"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec",
5272a598d0bSHerbert Xu 	"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee",
5282a598d0bSHerbert Xu 	NULL
5292a598d0bSHerbert Xu };
5302a598d0bSHerbert Xu 
5312a598d0bSHerbert Xu static const char *const curve448_bad_points[] = {
5322a598d0bSHerbert Xu 	"0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffe"
5332a598d0bSHerbert Xu 	"ffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
5342a598d0bSHerbert Xu 	"0x00000000000000000000000000000000000000000000000000000000"
5352a598d0bSHerbert Xu 	"00000000000000000000000000000000000000000000000000000000",
5362a598d0bSHerbert Xu 	"0x00000000000000000000000000000000000000000000000000000000"
5372a598d0bSHerbert Xu 	"00000000000000000000000000000000000000000000000000000001",
5382a598d0bSHerbert Xu 	"0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffe"
5392a598d0bSHerbert Xu 	"fffffffffffffffffffffffffffffffffffffffffffffffffffffffe",
5402a598d0bSHerbert Xu 	"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
5412a598d0bSHerbert Xu 	"00000000000000000000000000000000000000000000000000000000",
5422a598d0bSHerbert Xu 	NULL
5432a598d0bSHerbert Xu };
5442a598d0bSHerbert Xu 
5452a598d0bSHerbert Xu static const char *const *bad_points_table[] = {
5462a598d0bSHerbert Xu 	curve25519_bad_points,
5472a598d0bSHerbert Xu 	curve448_bad_points,
5482a598d0bSHerbert Xu };
5492a598d0bSHerbert Xu 
mpi_ec_coefficient_normalize(MPI a,MPI p)5502a598d0bSHerbert Xu static void mpi_ec_coefficient_normalize(MPI a, MPI p)
5512a598d0bSHerbert Xu {
5522a598d0bSHerbert Xu 	if (a->sign) {
5532a598d0bSHerbert Xu 		mpi_resize(a, p->nlimbs);
5542a598d0bSHerbert Xu 		mpihelp_sub_n(a->d, p->d, a->d, p->nlimbs);
5552a598d0bSHerbert Xu 		a->nlimbs = p->nlimbs;
5562a598d0bSHerbert Xu 		a->sign = 0;
5572a598d0bSHerbert Xu 	}
5582a598d0bSHerbert Xu }
5592a598d0bSHerbert Xu 
5602a598d0bSHerbert Xu /* This function initialized a context for elliptic curve based on the
5612a598d0bSHerbert Xu  * field GF(p).  P is the prime specifying this field, A is the first
5622a598d0bSHerbert Xu  * coefficient.  CTX is expected to be zeroized.
5632a598d0bSHerbert Xu  */
mpi_ec_init(struct mpi_ec_ctx * ctx,enum gcry_mpi_ec_models model,enum ecc_dialects dialect,int flags,MPI p,MPI a,MPI b)5642a598d0bSHerbert Xu void mpi_ec_init(struct mpi_ec_ctx *ctx, enum gcry_mpi_ec_models model,
5652a598d0bSHerbert Xu 			enum ecc_dialects dialect,
5662a598d0bSHerbert Xu 			int flags, MPI p, MPI a, MPI b)
5672a598d0bSHerbert Xu {
5682a598d0bSHerbert Xu 	int i;
5692a598d0bSHerbert Xu 	static int use_barrett = -1 /* TODO: 1 or -1 */;
5702a598d0bSHerbert Xu 
5712a598d0bSHerbert Xu 	mpi_ec_coefficient_normalize(a, p);
5722a598d0bSHerbert Xu 	mpi_ec_coefficient_normalize(b, p);
5732a598d0bSHerbert Xu 
5742a598d0bSHerbert Xu 	/* Fixme: Do we want to check some constraints? e.g.  a < p  */
5752a598d0bSHerbert Xu 
5762a598d0bSHerbert Xu 	ctx->model = model;
5772a598d0bSHerbert Xu 	ctx->dialect = dialect;
5782a598d0bSHerbert Xu 	ctx->flags = flags;
5792a598d0bSHerbert Xu 	if (dialect == ECC_DIALECT_ED25519)
5802a598d0bSHerbert Xu 		ctx->nbits = 256;
5812a598d0bSHerbert Xu 	else
5822a598d0bSHerbert Xu 		ctx->nbits = mpi_get_nbits(p);
5832a598d0bSHerbert Xu 	ctx->p = mpi_copy(p);
5842a598d0bSHerbert Xu 	ctx->a = mpi_copy(a);
5852a598d0bSHerbert Xu 	ctx->b = mpi_copy(b);
5862a598d0bSHerbert Xu 
587*7ebf812bSTianjia Zhang 	ctx->d = NULL;
588*7ebf812bSTianjia Zhang 	ctx->t.two_inv_p = NULL;
589*7ebf812bSTianjia Zhang 
5902a598d0bSHerbert Xu 	ctx->t.p_barrett = use_barrett > 0 ? mpi_barrett_init(ctx->p, 0) : NULL;
5912a598d0bSHerbert Xu 
5922a598d0bSHerbert Xu 	mpi_ec_get_reset(ctx);
5932a598d0bSHerbert Xu 
5942a598d0bSHerbert Xu 	if (model == MPI_EC_MONTGOMERY) {
5952a598d0bSHerbert Xu 		for (i = 0; i < DIM(bad_points_table); i++) {
5962a598d0bSHerbert Xu 			MPI p_candidate = mpi_scanval(bad_points_table[i][0]);
5972a598d0bSHerbert Xu 			int match_p = !mpi_cmp(ctx->p, p_candidate);
5982a598d0bSHerbert Xu 			int j;
5992a598d0bSHerbert Xu 
6002a598d0bSHerbert Xu 			mpi_free(p_candidate);
6012a598d0bSHerbert Xu 			if (!match_p)
6022a598d0bSHerbert Xu 				continue;
6032a598d0bSHerbert Xu 
6042a598d0bSHerbert Xu 			for (j = 0; i < DIM(ctx->t.scratch) && bad_points_table[i][j]; j++)
6052a598d0bSHerbert Xu 				ctx->t.scratch[j] = mpi_scanval(bad_points_table[i][j]);
6062a598d0bSHerbert Xu 		}
6072a598d0bSHerbert Xu 	} else {
6082a598d0bSHerbert Xu 		/* Allocate scratch variables.  */
6092a598d0bSHerbert Xu 		for (i = 0; i < DIM(ctx->t.scratch); i++)
6102a598d0bSHerbert Xu 			ctx->t.scratch[i] = mpi_alloc_like(ctx->p);
6112a598d0bSHerbert Xu 	}
6122a598d0bSHerbert Xu 
6132a598d0bSHerbert Xu 	ctx->addm = ec_addm;
6142a598d0bSHerbert Xu 	ctx->subm = ec_subm;
6152a598d0bSHerbert Xu 	ctx->mulm = ec_mulm;
6162a598d0bSHerbert Xu 	ctx->mul2 = ec_mul2;
6172a598d0bSHerbert Xu 	ctx->pow2 = ec_pow2;
6182a598d0bSHerbert Xu 
6192a598d0bSHerbert Xu 	for (i = 0; field_table[i].p; i++) {
6202a598d0bSHerbert Xu 		MPI f_p;
6212a598d0bSHerbert Xu 
6222a598d0bSHerbert Xu 		f_p = mpi_scanval(field_table[i].p);
6232a598d0bSHerbert Xu 		if (!f_p)
6242a598d0bSHerbert Xu 			break;
6252a598d0bSHerbert Xu 
6262a598d0bSHerbert Xu 		if (!mpi_cmp(p, f_p)) {
6272a598d0bSHerbert Xu 			ctx->addm = field_table[i].addm;
6282a598d0bSHerbert Xu 			ctx->subm = field_table[i].subm;
6292a598d0bSHerbert Xu 			ctx->mulm = field_table[i].mulm;
6302a598d0bSHerbert Xu 			ctx->mul2 = field_table[i].mul2;
6312a598d0bSHerbert Xu 			ctx->pow2 = field_table[i].pow2;
6322a598d0bSHerbert Xu 			mpi_free(f_p);
6332a598d0bSHerbert Xu 
6342a598d0bSHerbert Xu 			mpi_resize(ctx->a, ctx->p->nlimbs);
6352a598d0bSHerbert Xu 			ctx->a->nlimbs = ctx->p->nlimbs;
6362a598d0bSHerbert Xu 
6372a598d0bSHerbert Xu 			mpi_resize(ctx->b, ctx->p->nlimbs);
6382a598d0bSHerbert Xu 			ctx->b->nlimbs = ctx->p->nlimbs;
6392a598d0bSHerbert Xu 
6402a598d0bSHerbert Xu 			for (i = 0; i < DIM(ctx->t.scratch) && ctx->t.scratch[i]; i++)
6412a598d0bSHerbert Xu 				ctx->t.scratch[i]->nlimbs = ctx->p->nlimbs;
6422a598d0bSHerbert Xu 
6432a598d0bSHerbert Xu 			break;
6442a598d0bSHerbert Xu 		}
6452a598d0bSHerbert Xu 
6462a598d0bSHerbert Xu 		mpi_free(f_p);
6472a598d0bSHerbert Xu 	}
6482a598d0bSHerbert Xu }
6492a598d0bSHerbert Xu EXPORT_SYMBOL_GPL(mpi_ec_init);
6502a598d0bSHerbert Xu 
mpi_ec_deinit(struct mpi_ec_ctx * ctx)6512a598d0bSHerbert Xu void mpi_ec_deinit(struct mpi_ec_ctx *ctx)
6522a598d0bSHerbert Xu {
6532a598d0bSHerbert Xu 	int i;
6542a598d0bSHerbert Xu 
6552a598d0bSHerbert Xu 	mpi_barrett_free(ctx->t.p_barrett);
6562a598d0bSHerbert Xu 
6572a598d0bSHerbert Xu 	/* Domain parameter.  */
6582a598d0bSHerbert Xu 	mpi_free(ctx->p);
6592a598d0bSHerbert Xu 	mpi_free(ctx->a);
6602a598d0bSHerbert Xu 	mpi_free(ctx->b);
6612a598d0bSHerbert Xu 	mpi_point_release(ctx->G);
6622a598d0bSHerbert Xu 	mpi_free(ctx->n);
6632a598d0bSHerbert Xu 
6642a598d0bSHerbert Xu 	/* The key.  */
6652a598d0bSHerbert Xu 	mpi_point_release(ctx->Q);
6662a598d0bSHerbert Xu 	mpi_free(ctx->d);
6672a598d0bSHerbert Xu 
6682a598d0bSHerbert Xu 	/* Private data of ec.c.  */
6692a598d0bSHerbert Xu 	mpi_free(ctx->t.two_inv_p);
6702a598d0bSHerbert Xu 
6712a598d0bSHerbert Xu 	for (i = 0; i < DIM(ctx->t.scratch); i++)
6722a598d0bSHerbert Xu 		mpi_free(ctx->t.scratch[i]);
6732a598d0bSHerbert Xu }
6742a598d0bSHerbert Xu EXPORT_SYMBOL_GPL(mpi_ec_deinit);
6752a598d0bSHerbert Xu 
6762a598d0bSHerbert Xu /* Compute the affine coordinates from the projective coordinates in
6772a598d0bSHerbert Xu  * POINT.  Set them into X and Y.  If one coordinate is not required,
6782a598d0bSHerbert Xu  * X or Y may be passed as NULL.  CTX is the usual context. Returns: 0
6792a598d0bSHerbert Xu  * on success or !0 if POINT is at infinity.
6802a598d0bSHerbert Xu  */
mpi_ec_get_affine(MPI x,MPI y,MPI_POINT point,struct mpi_ec_ctx * ctx)6812a598d0bSHerbert Xu int mpi_ec_get_affine(MPI x, MPI y, MPI_POINT point, struct mpi_ec_ctx *ctx)
6822a598d0bSHerbert Xu {
6832a598d0bSHerbert Xu 	if (!mpi_cmp_ui(point->z, 0))
6842a598d0bSHerbert Xu 		return -1;
6852a598d0bSHerbert Xu 
6862a598d0bSHerbert Xu 	switch (ctx->model) {
6872a598d0bSHerbert Xu 	case MPI_EC_WEIERSTRASS: /* Using Jacobian coordinates.  */
6882a598d0bSHerbert Xu 		{
6892a598d0bSHerbert Xu 			MPI z1, z2, z3;
6902a598d0bSHerbert Xu 
6912a598d0bSHerbert Xu 			z1 = mpi_new(0);
6922a598d0bSHerbert Xu 			z2 = mpi_new(0);
6932a598d0bSHerbert Xu 			ec_invm(z1, point->z, ctx);  /* z1 = z^(-1) mod p  */
6942a598d0bSHerbert Xu 			ec_mulm(z2, z1, z1, ctx);    /* z2 = z^(-2) mod p  */
6952a598d0bSHerbert Xu 
6962a598d0bSHerbert Xu 			if (x)
6972a598d0bSHerbert Xu 				ec_mulm(x, point->x, z2, ctx);
6982a598d0bSHerbert Xu 
6992a598d0bSHerbert Xu 			if (y) {
7002a598d0bSHerbert Xu 				z3 = mpi_new(0);
7012a598d0bSHerbert Xu 				ec_mulm(z3, z2, z1, ctx);      /* z3 = z^(-3) mod p */
7022a598d0bSHerbert Xu 				ec_mulm(y, point->y, z3, ctx);
7032a598d0bSHerbert Xu 				mpi_free(z3);
7042a598d0bSHerbert Xu 			}
7052a598d0bSHerbert Xu 
7062a598d0bSHerbert Xu 			mpi_free(z2);
7072a598d0bSHerbert Xu 			mpi_free(z1);
7082a598d0bSHerbert Xu 		}
7092a598d0bSHerbert Xu 		return 0;
7102a598d0bSHerbert Xu 
7112a598d0bSHerbert Xu 	case MPI_EC_MONTGOMERY:
7122a598d0bSHerbert Xu 		{
7132a598d0bSHerbert Xu 			if (x)
7142a598d0bSHerbert Xu 				mpi_set(x, point->x);
7152a598d0bSHerbert Xu 
7162a598d0bSHerbert Xu 			if (y) {
7172a598d0bSHerbert Xu 				log_fatal("%s: Getting Y-coordinate on %s is not supported\n",
7182a598d0bSHerbert Xu 						"mpi_ec_get_affine", "Montgomery");
7192a598d0bSHerbert Xu 				return -1;
7202a598d0bSHerbert Xu 			}
7212a598d0bSHerbert Xu 		}
7222a598d0bSHerbert Xu 		return 0;
7232a598d0bSHerbert Xu 
7242a598d0bSHerbert Xu 	case MPI_EC_EDWARDS:
7252a598d0bSHerbert Xu 		{
7262a598d0bSHerbert Xu 			MPI z;
7272a598d0bSHerbert Xu 
7282a598d0bSHerbert Xu 			z = mpi_new(0);
7292a598d0bSHerbert Xu 			ec_invm(z, point->z, ctx);
7302a598d0bSHerbert Xu 
7312a598d0bSHerbert Xu 			mpi_resize(z, ctx->p->nlimbs);
7322a598d0bSHerbert Xu 			z->nlimbs = ctx->p->nlimbs;
7332a598d0bSHerbert Xu 
7342a598d0bSHerbert Xu 			if (x) {
7352a598d0bSHerbert Xu 				mpi_resize(x, ctx->p->nlimbs);
7362a598d0bSHerbert Xu 				x->nlimbs = ctx->p->nlimbs;
7372a598d0bSHerbert Xu 				ctx->mulm(x, point->x, z, ctx);
7382a598d0bSHerbert Xu 			}
7392a598d0bSHerbert Xu 			if (y) {
7402a598d0bSHerbert Xu 				mpi_resize(y, ctx->p->nlimbs);
7412a598d0bSHerbert Xu 				y->nlimbs = ctx->p->nlimbs;
7422a598d0bSHerbert Xu 				ctx->mulm(y, point->y, z, ctx);
7432a598d0bSHerbert Xu 			}
7442a598d0bSHerbert Xu 
7452a598d0bSHerbert Xu 			mpi_free(z);
7462a598d0bSHerbert Xu 		}
7472a598d0bSHerbert Xu 		return 0;
7482a598d0bSHerbert Xu 
7492a598d0bSHerbert Xu 	default:
7502a598d0bSHerbert Xu 		return -1;
7512a598d0bSHerbert Xu 	}
7522a598d0bSHerbert Xu }
7532a598d0bSHerbert Xu EXPORT_SYMBOL_GPL(mpi_ec_get_affine);
7542a598d0bSHerbert Xu 
7552a598d0bSHerbert Xu /*  RESULT = 2 * POINT  (Weierstrass version). */
dup_point_weierstrass(MPI_POINT result,MPI_POINT point,struct mpi_ec_ctx * ctx)7562a598d0bSHerbert Xu static void dup_point_weierstrass(MPI_POINT result,
7572a598d0bSHerbert Xu 		MPI_POINT point, struct mpi_ec_ctx *ctx)
7582a598d0bSHerbert Xu {
7592a598d0bSHerbert Xu #define x3 (result->x)
7602a598d0bSHerbert Xu #define y3 (result->y)
7612a598d0bSHerbert Xu #define z3 (result->z)
7622a598d0bSHerbert Xu #define t1 (ctx->t.scratch[0])
7632a598d0bSHerbert Xu #define t2 (ctx->t.scratch[1])
7642a598d0bSHerbert Xu #define t3 (ctx->t.scratch[2])
7652a598d0bSHerbert Xu #define l1 (ctx->t.scratch[3])
7662a598d0bSHerbert Xu #define l2 (ctx->t.scratch[4])
7672a598d0bSHerbert Xu #define l3 (ctx->t.scratch[5])
7682a598d0bSHerbert Xu 
7692a598d0bSHerbert Xu 	if (!mpi_cmp_ui(point->y, 0) || !mpi_cmp_ui(point->z, 0)) {
7702a598d0bSHerbert Xu 		/* P_y == 0 || P_z == 0 => [1:1:0] */
7712a598d0bSHerbert Xu 		mpi_set_ui(x3, 1);
7722a598d0bSHerbert Xu 		mpi_set_ui(y3, 1);
7732a598d0bSHerbert Xu 		mpi_set_ui(z3, 0);
7742a598d0bSHerbert Xu 	} else {
7752a598d0bSHerbert Xu 		if (ec_get_a_is_pminus3(ctx)) {
7762a598d0bSHerbert Xu 			/* Use the faster case.  */
7772a598d0bSHerbert Xu 			/* L1 = 3(X - Z^2)(X + Z^2) */
7782a598d0bSHerbert Xu 			/*                          T1: used for Z^2. */
7792a598d0bSHerbert Xu 			/*                          T2: used for the right term. */
7802a598d0bSHerbert Xu 			ec_pow2(t1, point->z, ctx);
7812a598d0bSHerbert Xu 			ec_subm(l1, point->x, t1, ctx);
7822a598d0bSHerbert Xu 			ec_mulm(l1, l1, mpi_const(MPI_C_THREE), ctx);
7832a598d0bSHerbert Xu 			ec_addm(t2, point->x, t1, ctx);
7842a598d0bSHerbert Xu 			ec_mulm(l1, l1, t2, ctx);
7852a598d0bSHerbert Xu 		} else {
7862a598d0bSHerbert Xu 			/* Standard case. */
7872a598d0bSHerbert Xu 			/* L1 = 3X^2 + aZ^4 */
7882a598d0bSHerbert Xu 			/*                          T1: used for aZ^4. */
7892a598d0bSHerbert Xu 			ec_pow2(l1, point->x, ctx);
7902a598d0bSHerbert Xu 			ec_mulm(l1, l1, mpi_const(MPI_C_THREE), ctx);
7912a598d0bSHerbert Xu 			ec_powm(t1, point->z, mpi_const(MPI_C_FOUR), ctx);
7922a598d0bSHerbert Xu 			ec_mulm(t1, t1, ctx->a, ctx);
7932a598d0bSHerbert Xu 			ec_addm(l1, l1, t1, ctx);
7942a598d0bSHerbert Xu 		}
7952a598d0bSHerbert Xu 		/* Z3 = 2YZ */
7962a598d0bSHerbert Xu 		ec_mulm(z3, point->y, point->z, ctx);
7972a598d0bSHerbert Xu 		ec_mul2(z3, z3, ctx);
7982a598d0bSHerbert Xu 
7992a598d0bSHerbert Xu 		/* L2 = 4XY^2 */
8002a598d0bSHerbert Xu 		/*                              T2: used for Y2; required later. */
8012a598d0bSHerbert Xu 		ec_pow2(t2, point->y, ctx);
8022a598d0bSHerbert Xu 		ec_mulm(l2, t2, point->x, ctx);
8032a598d0bSHerbert Xu 		ec_mulm(l2, l2, mpi_const(MPI_C_FOUR), ctx);
8042a598d0bSHerbert Xu 
8052a598d0bSHerbert Xu 		/* X3 = L1^2 - 2L2 */
8062a598d0bSHerbert Xu 		/*                              T1: used for L2^2. */
8072a598d0bSHerbert Xu 		ec_pow2(x3, l1, ctx);
8082a598d0bSHerbert Xu 		ec_mul2(t1, l2, ctx);
8092a598d0bSHerbert Xu 		ec_subm(x3, x3, t1, ctx);
8102a598d0bSHerbert Xu 
8112a598d0bSHerbert Xu 		/* L3 = 8Y^4 */
8122a598d0bSHerbert Xu 		/*                              T2: taken from above. */
8132a598d0bSHerbert Xu 		ec_pow2(t2, t2, ctx);
8142a598d0bSHerbert Xu 		ec_mulm(l3, t2, mpi_const(MPI_C_EIGHT), ctx);
8152a598d0bSHerbert Xu 
8162a598d0bSHerbert Xu 		/* Y3 = L1(L2 - X3) - L3 */
8172a598d0bSHerbert Xu 		ec_subm(y3, l2, x3, ctx);
8182a598d0bSHerbert Xu 		ec_mulm(y3, y3, l1, ctx);
8192a598d0bSHerbert Xu 		ec_subm(y3, y3, l3, ctx);
8202a598d0bSHerbert Xu 	}
8212a598d0bSHerbert Xu 
8222a598d0bSHerbert Xu #undef x3
8232a598d0bSHerbert Xu #undef y3
8242a598d0bSHerbert Xu #undef z3
8252a598d0bSHerbert Xu #undef t1
8262a598d0bSHerbert Xu #undef t2
8272a598d0bSHerbert Xu #undef t3
8282a598d0bSHerbert Xu #undef l1
8292a598d0bSHerbert Xu #undef l2
8302a598d0bSHerbert Xu #undef l3
8312a598d0bSHerbert Xu }
8322a598d0bSHerbert Xu 
8332a598d0bSHerbert Xu /*  RESULT = 2 * POINT  (Montgomery version). */
dup_point_montgomery(MPI_POINT result,MPI_POINT point,struct mpi_ec_ctx * ctx)8342a598d0bSHerbert Xu static void dup_point_montgomery(MPI_POINT result,
8352a598d0bSHerbert Xu 				MPI_POINT point, struct mpi_ec_ctx *ctx)
8362a598d0bSHerbert Xu {
8372a598d0bSHerbert Xu 	(void)result;
8382a598d0bSHerbert Xu 	(void)point;
8392a598d0bSHerbert Xu 	(void)ctx;
8402a598d0bSHerbert Xu 	log_fatal("%s: %s not yet supported\n",
8412a598d0bSHerbert Xu 			"mpi_ec_dup_point", "Montgomery");
8422a598d0bSHerbert Xu }
8432a598d0bSHerbert Xu 
8442a598d0bSHerbert Xu /*  RESULT = 2 * POINT  (Twisted Edwards version). */
dup_point_edwards(MPI_POINT result,MPI_POINT point,struct mpi_ec_ctx * ctx)8452a598d0bSHerbert Xu static void dup_point_edwards(MPI_POINT result,
8462a598d0bSHerbert Xu 		MPI_POINT point, struct mpi_ec_ctx *ctx)
8472a598d0bSHerbert Xu {
8482a598d0bSHerbert Xu #define X1 (point->x)
8492a598d0bSHerbert Xu #define Y1 (point->y)
8502a598d0bSHerbert Xu #define Z1 (point->z)
8512a598d0bSHerbert Xu #define X3 (result->x)
8522a598d0bSHerbert Xu #define Y3 (result->y)
8532a598d0bSHerbert Xu #define Z3 (result->z)
8542a598d0bSHerbert Xu #define B (ctx->t.scratch[0])
8552a598d0bSHerbert Xu #define C (ctx->t.scratch[1])
8562a598d0bSHerbert Xu #define D (ctx->t.scratch[2])
8572a598d0bSHerbert Xu #define E (ctx->t.scratch[3])
8582a598d0bSHerbert Xu #define F (ctx->t.scratch[4])
8592a598d0bSHerbert Xu #define H (ctx->t.scratch[5])
8602a598d0bSHerbert Xu #define J (ctx->t.scratch[6])
8612a598d0bSHerbert Xu 
8622a598d0bSHerbert Xu 	/* Compute: (X_3 : Y_3 : Z_3) = 2( X_1 : Y_1 : Z_1 ) */
8632a598d0bSHerbert Xu 
8642a598d0bSHerbert Xu 	/* B = (X_1 + Y_1)^2  */
8652a598d0bSHerbert Xu 	ctx->addm(B, X1, Y1, ctx);
8662a598d0bSHerbert Xu 	ctx->pow2(B, B, ctx);
8672a598d0bSHerbert Xu 
8682a598d0bSHerbert Xu 	/* C = X_1^2 */
8692a598d0bSHerbert Xu 	/* D = Y_1^2 */
8702a598d0bSHerbert Xu 	ctx->pow2(C, X1, ctx);
8712a598d0bSHerbert Xu 	ctx->pow2(D, Y1, ctx);
8722a598d0bSHerbert Xu 
8732a598d0bSHerbert Xu 	/* E = aC */
8742a598d0bSHerbert Xu 	if (ctx->dialect == ECC_DIALECT_ED25519)
8752a598d0bSHerbert Xu 		ctx->subm(E, ctx->p, C, ctx);
8762a598d0bSHerbert Xu 	else
8772a598d0bSHerbert Xu 		ctx->mulm(E, ctx->a, C, ctx);
8782a598d0bSHerbert Xu 
8792a598d0bSHerbert Xu 	/* F = E + D */
8802a598d0bSHerbert Xu 	ctx->addm(F, E, D, ctx);
8812a598d0bSHerbert Xu 
8822a598d0bSHerbert Xu 	/* H = Z_1^2 */
8832a598d0bSHerbert Xu 	ctx->pow2(H, Z1, ctx);
8842a598d0bSHerbert Xu 
8852a598d0bSHerbert Xu 	/* J = F - 2H */
8862a598d0bSHerbert Xu 	ctx->mul2(J, H, ctx);
8872a598d0bSHerbert Xu 	ctx->subm(J, F, J, ctx);
8882a598d0bSHerbert Xu 
8892a598d0bSHerbert Xu 	/* X_3 = (B - C - D) · J */
8902a598d0bSHerbert Xu 	ctx->subm(X3, B, C, ctx);
8912a598d0bSHerbert Xu 	ctx->subm(X3, X3, D, ctx);
8922a598d0bSHerbert Xu 	ctx->mulm(X3, X3, J, ctx);
8932a598d0bSHerbert Xu 
8942a598d0bSHerbert Xu 	/* Y_3 = F · (E - D) */
8952a598d0bSHerbert Xu 	ctx->subm(Y3, E, D, ctx);
8962a598d0bSHerbert Xu 	ctx->mulm(Y3, Y3, F, ctx);
8972a598d0bSHerbert Xu 
8982a598d0bSHerbert Xu 	/* Z_3 = F · J */
8992a598d0bSHerbert Xu 	ctx->mulm(Z3, F, J, ctx);
9002a598d0bSHerbert Xu 
9012a598d0bSHerbert Xu #undef X1
9022a598d0bSHerbert Xu #undef Y1
9032a598d0bSHerbert Xu #undef Z1
9042a598d0bSHerbert Xu #undef X3
9052a598d0bSHerbert Xu #undef Y3
9062a598d0bSHerbert Xu #undef Z3
9072a598d0bSHerbert Xu #undef B
9082a598d0bSHerbert Xu #undef C
9092a598d0bSHerbert Xu #undef D
9102a598d0bSHerbert Xu #undef E
9112a598d0bSHerbert Xu #undef F
9122a598d0bSHerbert Xu #undef H
9132a598d0bSHerbert Xu #undef J
9142a598d0bSHerbert Xu }
9152a598d0bSHerbert Xu 
9162a598d0bSHerbert Xu /*  RESULT = 2 * POINT  */
9172a598d0bSHerbert Xu static void
mpi_ec_dup_point(MPI_POINT result,MPI_POINT point,struct mpi_ec_ctx * ctx)9182a598d0bSHerbert Xu mpi_ec_dup_point(MPI_POINT result, MPI_POINT point, struct mpi_ec_ctx *ctx)
9192a598d0bSHerbert Xu {
9202a598d0bSHerbert Xu 	switch (ctx->model) {
9212a598d0bSHerbert Xu 	case MPI_EC_WEIERSTRASS:
9222a598d0bSHerbert Xu 		dup_point_weierstrass(result, point, ctx);
9232a598d0bSHerbert Xu 		break;
9242a598d0bSHerbert Xu 	case MPI_EC_MONTGOMERY:
9252a598d0bSHerbert Xu 		dup_point_montgomery(result, point, ctx);
9262a598d0bSHerbert Xu 		break;
9272a598d0bSHerbert Xu 	case MPI_EC_EDWARDS:
9282a598d0bSHerbert Xu 		dup_point_edwards(result, point, ctx);
9292a598d0bSHerbert Xu 		break;
9302a598d0bSHerbert Xu 	}
9312a598d0bSHerbert Xu }
9322a598d0bSHerbert Xu 
9332a598d0bSHerbert Xu /* RESULT = P1 + P2  (Weierstrass version).*/
add_points_weierstrass(MPI_POINT result,MPI_POINT p1,MPI_POINT p2,struct mpi_ec_ctx * ctx)9342a598d0bSHerbert Xu static void add_points_weierstrass(MPI_POINT result,
9352a598d0bSHerbert Xu 		MPI_POINT p1, MPI_POINT p2,
9362a598d0bSHerbert Xu 		struct mpi_ec_ctx *ctx)
9372a598d0bSHerbert Xu {
9382a598d0bSHerbert Xu #define x1 (p1->x)
9392a598d0bSHerbert Xu #define y1 (p1->y)
9402a598d0bSHerbert Xu #define z1 (p1->z)
9412a598d0bSHerbert Xu #define x2 (p2->x)
9422a598d0bSHerbert Xu #define y2 (p2->y)
9432a598d0bSHerbert Xu #define z2 (p2->z)
9442a598d0bSHerbert Xu #define x3 (result->x)
9452a598d0bSHerbert Xu #define y3 (result->y)
9462a598d0bSHerbert Xu #define z3 (result->z)
9472a598d0bSHerbert Xu #define l1 (ctx->t.scratch[0])
9482a598d0bSHerbert Xu #define l2 (ctx->t.scratch[1])
9492a598d0bSHerbert Xu #define l3 (ctx->t.scratch[2])
9502a598d0bSHerbert Xu #define l4 (ctx->t.scratch[3])
9512a598d0bSHerbert Xu #define l5 (ctx->t.scratch[4])
9522a598d0bSHerbert Xu #define l6 (ctx->t.scratch[5])
9532a598d0bSHerbert Xu #define l7 (ctx->t.scratch[6])
9542a598d0bSHerbert Xu #define l8 (ctx->t.scratch[7])
9552a598d0bSHerbert Xu #define l9 (ctx->t.scratch[8])
9562a598d0bSHerbert Xu #define t1 (ctx->t.scratch[9])
9572a598d0bSHerbert Xu #define t2 (ctx->t.scratch[10])
9582a598d0bSHerbert Xu 
9592a598d0bSHerbert Xu 	if ((!mpi_cmp(x1, x2)) && (!mpi_cmp(y1, y2)) && (!mpi_cmp(z1, z2))) {
9602a598d0bSHerbert Xu 		/* Same point; need to call the duplicate function.  */
9612a598d0bSHerbert Xu 		mpi_ec_dup_point(result, p1, ctx);
9622a598d0bSHerbert Xu 	} else if (!mpi_cmp_ui(z1, 0)) {
9632a598d0bSHerbert Xu 		/* P1 is at infinity.  */
9642a598d0bSHerbert Xu 		mpi_set(x3, p2->x);
9652a598d0bSHerbert Xu 		mpi_set(y3, p2->y);
9662a598d0bSHerbert Xu 		mpi_set(z3, p2->z);
9672a598d0bSHerbert Xu 	} else if (!mpi_cmp_ui(z2, 0)) {
9682a598d0bSHerbert Xu 		/* P2 is at infinity.  */
9692a598d0bSHerbert Xu 		mpi_set(x3, p1->x);
9702a598d0bSHerbert Xu 		mpi_set(y3, p1->y);
9712a598d0bSHerbert Xu 		mpi_set(z3, p1->z);
9722a598d0bSHerbert Xu 	} else {
9732a598d0bSHerbert Xu 		int z1_is_one = !mpi_cmp_ui(z1, 1);
9742a598d0bSHerbert Xu 		int z2_is_one = !mpi_cmp_ui(z2, 1);
9752a598d0bSHerbert Xu 
9762a598d0bSHerbert Xu 		/* l1 = x1 z2^2  */
9772a598d0bSHerbert Xu 		/* l2 = x2 z1^2  */
9782a598d0bSHerbert Xu 		if (z2_is_one)
9792a598d0bSHerbert Xu 			mpi_set(l1, x1);
9802a598d0bSHerbert Xu 		else {
9812a598d0bSHerbert Xu 			ec_pow2(l1, z2, ctx);
9822a598d0bSHerbert Xu 			ec_mulm(l1, l1, x1, ctx);
9832a598d0bSHerbert Xu 		}
9842a598d0bSHerbert Xu 		if (z1_is_one)
9852a598d0bSHerbert Xu 			mpi_set(l2, x2);
9862a598d0bSHerbert Xu 		else {
9872a598d0bSHerbert Xu 			ec_pow2(l2, z1, ctx);
9882a598d0bSHerbert Xu 			ec_mulm(l2, l2, x2, ctx);
9892a598d0bSHerbert Xu 		}
9902a598d0bSHerbert Xu 		/* l3 = l1 - l2 */
9912a598d0bSHerbert Xu 		ec_subm(l3, l1, l2, ctx);
9922a598d0bSHerbert Xu 		/* l4 = y1 z2^3  */
9932a598d0bSHerbert Xu 		ec_powm(l4, z2, mpi_const(MPI_C_THREE), ctx);
9942a598d0bSHerbert Xu 		ec_mulm(l4, l4, y1, ctx);
9952a598d0bSHerbert Xu 		/* l5 = y2 z1^3  */
9962a598d0bSHerbert Xu 		ec_powm(l5, z1, mpi_const(MPI_C_THREE), ctx);
9972a598d0bSHerbert Xu 		ec_mulm(l5, l5, y2, ctx);
9982a598d0bSHerbert Xu 		/* l6 = l4 - l5  */
9992a598d0bSHerbert Xu 		ec_subm(l6, l4, l5, ctx);
10002a598d0bSHerbert Xu 
10012a598d0bSHerbert Xu 		if (!mpi_cmp_ui(l3, 0)) {
10022a598d0bSHerbert Xu 			if (!mpi_cmp_ui(l6, 0)) {
10032a598d0bSHerbert Xu 				/* P1 and P2 are the same - use duplicate function. */
10042a598d0bSHerbert Xu 				mpi_ec_dup_point(result, p1, ctx);
10052a598d0bSHerbert Xu 			} else {
10062a598d0bSHerbert Xu 				/* P1 is the inverse of P2.  */
10072a598d0bSHerbert Xu 				mpi_set_ui(x3, 1);
10082a598d0bSHerbert Xu 				mpi_set_ui(y3, 1);
10092a598d0bSHerbert Xu 				mpi_set_ui(z3, 0);
10102a598d0bSHerbert Xu 			}
10112a598d0bSHerbert Xu 		} else {
10122a598d0bSHerbert Xu 			/* l7 = l1 + l2  */
10132a598d0bSHerbert Xu 			ec_addm(l7, l1, l2, ctx);
10142a598d0bSHerbert Xu 			/* l8 = l4 + l5  */
10152a598d0bSHerbert Xu 			ec_addm(l8, l4, l5, ctx);
10162a598d0bSHerbert Xu 			/* z3 = z1 z2 l3  */
10172a598d0bSHerbert Xu 			ec_mulm(z3, z1, z2, ctx);
10182a598d0bSHerbert Xu 			ec_mulm(z3, z3, l3, ctx);
10192a598d0bSHerbert Xu 			/* x3 = l6^2 - l7 l3^2  */
10202a598d0bSHerbert Xu 			ec_pow2(t1, l6, ctx);
10212a598d0bSHerbert Xu 			ec_pow2(t2, l3, ctx);
10222a598d0bSHerbert Xu 			ec_mulm(t2, t2, l7, ctx);
10232a598d0bSHerbert Xu 			ec_subm(x3, t1, t2, ctx);
10242a598d0bSHerbert Xu 			/* l9 = l7 l3^2 - 2 x3  */
10252a598d0bSHerbert Xu 			ec_mul2(t1, x3, ctx);
10262a598d0bSHerbert Xu 			ec_subm(l9, t2, t1, ctx);
10272a598d0bSHerbert Xu 			/* y3 = (l9 l6 - l8 l3^3)/2  */
10282a598d0bSHerbert Xu 			ec_mulm(l9, l9, l6, ctx);
10292a598d0bSHerbert Xu 			ec_powm(t1, l3, mpi_const(MPI_C_THREE), ctx); /* fixme: Use saved value*/
10302a598d0bSHerbert Xu 			ec_mulm(t1, t1, l8, ctx);
10312a598d0bSHerbert Xu 			ec_subm(y3, l9, t1, ctx);
10322a598d0bSHerbert Xu 			ec_mulm(y3, y3, ec_get_two_inv_p(ctx), ctx);
10332a598d0bSHerbert Xu 		}
10342a598d0bSHerbert Xu 	}
10352a598d0bSHerbert Xu 
10362a598d0bSHerbert Xu #undef x1
10372a598d0bSHerbert Xu #undef y1
10382a598d0bSHerbert Xu #undef z1
10392a598d0bSHerbert Xu #undef x2
10402a598d0bSHerbert Xu #undef y2
10412a598d0bSHerbert Xu #undef z2
10422a598d0bSHerbert Xu #undef x3
10432a598d0bSHerbert Xu #undef y3
10442a598d0bSHerbert Xu #undef z3
10452a598d0bSHerbert Xu #undef l1
10462a598d0bSHerbert Xu #undef l2
10472a598d0bSHerbert Xu #undef l3
10482a598d0bSHerbert Xu #undef l4
10492a598d0bSHerbert Xu #undef l5
10502a598d0bSHerbert Xu #undef l6
10512a598d0bSHerbert Xu #undef l7
10522a598d0bSHerbert Xu #undef l8
10532a598d0bSHerbert Xu #undef l9
10542a598d0bSHerbert Xu #undef t1
10552a598d0bSHerbert Xu #undef t2
10562a598d0bSHerbert Xu }
10572a598d0bSHerbert Xu 
10582a598d0bSHerbert Xu /* RESULT = P1 + P2  (Montgomery version).*/
add_points_montgomery(MPI_POINT result,MPI_POINT p1,MPI_POINT p2,struct mpi_ec_ctx * ctx)10592a598d0bSHerbert Xu static void add_points_montgomery(MPI_POINT result,
10602a598d0bSHerbert Xu 		MPI_POINT p1, MPI_POINT p2,
10612a598d0bSHerbert Xu 		struct mpi_ec_ctx *ctx)
10622a598d0bSHerbert Xu {
10632a598d0bSHerbert Xu 	(void)result;
10642a598d0bSHerbert Xu 	(void)p1;
10652a598d0bSHerbert Xu 	(void)p2;
10662a598d0bSHerbert Xu 	(void)ctx;
10672a598d0bSHerbert Xu 	log_fatal("%s: %s not yet supported\n",
10682a598d0bSHerbert Xu 			"mpi_ec_add_points", "Montgomery");
10692a598d0bSHerbert Xu }
10702a598d0bSHerbert Xu 
10712a598d0bSHerbert Xu /* RESULT = P1 + P2  (Twisted Edwards version).*/
add_points_edwards(MPI_POINT result,MPI_POINT p1,MPI_POINT p2,struct mpi_ec_ctx * ctx)10722a598d0bSHerbert Xu static void add_points_edwards(MPI_POINT result,
10732a598d0bSHerbert Xu 		MPI_POINT p1, MPI_POINT p2,
10742a598d0bSHerbert Xu 		struct mpi_ec_ctx *ctx)
10752a598d0bSHerbert Xu {
10762a598d0bSHerbert Xu #define X1 (p1->x)
10772a598d0bSHerbert Xu #define Y1 (p1->y)
10782a598d0bSHerbert Xu #define Z1 (p1->z)
10792a598d0bSHerbert Xu #define X2 (p2->x)
10802a598d0bSHerbert Xu #define Y2 (p2->y)
10812a598d0bSHerbert Xu #define Z2 (p2->z)
10822a598d0bSHerbert Xu #define X3 (result->x)
10832a598d0bSHerbert Xu #define Y3 (result->y)
10842a598d0bSHerbert Xu #define Z3 (result->z)
10852a598d0bSHerbert Xu #define A (ctx->t.scratch[0])
10862a598d0bSHerbert Xu #define B (ctx->t.scratch[1])
10872a598d0bSHerbert Xu #define C (ctx->t.scratch[2])
10882a598d0bSHerbert Xu #define D (ctx->t.scratch[3])
10892a598d0bSHerbert Xu #define E (ctx->t.scratch[4])
10902a598d0bSHerbert Xu #define F (ctx->t.scratch[5])
10912a598d0bSHerbert Xu #define G (ctx->t.scratch[6])
10922a598d0bSHerbert Xu #define tmp (ctx->t.scratch[7])
10932a598d0bSHerbert Xu 
10942a598d0bSHerbert Xu 	point_resize(result, ctx);
10952a598d0bSHerbert Xu 
10962a598d0bSHerbert Xu 	/* Compute: (X_3 : Y_3 : Z_3) = (X_1 : Y_1 : Z_1) + (X_2 : Y_2 : Z_3) */
10972a598d0bSHerbert Xu 
10982a598d0bSHerbert Xu 	/* A = Z1 · Z2 */
10992a598d0bSHerbert Xu 	ctx->mulm(A, Z1, Z2, ctx);
11002a598d0bSHerbert Xu 
11012a598d0bSHerbert Xu 	/* B = A^2 */
11022a598d0bSHerbert Xu 	ctx->pow2(B, A, ctx);
11032a598d0bSHerbert Xu 
11042a598d0bSHerbert Xu 	/* C = X1 · X2 */
11052a598d0bSHerbert Xu 	ctx->mulm(C, X1, X2, ctx);
11062a598d0bSHerbert Xu 
11072a598d0bSHerbert Xu 	/* D = Y1 · Y2 */
11082a598d0bSHerbert Xu 	ctx->mulm(D, Y1, Y2, ctx);
11092a598d0bSHerbert Xu 
11102a598d0bSHerbert Xu 	/* E = d · C · D */
11112a598d0bSHerbert Xu 	ctx->mulm(E, ctx->b, C, ctx);
11122a598d0bSHerbert Xu 	ctx->mulm(E, E, D, ctx);
11132a598d0bSHerbert Xu 
11142a598d0bSHerbert Xu 	/* F = B - E */
11152a598d0bSHerbert Xu 	ctx->subm(F, B, E, ctx);
11162a598d0bSHerbert Xu 
11172a598d0bSHerbert Xu 	/* G = B + E */
11182a598d0bSHerbert Xu 	ctx->addm(G, B, E, ctx);
11192a598d0bSHerbert Xu 
11202a598d0bSHerbert Xu 	/* X_3 = A · F · ((X_1 + Y_1) · (X_2 + Y_2) - C - D) */
11212a598d0bSHerbert Xu 	ctx->addm(tmp, X1, Y1, ctx);
11222a598d0bSHerbert Xu 	ctx->addm(X3, X2, Y2, ctx);
11232a598d0bSHerbert Xu 	ctx->mulm(X3, X3, tmp, ctx);
11242a598d0bSHerbert Xu 	ctx->subm(X3, X3, C, ctx);
11252a598d0bSHerbert Xu 	ctx->subm(X3, X3, D, ctx);
11262a598d0bSHerbert Xu 	ctx->mulm(X3, X3, F, ctx);
11272a598d0bSHerbert Xu 	ctx->mulm(X3, X3, A, ctx);
11282a598d0bSHerbert Xu 
11292a598d0bSHerbert Xu 	/* Y_3 = A · G · (D - aC) */
11302a598d0bSHerbert Xu 	if (ctx->dialect == ECC_DIALECT_ED25519) {
11312a598d0bSHerbert Xu 		ctx->addm(Y3, D, C, ctx);
11322a598d0bSHerbert Xu 	} else {
11332a598d0bSHerbert Xu 		ctx->mulm(Y3, ctx->a, C, ctx);
11342a598d0bSHerbert Xu 		ctx->subm(Y3, D, Y3, ctx);
11352a598d0bSHerbert Xu 	}
11362a598d0bSHerbert Xu 	ctx->mulm(Y3, Y3, G, ctx);
11372a598d0bSHerbert Xu 	ctx->mulm(Y3, Y3, A, ctx);
11382a598d0bSHerbert Xu 
11392a598d0bSHerbert Xu 	/* Z_3 = F · G */
11402a598d0bSHerbert Xu 	ctx->mulm(Z3, F, G, ctx);
11412a598d0bSHerbert Xu 
11422a598d0bSHerbert Xu 
11432a598d0bSHerbert Xu #undef X1
11442a598d0bSHerbert Xu #undef Y1
11452a598d0bSHerbert Xu #undef Z1
11462a598d0bSHerbert Xu #undef X2
11472a598d0bSHerbert Xu #undef Y2
11482a598d0bSHerbert Xu #undef Z2
11492a598d0bSHerbert Xu #undef X3
11502a598d0bSHerbert Xu #undef Y3
11512a598d0bSHerbert Xu #undef Z3
11522a598d0bSHerbert Xu #undef A
11532a598d0bSHerbert Xu #undef B
11542a598d0bSHerbert Xu #undef C
11552a598d0bSHerbert Xu #undef D
11562a598d0bSHerbert Xu #undef E
11572a598d0bSHerbert Xu #undef F
11582a598d0bSHerbert Xu #undef G
11592a598d0bSHerbert Xu #undef tmp
11602a598d0bSHerbert Xu }
11612a598d0bSHerbert Xu 
11622a598d0bSHerbert Xu /* Compute a step of Montgomery Ladder (only use X and Z in the point).
11632a598d0bSHerbert Xu  * Inputs:  P1, P2, and x-coordinate of DIF = P1 - P1.
11642a598d0bSHerbert Xu  * Outputs: PRD = 2 * P1 and  SUM = P1 + P2.
11652a598d0bSHerbert Xu  */
montgomery_ladder(MPI_POINT prd,MPI_POINT sum,MPI_POINT p1,MPI_POINT p2,MPI dif_x,struct mpi_ec_ctx * ctx)11662a598d0bSHerbert Xu static void montgomery_ladder(MPI_POINT prd, MPI_POINT sum,
11672a598d0bSHerbert Xu 		MPI_POINT p1, MPI_POINT p2, MPI dif_x,
11682a598d0bSHerbert Xu 		struct mpi_ec_ctx *ctx)
11692a598d0bSHerbert Xu {
11702a598d0bSHerbert Xu 	ctx->addm(sum->x, p2->x, p2->z, ctx);
11712a598d0bSHerbert Xu 	ctx->subm(p2->z, p2->x, p2->z, ctx);
11722a598d0bSHerbert Xu 	ctx->addm(prd->x, p1->x, p1->z, ctx);
11732a598d0bSHerbert Xu 	ctx->subm(p1->z, p1->x, p1->z, ctx);
11742a598d0bSHerbert Xu 	ctx->mulm(p2->x, p1->z, sum->x, ctx);
11752a598d0bSHerbert Xu 	ctx->mulm(p2->z, prd->x, p2->z, ctx);
11762a598d0bSHerbert Xu 	ctx->pow2(p1->x, prd->x, ctx);
11772a598d0bSHerbert Xu 	ctx->pow2(p1->z, p1->z, ctx);
11782a598d0bSHerbert Xu 	ctx->addm(sum->x, p2->x, p2->z, ctx);
11792a598d0bSHerbert Xu 	ctx->subm(p2->z, p2->x, p2->z, ctx);
11802a598d0bSHerbert Xu 	ctx->mulm(prd->x, p1->x, p1->z, ctx);
11812a598d0bSHerbert Xu 	ctx->subm(p1->z, p1->x, p1->z, ctx);
11822a598d0bSHerbert Xu 	ctx->pow2(sum->x, sum->x, ctx);
11832a598d0bSHerbert Xu 	ctx->pow2(sum->z, p2->z, ctx);
11842a598d0bSHerbert Xu 	ctx->mulm(prd->z, p1->z, ctx->a, ctx); /* CTX->A: (a-2)/4 */
11852a598d0bSHerbert Xu 	ctx->mulm(sum->z, sum->z, dif_x, ctx);
11862a598d0bSHerbert Xu 	ctx->addm(prd->z, p1->x, prd->z, ctx);
11872a598d0bSHerbert Xu 	ctx->mulm(prd->z, prd->z, p1->z, ctx);
11882a598d0bSHerbert Xu }
11892a598d0bSHerbert Xu 
11902a598d0bSHerbert Xu /* RESULT = P1 + P2 */
mpi_ec_add_points(MPI_POINT result,MPI_POINT p1,MPI_POINT p2,struct mpi_ec_ctx * ctx)11912a598d0bSHerbert Xu void mpi_ec_add_points(MPI_POINT result,
11922a598d0bSHerbert Xu 		MPI_POINT p1, MPI_POINT p2,
11932a598d0bSHerbert Xu 		struct mpi_ec_ctx *ctx)
11942a598d0bSHerbert Xu {
11952a598d0bSHerbert Xu 	switch (ctx->model) {
11962a598d0bSHerbert Xu 	case MPI_EC_WEIERSTRASS:
11972a598d0bSHerbert Xu 		add_points_weierstrass(result, p1, p2, ctx);
11982a598d0bSHerbert Xu 		break;
11992a598d0bSHerbert Xu 	case MPI_EC_MONTGOMERY:
12002a598d0bSHerbert Xu 		add_points_montgomery(result, p1, p2, ctx);
12012a598d0bSHerbert Xu 		break;
12022a598d0bSHerbert Xu 	case MPI_EC_EDWARDS:
12032a598d0bSHerbert Xu 		add_points_edwards(result, p1, p2, ctx);
12042a598d0bSHerbert Xu 		break;
12052a598d0bSHerbert Xu 	}
12062a598d0bSHerbert Xu }
12072a598d0bSHerbert Xu EXPORT_SYMBOL_GPL(mpi_ec_add_points);
12082a598d0bSHerbert Xu 
12092a598d0bSHerbert Xu /* Scalar point multiplication - the main function for ECC.  If takes
12102a598d0bSHerbert Xu  * an integer SCALAR and a POINT as well as the usual context CTX.
12112a598d0bSHerbert Xu  * RESULT will be set to the resulting point.
12122a598d0bSHerbert Xu  */
mpi_ec_mul_point(MPI_POINT result,MPI scalar,MPI_POINT point,struct mpi_ec_ctx * ctx)12132a598d0bSHerbert Xu void mpi_ec_mul_point(MPI_POINT result,
12142a598d0bSHerbert Xu 			MPI scalar, MPI_POINT point,
12152a598d0bSHerbert Xu 			struct mpi_ec_ctx *ctx)
12162a598d0bSHerbert Xu {
12172a598d0bSHerbert Xu 	MPI x1, y1, z1, k, h, yy;
12182a598d0bSHerbert Xu 	unsigned int i, loops;
12192a598d0bSHerbert Xu 	struct gcry_mpi_point p1, p2, p1inv;
12202a598d0bSHerbert Xu 
12212a598d0bSHerbert Xu 	if (ctx->model == MPI_EC_EDWARDS) {
12222a598d0bSHerbert Xu 		/* Simple left to right binary method.  Algorithm 3.27 from
12232a598d0bSHerbert Xu 		 * {author={Hankerson, Darrel and Menezes, Alfred J. and Vanstone, Scott},
12242a598d0bSHerbert Xu 		 *  title = {Guide to Elliptic Curve Cryptography},
12252a598d0bSHerbert Xu 		 *  year = {2003}, isbn = {038795273X},
12262a598d0bSHerbert Xu 		 *  url = {http://www.cacr.math.uwaterloo.ca/ecc/},
12272a598d0bSHerbert Xu 		 *  publisher = {Springer-Verlag New York, Inc.}}
12282a598d0bSHerbert Xu 		 */
12292a598d0bSHerbert Xu 		unsigned int nbits;
12302a598d0bSHerbert Xu 		int j;
12312a598d0bSHerbert Xu 
12322a598d0bSHerbert Xu 		if (mpi_cmp(scalar, ctx->p) >= 0)
12332a598d0bSHerbert Xu 			nbits = mpi_get_nbits(scalar);
12342a598d0bSHerbert Xu 		else
12352a598d0bSHerbert Xu 			nbits = mpi_get_nbits(ctx->p);
12362a598d0bSHerbert Xu 
12372a598d0bSHerbert Xu 		mpi_set_ui(result->x, 0);
12382a598d0bSHerbert Xu 		mpi_set_ui(result->y, 1);
12392a598d0bSHerbert Xu 		mpi_set_ui(result->z, 1);
12402a598d0bSHerbert Xu 		point_resize(point, ctx);
12412a598d0bSHerbert Xu 
12422a598d0bSHerbert Xu 		point_resize(result, ctx);
12432a598d0bSHerbert Xu 		point_resize(point, ctx);
12442a598d0bSHerbert Xu 
12452a598d0bSHerbert Xu 		for (j = nbits-1; j >= 0; j--) {
12462a598d0bSHerbert Xu 			mpi_ec_dup_point(result, result, ctx);
12472a598d0bSHerbert Xu 			if (mpi_test_bit(scalar, j))
12482a598d0bSHerbert Xu 				mpi_ec_add_points(result, result, point, ctx);
12492a598d0bSHerbert Xu 		}
12502a598d0bSHerbert Xu 		return;
12512a598d0bSHerbert Xu 	} else if (ctx->model == MPI_EC_MONTGOMERY) {
12522a598d0bSHerbert Xu 		unsigned int nbits;
12532a598d0bSHerbert Xu 		int j;
12542a598d0bSHerbert Xu 		struct gcry_mpi_point p1_, p2_;
12552a598d0bSHerbert Xu 		MPI_POINT q1, q2, prd, sum;
12562a598d0bSHerbert Xu 		unsigned long sw;
12572a598d0bSHerbert Xu 		mpi_size_t rsize;
12582a598d0bSHerbert Xu 
12592a598d0bSHerbert Xu 		/* Compute scalar point multiplication with Montgomery Ladder.
12602a598d0bSHerbert Xu 		 * Note that we don't use Y-coordinate in the points at all.
12612a598d0bSHerbert Xu 		 * RESULT->Y will be filled by zero.
12622a598d0bSHerbert Xu 		 */
12632a598d0bSHerbert Xu 
12642a598d0bSHerbert Xu 		nbits = mpi_get_nbits(scalar);
12652a598d0bSHerbert Xu 		point_init(&p1);
12662a598d0bSHerbert Xu 		point_init(&p2);
12672a598d0bSHerbert Xu 		point_init(&p1_);
12682a598d0bSHerbert Xu 		point_init(&p2_);
12692a598d0bSHerbert Xu 		mpi_set_ui(p1.x, 1);
12702a598d0bSHerbert Xu 		mpi_free(p2.x);
12712a598d0bSHerbert Xu 		p2.x = mpi_copy(point->x);
12722a598d0bSHerbert Xu 		mpi_set_ui(p2.z, 1);
12732a598d0bSHerbert Xu 
12742a598d0bSHerbert Xu 		point_resize(&p1, ctx);
12752a598d0bSHerbert Xu 		point_resize(&p2, ctx);
12762a598d0bSHerbert Xu 		point_resize(&p1_, ctx);
12772a598d0bSHerbert Xu 		point_resize(&p2_, ctx);
12782a598d0bSHerbert Xu 
12792a598d0bSHerbert Xu 		mpi_resize(point->x, ctx->p->nlimbs);
12802a598d0bSHerbert Xu 		point->x->nlimbs = ctx->p->nlimbs;
12812a598d0bSHerbert Xu 
12822a598d0bSHerbert Xu 		q1 = &p1;
12832a598d0bSHerbert Xu 		q2 = &p2;
12842a598d0bSHerbert Xu 		prd = &p1_;
12852a598d0bSHerbert Xu 		sum = &p2_;
12862a598d0bSHerbert Xu 
12872a598d0bSHerbert Xu 		for (j = nbits-1; j >= 0; j--) {
12882a598d0bSHerbert Xu 			MPI_POINT t;
12892a598d0bSHerbert Xu 
12902a598d0bSHerbert Xu 			sw = mpi_test_bit(scalar, j);
12912a598d0bSHerbert Xu 			point_swap_cond(q1, q2, sw, ctx);
12922a598d0bSHerbert Xu 			montgomery_ladder(prd, sum, q1, q2, point->x, ctx);
12932a598d0bSHerbert Xu 			point_swap_cond(prd, sum, sw, ctx);
12942a598d0bSHerbert Xu 			t = q1;  q1 = prd;  prd = t;
12952a598d0bSHerbert Xu 			t = q2;  q2 = sum;  sum = t;
12962a598d0bSHerbert Xu 		}
12972a598d0bSHerbert Xu 
12982a598d0bSHerbert Xu 		mpi_clear(result->y);
12992a598d0bSHerbert Xu 		sw = (nbits & 1);
13002a598d0bSHerbert Xu 		point_swap_cond(&p1, &p1_, sw, ctx);
13012a598d0bSHerbert Xu 
13022a598d0bSHerbert Xu 		rsize = p1.z->nlimbs;
13032a598d0bSHerbert Xu 		MPN_NORMALIZE(p1.z->d, rsize);
13042a598d0bSHerbert Xu 		if (rsize == 0) {
13052a598d0bSHerbert Xu 			mpi_set_ui(result->x, 1);
13062a598d0bSHerbert Xu 			mpi_set_ui(result->z, 0);
13072a598d0bSHerbert Xu 		} else {
13082a598d0bSHerbert Xu 			z1 = mpi_new(0);
13092a598d0bSHerbert Xu 			ec_invm(z1, p1.z, ctx);
13102a598d0bSHerbert Xu 			ec_mulm(result->x, p1.x, z1, ctx);
13112a598d0bSHerbert Xu 			mpi_set_ui(result->z, 1);
13122a598d0bSHerbert Xu 			mpi_free(z1);
13132a598d0bSHerbert Xu 		}
13142a598d0bSHerbert Xu 
13152a598d0bSHerbert Xu 		point_free(&p1);
13162a598d0bSHerbert Xu 		point_free(&p2);
13172a598d0bSHerbert Xu 		point_free(&p1_);
13182a598d0bSHerbert Xu 		point_free(&p2_);
13192a598d0bSHerbert Xu 		return;
13202a598d0bSHerbert Xu 	}
13212a598d0bSHerbert Xu 
13222a598d0bSHerbert Xu 	x1 = mpi_alloc_like(ctx->p);
13232a598d0bSHerbert Xu 	y1 = mpi_alloc_like(ctx->p);
13242a598d0bSHerbert Xu 	h  = mpi_alloc_like(ctx->p);
13252a598d0bSHerbert Xu 	k  = mpi_copy(scalar);
13262a598d0bSHerbert Xu 	yy = mpi_copy(point->y);
13272a598d0bSHerbert Xu 
13282a598d0bSHerbert Xu 	if (mpi_has_sign(k)) {
13292a598d0bSHerbert Xu 		k->sign = 0;
13302a598d0bSHerbert Xu 		ec_invm(yy, yy, ctx);
13312a598d0bSHerbert Xu 	}
13322a598d0bSHerbert Xu 
13332a598d0bSHerbert Xu 	if (!mpi_cmp_ui(point->z, 1)) {
13342a598d0bSHerbert Xu 		mpi_set(x1, point->x);
13352a598d0bSHerbert Xu 		mpi_set(y1, yy);
13362a598d0bSHerbert Xu 	} else {
13372a598d0bSHerbert Xu 		MPI z2, z3;
13382a598d0bSHerbert Xu 
13392a598d0bSHerbert Xu 		z2 = mpi_alloc_like(ctx->p);
13402a598d0bSHerbert Xu 		z3 = mpi_alloc_like(ctx->p);
13412a598d0bSHerbert Xu 		ec_mulm(z2, point->z, point->z, ctx);
13422a598d0bSHerbert Xu 		ec_mulm(z3, point->z, z2, ctx);
13432a598d0bSHerbert Xu 		ec_invm(z2, z2, ctx);
13442a598d0bSHerbert Xu 		ec_mulm(x1, point->x, z2, ctx);
13452a598d0bSHerbert Xu 		ec_invm(z3, z3, ctx);
13462a598d0bSHerbert Xu 		ec_mulm(y1, yy, z3, ctx);
13472a598d0bSHerbert Xu 		mpi_free(z2);
13482a598d0bSHerbert Xu 		mpi_free(z3);
13492a598d0bSHerbert Xu 	}
13502a598d0bSHerbert Xu 	z1 = mpi_copy(mpi_const(MPI_C_ONE));
13512a598d0bSHerbert Xu 
13522a598d0bSHerbert Xu 	mpi_mul(h, k, mpi_const(MPI_C_THREE)); /* h = 3k */
13532a598d0bSHerbert Xu 	loops = mpi_get_nbits(h);
13542a598d0bSHerbert Xu 	if (loops < 2) {
13552a598d0bSHerbert Xu 		/* If SCALAR is zero, the above mpi_mul sets H to zero and thus
13562a598d0bSHerbert Xu 		 * LOOPs will be zero.  To avoid an underflow of I in the main
13572a598d0bSHerbert Xu 		 * loop we set LOOP to 2 and the result to (0,0,0).
13582a598d0bSHerbert Xu 		 */
13592a598d0bSHerbert Xu 		loops = 2;
13602a598d0bSHerbert Xu 		mpi_clear(result->x);
13612a598d0bSHerbert Xu 		mpi_clear(result->y);
13622a598d0bSHerbert Xu 		mpi_clear(result->z);
13632a598d0bSHerbert Xu 	} else {
13642a598d0bSHerbert Xu 		mpi_set(result->x, point->x);
13652a598d0bSHerbert Xu 		mpi_set(result->y, yy);
13662a598d0bSHerbert Xu 		mpi_set(result->z, point->z);
13672a598d0bSHerbert Xu 	}
13682a598d0bSHerbert Xu 	mpi_free(yy); yy = NULL;
13692a598d0bSHerbert Xu 
13702a598d0bSHerbert Xu 	p1.x = x1; x1 = NULL;
13712a598d0bSHerbert Xu 	p1.y = y1; y1 = NULL;
13722a598d0bSHerbert Xu 	p1.z = z1; z1 = NULL;
13732a598d0bSHerbert Xu 	point_init(&p2);
13742a598d0bSHerbert Xu 	point_init(&p1inv);
13752a598d0bSHerbert Xu 
13762a598d0bSHerbert Xu 	/* Invert point: y = p - y mod p  */
13772a598d0bSHerbert Xu 	point_set(&p1inv, &p1);
13782a598d0bSHerbert Xu 	ec_subm(p1inv.y, ctx->p, p1inv.y, ctx);
13792a598d0bSHerbert Xu 
13802a598d0bSHerbert Xu 	for (i = loops-2; i > 0; i--) {
13812a598d0bSHerbert Xu 		mpi_ec_dup_point(result, result, ctx);
13822a598d0bSHerbert Xu 		if (mpi_test_bit(h, i) == 1 && mpi_test_bit(k, i) == 0) {
13832a598d0bSHerbert Xu 			point_set(&p2, result);
13842a598d0bSHerbert Xu 			mpi_ec_add_points(result, &p2, &p1, ctx);
13852a598d0bSHerbert Xu 		}
13862a598d0bSHerbert Xu 		if (mpi_test_bit(h, i) == 0 && mpi_test_bit(k, i) == 1) {
13872a598d0bSHerbert Xu 			point_set(&p2, result);
13882a598d0bSHerbert Xu 			mpi_ec_add_points(result, &p2, &p1inv, ctx);
13892a598d0bSHerbert Xu 		}
13902a598d0bSHerbert Xu 	}
13912a598d0bSHerbert Xu 
13922a598d0bSHerbert Xu 	point_free(&p1);
13932a598d0bSHerbert Xu 	point_free(&p2);
13942a598d0bSHerbert Xu 	point_free(&p1inv);
13952a598d0bSHerbert Xu 	mpi_free(h);
13962a598d0bSHerbert Xu 	mpi_free(k);
13972a598d0bSHerbert Xu }
13982a598d0bSHerbert Xu EXPORT_SYMBOL_GPL(mpi_ec_mul_point);
13992a598d0bSHerbert Xu 
14002a598d0bSHerbert Xu /* Return true if POINT is on the curve described by CTX.  */
mpi_ec_curve_point(MPI_POINT point,struct mpi_ec_ctx * ctx)14012a598d0bSHerbert Xu int mpi_ec_curve_point(MPI_POINT point, struct mpi_ec_ctx *ctx)
14022a598d0bSHerbert Xu {
14032a598d0bSHerbert Xu 	int res = 0;
14042a598d0bSHerbert Xu 	MPI x, y, w;
14052a598d0bSHerbert Xu 
14062a598d0bSHerbert Xu 	x = mpi_new(0);
14072a598d0bSHerbert Xu 	y = mpi_new(0);
14082a598d0bSHerbert Xu 	w = mpi_new(0);
14092a598d0bSHerbert Xu 
14102a598d0bSHerbert Xu 	/* Check that the point is in range.  This needs to be done here and
14112a598d0bSHerbert Xu 	 * not after conversion to affine coordinates.
14122a598d0bSHerbert Xu 	 */
14132a598d0bSHerbert Xu 	if (mpi_cmpabs(point->x, ctx->p) >= 0)
14142a598d0bSHerbert Xu 		goto leave;
14152a598d0bSHerbert Xu 	if (mpi_cmpabs(point->y, ctx->p) >= 0)
14162a598d0bSHerbert Xu 		goto leave;
14172a598d0bSHerbert Xu 	if (mpi_cmpabs(point->z, ctx->p) >= 0)
14182a598d0bSHerbert Xu 		goto leave;
14192a598d0bSHerbert Xu 
14202a598d0bSHerbert Xu 	switch (ctx->model) {
14212a598d0bSHerbert Xu 	case MPI_EC_WEIERSTRASS:
14222a598d0bSHerbert Xu 		{
14232a598d0bSHerbert Xu 			MPI xxx;
14242a598d0bSHerbert Xu 
14252a598d0bSHerbert Xu 			if (mpi_ec_get_affine(x, y, point, ctx))
14262a598d0bSHerbert Xu 				goto leave;
14272a598d0bSHerbert Xu 
14282a598d0bSHerbert Xu 			xxx = mpi_new(0);
14292a598d0bSHerbert Xu 
14302a598d0bSHerbert Xu 			/* y^2 == x^3 + a·x + b */
14312a598d0bSHerbert Xu 			ec_pow2(y, y, ctx);
14322a598d0bSHerbert Xu 
14332a598d0bSHerbert Xu 			ec_pow3(xxx, x, ctx);
14342a598d0bSHerbert Xu 			ec_mulm(w, ctx->a, x, ctx);
14352a598d0bSHerbert Xu 			ec_addm(w, w, ctx->b, ctx);
14362a598d0bSHerbert Xu 			ec_addm(w, w, xxx, ctx);
14372a598d0bSHerbert Xu 
14382a598d0bSHerbert Xu 			if (!mpi_cmp(y, w))
14392a598d0bSHerbert Xu 				res = 1;
14402a598d0bSHerbert Xu 
14412a598d0bSHerbert Xu 			mpi_free(xxx);
14422a598d0bSHerbert Xu 		}
14432a598d0bSHerbert Xu 		break;
14442a598d0bSHerbert Xu 
14452a598d0bSHerbert Xu 	case MPI_EC_MONTGOMERY:
14462a598d0bSHerbert Xu 		{
14472a598d0bSHerbert Xu #define xx y
14482a598d0bSHerbert Xu 			/* With Montgomery curve, only X-coordinate is valid. */
14492a598d0bSHerbert Xu 			if (mpi_ec_get_affine(x, NULL, point, ctx))
14502a598d0bSHerbert Xu 				goto leave;
14512a598d0bSHerbert Xu 
14522a598d0bSHerbert Xu 			/* The equation is: b * y^2 == x^3 + a · x^2 + x */
14532a598d0bSHerbert Xu 			/* We check if right hand is quadratic residue or not by
14542a598d0bSHerbert Xu 			 * Euler's criterion.
14552a598d0bSHerbert Xu 			 */
14562a598d0bSHerbert Xu 			/* CTX->A has (a-2)/4 and CTX->B has b^-1 */
14572a598d0bSHerbert Xu 			ec_mulm(w, ctx->a, mpi_const(MPI_C_FOUR), ctx);
14582a598d0bSHerbert Xu 			ec_addm(w, w, mpi_const(MPI_C_TWO), ctx);
14592a598d0bSHerbert Xu 			ec_mulm(w, w, x, ctx);
14602a598d0bSHerbert Xu 			ec_pow2(xx, x, ctx);
14612a598d0bSHerbert Xu 			ec_addm(w, w, xx, ctx);
14622a598d0bSHerbert Xu 			ec_addm(w, w, mpi_const(MPI_C_ONE), ctx);
14632a598d0bSHerbert Xu 			ec_mulm(w, w, x, ctx);
14642a598d0bSHerbert Xu 			ec_mulm(w, w, ctx->b, ctx);
14652a598d0bSHerbert Xu #undef xx
14662a598d0bSHerbert Xu 			/* Compute Euler's criterion: w^(p-1)/2 */
14672a598d0bSHerbert Xu #define p_minus1 y
14682a598d0bSHerbert Xu 			ec_subm(p_minus1, ctx->p, mpi_const(MPI_C_ONE), ctx);
14692a598d0bSHerbert Xu 			mpi_rshift(p_minus1, p_minus1, 1);
14702a598d0bSHerbert Xu 			ec_powm(w, w, p_minus1, ctx);
14712a598d0bSHerbert Xu 
14722a598d0bSHerbert Xu 			res = !mpi_cmp_ui(w, 1);
14732a598d0bSHerbert Xu #undef p_minus1
14742a598d0bSHerbert Xu 		}
14752a598d0bSHerbert Xu 		break;
14762a598d0bSHerbert Xu 
14772a598d0bSHerbert Xu 	case MPI_EC_EDWARDS:
14782a598d0bSHerbert Xu 		{
14792a598d0bSHerbert Xu 			if (mpi_ec_get_affine(x, y, point, ctx))
14802a598d0bSHerbert Xu 				goto leave;
14812a598d0bSHerbert Xu 
14822a598d0bSHerbert Xu 			mpi_resize(w, ctx->p->nlimbs);
14832a598d0bSHerbert Xu 			w->nlimbs = ctx->p->nlimbs;
14842a598d0bSHerbert Xu 
14852a598d0bSHerbert Xu 			/* a · x^2 + y^2 - 1 - b · x^2 · y^2 == 0 */
14862a598d0bSHerbert Xu 			ctx->pow2(x, x, ctx);
14872a598d0bSHerbert Xu 			ctx->pow2(y, y, ctx);
14882a598d0bSHerbert Xu 			if (ctx->dialect == ECC_DIALECT_ED25519)
14892a598d0bSHerbert Xu 				ctx->subm(w, ctx->p, x, ctx);
14902a598d0bSHerbert Xu 			else
14912a598d0bSHerbert Xu 				ctx->mulm(w, ctx->a, x, ctx);
14922a598d0bSHerbert Xu 			ctx->addm(w, w, y, ctx);
14932a598d0bSHerbert Xu 			ctx->mulm(x, x, y, ctx);
14942a598d0bSHerbert Xu 			ctx->mulm(x, x, ctx->b, ctx);
14952a598d0bSHerbert Xu 			ctx->subm(w, w, x, ctx);
14962a598d0bSHerbert Xu 			if (!mpi_cmp_ui(w, 1))
14972a598d0bSHerbert Xu 				res = 1;
14982a598d0bSHerbert Xu 		}
14992a598d0bSHerbert Xu 		break;
15002a598d0bSHerbert Xu 	}
15012a598d0bSHerbert Xu 
15022a598d0bSHerbert Xu leave:
15032a598d0bSHerbert Xu 	mpi_free(w);
15042a598d0bSHerbert Xu 	mpi_free(x);
15052a598d0bSHerbert Xu 	mpi_free(y);
15062a598d0bSHerbert Xu 
15072a598d0bSHerbert Xu 	return res;
15082a598d0bSHerbert Xu }
15092a598d0bSHerbert Xu EXPORT_SYMBOL_GPL(mpi_ec_curve_point);
1510