/************************************************* * BigInt Assignment Operators Source File * * (C) 1999-2007 Jack Lloyd * *************************************************/ #include #include #include #include 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 z(reg_size - 1); bigint_sub3(z, y.data(), reg_size - 1, data(), x_sw); copy_mem(reg.begin(), z.begin(), z.size()); set_sign(y.sign()); } else if(relative_size == 0) { 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 z(reg_size - 1); bigint_sub3(z, y.data(), reg_size - 1, data(), x_sw); copy_mem(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()) { 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) { 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 z(data(), x_sw); SecureVector 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); 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) reg[0] = mod - remainder; else 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); } }