Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clean out the BigInt interface #4056

Merged
merged 8 commits into from
May 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 10 additions & 16 deletions doc/api_ref/bigint.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,17 @@ declarations in ``botan/bigint.h`` and ``botan/numthry.h``.

Create a BigInt with value zero

.. cpp:function:: BigInt(uint64_t n)
.. cpp:function:: BigInt::from_u64(uint64_t n)

Create a BigInt with value *n*

.. cpp:function:: BigInt(const std::string& str)
.. cpp:function:: BigInt(std::string_view str)

Create a BigInt from a string. By default decimal is expected. With an 0x
prefix instead it is treated as hexadecimal.
prefix instead it is treated as hexadecimal. A ``-`` prefix to indicate
negative numbers is also accepted.

.. cpp:function:: BigInt(const uint8_t buf[], size_t length)
.. cpp:function:: BigInt(std::span<const uint8_t> buf)

Create a BigInt from a binary array (big-endian encoding).

Expand Down Expand Up @@ -199,28 +200,21 @@ declarations in ``botan/bigint.h`` and ``botan/numthry.h``.

Return absolute value of ``*this``

.. cpp:function:: void binary_encode(uint8_t buf[]) const
.. cpp:function:: void serialize_to(std::span<uint8_t> buf)

Encode this BigInt as a big-endian integer. The sign is ignored.

.. cpp:function:: void binary_encode(uint8_t buf[], size_t len) const

Encode this BigInt as a big-endian integer. The sign is ignored.
If ``len`` is less than ``bytes()`` then only the low ``len``
bytes are output. If ``len`` is greater than ``bytes()`` then
the output is padded with leading zeros.

.. cpp:function:: void binary_decode(uint8_t buf[])

Decode this BigInt as a big-endian integer.
There must be sufficient space to encode the entire integer in ``buf``.
If ``buf`` is larger than required, sufficient zero bytes will be
prefixed.

.. cpp:function:: std::string to_dec_string() const

Encode the integer as a decimal string.

.. cpp:function:: std::string to_hex_string() const

Encode the integer as a hexadecimal string.
Encode the integer as a hexadecimal string, with "0x" prefix

Number Theory
----------------------------------------
Expand Down
6 changes: 3 additions & 3 deletions src/lib/asn1/ber_dec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ BER_Decoder& BER_Decoder::decode_null() {
BER_Decoder& BER_Decoder::decode_octet_string_bigint(BigInt& out) {
secure_vector<uint8_t> out_vec;
decode(out_vec, ASN1_Type::OctetString);
out = BigInt::decode(out_vec.data(), out_vec.size());
out = BigInt::from_bytes(out_vec);
return (*this);
}

Expand Down Expand Up @@ -474,10 +474,10 @@ BER_Decoder& BER_Decoder::decode(BigInt& out, ASN1_Type type_tag, ASN1_Class cla
for(size_t i = 0; i != obj.length(); ++i) {
vec[i] = ~vec[i];
}
out = BigInt(vec.data(), vec.size());
out._assign_from_bytes(vec);
out.flip_sign();
} else {
out = BigInt(obj.bits(), obj.length());
out._assign_from_bytes(obj.data());
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/lib/asn1/der_enc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -296,8 +296,8 @@ DER_Encoder& DER_Encoder::encode(const BigInt& n, ASN1_Type type_tag, ASN1_Class
}

const size_t extra_zero = (n.bits() % 8 == 0) ? 1 : 0;
secure_vector<uint8_t> contents(extra_zero + n.bytes());
n.binary_encode(&contents[extra_zero]);

auto contents = n.serialize(n.bytes() + extra_zero);
if(n < 0) {
for(unsigned char& content : contents) {
content = ~content;
Expand Down
4 changes: 1 addition & 3 deletions src/lib/codec/base58/base58.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,9 +158,7 @@ std::vector<uint8_t> base58_decode(const char input[], size_t input_length) {
v += idx;
}

std::vector<uint8_t> output(v.bytes() + leading_zeros);
v.binary_encode(output.data() + leading_zeros);
return output;
return v.serialize(v.bytes() + leading_zeros);
}

std::vector<uint8_t> base58_check_decode(const char input[], size_t input_length) {
Expand Down
4 changes: 2 additions & 2 deletions src/lib/ffi/ffi_mp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ int botan_mp_flip_sign(botan_mp_t mp) {
}

int botan_mp_from_bin(botan_mp_t mp, const uint8_t bin[], size_t bin_len) {
return BOTAN_FFI_VISIT(mp, [=](auto& bn) { bn.binary_decode(bin, bin_len); });
return BOTAN_FFI_VISIT(mp, [=](auto& bn) { bn._assign_from_bytes({bin, bin_len}); });
}

int botan_mp_to_hex(const botan_mp_t mp, char* out) {
Expand All @@ -99,7 +99,7 @@ int botan_mp_to_str(const botan_mp_t mp, uint8_t digit_base, char* out, size_t*
}

int botan_mp_to_bin(const botan_mp_t mp, uint8_t vec[]) {
return BOTAN_FFI_VISIT(mp, [=](const auto& bn) { bn.binary_encode(vec); });
return BOTAN_FFI_VISIT(mp, [=](const auto& bn) { bn.serialize_to(std::span{vec, bn.bytes()}); });
}

int botan_mp_to_uint32(const botan_mp_t mp, uint32_t* val) {
Expand Down
12 changes: 6 additions & 6 deletions src/lib/ffi/ffi_srp6.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,9 @@ int botan_srp6_server_session_step1(botan_srp6_server_session_t srp6,
}
try {
Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
auto v_bn = Botan::BigInt::decode(verifier, verifier_len);
auto v_bn = Botan::BigInt::from_bytes(std::span{verifier, verifier_len});
auto b_pub_bn = s.step1(v_bn, group_id, hash_id, rng);
return write_vec_output(b_pub, b_pub_len, Botan::BigInt::encode(b_pub_bn));
return write_vec_output(b_pub, b_pub_len, b_pub_bn.serialize());
} catch(Botan::Decoding_Error&) {
return BOTAN_FFI_ERROR_BAD_PARAMETER;
} catch(Botan::Lookup_Error&) {
Expand All @@ -99,7 +99,7 @@ int botan_srp6_server_session_step2(
return BOTAN_FFI_ERROR_NULL_POINTER;
}
try {
Botan::BigInt a_bn = Botan::BigInt::decode(a, a_len);
Botan::BigInt a_bn = Botan::BigInt::from_bytes({a, a_len});
auto key_sk = s.step2(a_bn);
return write_vec_output(key, key_len, key_sk.bits_of());
} catch(Botan::Decoding_Error&) {
Expand Down Expand Up @@ -128,7 +128,7 @@ int botan_srp6_generate_verifier(const char* username,
try {
std::vector<uint8_t> salt_vec(salt, salt + salt_len);
auto verifier_bn = Botan::srp6_generate_verifier(username, password, salt_vec, group_id, hash_id);
return write_vec_output(verifier, verifier_len, Botan::BigInt::encode(verifier_bn));
return write_vec_output(verifier, verifier_len, verifier_bn.serialize());
} catch(Botan::Lookup_Error&) {
return BOTAN_FFI_ERROR_BAD_PARAMETER;
}
Expand Down Expand Up @@ -161,9 +161,9 @@ int botan_srp6_client_agree(const char* identity,
try {
std::vector<uint8_t> saltv(salt, salt + salt_len);
Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
auto b_bn = Botan::BigInt::decode(b, b_len);
auto b_bn = Botan::BigInt::from_bytes({b, b_len});
auto [A_bn, K_sk] = Botan::srp6_client_agree(identity, password, group_id, hash_id, saltv, b_bn, rng);
auto ret_a = write_vec_output(A, A_len, Botan::BigInt::encode(A_bn));
auto ret_a = write_vec_output(A, A_len, A_bn.serialize());
auto ret_k = write_vec_output(K, K_len, K_sk.bits_of());
if(ret_a != BOTAN_FFI_SUCCESS) {
return ret_a;
Expand Down
59 changes: 21 additions & 38 deletions src/lib/math/bigint/big_code.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include <botan/hex.h>
#include <botan/internal/divide.h>
#include <botan/internal/stl_util.h>

namespace Botan {

Expand Down Expand Up @@ -87,7 +88,7 @@ std::string BigInt::to_hex_string() const {
std::vector<uint8_t> bits(std::max<size_t>(1, this_bytes));

if(this_bytes > 0) {
this->binary_encode(bits.data());
this->serialize_to(bits);
}

std::string hrep;
Expand All @@ -99,36 +100,6 @@ std::string BigInt::to_hex_string() const {
return hrep;
}

/*
* Encode a BigInt, with leading 0s if needed
*/
secure_vector<uint8_t> BigInt::encode_1363(const BigInt& n, size_t bytes) {
if(n.bytes() > bytes) {
throw Encoding_Error("encode_1363: n is too large to encode properly");
}

secure_vector<uint8_t> output(bytes);
n.binary_encode(output.data(), output.size());
return output;
}

void BigInt::encode_1363(std::span<uint8_t> output, const BigInt& n) {
if(n.bytes() > output.size()) {
throw Encoding_Error("encode_1363: n is too large to encode properly");
}

n.binary_encode(output.data(), output.size());
}

//static
void BigInt::encode_1363(uint8_t output[], size_t bytes, const BigInt& n) {
if(n.bytes() > bytes) {
throw Encoding_Error("encode_1363: n is too large to encode properly");
}

n.binary_encode(output, bytes);
}

/*
* Encode two BigInt, with leading 0s if needed, and concatenate
*/
Expand All @@ -140,19 +111,27 @@ secure_vector<uint8_t> BigInt::encode_fixed_length_int_pair(const BigInt& n1, co
throw Encoding_Error("encode_fixed_length_int_pair: values too large to encode properly");
}
secure_vector<uint8_t> output(2 * bytes);
n1.binary_encode(output.data(), bytes);
n2.binary_encode(output.data() + bytes, bytes);
BufferStuffer stuffer(output);
n1.serialize_to(stuffer.next(bytes));
n2.serialize_to(stuffer.next(bytes));
return output;
}

BigInt BigInt::decode(std::span<const uint8_t> buf, Base base) {
if(base == Binary) {
return BigInt::from_bytes(buf);
}
return BigInt::decode(buf.data(), buf.size(), base);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps BigInt::decode(std::span<const uint8_t>, ..)?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For these functions using BigInt::Base I'm inclined to not do anything with span since already the whole set of functions and the enum itself are deprecated. We'd just be introducing new interfaces which begin life deprecated, which seems odd.

}

/*
* 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);
return BigInt::from_bytes(std::span{buf, length});
} else if(base == Hexadecimal) {
randombit marked this conversation as resolved.
Show resolved Hide resolved
BigInt r;
secure_vector<uint8_t> binary;

if(length % 2) {
Expand All @@ -161,13 +140,17 @@ BigInt BigInt::decode(const uint8_t buf[], size_t length, Base base) {

binary = hex_decode_locked(buf0_with_leading_0, 2);

binary += hex_decode_locked(cast_uint8_ptr_to_char(&buf[1]), length - 1, false);
if(length > 1) {
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());
r.assign_from_bytes(binary);
return r;
} else if(base == Decimal) {
BigInt r;
// This could be made faster using the same trick as to_dec_string
for(size_t i = 0; i != length; ++i) {
const char c = buf[i];
Expand All @@ -182,10 +165,10 @@ BigInt BigInt::decode(const uint8_t buf[], size_t length, Base base) {
r *= 10;
r += x;
}
return r;
} else {
throw Invalid_Argument("Unknown BigInt decoding method");
}
return r;
}

} // namespace Botan
8 changes: 2 additions & 6 deletions src/lib/math/bigint/big_io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,12 @@ std::ostream& operator<<(std::ostream& stream, const BigInt& n) {

const size_t base = (stream_flags & std::ios::hex) ? 16 : 10;

std::string enc;

if(base == 10) {
enc = n.to_dec_string();
stream << n.to_dec_string();
} else {
enc = n.to_hex_string();
stream << n.to_hex_string();
}

stream.write(enc.data(), enc.size());

if(!stream.good()) {
throw Stream_IO_Error("BigInt output operator has failed");
}
Expand Down
22 changes: 11 additions & 11 deletions src/lib/math/bigint/big_ops2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ BigInt& BigInt::add(const word y[], size_t y_words, Sign y_sign) {
if(sign() == y_sign) {
bigint_add2(mutable_data(), size() - 1, y, y_words);
} else {
const int32_t relative_size = bigint_cmp(data(), x_sw, y, y_words);
const int32_t relative_size = bigint_cmp(_data(), x_sw, y, y_words);

if(relative_size >= 0) {
// *this >= y
Expand Down Expand Up @@ -71,15 +71,15 @@ BigInt& BigInt::mod_add(const BigInt& s, const BigInt& mod, secure_vector<word>&
ws.resize(3 * mod_sw);
}

word borrow = bigint_sub3(&ws[0], mod.data(), mod_sw, s.data(), mod_sw);
word borrow = bigint_sub3(&ws[0], mod._data(), mod_sw, s._data(), mod_sw);
BOTAN_DEBUG_ASSERT(borrow == 0);
BOTAN_UNUSED(borrow);

// Compute t - ws
borrow = bigint_sub3(&ws[mod_sw], this->data(), mod_sw, &ws[0], mod_sw);
borrow = bigint_sub3(&ws[mod_sw], this->_data(), mod_sw, &ws[0], mod_sw);

// Compute t + s
bigint_add3_nc(&ws[mod_sw * 2], this->data(), mod_sw, s.data(), mod_sw);
bigint_add3_nc(&ws[mod_sw * 2], this->_data(), mod_sw, s._data(), mod_sw);

CT::conditional_copy_mem(borrow, &ws[0], &ws[mod_sw * 2], &ws[mod_sw], mod_sw);
set_words(&ws[0], mod_sw);
Expand All @@ -106,11 +106,11 @@ BigInt& BigInt::mod_sub(const BigInt& s, const BigInt& mod, secure_vector<word>&
}

if(mod_sw == 4) {
bigint_mod_sub_n<4>(mutable_data(), s.data(), mod.data(), ws.data());
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());
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());
bigint_mod_sub(mutable_data(), s._data(), mod._data(), mod_sw, ws.data());
}

return (*this);
Expand All @@ -137,7 +137,7 @@ BigInt& BigInt::rev_sub(const word y[], size_t y_sw, secure_vector<word>& ws) {
ws.resize(std::max(x_sw, y_sw));
clear_mem(ws.data(), ws.size());

const int32_t relative_size = bigint_sub_abs(ws.data(), data(), x_sw, y, y_sw);
const int32_t relative_size = bigint_sub_abs(ws.data(), _data(), x_sw, y, y_sw);

this->cond_flip_sign(relative_size > 0);
this->swap_reg(ws);
Expand All @@ -163,7 +163,7 @@ BigInt& BigInt::mul(const BigInt& y, secure_vector<word>& ws) {
set_sign(Positive);
} else if(x_sw == 1 && y_sw) {
grow_to(y_sw + 1);
bigint_linmul3(mutable_data(), y.data(), y_sw, word_at(0));
bigint_linmul3(mutable_data(), y._data(), y_sw, word_at(0));
} else if(y_sw == 1 && x_sw) {
word carry = bigint_linmul2(mutable_data(), x_sw, y.word_at(0));
set_word_at(x_sw, carry);
Expand All @@ -172,7 +172,7 @@ BigInt& BigInt::mul(const BigInt& y, secure_vector<word>& ws) {
ws.resize(new_size);
secure_vector<word> z_reg(new_size);

bigint_mul(z_reg.data(), z_reg.size(), data(), size(), x_sw, y.data(), y.size(), y_sw, ws.data(), ws.size());
bigint_mul(z_reg.data(), z_reg.size(), _data(), size(), x_sw, y._data(), y.size(), y_sw, ws.data(), ws.size());

this->swap_reg(z_reg);
}
Expand All @@ -186,7 +186,7 @@ BigInt& BigInt::square(secure_vector<word>& ws) {
secure_vector<word> z(2 * sw);
ws.resize(z.size());

bigint_sqr(z.data(), z.size(), data(), size(), sw, ws.data(), ws.size());
bigint_sqr(z.data(), z.size(), _data(), size(), sw, ws.data(), ws.size());

swap_reg(z);
set_sign(BigInt::Positive);
Expand Down
Loading
Loading