-/* $OpenBSD: bn_mod_exp.c,v 1.1 2022/12/01 21:21:51 tb Exp $ */
+/* $OpenBSD: bn_mod_exp.c,v 1.2 2022/12/02 17:33:38 tb Exp $ */
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
#include <openssl/bn.h>
#include <openssl/err.h>
-int BN_mod_exp_ct(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
- const BIGNUM *m, BN_CTX *ctx);
-int BN_mod_exp_nonct(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
- const BIGNUM *m, BN_CTX *ctx);
-int BN_mod_exp_mont_ct(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
- const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx);
-int BN_mod_exp_mont_nonct(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
- const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx);
+#include "bn_local.h"
#define NUM_BITS (BN_BITS*2)
-/*
- * Test that r == 0 in test_exp_mod_zero(). Returns one on success,
- * returns zero and prints debug output otherwise.
- */
-static int
-a_is_zero_mod_one(const char *method, const BIGNUM *r, const BIGNUM *a)
-{
- if (!BN_is_zero(r)) {
- fprintf(stderr, "%s failed:\n", method);
- fprintf(stderr, "a ** 0 mod 1 = r (should be 0)\n");
- fprintf(stderr, "a = ");
- BN_print_fp(stderr, a);
- fprintf(stderr, "\nr = ");
- BN_print_fp(stderr, r);
- fprintf(stderr, "\n");
- return 0;
- }
- return 1;
-}
-
-/*
- * test_exp_mod_zero tests that x**0 mod 1 == 0. It returns zero on success.
- */
-static int
-test_exp_mod_zero(void)
-{
- BIGNUM *a = NULL, *p = NULL, *m = NULL, *r = NULL;
- BN_ULONG one_word = 1;
- BN_CTX *ctx;
- int ret = 1, failed = 0;
-
- if ((ctx = BN_CTX_new()) == NULL)
- goto err;
- if ((m = BN_new()) == NULL)
- goto err;
- if (!BN_one(m))
- goto err;
-
- if ((a = BN_new()) == NULL)
- goto err;
- if (!BN_one(a))
- goto err;
-
- if ((p = BN_new()) == NULL)
- goto err;
- BN_zero(p);
-
- if ((r = BN_new()) == NULL)
- goto err;
-
- if (!BN_rand(a, 1024, 0, 0))
- goto err;
-
- if (!BN_mod_exp(r, a, p, m, ctx))
- goto err;
-
- if (!a_is_zero_mod_one("BN_mod_exp", r, a))
- failed = 1;
-
- if (!BN_mod_exp_ct(r, a, p, m, ctx))
- goto err;
-
- if (!a_is_zero_mod_one("BN_mod_exp_ct", r, a))
- failed = 1;
-
- if (!BN_mod_exp_nonct(r, a, p, m, ctx))
- goto err;
-
- if (!a_is_zero_mod_one("BN_mod_exp_nonct", r, a))
- failed = 1;
-
- if (!BN_mod_exp_recp(r, a, p, m, ctx))
- goto err;
-
- if (!a_is_zero_mod_one("BN_mod_exp_recp", r, a))
- failed = 1;
-
- if (!BN_mod_exp_simple(r, a, p, m, ctx))
- goto err;
-
- if (!a_is_zero_mod_one("BN_mod_exp_simple", r, a))
- failed = 1;
-
- if (!BN_mod_exp_mont(r, a, p, m, ctx, NULL))
- goto err;
-
- if (!a_is_zero_mod_one("BN_mod_exp_mont", r, a))
- failed = 1;
-
- if (!BN_mod_exp_mont_ct(r, a, p, m, ctx, NULL))
- goto err;
-
- if (!a_is_zero_mod_one("BN_mod_exp_mont_ct", r, a))
- failed = 1;
-
- if (!BN_mod_exp_mont_nonct(r, a, p, m, ctx, NULL))
- goto err;
-
- if (!a_is_zero_mod_one("BN_mod_exp_mont_nonct", r, a))
- failed = 1;
-
- if (!BN_mod_exp_mont_consttime(r, a, p, m, ctx, NULL)) {
- goto err;
- }
-
- if (!a_is_zero_mod_one("BN_mod_exp_mont_consttime", r, a))
- failed = 1;
-
- /*
- * A different codepath exists for single word multiplication
- * in non-constant-time only.
- */
- if (!BN_mod_exp_mont_word(r, one_word, p, m, ctx, NULL))
- goto err;
-
- if (!BN_is_zero(r)) {
- fprintf(stderr, "BN_mod_exp_mont_word failed:\n");
- fprintf(stderr, "1 ** 0 mod 1 = r (should be 0)\n");
- fprintf(stderr, "r = ");
- BN_print_fp(stderr, r);
- fprintf(stderr, "\n");
- return 0;
- }
-
- ret = failed;
-
- err:
- BN_free(r);
- BN_free(a);
- BN_free(p);
- BN_free(m);
- BN_CTX_free(ctx);
-
- return ret;
-}
-
int
main(int argc, char *argv[])
{
CRYPTO_mem_leaks(out);
BIO_free(out);
- if (test_exp_mod_zero() != 0)
- goto err;
-
return (0);
err:
--- /dev/null
+/* $OpenBSD: bn_mod_exp_zero.c,v 1.1 2022/12/02 17:33:38 tb Exp $ */
+
+/*
+ * Copyright (c) 2022 Theo Buehler <tb@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <err.h>
+
+#include <openssl/bn.h>
+#include <openssl/err.h>
+
+#include "bn_local.h"
+
+#define INIT_MOD_EXP_FN(f) { .name = #f, .mod_exp_fn = (f), }
+#define INIT_MOD_EXP_MONT_FN(f) { .name = #f, .mod_exp_mont_fn = (f), }
+
+static const struct mod_exp_zero_test {
+ const char *name;
+ int (*mod_exp_fn)(BIGNUM *,const BIGNUM *, const BIGNUM *,
+ const BIGNUM *, BN_CTX *);
+ int (*mod_exp_mont_fn)(BIGNUM *,const BIGNUM *, const BIGNUM *,
+ const BIGNUM *, BN_CTX *, BN_MONT_CTX *);
+} mod_exp_zero_test_data[] = {
+ INIT_MOD_EXP_FN(BN_mod_exp),
+ INIT_MOD_EXP_FN(BN_mod_exp_ct),
+ INIT_MOD_EXP_FN(BN_mod_exp_nonct),
+ INIT_MOD_EXP_FN(BN_mod_exp_recp),
+ INIT_MOD_EXP_FN(BN_mod_exp_simple),
+ INIT_MOD_EXP_MONT_FN(BN_mod_exp_mont),
+ INIT_MOD_EXP_MONT_FN(BN_mod_exp_mont_ct),
+ INIT_MOD_EXP_MONT_FN(BN_mod_exp_mont_consttime),
+ INIT_MOD_EXP_MONT_FN(BN_mod_exp_mont_nonct),
+};
+
+#define N_MOD_EXP_ZERO_TESTS \
+ (sizeof(mod_exp_zero_test_data) / sizeof(mod_exp_zero_test_data[0]))
+
+static void
+print_failure(const BIGNUM *result, const BIGNUM *a, const char *name)
+{
+ fprintf(stderr, "%s test failed for a = ", name);
+ BN_print_fp(stderr, a);
+ fprintf(stderr, "\nwant 0, got ");
+ BN_print_fp(stderr, result);
+ fprintf(stderr, "\n");
+}
+
+static int
+bn_mod_exp_zero_test(const struct mod_exp_zero_test *test, BN_CTX *ctx,
+ int use_random)
+{
+ const BIGNUM *one;
+ BIGNUM *a, *p, *result;
+ int failed = 1;
+
+ BN_CTX_start(ctx);
+
+ if ((a = BN_CTX_get(ctx)) == NULL)
+ errx(1, "BN_CTX_get");
+ if ((p = BN_CTX_get(ctx)) == NULL)
+ errx(1, "BN_CTX_get");
+ if ((result = BN_CTX_get(ctx)) == NULL)
+ errx(1, "BN_CTX_get");
+
+ one = BN_value_one();
+ BN_zero(a);
+ BN_zero(p);
+
+ if (use_random) {
+ if (!BN_rand(a, 1024, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY))
+ errx(1, "BN_rand");
+ }
+
+ if (test->mod_exp_fn != NULL) {
+ if (!test->mod_exp_fn(result, a, p, one, ctx)) {
+ fprintf(stderr, "%s failed\n", test->name);
+ ERR_print_errors_fp(stderr);
+ goto err;
+ }
+ } else {
+ if (!test->mod_exp_mont_fn(result, a, p, one, ctx, NULL)) {
+ fprintf(stderr, "%s failed\n", test->name);
+ ERR_print_errors_fp(stderr);
+ goto err;
+ }
+ }
+
+ if (!BN_is_zero(result)) {
+ print_failure(result, a, test->name);
+ goto err;
+ }
+
+ failed = 0;
+
+ err:
+ BN_CTX_end(ctx);
+
+ return failed;
+}
+
+static int
+bn_mod_exp_zero_word_test(BN_CTX *ctx)
+{
+ const char *name = "BN_mod_exp_mont_word";
+ const BIGNUM *one;
+ BIGNUM *p, *result;
+ int failed = 1;
+
+ BN_CTX_start(ctx);
+
+ if ((p = BN_CTX_get(ctx)) == NULL)
+ errx(1, "BN_CTX_get");
+ if ((result = BN_CTX_get(ctx)) == NULL)
+ errx(1, "BN_CTX_get");
+
+ one = BN_value_one();
+ BN_zero(p);
+
+ if (!BN_mod_exp_mont_word(result, 1, p, one, ctx, NULL)) {
+ fprintf(stderr, "%s failed\n", name);
+ ERR_print_errors_fp(stderr);
+ goto err;
+ }
+
+ if (!BN_is_zero(result)) {
+ print_failure(result, one, name);
+ goto err;
+ }
+
+ failed = 0;
+
+ err:
+ BN_CTX_end(ctx);
+
+ return failed;
+}
+
+static int
+run_bn_mod_exp_zero_tests(void)
+{
+ BN_CTX *ctx;
+ size_t i;
+ int use_random;
+ int failed = 0;
+
+ if ((ctx = BN_CTX_new()) == NULL)
+ errx(1, "BN_CTX_new");
+
+ use_random = 1;
+ for (i = 0; i < N_MOD_EXP_ZERO_TESTS; i++)
+ failed |= bn_mod_exp_zero_test(&mod_exp_zero_test_data[i], ctx,
+ use_random);
+
+ use_random = 0;
+ for (i = 0; i < N_MOD_EXP_ZERO_TESTS; i++)
+ failed |= bn_mod_exp_zero_test(&mod_exp_zero_test_data[i], ctx,
+ use_random);
+
+ failed |= bn_mod_exp_zero_word_test(ctx);
+
+ BN_CTX_free(ctx);
+
+ return failed;
+}
+
+int
+main(void)
+{
+ int failed = 0;
+
+ failed |= run_bn_mod_exp_zero_tests();
+
+ return failed;
+}