Rewrite the tests that various modular exponentiation functions
authortb <tb@openbsd.org>
Fri, 2 Dec 2022 17:33:38 +0000 (17:33 +0000)
committertb <tb@openbsd.org>
Fri, 2 Dec 2022 17:33:38 +0000 (17:33 +0000)
compute a^0 = 0 (mod 1) for all a from scratch.

regress/lib/libcrypto/bn/bn_mod_exp.c
regress/lib/libcrypto/bn/bn_mod_exp_zero.c [new file with mode: 0644]

index 337cbd1..dc0fe27 100644 (file)
@@ -1,4 +1,4 @@
-/*     $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[])
 {
@@ -346,9 +203,6 @@ main(int argc, char *argv[])
        CRYPTO_mem_leaks(out);
        BIO_free(out);
 
-       if (test_exp_mod_zero() != 0)
-               goto err;
-
        return (0);
 
  err:
diff --git a/regress/lib/libcrypto/bn/bn_mod_exp_zero.c b/regress/lib/libcrypto/bn/bn_mod_exp_zero.c
new file mode 100644 (file)
index 0000000..0e1e21d
--- /dev/null
@@ -0,0 +1,187 @@
+/*     $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;
+}