diff options
Diffstat (limited to 'src/crypto/fipsmodule/bn/bn_test.cc')
-rw-r--r-- | src/crypto/fipsmodule/bn/bn_test.cc | 218 |
1 files changed, 167 insertions, 51 deletions
diff --git a/src/crypto/fipsmodule/bn/bn_test.cc b/src/crypto/fipsmodule/bn/bn_test.cc index f73054d2..93d6d0ff 100644 --- a/src/crypto/fipsmodule/bn/bn_test.cc +++ b/src/crypto/fipsmodule/bn/bn_test.cc @@ -239,8 +239,7 @@ static void TestSum(BIGNUMFileTest *t, BN_CTX *ctx) { // having. Note that these functions are frequently used when the // prerequisites don't hold. In those cases, they are supposed to work as if // the prerequisite hold, but we don't test that yet. TODO: test that. - if (!BN_is_negative(a.get()) && - !BN_is_negative(b.get()) && BN_cmp(a.get(), b.get()) >= 0) { + if (!BN_is_negative(a.get()) && !BN_is_negative(b.get())) { ASSERT_TRUE(BN_uadd(ret.get(), a.get(), b.get())); EXPECT_BIGNUMS_EQUAL("A +u B", sum.get(), ret.get()); @@ -276,6 +275,16 @@ static void TestSum(BIGNUMFileTest *t, BN_CTX *ctx) { ASSERT_TRUE(BN_copy(ret.get(), b.get())); ASSERT_TRUE(BN_usub(ret.get(), sum.get(), ret.get())); EXPECT_BIGNUMS_EQUAL("Sum -u B (r is b)", a.get(), ret.get()); + + ASSERT_TRUE(bn_abs_sub_consttime(ret.get(), sum.get(), a.get(), ctx)); + EXPECT_BIGNUMS_EQUAL("|Sum - A|", b.get(), ret.get()); + ASSERT_TRUE(bn_abs_sub_consttime(ret.get(), a.get(), sum.get(), ctx)); + EXPECT_BIGNUMS_EQUAL("|A - Sum|", b.get(), ret.get()); + + ASSERT_TRUE(bn_abs_sub_consttime(ret.get(), sum.get(), b.get(), ctx)); + EXPECT_BIGNUMS_EQUAL("|Sum - B|", a.get(), ret.get()); + ASSERT_TRUE(bn_abs_sub_consttime(ret.get(), b.get(), sum.get(), ctx)); + EXPECT_BIGNUMS_EQUAL("|B - Sum|", a.get(), ret.get()); } // Test with |BN_add_word| and |BN_sub_word| if |b| is small enough. @@ -321,12 +330,18 @@ static void TestLShift1(BIGNUMFileTest *t, BN_CTX *ctx) { ASSERT_TRUE(BN_lshift1(ret.get(), a.get())); EXPECT_BIGNUMS_EQUAL("A << 1", lshift1.get(), ret.get()); - ASSERT_TRUE(BN_rshift1(ret.get(), lshift1.get())); - EXPECT_BIGNUMS_EQUAL("LShift >> 1", a.get(), ret.get()); + ASSERT_TRUE(BN_lshift(ret.get(), a.get(), 1)); + EXPECT_BIGNUMS_EQUAL("A << 1 (variable shift)", lshift1.get(), ret.get()); ASSERT_TRUE(BN_rshift1(ret.get(), lshift1.get())); EXPECT_BIGNUMS_EQUAL("LShift >> 1", a.get(), ret.get()); + ASSERT_TRUE(BN_rshift(ret.get(), lshift1.get(), 1)); + EXPECT_BIGNUMS_EQUAL("LShift >> 1 (variable shift)", a.get(), ret.get()); + + ASSERT_TRUE(bn_rshift_secret_shift(ret.get(), lshift1.get(), 1, ctx)); + EXPECT_BIGNUMS_EQUAL("LShift >> 1 (secret shift)", a.get(), ret.get()); + // Set the LSB to 1 and test rshift1 again. ASSERT_TRUE(BN_set_bit(lshift1.get(), 0)); ASSERT_TRUE( @@ -335,6 +350,13 @@ static void TestLShift1(BIGNUMFileTest *t, BN_CTX *ctx) { ASSERT_TRUE(BN_rshift1(ret.get(), lshift1.get())); EXPECT_BIGNUMS_EQUAL("(LShift | 1) >> 1", a.get(), ret.get()); + + ASSERT_TRUE(BN_rshift(ret.get(), lshift1.get(), 1)); + EXPECT_BIGNUMS_EQUAL("(LShift | 1) >> 1 (variable shift)", a.get(), + ret.get()); + + ASSERT_TRUE(bn_rshift_secret_shift(ret.get(), lshift1.get(), 1, ctx)); + EXPECT_BIGNUMS_EQUAL("(LShift | 1) >> 1 (secret shift)", a.get(), ret.get()); } static void TestLShift(BIGNUMFileTest *t, BN_CTX *ctx) { @@ -350,8 +372,15 @@ static void TestLShift(BIGNUMFileTest *t, BN_CTX *ctx) { ASSERT_TRUE(BN_lshift(ret.get(), a.get(), n)); EXPECT_BIGNUMS_EQUAL("A << N", lshift.get(), ret.get()); + ASSERT_TRUE(BN_copy(ret.get(), a.get())); + ASSERT_TRUE(BN_lshift(ret.get(), ret.get(), n)); + EXPECT_BIGNUMS_EQUAL("A << N (in-place)", lshift.get(), ret.get()); + ASSERT_TRUE(BN_rshift(ret.get(), lshift.get(), n)); EXPECT_BIGNUMS_EQUAL("A >> N", a.get(), ret.get()); + + ASSERT_TRUE(bn_rshift_secret_shift(ret.get(), lshift.get(), n, ctx)); + EXPECT_BIGNUMS_EQUAL("A >> N (secret shift)", a.get(), ret.get()); } static void TestRShift(BIGNUMFileTest *t, BN_CTX *ctx) { @@ -366,6 +395,18 @@ static void TestRShift(BIGNUMFileTest *t, BN_CTX *ctx) { ASSERT_TRUE(ret); ASSERT_TRUE(BN_rshift(ret.get(), a.get(), n)); EXPECT_BIGNUMS_EQUAL("A >> N", rshift.get(), ret.get()); + + ASSERT_TRUE(BN_copy(ret.get(), a.get())); + ASSERT_TRUE(BN_rshift(ret.get(), ret.get(), n)); + EXPECT_BIGNUMS_EQUAL("A >> N (in-place)", rshift.get(), ret.get()); + + ASSERT_TRUE(bn_rshift_secret_shift(ret.get(), a.get(), n, ctx)); + EXPECT_BIGNUMS_EQUAL("A >> N (secret shift)", rshift.get(), ret.get()); + + ASSERT_TRUE(BN_copy(ret.get(), a.get())); + ASSERT_TRUE(bn_rshift_secret_shift(ret.get(), ret.get(), n, ctx)); + EXPECT_BIGNUMS_EQUAL("A >> N (in-place secret shift)", rshift.get(), + ret.get()); } static void TestSquare(BIGNUMFileTest *t, BN_CTX *ctx) { @@ -525,9 +566,31 @@ static void TestQuotient(BIGNUMFileTest *t, BN_CTX *ctx) { ASSERT_TRUE(BN_add(ret.get(), ret.get(), remainder.get())); EXPECT_BIGNUMS_EQUAL("Quotient * B + Remainder", a.get(), ret.get()); + // The remaining division variants only handle a positive quotient. + if (BN_is_negative(b.get())) { + BN_set_negative(b.get(), 0); + BN_set_negative(quotient.get(), !BN_is_negative(quotient.get())); + } + + bssl::UniquePtr<BIGNUM> nnmod(BN_new()); + ASSERT_TRUE(nnmod); + ASSERT_TRUE(BN_copy(nnmod.get(), remainder.get())); + if (BN_is_negative(nnmod.get())) { + ASSERT_TRUE(BN_add(nnmod.get(), nnmod.get(), b.get())); + } + ASSERT_TRUE(BN_nnmod(ret.get(), a.get(), b.get(), ctx)); + EXPECT_BIGNUMS_EQUAL("A % B (non-negative)", nnmod.get(), ret.get()); + + // The remaining division variants only handle a positive numerator. + if (BN_is_negative(a.get())) { + BN_set_negative(a.get(), 0); + BN_set_negative(quotient.get(), 0); + BN_set_negative(remainder.get(), 0); + } + // Test with |BN_mod_word| and |BN_div_word| if the divisor is small enough. BN_ULONG b_word = BN_get_word(b.get()); - if (!BN_is_negative(b.get()) && b_word != (BN_ULONG)-1) { + if (b_word != (BN_ULONG)-1) { BN_ULONG remainder_word = BN_get_word(remainder.get()); ASSERT_NE(remainder_word, (BN_ULONG)-1); ASSERT_TRUE(BN_copy(ret.get(), a.get())); @@ -537,19 +600,15 @@ static void TestQuotient(BIGNUMFileTest *t, BN_CTX *ctx) { ret_word = BN_mod_word(a.get(), b_word); EXPECT_EQ(remainder_word, ret_word); - } - // Test BN_nnmod. - if (!BN_is_negative(b.get())) { - bssl::UniquePtr<BIGNUM> nnmod(BN_new()); - ASSERT_TRUE(nnmod); - ASSERT_TRUE(BN_copy(nnmod.get(), remainder.get())); - if (BN_is_negative(nnmod.get())) { - ASSERT_TRUE(BN_add(nnmod.get(), nnmod.get(), b.get())); + if (b_word <= 0xffff) { + EXPECT_EQ(remainder_word, bn_mod_u16_consttime(a.get(), b_word)); } - ASSERT_TRUE(BN_nnmod(ret.get(), a.get(), b.get(), ctx)); - EXPECT_BIGNUMS_EQUAL("A % B (non-negative)", nnmod.get(), ret.get()); } + + ASSERT_TRUE(bn_div_consttime(ret.get(), ret2.get(), a.get(), b.get(), ctx)); + EXPECT_BIGNUMS_EQUAL("A / B (constant-time)", quotient.get(), ret.get()); + EXPECT_BIGNUMS_EQUAL("A % B (constant-time)", remainder.get(), ret2.get()); } static void TestModMul(BIGNUMFileTest *t, BN_CTX *ctx) { @@ -808,15 +867,24 @@ static void TestModInv(BIGNUMFileTest *t, BN_CTX *ctx) { ASSERT_TRUE(BN_gcd(ret.get(), a.get(), m.get(), ctx)); EXPECT_BIGNUMS_EQUAL("GCD(A, M)", BN_value_one(), ret.get()); + + ASSERT_TRUE(BN_nnmod(a.get(), a.get(), m.get(), ctx)); + int no_inverse; + ASSERT_TRUE( + bn_mod_inverse_consttime(ret.get(), &no_inverse, a.get(), m.get(), ctx)); + EXPECT_BIGNUMS_EQUAL("inv(A) (mod M) (constant-time)", mod_inv.get(), + ret.get()); } static void TestGCD(BIGNUMFileTest *t, BN_CTX *ctx) { bssl::UniquePtr<BIGNUM> a = t->GetBIGNUM("A"); bssl::UniquePtr<BIGNUM> b = t->GetBIGNUM("B"); bssl::UniquePtr<BIGNUM> gcd = t->GetBIGNUM("GCD"); + bssl::UniquePtr<BIGNUM> lcm = t->GetBIGNUM("LCM"); ASSERT_TRUE(a); ASSERT_TRUE(b); ASSERT_TRUE(gcd); + ASSERT_TRUE(lcm); bssl::UniquePtr<BIGNUM> ret(BN_new()); ASSERT_TRUE(ret); @@ -828,6 +896,38 @@ static void TestGCD(BIGNUMFileTest *t, BN_CTX *ctx) { << "A^-1 (mod B) computed, but it does not exist"; EXPECT_FALSE(BN_mod_inverse(ret.get(), b.get(), a.get(), ctx)) << "B^-1 (mod A) computed, but it does not exist"; + + if (!BN_is_zero(b.get())) { + bssl::UniquePtr<BIGNUM> a_reduced(BN_new()); + ASSERT_TRUE(a_reduced); + ASSERT_TRUE(BN_nnmod(a_reduced.get(), a.get(), b.get(), ctx)); + int no_inverse; + EXPECT_FALSE(bn_mod_inverse_consttime(ret.get(), &no_inverse, + a_reduced.get(), b.get(), ctx)) + << "A^-1 (mod B) computed, but it does not exist"; + EXPECT_TRUE(no_inverse); + } + + if (!BN_is_zero(a.get())) { + bssl::UniquePtr<BIGNUM> b_reduced(BN_new()); + ASSERT_TRUE(b_reduced); + ASSERT_TRUE(BN_nnmod(b_reduced.get(), b.get(), a.get(), ctx)); + int no_inverse; + EXPECT_FALSE(bn_mod_inverse_consttime(ret.get(), &no_inverse, + b_reduced.get(), a.get(), ctx)) + << "B^-1 (mod A) computed, but it does not exist"; + EXPECT_TRUE(no_inverse); + } + } + + int is_relative_prime; + ASSERT_TRUE( + bn_is_relatively_prime(&is_relative_prime, a.get(), b.get(), ctx)); + EXPECT_EQ(is_relative_prime, BN_is_one(gcd.get())); + + if (!BN_is_zero(gcd.get())) { + ASSERT_TRUE(bn_lcm_consttime(ret.get(), a.get(), b.get(), ctx)); + EXPECT_BIGNUMS_EQUAL("LCM(A, B)", lcm.get(), ret.get()); } } @@ -1856,6 +1956,7 @@ TEST_F(BNTest, PrimeChecking) { bssl::UniquePtr<BIGNUM> p(BN_new()); ASSERT_TRUE(p); int is_probably_prime_1 = 0, is_probably_prime_2 = 0; + enum bn_primality_result_t result_3; const int max_prime = kPrimes[OPENSSL_ARRAY_SIZE(kPrimes)-1]; size_t next_prime_index = 0; @@ -1878,6 +1979,11 @@ TEST_F(BNTest, PrimeChecking) { &is_probably_prime_2, p.get(), BN_prime_checks, ctx(), true /* do_trial_division */, nullptr /* callback */)); EXPECT_EQ(is_prime ? 1 : 0, is_probably_prime_2); + if (i > 3 && i % 2 == 1) { + ASSERT_TRUE(BN_enhanced_miller_rabin_primality_test( + &result_3, p.get(), BN_prime_checks, ctx(), nullptr /* callback */)); + EXPECT_EQ(is_prime, result_3 == bn_probably_prime); + } } // Negative numbers are not prime. @@ -1920,7 +2026,18 @@ TEST_F(BNTest, PrimeChecking) { &is_probably_prime_2, p.get(), BN_prime_checks, ctx(), true /* do_trial_division */, nullptr /* callback */)); EXPECT_EQ(0, is_probably_prime_2); + + ASSERT_TRUE(BN_enhanced_miller_rabin_primality_test( + &result_3, p.get(), BN_prime_checks, ctx(), nullptr /* callback */)); + EXPECT_EQ(bn_composite, result_3); } + + // BN_primality_test works with null |BN_CTX|. + ASSERT_TRUE(BN_set_word(p.get(), 5)); + ASSERT_TRUE(BN_primality_test( + &is_probably_prime_1, p.get(), BN_prime_checks, nullptr /* ctx */, + false /* do_trial_division */, nullptr /* callback */)); + EXPECT_EQ(1, is_probably_prime_1); } TEST_F(BNTest, NumBitsWord) { @@ -2168,42 +2285,41 @@ TEST_F(BNTest, NonMinimal) { } TEST_F(BNTest, CountLowZeroBits) { - bssl::UniquePtr<BIGNUM> ten(BN_new()); - ASSERT_TRUE(ten); - ASSERT_TRUE(BN_set_word(ten.get(), 10)); - - bssl::UniquePtr<BIGNUM> eight(BN_new()); - ASSERT_TRUE(eight); - ASSERT_TRUE(BN_set_word(eight.get(), 8)); - - bssl::UniquePtr<BIGNUM> two_exp_256(BN_new()); - ASSERT_TRUE(two_exp_256); - ASSERT_TRUE(BN_lshift(two_exp_256.get(), BN_value_one(), 256)); - - bssl::UniquePtr<BIGNUM> two_exp_256_plus_4(BN_new()); - ASSERT_TRUE(two_exp_256_plus_4); - ASSERT_TRUE(BN_lshift(two_exp_256_plus_4.get(), BN_value_one(), 256)); - ASSERT_TRUE(BN_add_word(two_exp_256_plus_4.get(), 4)); + bssl::UniquePtr<BIGNUM> bn(BN_new()); + ASSERT_TRUE(bn); - bssl::UniquePtr<BIGNUM> zero(BN_new()); - ASSERT_TRUE(zero); - BN_zero(zero.get()); + for (int i = 0; i < BN_BITS2; i++) { + SCOPED_TRACE(i); + for (int set_high_bits = 0; set_high_bits < 2; set_high_bits++) { + BN_ULONG word = ((BN_ULONG)1) << i; + if (set_high_bits) { + BN_ULONG junk; + RAND_bytes(reinterpret_cast<uint8_t *>(&junk), sizeof(junk)); + word |= junk & ~(word - 1); + } + SCOPED_TRACE(word); + + ASSERT_TRUE(BN_set_word(bn.get(), word)); + EXPECT_EQ(i, BN_count_low_zero_bits(bn.get())); + ASSERT_TRUE(bn_resize_words(bn.get(), 16)); + EXPECT_EQ(i, BN_count_low_zero_bits(bn.get())); + + ASSERT_TRUE(BN_set_word(bn.get(), word)); + ASSERT_TRUE(BN_lshift(bn.get(), bn.get(), BN_BITS2 * 5)); + EXPECT_EQ(i + BN_BITS2 * 5, BN_count_low_zero_bits(bn.get())); + ASSERT_TRUE(bn_resize_words(bn.get(), 16)); + EXPECT_EQ(i + BN_BITS2 * 5, BN_count_low_zero_bits(bn.get())); + + ASSERT_TRUE(BN_set_word(bn.get(), word)); + ASSERT_TRUE(BN_set_bit(bn.get(), BN_BITS2 * 5)); + EXPECT_EQ(i, BN_count_low_zero_bits(bn.get())); + ASSERT_TRUE(bn_resize_words(bn.get(), 16)); + EXPECT_EQ(i, BN_count_low_zero_bits(bn.get())); + } + } - EXPECT_EQ(1, BN_count_low_zero_bits(ten.get())); - EXPECT_EQ(3, BN_count_low_zero_bits(eight.get())); - EXPECT_EQ(256, BN_count_low_zero_bits(two_exp_256.get())); - EXPECT_EQ(2, BN_count_low_zero_bits(two_exp_256_plus_4.get())); - EXPECT_EQ(0, BN_count_low_zero_bits(zero.get())); - - ASSERT_TRUE(bn_resize_words(ten.get(), 16)); - ASSERT_TRUE(bn_resize_words(eight.get(), 16)); - ASSERT_TRUE(bn_resize_words(two_exp_256.get(), 16)); - ASSERT_TRUE(bn_resize_words(two_exp_256_plus_4.get(), 16)); - ASSERT_TRUE(bn_resize_words(zero.get(), 16)); - - EXPECT_EQ(1, BN_count_low_zero_bits(ten.get())); - EXPECT_EQ(3, BN_count_low_zero_bits(eight.get())); - EXPECT_EQ(256, BN_count_low_zero_bits(two_exp_256.get())); - EXPECT_EQ(2, BN_count_low_zero_bits(two_exp_256_plus_4.get())); - EXPECT_EQ(0, BN_count_low_zero_bits(zero.get())); + BN_zero(bn.get()); + EXPECT_EQ(0, BN_count_low_zero_bits(bn.get())); + ASSERT_TRUE(bn_resize_words(bn.get(), 16)); + EXPECT_EQ(0, BN_count_low_zero_bits(bn.get())); } |