+ 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;