xref: /openbsd-src/regress/lib/libcrypto/bn/bn_mod_exp.c (revision 24882d0aebd3074ff4e57dba8113fde1c67534b0)
1*24882d0aStb /*	$OpenBSD: bn_mod_exp.c,v 1.40 2023/10/19 13:38:12 tb Exp $ */
22cac8f3aStb 
32cac8f3aStb /*
42cac8f3aStb  * Copyright (c) 2022,2023 Theo Buehler <tb@openbsd.org>
52cac8f3aStb  *
62cac8f3aStb  * Permission to use, copy, modify, and distribute this software for any
72cac8f3aStb  * purpose with or without fee is hereby granted, provided that the above
82cac8f3aStb  * copyright notice and this permission notice appear in all copies.
92cac8f3aStb  *
102cac8f3aStb  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
112cac8f3aStb  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
122cac8f3aStb  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
132cac8f3aStb  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
142cac8f3aStb  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
152cac8f3aStb  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
162cac8f3aStb  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
172cac8f3aStb  */
182cac8f3aStb 
192cac8f3aStb #include <err.h>
2058a53292Stb #include <stdio.h>
2158a53292Stb #include <string.h>
222cac8f3aStb 
232cac8f3aStb #include <openssl/bn.h>
242cac8f3aStb #include <openssl/err.h>
252cac8f3aStb 
262cac8f3aStb #include "bn_local.h"
272cac8f3aStb 
28a3971f08Stb #define N_MOD_EXP_TESTS		100
29a3971f08Stb #define N_MOD_EXP2_TESTS	50
3036cb5e34Stb 
312cac8f3aStb #define INIT_MOD_EXP_FN(f) { .name = #f, .mod_exp_fn = (f), }
322cac8f3aStb #define INIT_MOD_EXP_MONT_FN(f) { .name = #f, .mod_exp_mont_fn = (f), }
332cac8f3aStb 
343baba9acStb static int
bn_mod_exp2_mont_first(BIGNUM * r,const BIGNUM * a,const BIGNUM * p,const BIGNUM * m,BN_CTX * ctx,BN_MONT_CTX * mctx)353baba9acStb bn_mod_exp2_mont_first(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
363baba9acStb     const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *mctx)
373baba9acStb {
383baba9acStb 	const BIGNUM *one = BN_value_one();
393baba9acStb 
403baba9acStb 	return BN_mod_exp2_mont(r, a, p, one, one, m, ctx, mctx);
413baba9acStb }
423baba9acStb 
433baba9acStb static int
bn_mod_exp2_mont_second(BIGNUM * r,const BIGNUM * a,const BIGNUM * p,const BIGNUM * m,BN_CTX * ctx,BN_MONT_CTX * mctx)443baba9acStb bn_mod_exp2_mont_second(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
453baba9acStb     const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *mctx)
463baba9acStb {
473baba9acStb 	const BIGNUM *one = BN_value_one();
483baba9acStb 
493baba9acStb 	return BN_mod_exp2_mont(r, one, one, a, p, m, ctx, mctx);
503baba9acStb }
513baba9acStb 
52f5f16a4eStb static const struct mod_exp_test {
532cac8f3aStb 	const char *name;
542cac8f3aStb 	int (*mod_exp_fn)(BIGNUM *, const BIGNUM *, const BIGNUM *,
552cac8f3aStb 	    const BIGNUM *, BN_CTX *);
562cac8f3aStb 	int (*mod_exp_mont_fn)(BIGNUM *, const BIGNUM *, const BIGNUM *,
572cac8f3aStb 	    const BIGNUM *, BN_CTX *, BN_MONT_CTX *);
58f5f16a4eStb } mod_exp_fn[] = {
592cac8f3aStb 	INIT_MOD_EXP_FN(BN_mod_exp),
602cac8f3aStb 	INIT_MOD_EXP_FN(BN_mod_exp_ct),
612cac8f3aStb 	INIT_MOD_EXP_FN(BN_mod_exp_nonct),
622cac8f3aStb 	INIT_MOD_EXP_FN(BN_mod_exp_recp),
632cac8f3aStb 	INIT_MOD_EXP_FN(BN_mod_exp_simple),
642cac8f3aStb 	INIT_MOD_EXP_MONT_FN(BN_mod_exp_mont),
652cac8f3aStb 	INIT_MOD_EXP_MONT_FN(BN_mod_exp_mont_ct),
662cac8f3aStb 	INIT_MOD_EXP_MONT_FN(BN_mod_exp_mont_consttime),
672cac8f3aStb 	INIT_MOD_EXP_MONT_FN(BN_mod_exp_mont_nonct),
683baba9acStb 	INIT_MOD_EXP_MONT_FN(bn_mod_exp2_mont_first),
693baba9acStb 	INIT_MOD_EXP_MONT_FN(bn_mod_exp2_mont_second),
702cac8f3aStb };
712cac8f3aStb 
72f5f16a4eStb #define N_MOD_EXP_FN (sizeof(mod_exp_fn) / sizeof(mod_exp_fn[0]))
732cac8f3aStb 
742cac8f3aStb static void
bn_print(const char * name,const BIGNUM * bn)7558a53292Stb bn_print(const char *name, const BIGNUM *bn)
762cac8f3aStb {
7758a53292Stb 	size_t len;
7858a53292Stb 	int pad = 0;
7958a53292Stb 
80a0987236Stb 	if ((len = strlen(name)) < 7)
8158a53292Stb 		pad = 6 - len;
8258a53292Stb 
8358a53292Stb 	fprintf(stderr, "%s: %*s", name, pad, "");
8458a53292Stb 	BN_print_fp(stderr, bn);
852cac8f3aStb 	fprintf(stderr, "\n");
862cac8f3aStb }
872cac8f3aStb 
8858a53292Stb static void
print_zero_test_failure(const BIGNUM * got,const BIGNUM * a,const BIGNUM * m,const char * name)89b5847372Stb print_zero_test_failure(const BIGNUM *got, const BIGNUM *a, const BIGNUM *m,
90b5847372Stb     const char *name)
9158a53292Stb {
9258a53292Stb 	fprintf(stderr, "%s() zero test failed:\n", name);
9358a53292Stb 
9458a53292Stb 	bn_print("a", a);
95b5847372Stb 	bn_print("m", m);
9658a53292Stb 	bn_print("got", got);
9758a53292Stb }
9858a53292Stb 
992cac8f3aStb static int
bn_mod_exp_zero_test(const struct mod_exp_test * test,BN_CTX * ctx,int neg_modulus,int random_base)100b5847372Stb bn_mod_exp_zero_test(const struct mod_exp_test *test, BN_CTX *ctx,
101b5847372Stb     int neg_modulus, int random_base)
1022cac8f3aStb {
103b5847372Stb 	BIGNUM *a, *m, *p, *got;
1049cd3ae5cStb 	int mod_exp_ret;
1052cac8f3aStb 	int failed = 1;
1062cac8f3aStb 
1072cac8f3aStb 	BN_CTX_start(ctx);
1082cac8f3aStb 
1092cac8f3aStb 	if ((a = BN_CTX_get(ctx)) == NULL)
1102cac8f3aStb 		errx(1, "BN_CTX_get");
111b5847372Stb 	if ((m = BN_CTX_get(ctx)) == NULL)
112b5847372Stb 		errx(1, "BN_CTX_get");
1132cac8f3aStb 	if ((p = BN_CTX_get(ctx)) == NULL)
1142cac8f3aStb 		errx(1, "BN_CTX_get");
1152cac8f3aStb 	if ((got = BN_CTX_get(ctx)) == NULL)
1162cac8f3aStb 		errx(1, "BN_CTX_get");
1172cac8f3aStb 
118b5847372Stb 	if (!BN_one(m))
119b5847372Stb 		errx(1, "BN_one");
120b5847372Stb 	if (neg_modulus)
121b5847372Stb 		BN_set_negative(m, 1);
1222cac8f3aStb 	BN_zero(a);
1232cac8f3aStb 	BN_zero(p);
1242cac8f3aStb 
125b5847372Stb 	if (random_base) {
1262cac8f3aStb 		if (!BN_rand(a, 1024, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY))
1272cac8f3aStb 			errx(1, "BN_rand");
1282cac8f3aStb 	}
1292cac8f3aStb 
1302cac8f3aStb 	if (test->mod_exp_fn != NULL) {
131b5847372Stb 		mod_exp_ret = test->mod_exp_fn(got, a, p, m, ctx);
1322cac8f3aStb 	} else {
133b5847372Stb 		mod_exp_ret = test->mod_exp_mont_fn(got, a, p, m, ctx, NULL);
1349cd3ae5cStb 	}
1359cd3ae5cStb 
1369cd3ae5cStb 	if (!mod_exp_ret) {
1372cac8f3aStb 		fprintf(stderr, "%s failed\n", test->name);
1382cac8f3aStb 		ERR_print_errors_fp(stderr);
1392cac8f3aStb 		goto err;
1402cac8f3aStb 	}
1412cac8f3aStb 
1422cac8f3aStb 	if (!BN_is_zero(got)) {
143b5847372Stb 		print_zero_test_failure(got, a, m, test->name);
1442cac8f3aStb 		goto err;
1452cac8f3aStb 	}
1462cac8f3aStb 
1472cac8f3aStb 	failed = 0;
1482cac8f3aStb 
1492cac8f3aStb  err:
1502cac8f3aStb 	BN_CTX_end(ctx);
1512cac8f3aStb 
1522cac8f3aStb 	return failed;
1532cac8f3aStb }
1542cac8f3aStb 
1552cac8f3aStb static int
bn_mod_exp_zero_word_test(BN_CTX * ctx,int neg_modulus)156b5847372Stb bn_mod_exp_zero_word_test(BN_CTX *ctx, int neg_modulus)
1572cac8f3aStb {
1582cac8f3aStb 	const char *name = "BN_mod_exp_mont_word";
159b5847372Stb 	BIGNUM *m, *p, *got;
1602cac8f3aStb 	int failed = 1;
1612cac8f3aStb 
1622cac8f3aStb 	BN_CTX_start(ctx);
1632cac8f3aStb 
164b5847372Stb 	if ((m = BN_CTX_get(ctx)) == NULL)
165b5847372Stb 		errx(1, "BN_CTX_get");
1662cac8f3aStb 	if ((p = BN_CTX_get(ctx)) == NULL)
1672cac8f3aStb 		errx(1, "BN_CTX_get");
1682cac8f3aStb 	if ((got = BN_CTX_get(ctx)) == NULL)
1692cac8f3aStb 		errx(1, "BN_CTX_get");
1702cac8f3aStb 
171b5847372Stb 	if (!BN_one(m))
172b5847372Stb 		errx(1, "BN_one");
173b5847372Stb 	if (neg_modulus)
174b5847372Stb 		BN_set_negative(m, neg_modulus);
1752cac8f3aStb 	BN_zero(p);
1762cac8f3aStb 
177b5847372Stb 	if (!BN_mod_exp_mont_word(got, 1, p, m, ctx, NULL)) {
1782cac8f3aStb 		fprintf(stderr, "%s failed\n", name);
1792cac8f3aStb 		ERR_print_errors_fp(stderr);
1802cac8f3aStb 		goto err;
1812cac8f3aStb 	}
1822cac8f3aStb 
1832cac8f3aStb 	if (!BN_is_zero(got)) {
184b5847372Stb 		print_zero_test_failure(got, p, m, name);
1852cac8f3aStb 		goto err;
1862cac8f3aStb 	}
1872cac8f3aStb 
1882cac8f3aStb 	failed = 0;
1892cac8f3aStb 
1902cac8f3aStb  err:
1912cac8f3aStb 	BN_CTX_end(ctx);
1922cac8f3aStb 
1932cac8f3aStb 	return failed;
1942cac8f3aStb }
1952cac8f3aStb 
1962cac8f3aStb static int
test_bn_mod_exp_zero(void)19717db9b10Stb test_bn_mod_exp_zero(void)
1982cac8f3aStb {
1992cac8f3aStb 	BN_CTX *ctx;
200b5847372Stb 	size_t i, j;
2012cac8f3aStb 	int failed = 0;
2022cac8f3aStb 
2032cac8f3aStb 	if ((ctx = BN_CTX_new()) == NULL)
2042cac8f3aStb 		errx(1, "BN_CTX_new");
2052cac8f3aStb 
206b5847372Stb 	for (i = 0; i < N_MOD_EXP_FN; i++) {
207b5847372Stb 		for (j = 0; j < 4; j++) {
208b5847372Stb 			int neg_modulus = (j >> 0) & 1;
209b5847372Stb 			int random_base = (j >> 1) & 1;
2102cac8f3aStb 
211b5847372Stb 			failed |= bn_mod_exp_zero_test(&mod_exp_fn[i], ctx,
212b5847372Stb 			    neg_modulus, random_base);
213b5847372Stb 		}
214b5847372Stb 	}
2152cac8f3aStb 
216b5847372Stb 	failed |= bn_mod_exp_zero_word_test(ctx, 0);
217b5847372Stb 	failed |= bn_mod_exp_zero_word_test(ctx, 1);
2182cac8f3aStb 
2192cac8f3aStb 	BN_CTX_free(ctx);
2202cac8f3aStb 
2212cac8f3aStb 	return failed;
2222cac8f3aStb }
2232cac8f3aStb 
2242cac8f3aStb static int
generate_bn(BIGNUM * bn,int avg_bits,int deviate,int force_odd)2252cac8f3aStb generate_bn(BIGNUM *bn, int avg_bits, int deviate, int force_odd)
2262cac8f3aStb {
2272cac8f3aStb 	int bits;
2282cac8f3aStb 
229e0bdcda1Stb 	if (bn == NULL)
230e0bdcda1Stb 		return 1;
231e0bdcda1Stb 
2322cac8f3aStb 	if (avg_bits <= 0 || deviate <= 0 || deviate >= avg_bits)
2332cac8f3aStb 		return 0;
2342cac8f3aStb 
2352cac8f3aStb 	bits = avg_bits + arc4random_uniform(deviate) - deviate;
2362cac8f3aStb 
2372cac8f3aStb 	return BN_rand(bn, bits, 0, force_odd);
2382cac8f3aStb }
2392cac8f3aStb 
2402cac8f3aStb static int
generate_test_quintuple(int reduce,BIGNUM * a,BIGNUM * p,BIGNUM * b,BIGNUM * q,BIGNUM * m,BN_CTX * ctx)241e0bdcda1Stb generate_test_quintuple(int reduce, BIGNUM *a, BIGNUM *p, BIGNUM *b, BIGNUM *q,
242e0bdcda1Stb     BIGNUM *m, BN_CTX *ctx)
243f34e85acStb {
244f34e85acStb 	BIGNUM *mmodified;
245f34e85acStb 	BN_ULONG multiple;
246f34e85acStb 	int avg = 2 * BN_BITS, deviate = BN_BITS / 2;
247f34e85acStb 	int ret = 0;
248f34e85acStb 
249c0423487Stb 	if (!generate_bn(a, avg, deviate, 0))
250f34e85acStb 		return 0;
251f34e85acStb 
252c0423487Stb 	if (!generate_bn(p, avg, deviate, 0))
253f34e85acStb 		return 0;
254f34e85acStb 
255c0423487Stb 	if (!generate_bn(b, avg, deviate, 0))
256f34e85acStb 		return 0;
257f34e85acStb 
258c0423487Stb 	if (!generate_bn(q, avg, deviate, 0))
259f34e85acStb 		return 0;
260f34e85acStb 
261f34e85acStb 	if (!generate_bn(m, avg, deviate, 1))
262f34e85acStb 		return 0;
263f34e85acStb 
264f34e85acStb 	if (reduce) {
265c0423487Stb 		if (!BN_mod(a, a, m, ctx))
266f34e85acStb 			return 0;
267f34e85acStb 
268e0bdcda1Stb 		if (b == NULL)
269e0bdcda1Stb 			return 1;
270e0bdcda1Stb 
271c0423487Stb 		return BN_mod(b, b, m, ctx);
272f34e85acStb 	}
273f34e85acStb 
274f34e85acStb 	/*
275f34e85acStb 	 * Add a random multiple of m to a to test unreduced exponentiation.
276f34e85acStb 	 */
277f34e85acStb 
278f34e85acStb 	BN_CTX_start(ctx);
279f34e85acStb 
280f34e85acStb 	if ((mmodified = BN_CTX_get(ctx)) == NULL)
281f34e85acStb 		goto err;
282f34e85acStb 
2838e84e241Stb 	if (!bn_copy(mmodified, m))
284f34e85acStb 		goto err;
285f34e85acStb 
286f34e85acStb 	multiple = arc4random_uniform(16) + 2;
287f34e85acStb 
288f34e85acStb 	if (!BN_mul_word(mmodified, multiple))
289f34e85acStb 		goto err;
290f34e85acStb 
291c0423487Stb 	if (!BN_add(a, a, mmodified))
292f34e85acStb 		goto err;
293f34e85acStb 
294e0bdcda1Stb 	if (b == NULL)
295e0bdcda1Stb 		goto done;
296e0bdcda1Stb 
297c0423487Stb 	if (!BN_add(b, b, mmodified))
298f34e85acStb 		goto err;
299f34e85acStb 
300e0bdcda1Stb  done:
301f34e85acStb 	ret = 1;
302e0bdcda1Stb 
303f34e85acStb  err:
304f34e85acStb 	BN_CTX_end(ctx);
305f34e85acStb 
306f34e85acStb 	return ret;
307f34e85acStb }
308f34e85acStb 
309e0bdcda1Stb static int
generate_test_triple(int reduce,BIGNUM * a,BIGNUM * p,BIGNUM * m,BN_CTX * ctx)310e0bdcda1Stb generate_test_triple(int reduce, BIGNUM *a, BIGNUM *p, BIGNUM *m, BN_CTX *ctx)
311e0bdcda1Stb {
312e0bdcda1Stb 	return generate_test_quintuple(reduce, a, p, NULL, NULL, m, ctx);
313e0bdcda1Stb }
314e0bdcda1Stb 
3152cac8f3aStb static void
dump_results(const BIGNUM * a,const BIGNUM * p,const BIGNUM * b,const BIGNUM * q,const BIGNUM * m,const BIGNUM * want,const BIGNUM * got,const char * name)3167d8f44b3Stb dump_results(const BIGNUM *a, const BIGNUM *p, const BIGNUM *b, const BIGNUM *q,
3177d8f44b3Stb     const BIGNUM *m, const BIGNUM *want, const BIGNUM *got, const char *name)
3182cac8f3aStb {
31958a53292Stb 	fprintf(stderr, "BN_mod_exp_simple() and %s() disagree:\n", name);
3202cac8f3aStb 
32158a53292Stb 	bn_print("want", want);
32258a53292Stb 	bn_print("got", got);
3232cac8f3aStb 
32458a53292Stb 	bn_print("a", a);
32558a53292Stb 	bn_print("p", p);
3267d8f44b3Stb 
3277d8f44b3Stb 	if (b != NULL) {
32858a53292Stb 		bn_print("b", b);
32958a53292Stb 		bn_print("q", q);
3307d8f44b3Stb 	}
3317d8f44b3Stb 
33258a53292Stb 	bn_print("m", m);
3337d8f44b3Stb 
33458a53292Stb 	fprintf(stderr, "\n");
3352cac8f3aStb }
3362cac8f3aStb 
3372cac8f3aStb static int
test_mod_exp(const BIGNUM * want,const BIGNUM * a,const BIGNUM * p,const BIGNUM * m,BN_CTX * ctx,const struct mod_exp_test * test)3382cac8f3aStb test_mod_exp(const BIGNUM *want, const BIGNUM *a, const BIGNUM *p,
3392cac8f3aStb     const BIGNUM *m, BN_CTX *ctx, const struct mod_exp_test *test)
3402cac8f3aStb {
3412cac8f3aStb 	BIGNUM *got;
3424dc4dc58Stb 	int mod_exp_ret;
3432cac8f3aStb 	int ret = 0;
3442cac8f3aStb 
3452cac8f3aStb 	BN_CTX_start(ctx);
3462cac8f3aStb 
3472cac8f3aStb 	if ((got = BN_CTX_get(ctx)) == NULL)
3482cac8f3aStb 		goto err;
3492cac8f3aStb 
3502cac8f3aStb 	if (test->mod_exp_fn != NULL)
3514dc4dc58Stb 		mod_exp_ret = test->mod_exp_fn(got, a, p, m, ctx);
3522cac8f3aStb 	else
3534dc4dc58Stb 		mod_exp_ret = test->mod_exp_mont_fn(got, a, p, m, ctx, NULL);
3542cac8f3aStb 
3554dc4dc58Stb 	if (!mod_exp_ret)
3562cac8f3aStb 		errx(1, "%s() failed", test->name);
3572cac8f3aStb 
3582cac8f3aStb 	if (BN_cmp(want, got) != 0) {
3597d8f44b3Stb 		dump_results(a, p, NULL, NULL, m, want, got, test->name);
3602cac8f3aStb 		goto err;
3612cac8f3aStb 	}
3622cac8f3aStb 
3632cac8f3aStb 	ret = 1;
3642cac8f3aStb 
3652cac8f3aStb  err:
3662cac8f3aStb 	BN_CTX_end(ctx);
3672cac8f3aStb 
3682cac8f3aStb 	return ret;
3692cac8f3aStb }
3702cac8f3aStb 
3712cac8f3aStb static int
bn_mod_exp_test(int reduce,BIGNUM * want,BIGNUM * a,BIGNUM * p,BIGNUM * m,BN_CTX * ctx)3722cac8f3aStb bn_mod_exp_test(int reduce, BIGNUM *want, BIGNUM *a, BIGNUM *p, BIGNUM *m,
3732cac8f3aStb     BN_CTX *ctx)
3742cac8f3aStb {
3752cac8f3aStb 	size_t i, j;
3762cac8f3aStb 	int failed = 0;
3772cac8f3aStb 
3782cac8f3aStb 	if (!generate_test_triple(reduce, a, p, m, ctx))
3792cac8f3aStb 		errx(1, "generate_test_triple");
3802cac8f3aStb 
3814141cafdStb 	for (i = 0; i < 8 && !failed; i++) {
382c0423487Stb 		BN_set_negative(a, (i >> 0) & 1);
3832cac8f3aStb 		BN_set_negative(p, (i >> 1) & 1);
384a3971f08Stb 		BN_set_negative(m, (i >> 2) & 1);
3852cac8f3aStb 
3862cac8f3aStb 		if ((BN_mod_exp_simple(want, a, p, m, ctx)) <= 0)
3872cac8f3aStb 			errx(1, "BN_mod_exp_simple");
3882cac8f3aStb 
3892cac8f3aStb 		for (j = 0; j < N_MOD_EXP_FN; j++) {
3902cac8f3aStb 			const struct mod_exp_test *test = &mod_exp_fn[j];
3912cac8f3aStb 
3922cac8f3aStb 			if (!test_mod_exp(want, a, p, m, ctx, test))
3932cac8f3aStb 				failed |= 1;
3942cac8f3aStb 		}
3952cac8f3aStb 	}
3962cac8f3aStb 
3972cac8f3aStb 	return failed;
3982cac8f3aStb }
3992cac8f3aStb 
4002cac8f3aStb static int
test_bn_mod_exp(void)40117db9b10Stb test_bn_mod_exp(void)
4022cac8f3aStb {
4032cac8f3aStb 	BIGNUM *a, *p, *m, *want;
4042cac8f3aStb 	BN_CTX *ctx;
4052cac8f3aStb 	int i;
4062cac8f3aStb 	int reduce;
4072cac8f3aStb 	int failed = 0;
4082cac8f3aStb 
4092cac8f3aStb 	if ((ctx = BN_CTX_new()) == NULL)
4102cac8f3aStb 		errx(1, "BN_CTX_new");
4112cac8f3aStb 
4122cac8f3aStb 	BN_CTX_start(ctx);
4132cac8f3aStb 
4142cac8f3aStb 	if ((a = BN_CTX_get(ctx)) == NULL)
4152cac8f3aStb 		errx(1, "a = BN_CTX_get()");
4162cac8f3aStb 	if ((p = BN_CTX_get(ctx)) == NULL)
4172cac8f3aStb 		errx(1, "p = BN_CTX_get()");
4182cac8f3aStb 	if ((m = BN_CTX_get(ctx)) == NULL)
4192cac8f3aStb 		errx(1, "m = BN_CTX_get()");
4202cac8f3aStb 	if ((want = BN_CTX_get(ctx)) == NULL)
4212cac8f3aStb 		errx(1, "want = BN_CTX_get()");
4222cac8f3aStb 
4232cac8f3aStb 	reduce = 0;
4244141cafdStb 	for (i = 0; i < N_MOD_EXP_TESTS && !failed; i++)
4252cac8f3aStb 		failed |= bn_mod_exp_test(reduce, want, a, p, m, ctx);
4262cac8f3aStb 
4272cac8f3aStb 	reduce = 1;
4284141cafdStb 	for (i = 0; i < N_MOD_EXP_TESTS && !failed; i++)
4292cac8f3aStb 		failed |= bn_mod_exp_test(reduce, want, a, p, m, ctx);
4302cac8f3aStb 
4312cac8f3aStb 	BN_CTX_end(ctx);
4322cac8f3aStb 	BN_CTX_free(ctx);
4332cac8f3aStb 
4342cac8f3aStb 	return failed;
4352cac8f3aStb }
4362cac8f3aStb 
437f34e85acStb static int
bn_mod_exp2_simple(BIGNUM * out,const BIGNUM * a,const BIGNUM * p,const BIGNUM * b,const BIGNUM * q,const BIGNUM * m,BN_CTX * ctx)438c0423487Stb bn_mod_exp2_simple(BIGNUM *out, const BIGNUM *a, const BIGNUM *p,
439c0423487Stb     const BIGNUM *b, const BIGNUM *q, const BIGNUM *m, BN_CTX *ctx)
440f34e85acStb {
441f34e85acStb 	BIGNUM *fact1, *fact2;
442f34e85acStb 	int ret = 0;
443f34e85acStb 
444f34e85acStb 	BN_CTX_start(ctx);
445f34e85acStb 
446f34e85acStb 	if ((fact1 = BN_CTX_get(ctx)) == NULL)
447f34e85acStb 		goto err;
448f34e85acStb 	if ((fact2 = BN_CTX_get(ctx)) == NULL)
449f34e85acStb 		goto err;
450f34e85acStb 
451c0423487Stb 	if (!BN_mod_exp_simple(fact1, a, p, m, ctx))
452f34e85acStb 		goto err;
453c0423487Stb 	if (!BN_mod_exp_simple(fact2, b, q, m, ctx))
454f34e85acStb 		goto err;
455f34e85acStb 	if (!BN_mod_mul(out, fact1, fact2, m, ctx))
456f34e85acStb 		goto err;
457f34e85acStb 
458f34e85acStb 	ret = 1;
459f34e85acStb  err:
460f34e85acStb 	BN_CTX_end(ctx);
461f34e85acStb 
462f34e85acStb 	return ret;
463f34e85acStb }
464f34e85acStb 
465f34e85acStb static int
bn_mod_exp2_test(int reduce,BIGNUM * want,BIGNUM * got,BIGNUM * a,BIGNUM * p,BIGNUM * b,BIGNUM * q,BIGNUM * m,BN_CTX * ctx)466c0423487Stb bn_mod_exp2_test(int reduce, BIGNUM *want, BIGNUM *got, BIGNUM *a, BIGNUM *p,
467c0423487Stb     BIGNUM *b, BIGNUM *q, BIGNUM *m, BN_CTX *ctx)
468f34e85acStb {
469f34e85acStb 	size_t i;
470f34e85acStb 	int failed = 0;
471f34e85acStb 
472c0423487Stb 	if (!generate_test_quintuple(reduce, a, p, b, q, m, ctx))
473f34e85acStb 		errx(1, "generate_test_quintuple");
474f34e85acStb 
4754141cafdStb 	for (i = 0; i < 32 && !failed; i++) {
476c0423487Stb 		BN_set_negative(a, (i >> 0) & 1);
477c0423487Stb 		BN_set_negative(p, (i >> 1) & 1);
478c0423487Stb 		BN_set_negative(b, (i >> 2) & 1);
479c0423487Stb 		BN_set_negative(q, (i >> 3) & 1);
480a3971f08Stb 		BN_set_negative(m, (i >> 4) & 1);
481f34e85acStb 
482c0423487Stb 		if (!bn_mod_exp2_simple(want, a, p, b, q, m, ctx))
483f34e85acStb 			errx(1, "BN_mod_exp_simple");
484f34e85acStb 
485c0423487Stb 		if (!BN_mod_exp2_mont(got, a, p, b, q, m, ctx, NULL))
486f34e85acStb 			errx(1, "BN_mod_exp2_mont");
487f34e85acStb 
488f34e85acStb 		if (BN_cmp(want, got) != 0) {
4897d8f44b3Stb 			dump_results(a, p, b, q, m, want, got, "BN_mod_exp2_mont");
490f34e85acStb 			failed |= 1;
491f34e85acStb 		}
492f34e85acStb 	}
493f34e85acStb 
494f34e85acStb 	return failed;
495f34e85acStb }
4969cd3ae5cStb 
497f34e85acStb static int
test_bn_mod_exp2(void)49817db9b10Stb test_bn_mod_exp2(void)
499f34e85acStb {
500c0423487Stb 	BIGNUM *a, *p, *b, *q, *m, *want, *got;
501f34e85acStb 	BN_CTX *ctx;
502f34e85acStb 	int i;
503f34e85acStb 	int reduce;
504f34e85acStb 	int failed = 0;
505f34e85acStb 
506f34e85acStb 	if ((ctx = BN_CTX_new()) == NULL)
507f34e85acStb 		errx(1, "BN_CTX_new");
508f34e85acStb 
509f34e85acStb 	BN_CTX_start(ctx);
510f34e85acStb 
511c0423487Stb 	if ((a = BN_CTX_get(ctx)) == NULL)
512c0423487Stb 		errx(1, "a = BN_CTX_get()");
513c0423487Stb 	if ((p = BN_CTX_get(ctx)) == NULL)
514c0423487Stb 		errx(1, "p = BN_CTX_get()");
515c0423487Stb 	if ((b = BN_CTX_get(ctx)) == NULL)
516c0423487Stb 		errx(1, "b = BN_CTX_get()");
517c0423487Stb 	if ((q = BN_CTX_get(ctx)) == NULL)
518c0423487Stb 		errx(1, "q = BN_CTX_get()");
519f34e85acStb 	if ((m = BN_CTX_get(ctx)) == NULL)
520f34e85acStb 		errx(1, "m = BN_CTX_get()");
521f34e85acStb 	if ((want = BN_CTX_get(ctx)) == NULL)
522f34e85acStb 		errx(1, "want = BN_CTX_get()");
523f34e85acStb 	if ((got = BN_CTX_get(ctx)) == NULL)
524f1a5dec3Stb 		errx(1, "got = BN_CTX_get()");
525f34e85acStb 
526f34e85acStb 	reduce = 0;
5274141cafdStb 	for (i = 0; i < N_MOD_EXP_TESTS && !failed; i++)
528c0423487Stb 		failed |= bn_mod_exp2_test(reduce, want, got, a, p, b, q, m, ctx);
529f34e85acStb 
530f34e85acStb 	reduce = 1;
5314141cafdStb 	for (i = 0; i < N_MOD_EXP_TESTS && !failed; i++)
532c0423487Stb 		failed |= bn_mod_exp2_test(reduce, want, got, a, p, b, q, m, ctx);
533f34e85acStb 
534f34e85acStb 	BN_CTX_end(ctx);
535f34e85acStb 	BN_CTX_free(ctx);
536f34e85acStb 
537f34e85acStb 	return failed;
538f34e85acStb }
539f34e85acStb 
54039f402e9Stb /*
54139f402e9Stb  * Small test for a crash reported by Guido Vranken, fixed in bn_exp2.c r1.13.
54239f402e9Stb  * https://github.com/openssl/openssl/issues/17648
54339f402e9Stb  */
54439f402e9Stb 
54539f402e9Stb static int
test_bn_mod_exp2_mont_crash(void)54639f402e9Stb test_bn_mod_exp2_mont_crash(void)
54739f402e9Stb {
54839f402e9Stb 	BIGNUM *m;
54939f402e9Stb 	int failed = 0;
55039f402e9Stb 
55139f402e9Stb 	if ((m = BN_new()) == NULL)
55239f402e9Stb 		errx(1, "BN_new");
55339f402e9Stb 
55439f402e9Stb 	if (BN_mod_exp2_mont(NULL, NULL, NULL, NULL, NULL, m, NULL, NULL)) {
55539f402e9Stb 		fprintf(stderr, "BN_mod_exp2_mont succeeded\n");
55639f402e9Stb 		failed |= 1;
55739f402e9Stb 	}
55839f402e9Stb 
55939f402e9Stb 	BN_free(m);
56039f402e9Stb 
56139f402e9Stb 	return failed;
56239f402e9Stb }
56339f402e9Stb 
564*24882d0aStb const struct aliasing_test_case {
565*24882d0aStb 	BN_ULONG a;
566*24882d0aStb 	BN_ULONG p;
567*24882d0aStb 	BN_ULONG m;
568*24882d0aStb } aliasing_test_cases[] = {
569*24882d0aStb 	{
570*24882d0aStb 		.a = 1031,
571*24882d0aStb 		.p = 1033,
572*24882d0aStb 		.m = 1039,
573*24882d0aStb 	},
574*24882d0aStb 	{
575*24882d0aStb 		.a = 3,
576*24882d0aStb 		.p = 4,
577*24882d0aStb 		.m = 5,
578*24882d0aStb 	},
579*24882d0aStb 	{
580*24882d0aStb 		.a = 97,
581*24882d0aStb 		.p = 17,
582*24882d0aStb 		.m = 11,
583*24882d0aStb 	},
584*24882d0aStb 	{
585*24882d0aStb 		.a = 999961,
586*24882d0aStb 		.p = 999979,
587*24882d0aStb 		.m = 999983,
588*24882d0aStb 	},
589*24882d0aStb };
590*24882d0aStb 
591*24882d0aStb #define N_ALIASING_TEST_CASES \
592*24882d0aStb 	(sizeof(aliasing_test_cases) / sizeof(aliasing_test_cases[0]))
593*24882d0aStb 
594*24882d0aStb static void
test_bn_mod_exp_aliasing_setup(BIGNUM * want,BIGNUM * a,BIGNUM * p,BIGNUM * m,BN_CTX * ctx,const struct aliasing_test_case * tc)595*24882d0aStb test_bn_mod_exp_aliasing_setup(BIGNUM *want, BIGNUM *a, BIGNUM *p, BIGNUM *m,
596*24882d0aStb     BN_CTX *ctx, const struct aliasing_test_case *tc)
597*24882d0aStb {
598*24882d0aStb 	if (!BN_set_word(a, tc->a))
599*24882d0aStb 		errx(1, "BN_set_word");
600*24882d0aStb 	if (!BN_set_word(p, tc->p))
601*24882d0aStb 		errx(1, "BN_set_word");
602*24882d0aStb 	if (!BN_set_word(m, tc->m))
603*24882d0aStb 		errx(1, "BN_set_word");
604*24882d0aStb 
605*24882d0aStb 	if (!BN_mod_exp_simple(want, a, p, m, ctx))
606*24882d0aStb 		errx(1, "BN_mod_exp");
607*24882d0aStb }
608*24882d0aStb 
6097849ca55Stb static int
test_mod_exp_aliased(const char * alias,int want_ret,BIGNUM * got,const BIGNUM * want,const BIGNUM * a,const BIGNUM * p,const BIGNUM * m,BN_CTX * ctx,const struct mod_exp_test * test)6107849ca55Stb test_mod_exp_aliased(const char *alias, int want_ret, BIGNUM *got,
6117849ca55Stb     const BIGNUM *want, const BIGNUM *a, const BIGNUM *p, const BIGNUM *m,
6127849ca55Stb     BN_CTX *ctx, const struct mod_exp_test *test)
6137849ca55Stb {
6147849ca55Stb 	int mod_exp_ret;
6157849ca55Stb 	int ret = 0;
6167849ca55Stb 
6177849ca55Stb 	BN_CTX_start(ctx);
6187849ca55Stb 
6197849ca55Stb 	if (test->mod_exp_fn != NULL)
6207849ca55Stb 		mod_exp_ret = test->mod_exp_fn(got, a, p, m, ctx);
6217849ca55Stb 	else
6227849ca55Stb 		mod_exp_ret = test->mod_exp_mont_fn(got, a, p, m, ctx, NULL);
6237849ca55Stb 
624*24882d0aStb 	if (mod_exp_ret != want_ret) {
625*24882d0aStb 		warnx("%s() %s aliased with result failed", test->name, alias);
626*24882d0aStb 		goto err;
627*24882d0aStb 	}
6287849ca55Stb 
6297849ca55Stb 	if (!mod_exp_ret)
6307849ca55Stb 		goto done;
6317849ca55Stb 
6327849ca55Stb 	if (BN_cmp(want, got) != 0) {
6337849ca55Stb 		dump_results(a, p, NULL, NULL, m, want, got, test->name);
6347849ca55Stb 		goto err;
6357849ca55Stb 	}
6367849ca55Stb 
6377849ca55Stb  done:
6387849ca55Stb 	ret = 1;
6397849ca55Stb 
6407849ca55Stb  err:
6417849ca55Stb 	BN_CTX_end(ctx);
6427849ca55Stb 
6437849ca55Stb 	return ret;
6447849ca55Stb }
6457849ca55Stb 
646*24882d0aStb static int
test_bn_mod_exp_aliasing_test(const struct mod_exp_test * test,BIGNUM * a,BIGNUM * p,BIGNUM * m,BIGNUM * want,BIGNUM * got,BN_CTX * ctx)647*24882d0aStb test_bn_mod_exp_aliasing_test(const struct mod_exp_test *test,
648*24882d0aStb     BIGNUM *a, BIGNUM *p, BIGNUM *m, BIGNUM *want, BIGNUM *got, BN_CTX *ctx)
6497849ca55Stb {
650*24882d0aStb 	int modulus_alias_works = test->mod_exp_fn != BN_mod_exp_simple;
651*24882d0aStb 	size_t i;
652*24882d0aStb 	int failed = 0;
6537849ca55Stb 
654*24882d0aStb 	for (i = 0; i < N_ALIASING_TEST_CASES; i++) {
655*24882d0aStb 		const struct aliasing_test_case *tc = &aliasing_test_cases[i];
656*24882d0aStb 
657*24882d0aStb 		test_bn_mod_exp_aliasing_setup(want, a, p, m, ctx, tc);
658*24882d0aStb 		if (!test_mod_exp_aliased("nothing", 1, got, want, a, p, m, ctx,
659*24882d0aStb 		    test))
660*24882d0aStb 			failed |= 1;
661*24882d0aStb 		test_bn_mod_exp_aliasing_setup(want, a, p, m, ctx, tc);
662*24882d0aStb 		if (!test_mod_exp_aliased("a", 1, a, want, a, p, m, ctx, test))
663*24882d0aStb 			failed |= 1;
664*24882d0aStb 		test_bn_mod_exp_aliasing_setup(want, a, p, m, ctx, tc);
665*24882d0aStb 		if (!test_mod_exp_aliased("p", 1, p, want, a, p, m, ctx, test))
666*24882d0aStb 			failed |= 1;
667*24882d0aStb 		test_bn_mod_exp_aliasing_setup(want, a, p, m, ctx, tc);
668*24882d0aStb 		if (!test_mod_exp_aliased("m", modulus_alias_works, m, want,
669*24882d0aStb 		    a, p, m, ctx, test))
670*24882d0aStb 			failed |= 1;
671*24882d0aStb 	}
672*24882d0aStb 
673*24882d0aStb 	return failed;
6747849ca55Stb }
6757849ca55Stb 
6767849ca55Stb static int
test_bn_mod_exp_aliasing(void)6777849ca55Stb test_bn_mod_exp_aliasing(void)
6787849ca55Stb {
6797849ca55Stb 	BN_CTX *ctx;
6807849ca55Stb 	BIGNUM *a, *p, *m, *want, *got;
6817849ca55Stb 	size_t i;
6827849ca55Stb 	int failed = 0;
6837849ca55Stb 
6847849ca55Stb 	if ((ctx = BN_CTX_new()) == NULL)
6857849ca55Stb 		errx(1, "BN_CTX_new");
6867849ca55Stb 
6877849ca55Stb 	BN_CTX_start(ctx);
6887849ca55Stb 
6897849ca55Stb 	if ((a = BN_CTX_get(ctx)) == NULL)
6907849ca55Stb 		errx(1, "a = BN_CTX_get()");
6917849ca55Stb 	if ((p = BN_CTX_get(ctx)) == NULL)
6927849ca55Stb 		errx(1, "p = BN_CTX_get()");
6937849ca55Stb 	if ((m = BN_CTX_get(ctx)) == NULL)
6947849ca55Stb 		errx(1, "m = BN_CTX_get()");
6957849ca55Stb 	if ((want = BN_CTX_get(ctx)) == NULL)
6967849ca55Stb 		errx(1, "want = BN_CTX_get()");
6977849ca55Stb 	if ((got = BN_CTX_get(ctx)) == NULL)
6987849ca55Stb 		errx(1, "got = BN_CTX_get()");
6997849ca55Stb 
7007849ca55Stb 	for (i = 0; i < N_MOD_EXP_FN; i++) {
7017849ca55Stb 		const struct mod_exp_test *test = &mod_exp_fn[i];
702*24882d0aStb 		failed |= test_bn_mod_exp_aliasing_test(test, a, p, m,
703*24882d0aStb 		    want, got, ctx);
7047849ca55Stb 	}
7057849ca55Stb 
7067849ca55Stb 	BN_CTX_end(ctx);
7077849ca55Stb 	BN_CTX_free(ctx);
7087849ca55Stb 
7097849ca55Stb 	return failed;
7107849ca55Stb }
7117849ca55Stb 
7122cac8f3aStb int
main(void)7132cac8f3aStb main(void)
7142cac8f3aStb {
7152cac8f3aStb 	int failed = 0;
7162cac8f3aStb 
71717db9b10Stb 	failed |= test_bn_mod_exp_zero();
71817db9b10Stb 	failed |= test_bn_mod_exp();
71917db9b10Stb 	failed |= test_bn_mod_exp2();
72039f402e9Stb 	failed |= test_bn_mod_exp2_mont_crash();
7217849ca55Stb 	failed |= test_bn_mod_exp_aliasing();
7222cac8f3aStb 
7232cac8f3aStb 	return failed;
7242cac8f3aStb }
725