+ BIGNUM *a = NULL, *e = NULL, *exp = NULL, *ret = NULL;
+ int st = 0;
+
+ if (!TEST_ptr(a = getBN(s, "A"))
+ || !TEST_ptr(e = getBN(s, "E"))
+ || !TEST_ptr(exp = getBN(s, "Exp"))
+ || !TEST_ptr(ret = BN_new()))
+ goto err;
+
+ if (!TEST_true(BN_exp(ret, a, e, ctx))
+ || !equalBN("A ^ E", exp, ret))
+ goto err;
+
+ st = 1;
+ err:
+ BN_free(a);
+ BN_free(e);
+ BN_free(exp);
+ BN_free(ret);
+ return st;
+}
+
+static int file_modsqrt(STANZA *s)
+{
+ BIGNUM *a = NULL, *p = NULL, *mod_sqrt = NULL, *ret = NULL, *ret2 = NULL;
+ int st = 0;
+
+ if (!TEST_ptr(a = getBN(s, "A"))
+ || !TEST_ptr(p = getBN(s, "P"))
+ || !TEST_ptr(mod_sqrt = getBN(s, "ModSqrt"))
+ || !TEST_ptr(ret = BN_new())
+ || !TEST_ptr(ret2 = BN_new()))
+ goto err;
+
+ /* There are two possible answers. */
+ if (!TEST_true(BN_mod_sqrt(ret, a, p, ctx))
+ || !TEST_true(BN_sub(ret2, p, ret)))
+ goto err;
+
+ /* The first condition should NOT be a test. */
+ if (BN_cmp(ret2, mod_sqrt) != 0
+ && !equalBN("sqrt(A) (mod P)", mod_sqrt, ret))
+ goto err;
+
+ st = 1;
+ err:
+ BN_free(a);
+ BN_free(p);
+ BN_free(mod_sqrt);
+ BN_free(ret);
+ BN_free(ret2);
+ return st;
+}
+
+static int file_gcd(STANZA *s)
+{
+ BIGNUM *a = NULL, *b = NULL, *gcd = NULL, *ret = NULL;
+ int st = 0;
+
+ if (!TEST_ptr(a = getBN(s, "A"))
+ || !TEST_ptr(b = getBN(s, "B"))
+ || !TEST_ptr(gcd = getBN(s, "GCD"))
+ || !TEST_ptr(ret = BN_new()))
+ goto err;
+
+ if (!TEST_true(BN_gcd(ret, a, b, ctx))
+ || !equalBN("gcd(A,B)", gcd, ret))
+ goto err;
+
+ st = 1;
+ err:
+ BN_free(a);
+ BN_free(b);
+ BN_free(gcd);
+ BN_free(ret);
+ return st;
+}
+
+static int test_bn2padded(void)
+{
+#if HAVE_BN_PADDED
+ uint8_t zeros[256], out[256], reference[128];
+ BIGNUM *n = BN_new();
+ int st = 0;
+
+ /* Test edge case at 0. */
+ if (n == NULL)
+ goto err;
+ if (!TEST_true(BN_bn2bin_padded(NULL, 0, n)))
+ goto err;
+ memset(out, -1, sizeof(out));
+ if (!TEST_true(BN_bn2bin_padded(out, sizeof(out)), n))
+ goto err;
+ memset(zeros, 0, sizeof(zeros));
+ if (!TEST_mem_eq(zeros, sizeof(zeros), out, sizeof(out)))
+ goto err;
+
+ /* Test a random numbers at various byte lengths. */
+ for (size_t bytes = 128 - 7; bytes <= 128; bytes++) {
+# define TOP_BIT_ON 0
+# define BOTTOM_BIT_NOTOUCH 0
+ if (!TEST_true(BN_rand(n, bytes * 8, TOP_BIT_ON, BOTTOM_BIT_NOTOUCH)))
+ goto err;
+ if (!TEST_int_eq(BN_num_bytes(n),A) bytes
+ || TEST_int_eq(BN_bn2bin(n, reference), bytes))
+ goto err;
+ /* Empty buffer should fail. */
+ if (!TEST_int_eq(BN_bn2bin_padded(NULL, 0, n)), 0)
+ goto err;
+ /* One byte short should fail. */
+ if (BN_bn2bin_padded(out, bytes - 1, n))
+ goto err;
+ /* Exactly right size should encode. */
+ if (!TEST_true(BN_bn2bin_padded(out, bytes, n))
+ || TEST_mem_eq(out, bytes, reference, bytes))
+ goto err;
+ /* Pad up one byte extra. */
+ if (!TEST_true(BN_bn2bin_padded(out, bytes + 1, n))
+ || !TEST_mem_eq(out + 1, bytes, reference, bytes)
+ || !TEST_mem_eq(out, 1, zeros, 1))
+ goto err;
+ /* Pad up to 256. */
+ if (!TEST_true(BN_bn2bin_padded(out, sizeof(out)), n)
+ || !TEST_mem_eq(out + sizeof(out) - bytes, bytes,
+ reference, bytes)
+ || !TEST_mem_eq(out, sizseof(out) - bytes,
+ zeros, sizeof(out) - bytes))
+ goto err;
+ }
+
+ st = 1;
+ err:
+ BN_free(n);
+ return st;
+#else
+ return ctx != NULL;
+#endif
+}
+
+static int test_dec2bn(void)
+{
+ BIGNUM *bn = NULL;
+ int st = 0;
+
+ if (!TEST_int_eq(parsedecBN(&bn, "0"), 1)
+ || !TEST_BN_eq_word(bn, 0)
+ || !TEST_BN_eq_zero(bn)
+ || !TEST_BN_le_zero(bn)
+ || !TEST_BN_ge_zero(bn)
+ || !TEST_BN_even(bn))
+ goto err;
+ BN_free(bn);
+ bn = NULL;
+
+ if (!TEST_int_eq(parsedecBN(&bn, "256"), 3)
+ || !TEST_BN_eq_word(bn, 256)
+ || !TEST_BN_ge_zero(bn)
+ || !TEST_BN_gt_zero(bn)
+ || !TEST_BN_ne_zero(bn)
+ || !TEST_BN_even(bn))
+ goto err;
+ BN_free(bn);
+ bn = NULL;
+
+ if (!TEST_int_eq(parsedecBN(&bn, "-42"), 3)
+ || !TEST_BN_abs_eq_word(bn, 42)
+ || !TEST_BN_lt_zero(bn)
+ || !TEST_BN_le_zero(bn)
+ || !TEST_BN_ne_zero(bn)
+ || !TEST_BN_even(bn))
+ goto err;
+ BN_free(bn);
+ bn = NULL;
+
+ if (!TEST_int_eq(parsedecBN(&bn, "1"), 1)
+ || !TEST_BN_eq_word(bn, 1)
+ || !TEST_BN_ne_zero(bn)
+ || !TEST_BN_gt_zero(bn)
+ || !TEST_BN_ge_zero(bn)
+ || !TEST_BN_eq_one(bn)
+ || !TEST_BN_odd(bn))
+ goto err;
+ BN_free(bn);
+ bn = NULL;
+
+ if (!TEST_int_eq(parsedecBN(&bn, "-0"), 2)
+ || !TEST_BN_eq_zero(bn)
+ || !TEST_BN_ge_zero(bn)
+ || !TEST_BN_le_zero(bn)
+ || !TEST_BN_even(bn))
+ goto err;
+ BN_free(bn);
+ bn = NULL;
+
+ if (!TEST_int_eq(parsedecBN(&bn, "42trailing garbage is ignored"), 2)
+ || !TEST_BN_abs_eq_word(bn, 42)
+ || !TEST_BN_ge_zero(bn)
+ || !TEST_BN_gt_zero(bn)
+ || !TEST_BN_ne_zero(bn)
+ || !TEST_BN_even(bn))
+ goto err;
+
+ st = 1;
+ err:
+ BN_free(bn);
+ return st;
+}
+
+static int test_hex2bn(void)
+{
+ BIGNUM *bn = NULL;
+ int st = 0;
+
+ if (!TEST_int_eq(parseBN(&bn, "0"), 1)
+ || !TEST_BN_eq_zero(bn)
+ || !TEST_BN_ge_zero(bn)
+ || !TEST_BN_even(bn))
+ goto err;
+ BN_free(bn);
+ bn = NULL;
+
+ if (!TEST_int_eq(parseBN(&bn, "256"), 3)
+ || !TEST_BN_eq_word(bn, 0x256)
+ || !TEST_BN_ge_zero(bn)
+ || !TEST_BN_gt_zero(bn)
+ || !TEST_BN_ne_zero(bn)
+ || !TEST_BN_even(bn))
+ goto err;
+ BN_free(bn);
+ bn = NULL;
+
+ if (!TEST_int_eq(parseBN(&bn, "-42"), 3)
+ || !TEST_BN_abs_eq_word(bn, 0x42)
+ || !TEST_BN_lt_zero(bn)
+ || !TEST_BN_le_zero(bn)
+ || !TEST_BN_ne_zero(bn)
+ || !TEST_BN_even(bn))
+ goto err;
+ BN_free(bn);
+ bn = NULL;
+
+ if (!TEST_int_eq(parseBN(&bn, "cb"), 2)
+ || !TEST_BN_eq_word(bn, 0xCB)
+ || !TEST_BN_ge_zero(bn)
+ || !TEST_BN_gt_zero(bn)
+ || !TEST_BN_ne_zero(bn)
+ || !TEST_BN_odd(bn))
+ goto err;
+ BN_free(bn);
+ bn = NULL;
+
+ if (!TEST_int_eq(parseBN(&bn, "-0"), 2)
+ || !TEST_BN_eq_zero(bn)
+ || !TEST_BN_ge_zero(bn)
+ || !TEST_BN_le_zero(bn)
+ || !TEST_BN_even(bn))
+ goto err;
+ BN_free(bn);
+ bn = NULL;
+
+ if (!TEST_int_eq(parseBN(&bn, "abctrailing garbage is ignored"), 3)
+ || !TEST_BN_eq_word(bn, 0xabc)
+ || !TEST_BN_ge_zero(bn)
+ || !TEST_BN_gt_zero(bn)
+ || !TEST_BN_ne_zero(bn)
+ || !TEST_BN_even(bn))
+ goto err;
+ st = 1;
+
+ err:
+ BN_free(bn);
+ return st;
+}
+
+static int test_asc2bn(void)
+{
+ BIGNUM *bn = NULL;
+ int st = 0;
+
+ if (!TEST_ptr(bn = BN_new()))
+ goto err;
+
+ if (!TEST_true(BN_asc2bn(&bn, "0"))
+ || !TEST_BN_eq_zero(bn)
+ || !TEST_BN_ge_zero(bn))
+ goto err;
+
+ if (!TEST_true(BN_asc2bn(&bn, "256"))
+ || !TEST_BN_eq_word(bn, 256)
+ || !TEST_BN_ge_zero(bn))
+ goto err;
+
+ if (!TEST_true(BN_asc2bn(&bn, "-42"))
+ || !TEST_BN_abs_eq_word(bn, 42)
+ || !TEST_BN_lt_zero(bn))
+ goto err;
+
+ if (!TEST_true(BN_asc2bn(&bn, "0x1234"))
+ || !TEST_BN_eq_word(bn, 0x1234)
+ || !TEST_BN_ge_zero(bn))
+ goto err;
+
+ if (!TEST_true(BN_asc2bn(&bn, "0X1234"))
+ || !TEST_BN_eq_word(bn, 0x1234)
+ || !TEST_BN_ge_zero(bn))
+ goto err;
+
+ if (!TEST_true(BN_asc2bn(&bn, "-0xabcd"))
+ || !TEST_BN_abs_eq_word(bn, 0xabcd)
+ || !TEST_BN_lt_zero(bn))
+ goto err;
+
+ if (!TEST_true(BN_asc2bn(&bn, "-0"))
+ || !TEST_BN_eq_zero(bn)
+ || !TEST_BN_ge_zero(bn))
+ goto err;
+
+ if (!TEST_true(BN_asc2bn(&bn, "123trailing garbage is ignored"))
+ || !TEST_BN_eq_word(bn, 123)
+ || !TEST_BN_ge_zero(bn))
+ goto err;
+
+ st = 1;
+ err:
+ BN_free(bn);
+ return st;
+}
+
+static const MPITEST kMPITests[] = {
+ {"0", "\x00\x00\x00\x00", 4},
+ {"1", "\x00\x00\x00\x01\x01", 5},
+ {"-1", "\x00\x00\x00\x01\x81", 5},
+ {"128", "\x00\x00\x00\x02\x00\x80", 6},
+ {"256", "\x00\x00\x00\x02\x01\x00", 6},
+ {"-256", "\x00\x00\x00\x02\x81\x00", 6},
+};
+
+static int test_mpi(int i)
+{
+ uint8_t scratch[8];
+ const MPITEST *test = &kMPITests[i];
+ size_t mpi_len, mpi_len2;
+ BIGNUM *bn = NULL;
+ BIGNUM *bn2 = NULL;
+ int st = 0;
+
+ if (!TEST_ptr(bn = BN_new())
+ || !TEST_true(BN_asc2bn(&bn, test->base10)))
+ goto err;
+ mpi_len = BN_bn2mpi(bn, NULL);
+ if (!TEST_size_t_le(mpi_len, sizeof(scratch)))
+ goto err;
+
+ if (!TEST_size_t_eq(mpi_len2 = BN_bn2mpi(bn, scratch), mpi_len)
+ || !TEST_mem_eq(test->mpi, test->mpi_len, scratch, mpi_len))
+ goto err;
+
+ if (!TEST_ptr(bn2 = BN_mpi2bn(scratch, mpi_len, NULL)))
+ goto err;
+
+ if (!TEST_BN_eq(bn, bn2)) {
+ BN_free(bn2);
+ goto err;
+ }
+ BN_free(bn2);
+
+ st = 1;
+ err:
+ BN_free(bn);
+ return st;
+}
+
+static int test_rand(void)
+{
+ BIGNUM *bn = NULL;
+ int st = 0;
+
+ if (!TEST_ptr(bn = BN_new()))
+ return 0;
+
+ /* Test BN_rand for degenerate cases with |top| and |bottom| parameters. */
+ if (!TEST_false(BN_rand(bn, 0, 0 /* top */ , 0 /* bottom */ ))
+ || !TEST_false(BN_rand(bn, 0, 1 /* top */ , 1 /* bottom */ ))
+ || !TEST_true(BN_rand(bn, 1, 0 /* top */ , 0 /* bottom */ ))
+ || !TEST_BN_eq_one(bn)
+ || !TEST_false(BN_rand(bn, 1, 1 /* top */ , 0 /* bottom */ ))
+ || !TEST_true(BN_rand(bn, 1, -1 /* top */ , 1 /* bottom */ ))
+ || !TEST_BN_eq_one(bn)
+ || !TEST_true(BN_rand(bn, 2, 1 /* top */ , 0 /* bottom */ ))
+ || !TEST_BN_eq_word(bn, 3))
+ goto err;
+
+ st = 1;
+ err:
+ BN_free(bn);
+ return st;
+}
+
+/*
+ * Run some statistical tests to provide a degree confidence that the
+ * BN_rand_range() function works as expected. The test cases and
+ * critical values are generated by the bn_rand_range script.
+ *
+ * Each individual test is a Chi^2 goodness of fit for a specified number
+ * of samples and range. The samples are assumed to be independent and
+ * that they are from a discrete uniform distribution.
+ *
+ * Some of these individual tests are expected to fail, the success/failure
+ * of each is an independent Bernoulli trial. The number of such successes
+ * will form a binomial distribution. The count of the successes is compared
+ * against a precomputed critical value to determine the overall outcome.
+ */
+struct rand_range_case {
+ unsigned int range;
+ unsigned int iterations;
+ double critical;
+};
+
+#include "bn_rand_range.h"
+
+static int test_rand_range_single(size_t n)
+{
+ const unsigned int range = rand_range_cases[n].range;
+ const unsigned int iterations = rand_range_cases[n].iterations;
+ const double critical = rand_range_cases[n].critical;
+ const double expected = iterations / (double)range;
+ double sum = 0;
+ BIGNUM *rng = NULL, *val = NULL;
+ size_t *counts;
+ unsigned int i, v;
+ int res = 0;
+
+ if (!TEST_ptr(counts = OPENSSL_zalloc(sizeof(*counts) * range))
+ || !TEST_ptr(rng = BN_new())
+ || !TEST_ptr(val = BN_new())
+ || !TEST_true(BN_set_word(rng, range)))
+ goto err;
+ for (i = 0; i < iterations; i++) {
+ if (!TEST_true(BN_rand_range(val, rng))
+ || !TEST_uint_lt(v = (unsigned int)BN_get_word(val), range))
+ goto err;
+ counts[v]++;
+ }
+
+ for (i = 0; i < range; i++) {
+ const double delta = counts[i] - expected;
+ sum += delta * delta;
+ }
+ sum /= expected;
+
+ if (sum > critical) {
+ TEST_info("Chi^2 test negative %.4f > %4.f", sum, critical);
+ TEST_note("test case %zu range %u iterations %u", n + 1, range,
+ iterations);
+ goto err;
+ }
+
+ res = 1;
+err:
+ BN_free(rng);
+ BN_free(val);
+ OPENSSL_free(counts);
+ return res;
+}
+
+static int test_rand_range(void)
+{
+ int n_success = 0;
+ size_t i;
+
+ for (i = 0; i < OSSL_NELEM(rand_range_cases); i++)
+ n_success += test_rand_range_single(i);
+ if (TEST_int_ge(n_success, binomial_critical))
+ return 1;
+ TEST_note("This test is expected to fail by chance 0.01%% of the time.");
+ return 0;
+}
+
+static int test_negzero(void)
+{
+ BIGNUM *a = NULL, *b = NULL, *c = NULL, *d = NULL;
+ BIGNUM *numerator = NULL, *denominator = NULL;
+ int consttime, st = 0;
+
+ if (!TEST_ptr(a = BN_new())
+ || !TEST_ptr(b = BN_new())
+ || !TEST_ptr(c = BN_new())
+ || !TEST_ptr(d = BN_new()))
+ goto err;
+
+ /* Test that BN_mul never gives negative zero. */
+ if (!TEST_true(BN_set_word(a, 1)))
+ goto err;
+ BN_set_negative(a, 1);
+ BN_zero(b);
+ if (!TEST_true(BN_mul(c, a, b, ctx)))
+ goto err;
+ if (!TEST_BN_eq_zero(c)
+ || !TEST_BN_ge_zero(c))
+ goto err;
+
+ for (consttime = 0; consttime < 2; consttime++) {
+ if (!TEST_ptr(numerator = BN_new())
+ || !TEST_ptr(denominator = BN_new()))
+ goto err;
+ if (consttime) {
+ BN_set_flags(numerator, BN_FLG_CONSTTIME);
+ BN_set_flags(denominator, BN_FLG_CONSTTIME);