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