diff options
author | Jack Lloyd <[email protected]> | 2015-08-08 12:41:26 -0400 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2015-08-08 12:41:26 -0400 |
commit | 549aaeccca01671ca94b422fe589c772349983ff (patch) | |
tree | 27bb784b27c7ac85717b9a3ff7cda4d8ea6c4523 /src | |
parent | 63c1958b841d26184c526b54c531b0188c34ab0a (diff) |
Expose the NIST prime values and reduction operations as plain functions.
Previously they were hidden away as private functions on the CurveGFp
types. This allows directly testing the reduction functions against
other computational methods.
Diffstat (limited to 'src')
-rw-r--r-- | src/lib/math/ec_gfp/curve_gfp.cpp | 172 | ||||
-rw-r--r-- | src/lib/math/ec_gfp/curve_gfp.h | 14 | ||||
-rw-r--r-- | src/lib/math/ec_gfp/curve_nistp.cpp | 137 | ||||
-rw-r--r-- | src/lib/math/ec_gfp/curve_nistp.h | 152 | ||||
-rw-r--r-- | src/lib/math/ec_gfp/info.txt | 9 | ||||
-rw-r--r-- | src/lib/math/numbertheory/info.txt | 14 | ||||
-rw-r--r-- | src/tests/test_bigint.cpp | 154 |
7 files changed, 367 insertions, 285 deletions
diff --git a/src/lib/math/ec_gfp/curve_gfp.cpp b/src/lib/math/ec_gfp/curve_gfp.cpp index 64d45572d..96fe873af 100644 --- a/src/lib/math/ec_gfp/curve_gfp.cpp +++ b/src/lib/math/ec_gfp/curve_gfp.cpp @@ -1,12 +1,12 @@ /* * Elliptic curves over GF(p) Montgomery Representation -* (C) 2014 Jack Lloyd +* (C) 2014,2015 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #include <botan/curve_gfp.h> -#include <botan/internal/curve_nistp.h> +#include <botan/curve_nistp.h> #include <botan/internal/mp_core.h> #include <botan/internal/mp_asmi.h> @@ -115,54 +115,170 @@ void CurveGFp_Montgomery::curve_sqr(BigInt& z, const BigInt& x, ws.data()); } -} +class CurveGFp_NIST : public CurveGFp_Repr + { + public: + CurveGFp_NIST(size_t p_bits, const BigInt& a, const BigInt& b) : + m_a(a), m_b(b), m_p_words((p_bits + BOTAN_MP_WORD_BITS - 1) / BOTAN_MP_WORD_BITS) + { + } + + const BigInt& get_a() const override { return m_a; } + + const BigInt& get_b() const override { return m_b; } + + size_t get_p_words() const override { return m_p_words; } + + const BigInt& get_a_rep() const override { return m_a; } + + const BigInt& get_b_rep() const override { return m_b; } + + void to_curve_rep(BigInt& x, secure_vector<word>& ws) const override + { redc(x, ws); } + + void from_curve_rep(BigInt& x, secure_vector<word>& ws) const override + { redc(x, ws); } + + void curve_mul(BigInt& z, const BigInt& x, const BigInt& y, + secure_vector<word>& ws) const override; + + void curve_sqr(BigInt& z, const BigInt& x, + secure_vector<word>& ws) const override; + private: + virtual void redc(BigInt& x, secure_vector<word>& ws) const = 0; + + // Curve parameters + BigInt m_a, m_b; + size_t m_p_words; // cache of m_p.sig_words() + }; -// Default implementation -void CurveGFp_Repr::normalize(BigInt& x, secure_vector<word>& ws, size_t bound) const +void CurveGFp_NIST::curve_mul(BigInt& z, const BigInt& x, const BigInt& y, + secure_vector<word>& ws) const { - const BigInt& p = get_p(); - const word* prime = p.data(); + if(x.is_zero() || y.is_zero()) + { + z = 0; + return; + } + const size_t p_words = get_p_words(); + const size_t output_size = 2*p_words + 1; + ws.resize(2*(p_words+2)); - while(x.is_negative()) - x += p; + z.grow_to(output_size); + z.clear(); - x.grow_to(p_words + 1); + bigint_mul(z.mutable_data(), output_size, ws.data(), + x.data(), x.size(), x.sig_words(), + y.data(), y.size(), y.sig_words()); - if(ws.size() < p_words + 1) - ws.resize(p_words + 1); + this->redc(z, ws); + } - for(size_t i = 0; bound == 0 || i < bound; ++i) +void CurveGFp_NIST::curve_sqr(BigInt& z, const BigInt& x, + secure_vector<word>& ws) const + { + if(x.is_zero()) { - const word* xd = x.data(); - word borrow = 0; + z = 0; + return; + } + + const size_t p_words = get_p_words(); + const size_t output_size = 2*p_words + 1; - for(size_t i = 0; i != p_words; ++i) - ws[i] = word_sub(xd[i], prime[i], &borrow); - ws[p_words] = word_sub(xd[p_words], 0, &borrow); + ws.resize(2*(p_words+2)); - if(borrow) - break; + z.grow_to(output_size); + z.clear(); - x.swap_reg(ws); - } + bigint_sqr(z.mutable_data(), output_size, ws.data(), + x.data(), x.size(), x.sig_words()); + + this->redc(z, ws); } +#if defined(BOTAN_HAS_NIST_PRIME_REDUCERS_W32) + +/** +* The NIST P-192 curve +*/ +class CurveGFp_P192 : public CurveGFp_NIST + { + public: + CurveGFp_P192(const BigInt& a, const BigInt& b) : CurveGFp_NIST(192, a, b) {} + const BigInt& get_p() const override { return prime_p192(); } + private: + void redc(BigInt& x, secure_vector<word>& ws) const override { redc_p192(x, ws); } + }; + +/** +* The NIST P-224 curve +*/ +class CurveGFp_P224 : public CurveGFp_NIST + { + public: + CurveGFp_P224(const BigInt& a, const BigInt& b) : CurveGFp_NIST(224, a, b) {} + const BigInt& get_p() const override { return prime_p224(); } + private: + void redc(BigInt& x, secure_vector<word>& ws) const override { redc_p224(x, ws); } + }; + +/** +* The NIST P-256 curve +*/ +class CurveGFp_P256 : public CurveGFp_NIST + { + public: + CurveGFp_P256(const BigInt& a, const BigInt& b) : CurveGFp_NIST(256, a, b) {} + const BigInt& get_p() const override { return prime_p256(); } + private: + void redc(BigInt& x, secure_vector<word>& ws) const override { redc_p256(x, ws); } + }; + +/** +* The NIST P-384 curve +*/ +class CurveGFp_P384 : public CurveGFp_NIST + { + public: + CurveGFp_P384(const BigInt& a, const BigInt& b) : CurveGFp_NIST(384, a, b) {} + const BigInt& get_p() const override { return prime_p384(); } + private: + void redc(BigInt& x, secure_vector<word>& ws) const override { redc_p384(x, ws); } + }; + +#endif + +/** +* The NIST P-521 curve +*/ +class CurveGFp_P521 : public CurveGFp_NIST + { + public: + CurveGFp_P521(const BigInt& a, const BigInt& b) : CurveGFp_NIST(521, a, b) {} + const BigInt& get_p() const override { return prime_p521(); } + private: + void redc(BigInt& x, secure_vector<word>& ws) const override { redc_p521(x, ws); } + }; + +} + std::shared_ptr<CurveGFp_Repr> CurveGFp::choose_repr(const BigInt& p, const BigInt& a, const BigInt& b) { -#if defined(BOTAN_HAS_CURVEGFP_NISTP_M32) - if(p == CurveGFp_P192::prime()) +#if defined(BOTAN_HAS_NIST_PRIME_REDUCERS_W32) + if(p == prime_p192()) return std::shared_ptr<CurveGFp_Repr>(new CurveGFp_P192(a, b)); - if(p == CurveGFp_P224::prime()) + if(p == prime_p224()) return std::shared_ptr<CurveGFp_Repr>(new CurveGFp_P224(a, b)); - if(p == CurveGFp_P256::prime()) + if(p == prime_p256()) return std::shared_ptr<CurveGFp_Repr>(new CurveGFp_P256(a, b)); - if(p == CurveGFp_P384::prime()) + if(p == prime_p384()) return std::shared_ptr<CurveGFp_Repr>(new CurveGFp_P384(a, b)); #endif - if(p == CurveGFp_P521::prime()) + if(p == prime_p521()) return std::shared_ptr<CurveGFp_Repr>(new CurveGFp_P521(a, b)); return std::shared_ptr<CurveGFp_Repr>(new CurveGFp_Montgomery(p, a, b)); diff --git a/src/lib/math/ec_gfp/curve_gfp.h b/src/lib/math/ec_gfp/curve_gfp.h index 68fe93274..dde9f633e 100644 --- a/src/lib/math/ec_gfp/curve_gfp.h +++ b/src/lib/math/ec_gfp/curve_gfp.h @@ -45,10 +45,6 @@ class CurveGFp_Repr virtual void curve_sqr(BigInt& z, const BigInt& x, secure_vector<word>& ws) const = 0; - - virtual void normalize(BigInt& x, - secure_vector<word>& ws, - size_t bound) const; }; /** @@ -141,16 +137,6 @@ class BOTAN_DLL CurveGFp return z; } - /** - * Adjust x to be in [0,p) - * @param bound if greater than zero, assume that no more than bound - * additions or subtractions are required to move x into range. - */ - void normalize(BigInt& x, secure_vector<word>& ws, size_t bound = 0) const - { - m_repr->normalize(x, ws, bound); - } - void swap(CurveGFp& other) { std::swap(m_repr, other.m_repr); diff --git a/src/lib/math/ec_gfp/curve_nistp.cpp b/src/lib/math/ec_gfp/curve_nistp.cpp index 002cf2d47..bbc11ff21 100644 --- a/src/lib/math/ec_gfp/curve_nistp.cpp +++ b/src/lib/math/ec_gfp/curve_nistp.cpp @@ -1,63 +1,51 @@ /* -* NIST curve reduction +* NIST prime reductions * (C) 2014,2015 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ -#include <botan/internal/curve_nistp.h> +#include <botan/curve_nistp.h> #include <botan/internal/mp_core.h> +#include <botan/internal/mp_asmi.h> namespace Botan { -void CurveGFp_NIST::curve_mul(BigInt& z, const BigInt& x, const BigInt& y, - secure_vector<word>& ws) const - { - if(x.is_zero() || y.is_zero()) - { - z = 0; - return; - } +namespace { - const size_t p_words = get_p_words(); - const size_t output_size = 2*p_words + 1; - ws.resize(2*(p_words+2)); +void normalize(const BigInt& p, BigInt& x, secure_vector<word>& ws, size_t bound) + { + const word* prime = p.data(); + const size_t p_words = p.sig_words(); - z.grow_to(output_size); - z.clear(); + while(x.is_negative()) + x += p; - bigint_mul(z.mutable_data(), output_size, ws.data(), - x.data(), x.size(), x.sig_words(), - y.data(), y.size(), y.sig_words()); + // TODO: provide a high level function for this compare-and-sub operation + x.grow_to(p_words + 1); - this->redc(z, ws); - } + if(ws.size() < p_words + 1) + ws.resize(p_words + 1); -void CurveGFp_NIST::curve_sqr(BigInt& z, const BigInt& x, - secure_vector<word>& ws) const - { - if(x.is_zero()) + for(size_t i = 0; bound == 0 || i < bound; ++i) { - z = 0; - return; - } - - const size_t p_words = get_p_words(); - const size_t output_size = 2*p_words + 1; - - ws.resize(2*(p_words+2)); + const word* xd = x.data(); + word borrow = 0; - z.grow_to(output_size); - z.clear(); + for(size_t i = 0; i != p_words; ++i) + ws[i] = word_sub(xd[i], prime[i], &borrow); + ws[p_words] = word_sub(xd[p_words], 0, &borrow); - bigint_sqr(z.mutable_data(), output_size, ws.data(), - x.data(), x.size(), x.sig_words()); + if(borrow) + break; - this->redc(z, ws); + x.swap_reg(ws); + } } -//static -const BigInt& CurveGFp_P521::prime() +} + +const BigInt& prime_p521() { static const BigInt p521("0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); @@ -65,12 +53,11 @@ const BigInt& CurveGFp_P521::prime() return p521; } -void CurveGFp_P521::redc(BigInt& x, secure_vector<word>& ws) const +void redc_p521(BigInt& x, secure_vector<word>& ws) { - const size_t p_words = get_p_words(); - - const size_t shift_words = 521 / MP_WORD_BITS, - shift_bits = 521 % MP_WORD_BITS; + const size_t p_full_words = 521 / MP_WORD_BITS; + const size_t p_top_bits = 521 % MP_WORD_BITS; + const size_t p_words = p_full_words + 1; const size_t x_sw = x.sig_words(); @@ -81,16 +68,16 @@ void CurveGFp_P521::redc(BigInt& x, secure_vector<word>& ws) const ws.resize(p_words + 1); clear_mem(ws.data(), ws.size()); - bigint_shr2(ws.data(), x.data(), x_sw, shift_words, shift_bits); + bigint_shr2(ws.data(), x.data(), x_sw, p_full_words, p_top_bits); x.mask_bits(521); bigint_add3(x.mutable_data(), x.data(), p_words, ws.data(), p_words); - normalize(x, ws, max_redc_subtractions()); + normalize(prime_p521(), x, ws, 1); } -#if defined(BOTAN_HAS_CURVEGFP_NISTP_M32) +#if defined(BOTAN_HAS_NIST_PRIME_REDUCERS_W32) namespace { @@ -130,14 +117,13 @@ inline void set_u32bit(BigInt& x, size_t i, T v_in) } -//static -const BigInt& CurveGFp_P192::prime() +const BigInt& prime_p192() { static const BigInt p192("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF"); return p192; } -void CurveGFp_P192::redc(BigInt& x, secure_vector<word>& ws) const +void redc_p192(BigInt& x, secure_vector<word>& ws) { const u32bit X6 = get_u32bit(x, 6); const u32bit X7 = get_u32bit(x, 7); @@ -192,17 +178,16 @@ void CurveGFp_P192::redc(BigInt& x, secure_vector<word>& ws) const // No underflow possible - normalize(x, ws, max_redc_subtractions()); + normalize(prime_p192(), x, ws, 3); } -//static -const BigInt& CurveGFp_P224::prime() +const BigInt& prime_p224() { static const BigInt p224("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001"); return p224; } -void CurveGFp_P224::redc(BigInt& x, secure_vector<word>& ws) const +void redc_p224(BigInt& x, secure_vector<word>& ws) { const u32bit X7 = get_u32bit(x, 7); const u32bit X8 = get_u32bit(x, 8); @@ -271,17 +256,16 @@ void CurveGFp_P224::redc(BigInt& x, secure_vector<word>& ws) const BOTAN_ASSERT_EQUAL(S >> 32, 0, "No underflow"); - normalize(x, ws, max_redc_subtractions()); + normalize(prime_p224(), x, ws, 3); } -//static -const BigInt& CurveGFp_P256::prime() +const BigInt& prime_p256() { static const BigInt p256("0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF"); return p256; } -void CurveGFp_P256::redc(BigInt& x, secure_vector<word>& ws) const +void redc_p256(BigInt& x, secure_vector<word>& ws) { const u32bit X8 = get_u32bit(x, 8); const u32bit X9 = get_u32bit(x, 9); @@ -396,34 +380,35 @@ void CurveGFp_P256::redc(BigInt& x, secure_vector<word>& ws) const BOTAN_ASSERT_EQUAL(S >> 32, 0, "No underflow"); + #if 0 if(S >= 2) { BOTAN_ASSERT(S <= 10, "Expected overflow"); static const BigInt P256_mults[9] = { - 2*get_p(), - 3*get_p(), - 4*get_p(), - 5*get_p(), - 6*get_p(), - 7*get_p(), - 8*get_p(), - 9*get_p(), - 10*get_p() + 2*CurveGFp_P256::prime(), + 3*CurveGFp_P256::prime(), + 4*CurveGFp_P256::prime(), + 5*CurveGFp_P256::prime(), + 6*CurveGFp_P256::prime(), + 7*CurveGFp_P256::prime(), + 8*CurveGFp_P256::prime(), + 9*CurveGFp_P256::prime(), + 10*CurveGFp_P256::prime() }; x -= P256_mults[S - 2]; } + #endif - normalize(x, ws, max_redc_subtractions()); + normalize(prime_p256(), x, ws, 10); } -//static -const BigInt& CurveGFp_P384::prime() +const BigInt& prime_p384() { static const BigInt p384("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF"); return p384; } -void CurveGFp_P384::redc(BigInt& x, secure_vector<word>& ws) const +void redc_p384(BigInt& x, secure_vector<word>& ws) { const u32bit X12 = get_u32bit(x, 12); const u32bit X13 = get_u32bit(x, 13); @@ -569,20 +554,22 @@ void CurveGFp_P384::redc(BigInt& x, secure_vector<word>& ws) const BOTAN_ASSERT_EQUAL(S >> 32, 0, "No underflow"); set_u32bit(x, 12, S); + #if 0 if(S >= 2) { BOTAN_ASSERT(S <= 4, "Expected overflow"); static const BigInt P384_mults[3] = { - 2*get_p(), - 3*get_p(), - 4*get_p() + 2*CurveGFp_P384::prime(), + 3*CurveGFp_P384::prime(), + 4*CurveGFp_P384::prime() }; x -= P384_mults[S - 2]; } + #endif - normalize(x, ws, max_redc_subtractions()); + normalize(prime_p384(), x, ws, 4); } #endif diff --git a/src/lib/math/ec_gfp/curve_nistp.h b/src/lib/math/ec_gfp/curve_nistp.h index 0bf707f58..e7af69964 100644 --- a/src/lib/math/ec_gfp/curve_nistp.h +++ b/src/lib/math/ec_gfp/curve_nistp.h @@ -1,152 +1,46 @@ /* -* NIST elliptic curves over GF(p) -* (C) 2014 Jack Lloyd +* Arithmetic operations specialized for NIST ECC primes +* (C) 2014,2015 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ -#ifndef BOTAN_GFP_CURVE_NIST_H__ -#define BOTAN_GFP_CURVE_NIST_H__ +#ifndef BOTAN_NIST_PRIMES_H__ +#define BOTAN_NIST_PRIMES_H__ -#include <botan/curve_gfp.h> -#include <memory> +#include <botan/bigint.h> namespace Botan { -class CurveGFp_NIST : public CurveGFp_Repr - { - public: - CurveGFp_NIST(size_t p_bits, const BigInt& a, const BigInt& b) : - m_a(a), m_b(b), m_p_words((p_bits + BOTAN_MP_WORD_BITS - 1) / BOTAN_MP_WORD_BITS) - { - } - - size_t get_p_words() const override { return m_p_words; } - - const BigInt& get_a() const override { return m_a; } - - const BigInt& get_b() const override { return m_b; } - - const BigInt& get_a_rep() const override { return m_a; } - - const BigInt& get_b_rep() const override { return m_b; } - - void to_curve_rep(BigInt& x, secure_vector<word>& ws) const override - { redc(x, ws); } - - void from_curve_rep(BigInt& x, secure_vector<word>& ws) const override - { redc(x, ws); } - - void curve_mul(BigInt& z, const BigInt& x, const BigInt& y, - secure_vector<word>& ws) const override; - - void curve_sqr(BigInt& z, const BigInt& x, - secure_vector<word>& ws) const override; - private: - virtual void redc(BigInt& x, secure_vector<word>& ws) const = 0; - - virtual size_t max_redc_subtractions() const = 0; - - // Curve parameters - BigInt m_a, m_b; - size_t m_p_words; // cache of m_p.sig_words() - }; - -#if (BOTAN_MP_WORD_BITS == 32) || (BOTAN_MP_WORD_BITS == 64) - -#define BOTAN_HAS_CURVEGFP_NISTP_M32 - -/** -* The NIST P-192 curve -*/ -class CurveGFp_P192 : public CurveGFp_NIST - { - public: - CurveGFp_P192(const BigInt& a, const BigInt& b) : CurveGFp_NIST(192, a, b) {} - - static const BigInt& prime(); - - const BigInt& get_p() const override { return CurveGFp_P192::prime(); } - - private: - void redc(BigInt& x, secure_vector<word>& ws) const override; - - size_t max_redc_subtractions() const override { return 3; } - }; - /** -* The NIST P-224 curve -*/ -class CurveGFp_P224 : public CurveGFp_NIST - { - public: - CurveGFp_P224(const BigInt& a, const BigInt& b) : CurveGFp_NIST(224, a, b) {} - - static const BigInt& prime(); - - const BigInt& get_p() const override { return CurveGFp_P224::prime(); } - private: - void redc(BigInt& x, secure_vector<word>& ws) const override; - - size_t max_redc_subtractions() const override { return 3; } - }; - -/** -* The NIST P-256 curve +* NIST Prime reduction functions. +* +* Reduces the value in place +* +* ws is a workspace function which is used as a temporary, +* and will be resized as needed. */ -class CurveGFp_P256 : public CurveGFp_NIST - { - public: - CurveGFp_P256(const BigInt& a, const BigInt& b) : CurveGFp_NIST(256, a, b) {} - - static const BigInt& prime(); - - const BigInt& get_p() const override { return CurveGFp_P256::prime(); } - - private: - void redc(BigInt& x, secure_vector<word>& ws) const override; +BOTAN_DLL const BigInt& prime_p521(); +BOTAN_DLL void redc_p521(BigInt& x, secure_vector<word>& ws); - size_t max_redc_subtractions() const override { return 10; } - }; +#if (BOTAN_MP_WORD_BITS == 32) || (BOTAN_MP_WORD_BITS == 64) -/** -* The NIST P-384 curve -*/ -class CurveGFp_P384 : public CurveGFp_NIST - { - public: - CurveGFp_P384(const BigInt& a, const BigInt& b) : CurveGFp_NIST(384, a, b) {} +#define BOTAN_HAS_NIST_PRIME_REDUCERS_W32 - static const BigInt& prime(); +BOTAN_DLL const BigInt& prime_p384(); +BOTAN_DLL void redc_p384(BigInt& x, secure_vector<word>& ws); - const BigInt& get_p() const override { return CurveGFp_P384::prime(); } +BOTAN_DLL const BigInt& prime_p256(); +BOTAN_DLL void redc_p256(BigInt& x, secure_vector<word>& ws); - private: - void redc(BigInt& x, secure_vector<word>& ws) const override; +BOTAN_DLL const BigInt& prime_p224(); +BOTAN_DLL void redc_p224(BigInt& x, secure_vector<word>& ws); - size_t max_redc_subtractions() const override { return 4; } - }; +BOTAN_DLL const BigInt& prime_p192(); +BOTAN_DLL void redc_p192(BigInt& x, secure_vector<word>& ws); #endif -/** -* The NIST P-521 curve -*/ -class CurveGFp_P521 : public CurveGFp_NIST - { - public: - CurveGFp_P521(const BigInt& a, const BigInt& b) : CurveGFp_NIST(521, a, b) {} - - static const BigInt& prime(); - - const BigInt& get_p() const override { return CurveGFp_P521::prime(); } - - private: - void redc(BigInt& x, secure_vector<word>& ws) const override; - - size_t max_redc_subtractions() const override { return 1; } - }; - } #endif diff --git a/src/lib/math/ec_gfp/info.txt b/src/lib/math/ec_gfp/info.txt index 9af40c752..060551562 100644 --- a/src/lib/math/ec_gfp/info.txt +++ b/src/lib/math/ec_gfp/info.txt @@ -2,15 +2,6 @@ define EC_CURVE_GFP 20131128 load_on auto -<header:public> -curve_gfp.h -point_gfp.h -</header:public> - -<header:internal> -curve_nistp.h -</header:internal> - <requires> numbertheory </requires> diff --git a/src/lib/math/numbertheory/info.txt b/src/lib/math/numbertheory/info.txt index e39a236cb..49f7ab2fb 100644 --- a/src/lib/math/numbertheory/info.txt +++ b/src/lib/math/numbertheory/info.txt @@ -12,20 +12,6 @@ reducer.h def_powm.h </header:internal> -<source> -dsa_gen.cpp -jacobi.cpp -make_prm.cpp -mp_numth.cpp -numthry.cpp -pow_mod.cpp -powm_fw.cpp -powm_mnt.cpp -primes.cpp -reducer.cpp -ressol.cpp -</source> - <requires> bigint hash diff --git a/src/tests/test_bigint.cpp b/src/tests/test_bigint.cpp index 748f26ce9..dabe5746e 100644 --- a/src/tests/test_bigint.cpp +++ b/src/tests/test_bigint.cpp @@ -21,27 +21,43 @@ #include <botan/bigint.h> #include <botan/exceptn.h> #include <botan/numthry.h> +#include <botan/reducer.h> + +#if defined(BOTAN_HAS_EC_CURVE_GFP) +#include <botan/curve_nistp.h> +#endif using namespace Botan; namespace { -void test_failure(const char* function, const char* file, int line, - const std::string& what_failed) +class Test_State { - std::cout << "FAIL " << function << " " << file << ":" << line << " " - << what_failed << std::endl; - } + public: + void started(const std::string& /*msg*/) { m_tests_run++; } + + void test_ran(const char* msg); + + void failure(const char* test, const std::string& what_failed) + { + std::cout << "FAIL " << test << " " << what_failed << "\n"; + m_tests_failed++; + } + + size_t ran() const { return m_tests_run; } + size_t failed() const { return m_tests_failed; } + private: + size_t m_tests_run = 0, m_tests_failed = 0; + }; #define BOTAN_CONFIRM_NOTHROW(block) do { \ try { block } \ catch(std::exception& e) { \ - test_failure(BOTAN_CURRENT_FUNCTION, __FILE__, __LINE__, e.what()); \ - ++tests_failed; \ + _test.failure(BOTAN_CURRENT_FUNCTION, e.what()); \ } } while(0) \ #define BOTAN_TEST(lhs, rhs, msg) do { \ - ++tests_run; \ + _test.started(msg); \ BOTAN_CONFIRM_NOTHROW({ \ const auto lhs_val = lhs; \ const auto rhs_val = rhs; \ @@ -52,19 +68,19 @@ void test_failure(const char* function, const char* file, int line, fmt << "expr '" << #lhs << " == " << #rhs << "' false, " \ << "actually " << lhs_val << " " << rhs_val \ << " (" << msg << ")"; \ - test_failure(BOTAN_CURRENT_FUNCTION, __FILE__, __LINE__, fmt.str()); \ - ++tests_failed; \ + _test.failure(BOTAN_CURRENT_FUNCTION, fmt.str()); \ } \ }); \ } while(0) -#define BOTAN_TEST_CASE(name, block) size_t test_ ## name() { \ - size_t tests_run = 0, tests_failed = 0; \ +#define BOTAN_TEST_CASE(name, descr, block) size_t test_ ## name() { \ + Test_State _test; \ BOTAN_CONFIRM_NOTHROW(block); \ - return tests_failed; \ + test_report(descr, _test.ran(), _test.failed()); \ + return _test.failed(); \ } -BOTAN_TEST_CASE(bigint_to_u32bit, { +BOTAN_TEST_CASE(bigint_to_u32bit, "BigInt to_u32bit", { for(size_t i = 0; i != 32; ++i) { const u32bit in = 1 << i; @@ -72,6 +88,100 @@ BOTAN_TEST_CASE(bigint_to_u32bit, { } }); +BigInt test_integer(RandomNumberGenerator& rng, size_t bits) + { + /* + Produces integers with long runs of ones and zeros, for testing for + carry handling problems. + */ + BigInt x = 0; + + auto flip_prob = [](size_t i) { + if(i % 64 == 0) + return .5; + if(i % 32 == 0) + return .4; + if(i % 8 == 0) + return .05; + return .01; + }; + + bool active = rng.next_byte() % 2; + for(size_t i = 0; i != bits; ++i) + { + x <<= 1; + x += static_cast<int>(active); + + const double prob = flip_prob(i); + const double sample = double(rng.next_byte() % 100) / 100.0; // biased + + if(sample < prob) + active = !active; + } + + //std::cout << std::hex << x << "\n"; + return x; + } + +#if defined(BOTAN_HAS_EC_CURVE_GFP) + +void nist_redc_test(Test_State& _test, + const std::string& prime_name, + const BigInt& p, + std::function<void (BigInt&, secure_vector<word>&)> redc_fn) + { + auto& rng = test_rng(); + const size_t trials = 100; + const size_t p_bits = p.bits(); + + Modular_Reducer p_redc(p); + secure_vector<word> ws; + + for(size_t i = 0; i != trials; ++i) + { + const BigInt x = test_integer(rng, 2*p_bits); + + // TODO: time and report all three approaches + const BigInt v1 = x % p; + const BigInt v2 = p_redc.reduce(x); + + BigInt v3 = x; + redc_fn(v3, ws); + + BOTAN_TEST(v1, v2, "reference"); + BOTAN_TEST(v2, v3, "specialized"); + + if(v1 != v2 || v2 != v3) + std::cout << "Prime " << prime_name << " input " << x << "\n"; + } + } + +#if defined(BOTAN_HAS_NIST_PRIME_REDUCERS_W32) + +BOTAN_TEST_CASE(bigint_redc_p192, "P-192 reduction", { + nist_redc_test(_test, "P-192", prime_p192(), redc_p192); + }); + +BOTAN_TEST_CASE(bigint_redc_p224, "P-224 reduction", { + nist_redc_test(_test, "P-224", prime_p224(), redc_p224); + }); + +BOTAN_TEST_CASE(bigint_redc_p256, "P-256 reduction", { + nist_redc_test(_test, "P-256", prime_p256(), redc_p256); + }); + +BOTAN_TEST_CASE(bigint_redc_p384, "P-384 reduction", { + nist_redc_test(_test, "P-384", prime_p384(), redc_p384); + }); + +#endif + +BOTAN_TEST_CASE(bigint_redc_p521, "P-521 reduction", { + nist_redc_test(_test, "P-521", prime_p521(), redc_p521); + }); + +#endif + void strip_comments(std::string& line) { if(line.find('#') != std::string::npos) @@ -349,8 +459,6 @@ size_t test_bigint() bool first = true; size_t counter = 0; - total_errors += test_bigint_to_u32bit(); - auto& rng = test_rng(); while(!test_data.eof()) @@ -429,6 +537,20 @@ size_t test_bigint() << std::dec << alg_count << std::endl; } + total_errors += test_bigint_to_u32bit(); + +#if defined(BOTAN_HAS_EC_CURVE_GFP) + +#if defined(BOTAN_HAS_NIST_PRIME_REDUCERS_W32) + total_errors += test_bigint_redc_p192(); + total_errors += test_bigint_redc_p224(); + total_errors += test_bigint_redc_p256(); + total_errors += test_bigint_redc_p384(); + #endif + + total_errors += test_bigint_redc_p521(); +#endif + return total_errors; } |