/* * BigInt Encoding/Decoding * (C) 1999-2010,2012 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #include #include #include #include namespace Botan { std::string BigInt::to_dec_string() const { BigInt copy = *this; copy.set_sign(Positive); BigInt remainder; std::vector digits; while(copy > 0) { divide(copy, 10, copy, remainder); digits.push_back(static_cast(remainder.word_at(0))); } std::string s; for(auto i = digits.rbegin(); i != digits.rend(); ++i) { s.push_back(Charset::digit2char(*i)); } if(s.empty()) s += "0"; return s; } std::string BigInt::to_hex_string() const { const std::vector bits = BigInt::encode(*this); if(bits.empty()) return "00"; else return hex_encode(bits); } /* * Encode a BigInt */ void BigInt::encode(uint8_t output[], const BigInt& n, Base base) { if(base == Binary) { n.binary_encode(output); } else if(base == Hexadecimal) { secure_vector binary(n.encoded_size(Binary)); n.binary_encode(binary.data()); hex_encode(cast_uint8_ptr_to_char(output), binary.data(), binary.size()); } else if(base == Decimal) { BigInt copy = n; BigInt remainder; copy.set_sign(Positive); const size_t output_size = n.encoded_size(Decimal); for(size_t j = 0; j != output_size; ++j) { divide(copy, 10, copy, remainder); output[output_size - 1 - j] = Charset::digit2char(static_cast(remainder.word_at(0))); if(copy.is_zero()) break; } } else throw Invalid_Argument("Unknown BigInt encoding method"); } /* * Encode a BigInt */ std::vector BigInt::encode(const BigInt& n, Base base) { if(base == Binary) return BigInt::encode(n); std::vector output(n.encoded_size(base)); encode(output.data(), n, base); for(size_t j = 0; j != output.size(); ++j) if(output[j] == 0) output[j] = '0'; return output; } /* * Encode a BigInt */ secure_vector BigInt::encode_locked(const BigInt& n, Base base) { if(base == Binary) return BigInt::encode_locked(n); secure_vector output(n.encoded_size(base)); encode(output.data(), n, base); for(size_t j = 0; j != output.size(); ++j) if(output[j] == 0) output[j] = '0'; return output; } /* * Encode a BigInt, with leading 0s if needed */ secure_vector BigInt::encode_1363(const BigInt& n, size_t bytes) { secure_vector output(bytes); BigInt::encode_1363(output.data(), output.size(), n); return output; } //static void BigInt::encode_1363(uint8_t output[], size_t bytes, const BigInt& n) { const size_t n_bytes = n.bytes(); if(n_bytes > bytes) throw Encoding_Error("encode_1363: n is too large to encode properly"); const size_t leading_0s = bytes - n_bytes; encode(&output[leading_0s], n, Binary); } /* * Encode two BigInt, with leading 0s if needed, and concatenate */ secure_vector BigInt::encode_fixed_length_int_pair(const BigInt& n1, const BigInt& n2, size_t bytes) { secure_vector output(2 * bytes); BigInt::encode_1363(output.data(), bytes, n1); BigInt::encode_1363(output.data() + bytes, bytes, n2); return output; } /* * Decode a BigInt */ BigInt BigInt::decode(const uint8_t buf[], size_t length, Base base) { BigInt r; if(base == Binary) r.binary_decode(buf, length); else if(base == Hexadecimal) { secure_vector binary; if(length % 2) { // Handle lack of leading 0 const char buf0_with_leading_0[2] = { '0', static_cast(buf[0]) }; binary = hex_decode_locked(buf0_with_leading_0, 2); binary += hex_decode_locked(cast_uint8_ptr_to_char(&buf[1]), length - 1, false); } else binary = hex_decode_locked(cast_uint8_ptr_to_char(buf), length, false); r.binary_decode(binary.data(), binary.size()); } else if(base == Decimal) { for(size_t i = 0; i != length; ++i) { if(Charset::is_space(buf[i])) continue; if(!Charset::is_digit(buf[i])) throw Invalid_Argument("BigInt::decode: " "Invalid character in decimal input"); const uint8_t x = Charset::char2digit(buf[i]); if(x >= 10) throw Invalid_Argument("BigInt: Invalid decimal string"); r *= 10; r += x; } } else throw Invalid_Argument("Unknown BigInt decoding method"); return r; } }