diff options
Diffstat (limited to 'botan/src/math/bigint/big_ops2.cpp')
-rw-r--r-- | botan/src/math/bigint/big_ops2.cpp | 224 |
1 files changed, 224 insertions, 0 deletions
diff --git a/botan/src/math/bigint/big_ops2.cpp b/botan/src/math/bigint/big_ops2.cpp new file mode 100644 index 0000000..488eca9 --- /dev/null +++ b/botan/src/math/bigint/big_ops2.cpp @@ -0,0 +1,224 @@ +/* +* BigInt Assignment Operators +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/bigint.h> +#include <botan/mp_core.h> +#include <botan/bit_ops.h> +#include <algorithm> + +namespace Botan { + +/* +* Addition Operator +*/ +BigInt& BigInt::operator+=(const BigInt& y) + { + const u32bit x_sw = sig_words(), y_sw = y.sig_words(); + + const u32bit reg_size = std::max(x_sw, y_sw) + 1; + grow_to(reg_size); + + if(sign() == y.sign()) + bigint_add2(get_reg(), reg_size - 1, y.data(), y_sw); + else + { + s32bit relative_size = bigint_cmp(data(), x_sw, y.data(), y_sw); + + if(relative_size < 0) + { + SecureVector<word> z(reg_size - 1); + bigint_sub3(z, y.data(), reg_size - 1, data(), x_sw); + copy_mem(get_reg().begin(), z.begin(), z.size()); + set_sign(y.sign()); + } + else if(relative_size == 0) + { + get_reg().clear(); + set_sign(Positive); + } + else if(relative_size > 0) + bigint_sub2(get_reg(), x_sw, y.data(), y_sw); + } + + return (*this); + } + +/* +* Subtraction Operator +*/ +BigInt& BigInt::operator-=(const BigInt& y) + { + const u32bit x_sw = sig_words(), y_sw = y.sig_words(); + + s32bit relative_size = bigint_cmp(data(), x_sw, y.data(), y_sw); + + const u32bit reg_size = std::max(x_sw, y_sw) + 1; + grow_to(reg_size); + + if(relative_size < 0) + { + if(sign() == y.sign()) + { + SecureVector<word> z(reg_size - 1); + bigint_sub3(z, y.data(), reg_size - 1, data(), x_sw); + copy_mem(get_reg().begin(), z.begin(), z.size()); + } + else + bigint_add2(get_reg(), reg_size - 1, y.data(), y_sw); + + set_sign(y.reverse_sign()); + } + else if(relative_size == 0) + { + if(sign() == y.sign()) + { + get_reg().clear(); + set_sign(Positive); + } + else + bigint_shl1(get_reg(), x_sw, 0, 1); + } + else if(relative_size > 0) + { + if(sign() == y.sign()) + bigint_sub2(get_reg(), x_sw, y.data(), y_sw); + else + bigint_add2(get_reg(), reg_size - 1, y.data(), y_sw); + } + + return (*this); + } + +/* +* Multiplication Operator +*/ +BigInt& BigInt::operator*=(const BigInt& y) + { + const u32bit x_sw = sig_words(), y_sw = y.sig_words(); + set_sign((sign() == y.sign()) ? Positive : Negative); + + if(x_sw == 0 || y_sw == 0) + { + get_reg().clear(); + set_sign(Positive); + } + else if(x_sw == 1 && y_sw) + { + grow_to(y_sw + 2); + bigint_linmul3(get_reg(), y.data(), y_sw, word_at(0)); + } + else if(y_sw == 1 && x_sw) + { + grow_to(x_sw + 2); + bigint_linmul2(get_reg(), x_sw, y.word_at(0)); + } + else + { + grow_to(size() + y.size()); + + SecureVector<word> z(data(), x_sw); + SecureVector<word> workspace(size()); + + bigint_mul(get_reg(), size(), workspace, + z, z.size(), x_sw, + y.data(), y.size(), y_sw); + } + + return (*this); + } + +/* +* Division Operator +*/ +BigInt& BigInt::operator/=(const BigInt& y) + { + if(y.sig_words() == 1 && power_of_2(y.word_at(0))) + (*this) >>= (y.bits() - 1); + else + (*this) = (*this) / y; + return (*this); + } + +/* +* Modulo Operator +*/ +BigInt& BigInt::operator%=(const BigInt& mod) + { + return (*this = (*this) % mod); + } + +/* +* Modulo Operator +*/ +word BigInt::operator%=(word mod) + { + if(mod == 0) + throw BigInt::DivideByZero(); + if(power_of_2(mod)) + { + word result = (word_at(0) & (mod - 1)); + clear(); + grow_to(2); + get_reg()[0] = result; + return result; + } + + word remainder = 0; + + for(u32bit j = sig_words(); j > 0; --j) + remainder = bigint_modop(remainder, word_at(j-1), mod); + clear(); + grow_to(2); + + if(remainder && sign() == BigInt::Negative) + get_reg()[0] = mod - remainder; + else + get_reg()[0] = remainder; + + set_sign(BigInt::Positive); + + return word_at(0); + } + +/* +* Left Shift Operator +*/ +BigInt& BigInt::operator<<=(u32bit shift) + { + if(shift) + { + const u32bit shift_words = shift / MP_WORD_BITS, + shift_bits = shift % MP_WORD_BITS, + words = sig_words(); + + grow_to(words + shift_words + (shift_bits ? 1 : 0)); + bigint_shl1(get_reg(), words, shift_words, shift_bits); + } + + return (*this); + } + +/* +* Right Shift Operator +*/ +BigInt& BigInt::operator>>=(u32bit shift) + { + if(shift) + { + const u32bit shift_words = shift / MP_WORD_BITS, + shift_bits = shift % MP_WORD_BITS; + + bigint_shr1(get_reg(), sig_words(), shift_words, shift_bits); + + if(is_zero()) + set_sign(Positive); + } + + return (*this); + } + +} |