diff options
author | Jack Lloyd <[email protected]> | 2018-12-01 14:05:24 -0500 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2018-12-01 14:05:24 -0500 |
commit | 931302e2457ef90b3b3b7dacdeeee2b143bfee66 (patch) | |
tree | 0b2607f4193a899c4012e3072f4a71e9d17128e4 | |
parent | 1e9e5d2f3bdac32838ad99b5718cad46cca693f3 (diff) | |
parent | be796a3f30d4bec1af7c0e6770a0397dca6ccd4a (diff) |
Merge GH #1755 Various BigInt improvements
-rw-r--r-- | src/lib/math/bigint/big_ops2.cpp | 70 | ||||
-rw-r--r-- | src/lib/math/bigint/big_ops3.cpp | 17 | ||||
-rw-r--r-- | src/lib/math/bigint/bigint.cpp | 2 | ||||
-rw-r--r-- | src/lib/math/bigint/bigint.h | 14 | ||||
-rw-r--r-- | src/lib/math/mp/mp_core.h | 41 | ||||
-rw-r--r-- | src/lib/math/numbertheory/monty.cpp | 22 | ||||
-rw-r--r-- | src/lib/math/numbertheory/nistp_redc.cpp | 61 | ||||
-rw-r--r-- | src/lib/pubkey/ec_group/curve_gfp.cpp | 9 | ||||
-rw-r--r-- | src/lib/pubkey/ec_group/curve_gfp.h | 7 | ||||
-rw-r--r-- | src/lib/pubkey/ec_group/point_gfp.cpp | 21 | ||||
-rw-r--r-- | src/lib/pubkey/ec_group/point_gfp.h | 3 | ||||
-rw-r--r-- | src/tests/data/bn/mod.vec | 12 | ||||
-rw-r--r-- | src/tests/test_bigint.cpp | 7 |
13 files changed, 178 insertions, 108 deletions
diff --git a/src/lib/math/bigint/big_ops2.cpp b/src/lib/math/bigint/big_ops2.cpp index 6ce14f8f1..d35dc082e 100644 --- a/src/lib/math/bigint/big_ops2.cpp +++ b/src/lib/math/bigint/big_ops2.cpp @@ -126,19 +126,41 @@ BigInt& BigInt::mod_sub(const BigInt& s, const BigInt& mod, secure_vector<word>& swap_reg(ws); } #else - // is t < s or not? - const auto is_lt = bigint_ct_is_lt(data(), mod_sw, s.data(), mod_sw); + if(mod_sw == 4) + bigint_mod_sub_n<4>(mutable_data(), s.data(), mod.data(), ws.data()); + else if(mod_sw == 6) + bigint_mod_sub_n<6>(mutable_data(), s.data(), mod.data(), ws.data()); + else + bigint_mod_sub(mutable_data(), s.data(), mod.data(), mod_sw, ws.data()); +#endif - // ws = p - s - const word borrow = bigint_sub3(ws.data(), mod.data(), mod_sw, s.data(), mod_sw); + return (*this); + } - // Compute either (t - s) or (t + (p - s)) depending on mask - const word carry = bigint_cnd_addsub(is_lt, mutable_data(), ws.data(), s.data(), mod_sw); +BigInt& BigInt::mod_mul(uint8_t y, const BigInt& mod, secure_vector<word>& ws) + { + BOTAN_ARG_CHECK(this->is_negative() == false, "*this must be positive"); + BOTAN_ARG_CHECK(y < 16, "y too large"); - BOTAN_DEBUG_ASSERT(borrow == 0 && carry == 0); - BOTAN_UNUSED(carry, borrow); -#endif + BOTAN_DEBUG_ASSERT(*this < mod); + + switch(y) + { + case 2: + *this <<= 1; + break; + case 4: + *this <<= 2; + break; + case 8: + *this <<= 3; + break; + default: + *this *= static_cast<word>(y); + break; + } + this->reduce_below(mod, ws); return (*this); } @@ -271,18 +293,18 @@ word BigInt::operator%=(word mod) if(mod == 0) throw BigInt::DivideByZero(); + word remainder = 0; + if(is_power_of_2(mod)) { - const word remainder = (word_at(0) & (mod - 1)); - m_data.set_to_zero(); - m_data.set_word_at(0, remainder); - return remainder; + remainder = (word_at(0) & (mod - 1)); } - - word remainder = 0; - - for(size_t j = sig_words(); j > 0; --j) - remainder = bigint_modop(remainder, word_at(j-1), mod); + else + { + const size_t sw = sig_words(); + for(size_t i = sw; i > 0; --i) + remainder = bigint_modop(remainder, word_at(i-1), mod); + } if(remainder && sign() == BigInt::Negative) remainder = mod - remainder; @@ -290,8 +312,7 @@ word BigInt::operator%=(word mod) m_data.set_to_zero(); m_data.set_word_at(0, remainder); set_sign(BigInt::Positive); - - return word_at(0); + return remainder; } /* @@ -301,9 +322,9 @@ BigInt& BigInt::operator<<=(size_t shift) { if(shift) { - const size_t shift_words = shift / BOTAN_MP_WORD_BITS, - shift_bits = shift % BOTAN_MP_WORD_BITS, - words = sig_words(); + const size_t shift_words = shift / BOTAN_MP_WORD_BITS; + const size_t shift_bits = shift % BOTAN_MP_WORD_BITS; + const size_t words = size(); /* * FIXME - if shift_words == 0 && the top shift_bits of the top word @@ -329,9 +350,8 @@ BigInt& BigInt::operator>>=(size_t shift) { const size_t shift_words = shift / BOTAN_MP_WORD_BITS; const size_t shift_bits = shift % BOTAN_MP_WORD_BITS; - const size_t sw = sig_words(); - bigint_shr1(m_data.mutable_data(), sw, shift_words, shift_bits); + bigint_shr1(m_data.mutable_data(), m_data.size(), shift_words, shift_bits); if(is_negative() && is_zero()) set_sign(Positive); diff --git a/src/lib/math/bigint/big_ops3.cpp b/src/lib/math/bigint/big_ops3.cpp index a38448050..7a4c8f215 100644 --- a/src/lib/math/bigint/big_ops3.cpp +++ b/src/lib/math/bigint/big_ops3.cpp @@ -127,13 +127,20 @@ word operator%(const BigInt& n, word mod) if(mod == 1) return 0; - if(is_power_of_2(mod)) - return (n.word_at(0) & (mod - 1)); - word remainder = 0; - for(size_t j = n.sig_words(); j > 0; --j) - remainder = bigint_modop(remainder, n.word_at(j-1), mod); + if(is_power_of_2(mod)) + { + remainder = (n.word_at(0) & (mod - 1)); + } + else + { + const size_t sw = n.sig_words(); + for(size_t i = sw; i > 0; --i) + { + remainder = bigint_modop(remainder, n.word_at(i-1), mod); + } + } if(remainder && n.sign() == BigInt::Negative) return mod - remainder; diff --git a/src/lib/math/bigint/bigint.cpp b/src/lib/math/bigint/bigint.cpp index 667035686..d64082476 100644 --- a/src/lib/math/bigint/bigint.cpp +++ b/src/lib/math/bigint/bigint.cpp @@ -335,8 +335,6 @@ void BigInt::reduce_below(const BigInt& p, secure_vector<word>& ws) for(;;) { word borrow = bigint_sub3(ws.data(), data(), p_words + 1, p.data(), p_words); - - //CT::unpoison(borrow); // fixme if(borrow) break; diff --git a/src/lib/math/bigint/bigint.h b/src/lib/math/bigint/bigint.h index 58c45dd67..9b385348e 100644 --- a/src/lib/math/bigint/bigint.h +++ b/src/lib/math/bigint/bigint.h @@ -328,7 +328,17 @@ class BOTAN_PUBLIC_API(2,0) BigInt final BigInt& mod_sub(const BigInt& y, const BigInt& mod, secure_vector<word>& ws); /** - * Return *this below mod + * Set *this to (*this * y) % mod + * This function assumes *this is >= 0 && < mod + * y should be small, less than 16 + * @param y the small integer to multiply by + * @param mod the positive modulus + * @param ws a temp workspace + */ + BigInt& mod_mul(uint8_t y, const BigInt& mod, secure_vector<word>& ws); + + /** + * Return *this % mod * * Assumes that *this is (if anything) only slightly larger than * mod and performs repeated subtractions. It should not be used if @@ -933,7 +943,7 @@ class BOTAN_PUBLIC_API(2,0) BigInt final if(n > size()) { if(n <= m_reg.capacity()) - m_reg.resize(m_reg.capacity()); + m_reg.resize(n); else m_reg.resize(n + (8 - (n % 8))); } diff --git a/src/lib/math/mp/mp_core.h b/src/lib/math/mp/mp_core.h index 6e2fba049..2824a3456 100644 --- a/src/lib/math/mp/mp_core.h +++ b/src/lib/math/mp/mp_core.h @@ -685,6 +685,47 @@ bigint_sub_abs(word z[], } /** +* Set t to t-s modulo mod +* +* @param t first integer +* @param s second integer +* @param mod the modulus +* @param mod_sw size of t, s, and mod +* @param ws workspace of size mod_sw +*/ +inline void +bigint_mod_sub(word t[], const word s[], const word mod[], size_t mod_sw, word ws[]) + { + // is t < s or not? + const auto is_lt = bigint_ct_is_lt(t, mod_sw, s, mod_sw); + + // ws = p - s + const word borrow = bigint_sub3(ws, mod, mod_sw, s, mod_sw); + + // Compute either (t - s) or (t + (p - s)) depending on mask + const word carry = bigint_cnd_addsub(is_lt, t, ws, s, mod_sw); + + BOTAN_DEBUG_ASSERT(borrow == 0 && carry == 0); + BOTAN_UNUSED(carry, borrow); + } + +template<size_t N> +inline void bigint_mod_sub_n(word t[], const word s[], const word mod[], word ws[]) + { + // is t < s or not? + const auto is_lt = bigint_ct_is_lt(t, N, s, N); + + // ws = p - s + const word borrow = bigint_sub3(ws, mod, N, s, N); + + // Compute either (t - s) or (t + (p - s)) depending on mask + const word carry = bigint_cnd_addsub(is_lt, t, ws, s, N); + + BOTAN_DEBUG_ASSERT(borrow == 0 && carry == 0); + BOTAN_UNUSED(carry, borrow); + } + +/** * Compute ((n1<<bits) + n0) / d */ inline word bigint_divop(word n1, word n0, word d) diff --git a/src/lib/math/numbertheory/monty.cpp b/src/lib/math/numbertheory/monty.cpp index 61a10eae5..f3d85e44c 100644 --- a/src/lib/math/numbertheory/monty.cpp +++ b/src/lib/math/numbertheory/monty.cpp @@ -312,17 +312,17 @@ BigInt Montgomery_Int::value() const Montgomery_Int Montgomery_Int::operator+(const Montgomery_Int& other) const { - BigInt z = m_v + other.m_v; secure_vector<word> ws; - z.reduce_below(m_params->p(), ws); + BigInt z = m_v; + z.mod_add(other.m_v, m_params->p(), ws); return Montgomery_Int(m_params, z, false); } Montgomery_Int Montgomery_Int::operator-(const Montgomery_Int& other) const { - BigInt z = m_v - other.m_v; - if(z.is_negative()) - z += m_params->p(); + secure_vector<word> ws; + BigInt z = m_v; + z.mod_sub(other.m_v, m_params->p(), ws); return Montgomery_Int(m_params, z, false); } @@ -420,29 +420,25 @@ Montgomery_Int Montgomery_Int::additive_inverse() const Montgomery_Int& Montgomery_Int::mul_by_2(secure_vector<word>& ws) { - m_v <<= 1; - m_v.reduce_below(m_params->p(), ws); + m_v.mod_mul(2, m_params->p(), ws); return (*this); } Montgomery_Int& Montgomery_Int::mul_by_3(secure_vector<word>& ws) { - m_v *= 3; - m_v.reduce_below(m_params->p(), ws); + m_v.mod_mul(3, m_params->p(), ws); return (*this); } Montgomery_Int& Montgomery_Int::mul_by_4(secure_vector<word>& ws) { - m_v <<= 2; - m_v.reduce_below(m_params->p(), ws); + m_v.mod_mul(4, m_params->p(), ws); return (*this); } Montgomery_Int& Montgomery_Int::mul_by_8(secure_vector<word>& ws) { - m_v <<= 3; - m_v.reduce_below(m_params->p(), ws); + m_v.mod_mul(8, m_params->p(), ws); return (*this); } diff --git a/src/lib/math/numbertheory/nistp_redc.cpp b/src/lib/math/numbertheory/nistp_redc.cpp index a74c4de9f..caa071668 100644 --- a/src/lib/math/numbertheory/nistp_redc.cpp +++ b/src/lib/math/numbertheory/nistp_redc.cpp @@ -8,6 +8,7 @@ #include <botan/curve_nistp.h> #include <botan/internal/mp_core.h> #include <botan/internal/mp_asmi.h> +#include <botan/internal/ct_utils.h> namespace Botan { @@ -25,6 +26,20 @@ void redc_p521(BigInt& x, secure_vector<word>& ws) const size_t p_top_bits = 521 % BOTAN_MP_WORD_BITS; const size_t p_words = p_full_words + 1; +#if (BOTAN_MP_WORD_BITS == 64) + static const word p521_words[p_words] = { + 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, + 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, + 0x1FF }; +#else + static const word p521_words[p_words] = { + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x1FF }; +#endif + if(ws.size() < p_words + 1) ws.resize(p_words + 1); @@ -38,39 +53,26 @@ void redc_p521(BigInt& x, secure_vector<word>& ws) word carry = bigint_add3_nc(x.mutable_data(), x.data(), p_words, ws.data(), p_words); BOTAN_ASSERT_EQUAL(carry, 0, "Final carry in P-521 reduction"); - // Now find the actual carry in bit 522 - const word bit_522_set = x.word_at(p_full_words) >> p_top_bits; + const word top_word = x.word_at(p_full_words); /* - * If bit 522 is set then we overflowed and must reduce. Otherwise, if the - * top bit is set, it is possible we have x == 2**521 - 1 so check for that. + * Check if we need to reduce modulo P + * There are two possible cases: + * - The result overflowed past 521 bits, in which case bit 522 will be set + * - The result is exactly 2**521 - 1 */ - if(bit_522_set) - { -#if (BOTAN_MP_WORD_BITS == 64) - static const word p521_words[9] = { - 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, - 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, - 0x1FF }; + const auto bit_522_set = CT::Mask<word>::expand(top_word >> p_top_bits); - bigint_sub2(x.mutable_data(), p_words, p521_words, 9); -#else - x -= prime_p521(); -#endif - } - else if(x.word_at(p_full_words) >> (p_top_bits - 1)) - { - /* - * Otherwise we must reduce if p is exactly 2^512-1 - */ - - word possibly_521 = MP_WORD_MAX; - for(size_t i = 0; i != p_full_words; ++i) - possibly_521 &= x.word_at(i); - - if(possibly_521 == MP_WORD_MAX) - x.reduce_below(prime_p521(), ws); - } + word and_512 = MP_WORD_MAX; + for(size_t i = 0; i != p_full_words; ++i) + and_512 &= x.word_at(i); + const auto all_512_low_bits_set = CT::Mask<word>::is_equal(and_512, MP_WORD_MAX); + const auto has_p521_top_word = CT::Mask<word>::is_equal(top_word, 0x1FF); + const auto is_p521 = all_512_low_bits_set & has_p521_top_word; + + const auto needs_reduction = is_p521 | bit_522_set; + + bigint_cnd_sub(needs_reduction.value(), x.mutable_data(), p521_words, p_words); } #if defined(BOTAN_HAS_NIST_PRIME_REDUCERS_W32) @@ -576,5 +578,4 @@ void redc_p384(BigInt& x, secure_vector<word>& ws) #endif - } diff --git a/src/lib/pubkey/ec_group/curve_gfp.cpp b/src/lib/pubkey/ec_group/curve_gfp.cpp index bd68a3ed7..f2f5607e1 100644 --- a/src/lib/pubkey/ec_group/curve_gfp.cpp +++ b/src/lib/pubkey/ec_group/curve_gfp.cpp @@ -60,8 +60,6 @@ class CurveGFp_Montgomery final : public CurveGFp_Repr size_t get_ws_size() const override { return 2*m_p_words + 4; } - void redc_mod_p(BigInt& z, secure_vector<word>& ws) const override; - BigInt invert_element(const BigInt& x, secure_vector<word>& ws) const override; void to_curve_rep(BigInt& x, secure_vector<word>& ws) const override; @@ -93,11 +91,6 @@ class CurveGFp_Montgomery final : public CurveGFp_Repr bool m_a_is_minus_3; }; -void CurveGFp_Montgomery::redc_mod_p(BigInt& z, secure_vector<word>& ws) const - { - z.reduce_below(m_p, ws); - } - BigInt CurveGFp_Montgomery::invert_element(const BigInt& x, secure_vector<word>& ws) const { // Should we use Montgomery inverse instead? @@ -207,6 +200,8 @@ class CurveGFp_NIST : public CurveGFp_Repr void from_curve_rep(BigInt& x, secure_vector<word>& ws) const override { redc_mod_p(x, ws); } + virtual void redc_mod_p(BigInt& z, secure_vector<word>& ws) const = 0; + BigInt invert_element(const BigInt& x, secure_vector<word>& ws) const override; void curve_mul_words(BigInt& z, diff --git a/src/lib/pubkey/ec_group/curve_gfp.h b/src/lib/pubkey/ec_group/curve_gfp.h index d03247244..fe7a0a54d 100644 --- a/src/lib/pubkey/ec_group/curve_gfp.h +++ b/src/lib/pubkey/ec_group/curve_gfp.h @@ -49,8 +49,6 @@ class BOTAN_UNSTABLE_API CurveGFp_Repr */ virtual const BigInt& get_1_rep() const = 0; - virtual void redc_mod_p(BigInt& z, secure_vector<word>& ws) const = 0; - virtual BigInt invert_element(const BigInt& x, secure_vector<word>& ws) const = 0; virtual void to_curve_rep(BigInt& x, secure_vector<word>& ws) const = 0; @@ -171,11 +169,6 @@ class BOTAN_UNSTABLE_API CurveGFp final // TODO: from_rep taking && ref - void redc_mod_p(BigInt& z, secure_vector<word>& ws) const - { - m_repr->redc_mod_p(z, ws); - } - void mul(BigInt& z, const BigInt& x, const BigInt& y, secure_vector<word>& ws) const { m_repr->curve_mul(z, x, y, ws); diff --git a/src/lib/pubkey/ec_group/point_gfp.cpp b/src/lib/pubkey/ec_group/point_gfp.cpp index 7bc6c4975..b4b3871cb 100644 --- a/src/lib/pubkey/ec_group/point_gfp.cpp +++ b/src/lib/pubkey/ec_group/point_gfp.cpp @@ -2,7 +2,7 @@ * Point arithmetic on elliptic curves over GF(p) * * (C) 2007 Martin Doering, Christoph Ludwig, Falko Strenzke -* 2008-2011,2012,2014,2015 Jack Lloyd +* 2008-2011,2012,2014,2015,2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ @@ -152,6 +152,7 @@ void PointGFp::add_affine(const word x_words[], size_t x_size, m_curve.sqr(m_coord_x, T0, ws); m_coord_x.mod_sub(T1, p, sub_ws); + m_coord_x.mod_sub(T3, p, sub_ws); m_coord_x.mod_sub(T3, p, sub_ws); @@ -303,15 +304,13 @@ void PointGFp::mult2(std::vector<BigInt>& ws_bn) m_curve.sqr(T0, m_coord_y, ws); m_curve.mul(T1, m_coord_x, T0, ws); - T1 <<= 2; // * 4 - m_curve.redc_mod_p(T1, sub_ws); + T1.mod_mul(4, p, sub_ws); if(m_curve.a_is_zero()) { // if a == 0 then 3*x^2 + a*z^4 is just 3*x^2 m_curve.sqr(T4, m_coord_x, ws); // x^2 - T4 *= 3; // 3*x^2 - m_curve.redc_mod_p(T4, sub_ws); + T4.mod_mul(3, p, sub_ws); // 3*x^2 } else if(m_curve.a_is_minus_3()) { @@ -330,8 +329,7 @@ void PointGFp::mult2(std::vector<BigInt>& ws_bn) m_curve.mul(T4, T2, T3, ws); // (x-z^2)*(x+z^2) - T4 *= 3; // 3*(x-z^2)*(x+z^2) - m_curve.redc_mod_p(T4, sub_ws); + T4.mod_mul(3, p, sub_ws); // 3*(x-z^2)*(x+z^2) } else { @@ -340,8 +338,7 @@ void PointGFp::mult2(std::vector<BigInt>& ws_bn) m_curve.mul(T3, m_curve.get_a_rep(), T4, ws); // a*z^4 m_curve.sqr(T4, m_coord_x, ws); // x^2 - T4 *= 3; // 3*x^2 - T4.reduce_below(p, sub_ws); + T4.mod_mul(3, p, sub_ws); T4.mod_add(T3, p, sub_ws); // 3*x^2 + a*z^4 } @@ -350,8 +347,7 @@ void PointGFp::mult2(std::vector<BigInt>& ws_bn) T2.mod_sub(T1, p, sub_ws); m_curve.sqr(T3, T0, ws); - T3 <<= 3; - m_curve.redc_mod_p(T3, sub_ws); + T3.mod_mul(8, p, sub_ws); T1.mod_sub(T2, p, sub_ws); @@ -361,8 +357,7 @@ void PointGFp::mult2(std::vector<BigInt>& ws_bn) m_coord_x = T2; m_curve.mul(T2, m_coord_y, m_coord_z, ws); - T2 <<= 1; - m_curve.redc_mod_p(T2, sub_ws); + T2.mod_mul(2, p, sub_ws); m_coord_y = T0; m_coord_z = T2; diff --git a/src/lib/pubkey/ec_group/point_gfp.h b/src/lib/pubkey/ec_group/point_gfp.h index 222b5f474..aa8a7d7bc 100644 --- a/src/lib/pubkey/ec_group/point_gfp.h +++ b/src/lib/pubkey/ec_group/point_gfp.h @@ -180,8 +180,7 @@ class BOTAN_PUBLIC_API(2,0) PointGFp final * Is this the point at infinity? * @result true, if this point is at infinity, false otherwise. */ - bool is_zero() const - { return (m_coord_x.is_zero() && m_coord_z.is_zero()); } + bool is_zero() const { return m_coord_z.is_zero(); } /** * Checks whether the point is to be found on the underlying diff --git a/src/tests/data/bn/mod.vec b/src/tests/data/bn/mod.vec index fe6492e64..2d4196dbe 100644 --- a/src/tests/data/bn/mod.vec +++ b/src/tests/data/bn/mod.vec @@ -19,6 +19,18 @@ In1 = -0xE In2 = 0x7 Output = 0x0 +In1 = -15 +In2 = 7 +Output = 6 + +In1 = -15 +In2 = 8 +Output = 1 + +In1 = -15 +In2 = 128 +Output = 113 + In1 = 0x0 In2 = 0x1E8D2D00 Output = 0x0 diff --git a/src/tests/test_bigint.cpp b/src/tests/test_bigint.cpp index 3870c5c6f..c7b95b89a 100644 --- a/src/tests/test_bigint.cpp +++ b/src/tests/test_bigint.cpp @@ -433,12 +433,15 @@ class BigInt_Mod_Test final : public Text_Based_Test result.test_eq("Barrett", mod_b.reduce(a), c); // if b fits into a Botan::word test %= operator for words - if(b.bytes() <= sizeof(Botan::word)) + if(b.sig_words() == 1) { - Botan::word b_word = b.word_at(0); + const Botan::word b_word = b.word_at(0); + e = a; e %= b_word; result.test_eq("a %= b (as word)", e, c); + + result.test_eq("a % b (as word)", a % b_word, c); } return result; |