Repository: randombit/botan
Pull request #2725 (2021-04-24 13:20:15)

Modify BigInt constructors
Add static methods for very common (eg zero, one) or very uncommon (eg
ECSDA truncated integers) construction methods, instead of using C++
constructors for all of these.

Also adds from_s32 which allows creating a negative BigInt easily,
instead of -BigInt(-x) -> BigInt::from_s32(x)

codecov-commenter: # [Codecov](https://codecov.io/gh/randombit/botan/pull/2725?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jack+Lloyd) Report
> Merging [#2725](https://codecov.io/gh/randombit/botan/pull/2725?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jack+Lloyd) (0450150) into [master](https://codecov.io/gh/randombit/botan/commit/225727ec8d5c057f8b9d419ca90904df0bb9feee?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jack+Lloyd) (225727e) will **increase** coverage by `0.04%`.
> The diff coverage is `90.00%`.

[![Impacted file tree graph](https://codecov.io/gh/randombit/botan/pull/2725/graphs/tree.svg?width=650&height=150&src=pr&token=VR6iYmSPH8&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jack+Lloyd)](https://codecov.io/gh/randombit/botan/pull/2725?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jack+Lloyd)

```diff
@@            Coverage Diff             @@
##           master    #2725      +/-   ##
==========================================
+ Coverage   92.31%   92.36%   +0.04%     
==========================================
  Files         565      565              
  Lines       62780    62803      +23     
  Branches     6142     6135       -7     
==========================================
+ Hits        57957    58009      +52     
+ Misses       4791     4762      -29     
  Partials       32       32              
```


| [Impacted Files](https://codecov.io/gh/randombit/botan/pull/2725?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jack+Lloyd) | Coverage Δ | |
|---|---|---|
| [src/lib/ffi/ffi\_mp.cpp](https://codecov.io/gh/randombit/botan/pull/2725/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jack+Lloyd#diff-c3JjL2xpYi9mZmkvZmZpX21wLmNwcA==) | `95.45% <ø> (ø)` | |
| [src/lib/math/numbertheory/monty\_exp.cpp](https://codecov.io/gh/randombit/botan/pull/2725/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jack+Lloyd#diff-c3JjL2xpYi9tYXRoL251bWJlcnRoZW9yeS9tb250eV9leHAuY3Bw) | `95.87% <0.00%> (ø)` | |
| [src/lib/pubkey/ec\_group/ec\_group.cpp](https://codecov.io/gh/randombit/botan/pull/2725/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jack+Lloyd#diff-c3JjL2xpYi9wdWJrZXkvZWNfZ3JvdXAvZWNfZ3JvdXAuY3Bw) | `91.01% <50.00%> (ø)` | |
| [src/lib/pubkey/gost\_3410/gost\_3410.cpp](https://codecov.io/gh/randombit/botan/pull/2725/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jack+Lloyd#diff-c3JjL2xpYi9wdWJrZXkvZ29zdF8zNDEwL2dvc3RfMzQxMC5jcHA=) | `92.72% <50.00%> (ø)` | |
| [src/lib/math/numbertheory/numthry.cpp](https://codecov.io/gh/randombit/botan/pull/2725/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jack+Lloyd#diff-c3JjL2xpYi9tYXRoL251bWJlcnRoZW9yeS9udW10aHJ5LmNwcA==) | `95.05% <76.92%> (ø)` | |
| [src/lib/math/numbertheory/monty.cpp](https://codecov.io/gh/randombit/botan/pull/2725/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jack+Lloyd#diff-c3JjL2xpYi9tYXRoL251bWJlcnRoZW9yeS9tb250eS5jcHA=) | `66.52% <80.00%> (+0.13%)` | :arrow_up: |
| [src/lib/pubkey/dl\_group/dl\_group.cpp](https://codecov.io/gh/randombit/botan/pull/2725/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jack+Lloyd#diff-c3JjL2xpYi9wdWJrZXkvZGxfZ3JvdXAvZGxfZ3JvdXAuY3Bw) | `91.60% <80.00%> (ø)` | |
| [src/lib/math/numbertheory/mod\_inv.cpp](https://codecov.io/gh/randombit/botan/pull/2725/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jack+Lloyd#diff-c3JjL2xpYi9tYXRoL251bWJlcnRoZW9yeS9tb2RfaW52LmNwcA==) | `97.34% <85.71%> (ø)` | |
| [src/lib/math/bigint/divide.cpp](https://codecov.io/gh/randombit/botan/pull/2725/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jack+Lloyd#diff-c3JjL2xpYi9tYXRoL2JpZ2ludC9kaXZpZGUuY3Bw) | `97.45% <91.66%> (-0.78%)` | :arrow_down: |
| [src/cli/speed.cpp](https://codecov.io/gh/randombit/botan/pull/2725/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jack+Lloyd#diff-c3JjL2NsaS9zcGVlZC5jcHA=) | `95.36% <100.00%> (+<0.01%)` | :arrow_up: |
| ... and [16 more](https://codecov.io/gh/randombit/botan/pull/2725/diff?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jack+Lloyd) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/randombit/botan/pull/2725?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jack+Lloyd).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jack+Lloyd)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/randombit/botan/pull/2725?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jack+Lloyd). Last update [225727e...0450150](https://codecov.io/gh/randombit/botan/pull/2725?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jack+Lloyd). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jack+Lloyd).


Patch:
diff --git a/src/cli/speed.cpp b/src/cli/speed.cpp
index cc9cfb09a..a68a94005 100644
--- a/src/cli/speed.cpp
+++ b/src/cli/speed.cpp
@@ -1124,7 +1124,10 @@ class Speed final : public Command
             auto dbl_timer = make_timer(group_name + " dbl");
 
             const Botan::PointGFp& base_point = ec_group.get_base_point();
-            Botan::PointGFp non_affine_pt = ec_group.get_base_point() * 1776; // create a non-affine point
+
+            // create a non-affine point
+            const auto random_k = Botan::BigInt::from_u64(0x4E6F537465707E);
+            Botan::PointGFp non_affine_pt = ec_group.get_base_point() * random_k;
             Botan::PointGFp pt = ec_group.get_base_point();
 
             std::vector<Botan::BigInt> ws(Botan::PointGFp::WORKSPACE_SIZE);
@@ -1227,7 +1230,7 @@ class Speed final : public Command
 
       void bench_fpe_fe1(const std::chrono::milliseconds runtime)
          {
-         const Botan::BigInt n = 1000000000000000;
+         const auto n = Botan::BigInt::from_u64(1000000000000000);
 
          auto enc_timer = make_timer("FPE_FE1 encrypt");
          auto dec_timer = make_timer("FPE_FE1 decrypt");
@@ -1235,7 +1238,7 @@ class Speed final : public Command
          const Botan::SymmetricKey key(rng(), 32);
          const std::vector<uint8_t> tweak(8); // 8 zeros
 
-         Botan::BigInt x = 1;
+         auto x = Botan::BigInt::one();
 
          Botan::FPE_FE1 fpe_fe1(n);
          fpe_fe1.set_key(key);
@@ -1377,7 +1380,7 @@ class Speed final : public Command
             Botan::BigInt x;
             Botan::secure_vector<Botan::word> ws;
 
-            const Botan::BigInt ten(10);
+            const auto ten = Botan::BigInt::from_word(10);
             Botan::BigInt q1, r1, q2;
             uint8_t r2;
 
@@ -1585,7 +1588,7 @@ class Speed final : public Command
 
       void bench_random_prime(const std::chrono::milliseconds runtime)
          {
-         const size_t coprime = 65537; // simulates RSA key gen
+         const auto coprime = Botan::BigInt::from_word(0x10001);
 
          for(size_t bits : { 256, 384, 512, 768, 1024, 1536 })
             {
diff --git a/src/lib/asn1/ber_dec.cpp b/src/lib/asn1/ber_dec.cpp
index 11f9b5412..c35cd1024 100644
--- a/src/lib/asn1/ber_dec.cpp
+++ b/src/lib/asn1/ber_dec.cpp
@@ -467,7 +467,7 @@ BER_Decoder& BER_Decoder::decode(BigInt& out,
 
    if(obj.length() == 0)
       {
-      out = 0;
+      out.clear();
       }
    else
       {
diff --git a/src/lib/asn1/der_enc.cpp b/src/lib/asn1/der_enc.cpp
index bdae43075..e40b492d8 100644
--- a/src/lib/asn1/der_enc.cpp
+++ b/src/lib/asn1/der_enc.cpp
@@ -295,7 +295,7 @@ DER_Encoder& DER_Encoder::encode(bool is_true)
 */
 DER_Encoder& DER_Encoder::encode(size_t n)
    {
-   return encode(BigInt(n), ASN1_Type::Integer, ASN1_Class::Universal);
+   return encode(BigInt::from_u64(n), ASN1_Type::Integer, ASN1_Class::Universal);
    }
 
 /*
@@ -331,7 +331,7 @@ DER_Encoder& DER_Encoder::encode(bool is_true,
 DER_Encoder& DER_Encoder::encode(size_t n,
                                  ASN1_Type type_tag, ASN1_Class class_tag)
    {
-   return encode(BigInt(n), type_tag, class_tag);
+   return encode(BigInt::from_u64(n), type_tag, class_tag);
    }
 
 /*
diff --git a/src/lib/ffi/ffi_mp.cpp b/src/lib/ffi/ffi_mp.cpp
index 96ef9998f..1f7dece47 100644
--- a/src/lib/ffi/ffi_mp.cpp
+++ b/src/lib/ffi/ffi_mp.cpp
@@ -37,15 +37,7 @@ int botan_mp_clear(botan_mp_t mp)
 int botan_mp_set_from_int(botan_mp_t mp, int initial_value)
    {
    return BOTAN_FFI_DO(Botan::BigInt, mp, bn, {
-      if(initial_value >= 0)
-         {
-         bn = Botan::BigInt(static_cast<uint64_t>(initial_value));
-         }
-      else
-         {
-         bn = Botan::BigInt(static_cast<uint64_t>(-initial_value));
-         bn.flip_sign();
-         }
+      bn = Botan::BigInt::from_s32(initial_value);
       });
    }
 
diff --git a/src/lib/math/bigint/big_ops3.cpp b/src/lib/math/bigint/big_ops3.cpp
index e686e951c..43a722ee8 100644
--- a/src/lib/math/bigint/big_ops3.cpp
+++ b/src/lib/math/bigint/big_ops3.cpp
@@ -19,11 +19,12 @@ BigInt BigInt::add2(const BigInt& x, const word y[], size_t y_words, BigInt::Sig
    {
    const size_t x_sw = x.sig_words();
 
-   BigInt z(x.sign(), std::max(x_sw, y_words) + 1);
+   BigInt z = BigInt::with_capacity(std::max(x_sw, y_words) + 1);
 
    if(x.sign() == y_sign)
       {
       bigint_add3(z.mutable_data(), x.data(), x_sw, y, y_words);
+      z.set_sign(x.sign());
       }
    else
       {
@@ -34,6 +35,8 @@ BigInt BigInt::add2(const BigInt& x, const word y[], size_t y_words, BigInt::Sig
          z.set_sign(y_sign);
       else if(relative_size == 0)
          z.set_sign(BigInt::Positive);
+      else
+         z.set_sign(x.sign());
       }
 
    return z;
@@ -47,7 +50,7 @@ BigInt operator*(const BigInt& x, const BigInt& y)
    const size_t x_sw = x.sig_words();
    const size_t y_sw = y.sig_words();
 
-   BigInt z(BigInt::Positive, x.size() + y.size());
+   BigInt z = BigInt::with_capacity(x.size() + y.size());
 
    if(x_sw == 1 && y_sw)
       bigint_linmul3(z.mutable_data(), y.data(), y_sw, x.word_at(0));
@@ -75,7 +78,7 @@ BigInt operator*(const BigInt& x, word y)
    {
    const size_t x_sw = x.sig_words();
 
-   BigInt z(BigInt::Positive, x_sw + 1);
+   BigInt z = BigInt::with_capacity(x_sw + 1);
 
    if(x_sw && y)
       {
@@ -121,7 +124,7 @@ BigInt operator/(const BigInt& x, word y)
       }
 
    BigInt q, r;
-   vartime_divide(x, y, q, r);
+   vartime_divide_word(x, y, q, r);
    return q;
    }
 
@@ -139,7 +142,7 @@ BigInt operator%(const BigInt& n, const BigInt& mod)
 
    if(mod.sig_words() == 1)
       {
-      return n % mod.word_at(0);
+      return BigInt::from_word(n % mod.word_at(0));
       }
 
    BigInt q, r;
@@ -188,8 +191,9 @@ BigInt operator<<(const BigInt& x, size_t shift)
 
    const size_t x_sw = x.sig_words();
 
-   BigInt y(x.sign(), x_sw + shift_words + (shift_bits ? 1 : 0));
+   BigInt y = BigInt::with_capacity(x_sw + shift_words + (shift_bits ? 1 : 0));
    bigint_shl2(y.mutable_data(), x.data(), x_sw, shift_words, shift_bits);
+   y.set_sign(x.sign());
    return y;
    }
 
@@ -203,13 +207,15 @@ BigInt operator>>(const BigInt& x, size_t shift)
    const size_t x_sw = x.sig_words();
 
    if(shift_words >= x_sw)
-      return 0;
+      return BigInt::zero();
 
-   BigInt y(x.sign(), x_sw - shift_words);
+   BigInt y = BigInt::with_capacity(x_sw - shift_words);
    bigint_shr2(y.mutable_data(), x.data(), x_sw, shift_words, shift_bits);
 
    if(x.is_negative() && y.is_zero())
       y.set_sign(BigInt::Positive);
+   else
+      y.set_sign(x.sign());
 
    return y;
    }
diff --git a/src/lib/math/bigint/bigint.cpp b/src/lib/math/bigint/bigint.cpp
index 33681f9e5..3856ac1fe 100644
--- a/src/lib/math/bigint/bigint.cpp
+++ b/src/lib/math/bigint/bigint.cpp
@@ -14,35 +14,54 @@
 
 namespace Botan {
 
-BigInt::BigInt(const word words[], size_t length)
+BigInt::BigInt(uint64_t n)
    {
-   m_data.set_words(words, length);
+#if BOTAN_MP_WORD_BITS == 64
+   m_data.set_word_at(0, n);
+#else
+   m_data.set_word_at(1, static_cast<word>(n >> 32));
+   m_data.set_word_at(0, static_cast<word>(n));
+#endif
    }
 
-/*
-* Construct a BigInt from a regular number
-*/
-BigInt::BigInt(uint64_t n)
+//static
+BigInt BigInt::from_u64(uint64_t n)
    {
-   if(n > 0)
-      {
-#if BOTAN_MP_WORD_BITS == 32
-      m_data.set_word_at(0, static_cast<word>(n));
-      m_data.set_word_at(1, static_cast<word>(n >> 32));
+   BigInt bn;
+
+#if BOTAN_MP_WORD_BITS == 64
+   bn.set_word_at(0, n);
 #else
-      m_data.set_word_at(0, n);
+   bn.set_word_at(1, static_cast<word>(n >> 32));
+   bn.set_word_at(0, static_cast<word>(n));
 #endif
-      }
 
+   return bn;
    }
 
-/*
-* Construct a BigInt of the specified size
-*/
-BigInt::BigInt(Sign s, size_t size)
+//static
+BigInt BigInt::from_word(word n)
    {
-   m_data.set_size(size);
-   m_signedness = s;
+   BigInt bn;
+   bn.set_word_at(0, n);
+   return bn;
+   }
+
+//static
+BigInt BigInt::from_s32(int32_t n)
+   {
+   if(n >= 0)
+      return BigInt::from_u64(static_cast<uint64_t>(n));
+   else
+      return -BigInt::from_u64(static_cast<uint64_t>(-n));
+   }
+
+//static
+BigInt BigInt::with_capacity(size_t size)
+   {
+   BigInt bn;
+   bn.grow_to(size);
+   return bn;
    }
 
 /*
@@ -87,15 +106,19 @@ BigInt::BigInt(const uint8_t input[], size_t length, Base base)
    *this = decode(input, length, base);
    }
 
-BigInt::BigInt(const uint8_t buf[], size_t length, size_t max_bits)
+//static
+BigInt BigInt::from_bytes_with_max_bits(const uint8_t buf[], size_t length, size_t max_bits)
    {
    if(8 * length > max_bits)
       length = (max_bits + 7) / 8;
 
-   binary_decode(buf, length);
+   BigInt bn;
+   bn.binary_decode(buf, length);
 
    if(8 * length > max_bits)
-      *this >>= (8 - (max_bits % 8));
+      bn >>= (8 - (max_bits % 8));
+
+   return bn;
    }
 
 /*
diff --git a/src/lib/math/bigint/bigint.h b/src/lib/math/bigint/bigint.h
index 1712724b1..352a4a0d0 100644
--- a/src/lib/math/bigint/bigint.h
+++ b/src/lib/math/bigint/bigint.h
@@ -35,12 +35,40 @@ class BOTAN_PUBLIC_API(2,0) BigInt final
      enum Sign { Negative = 0, Positive = 1 };
 
      /**
-     * Create empty BigInt
+     * Create empty (zero) BigInt
      */
      BigInt() = default;
 
      /**
-     * Create BigInt from 64 bit integer
+     * Create a 0-value BigInt
+     */
+     static BigInt zero() { return BigInt(); }
+
+     /**
+     * Create a 1-value BigInt
+     */
+     static BigInt one() { return BigInt::from_word(1); }
+
+     /**
+     * Create BigInt from an unsigned 64 bit integer
+     * @param n initial value of this BigInt
+     */
+     static BigInt from_u64(uint64_t n);
+
+     /**
+     * Create BigInt from a word (limb)
+     * @param n initial value of this BigInt
+     */
+     static BigInt from_word(word n);
+
+     /**
+     * Create BigInt from a signed 32 bit integer
+     * @param n initial value of this BigInt
+     */
+     static BigInt from_s32(int32_t n);
+
+     /**
+     * Create BigInt from an unsigned 64 bit integer
      * @param n initial value of this BigInt
      */
      BigInt(uint64_t n);
@@ -89,14 +117,8 @@ class BOTAN_PUBLIC_API(2,0) BigInt final
      * @param max_bits if the resulting integer is more than max_bits,
      *        it will be shifted so it is at most max_bits in length.
      */
-     BigInt(const uint8_t buf[], size_t length, size_t max_bits);
-
-     /**
-     * Create a BigInt from an array of words
-     * @param words the words
-     * @param length number of words
-     */
-     BigInt(const word words[], size_t length);
+     static BigInt from_bytes_with_max_bits(const uint8_t buf[], size_t length,
+                                            size_t max_bits);
 
      /**
      * \brief Create a random BigInt of the specified size
@@ -111,10 +133,9 @@ class BOTAN_PUBLIC_API(2,0) BigInt final
 
      /**
      * Create BigInt of specified size, all zeros
-     * @param sign the sign
      * @param n size of the internal register in words
      */
-     BigInt(Sign sign, size_t n);
+     static BigInt with_capacity(size_t n);
 
      /**
      * Move constructor
diff --git a/src/lib/math/bigint/divide.cpp b/src/lib/math/bigint/divide.cpp
index b1d106872..9b92c9e39 100644
--- a/src/lib/math/bigint/divide.cpp
+++ b/src/lib/math/bigint/divide.cpp
@@ -56,9 +56,9 @@ void ct_divide(const BigInt& x, const BigInt& y, BigInt& q_out, BigInt& r_out)
 
    const size_t x_bits = x.bits();
 
-   BigInt q(BigInt::Positive, x_words);
-   BigInt r(BigInt::Positive, y_words);
-   BigInt t(BigInt::Positive, y_words); // a temporary
+   BigInt q = BigInt::with_capacity(x_words);
+   BigInt r = BigInt::with_capacity(y_words);
+   BigInt t = BigInt::with_capacity(y_words); // a temporary
 
    for(size_t i = 0; i != x_bits; ++i)
       {
@@ -84,7 +84,7 @@ void ct_divide_u8(const BigInt& x, uint8_t y, BigInt& q_out, uint8_t& r_out)
    const size_t x_words = x.sig_words();
    const size_t x_bits = x.bits();
 
-   BigInt q(BigInt::Positive, x_words);
+   BigInt q = BigInt::with_capacity(x_words);
    uint32_t r = 0;
 
    for(size_t i = 0; i != x_bits; ++i)
@@ -124,8 +124,8 @@ BigInt ct_modulo(const BigInt& x, const BigInt& y)
 
    const size_t x_bits = x.bits();
 
-   BigInt r(BigInt::Positive, y_words);
-   BigInt t(BigInt::Positive, y_words);
+   BigInt r = BigInt::with_capacity(y_words);
+   BigInt t = BigInt::with_capacity(y_words);
 
    for(size_t i = 0; i != x_bits; ++i)
       {
@@ -151,6 +151,17 @@ BigInt ct_modulo(const BigInt& x, const BigInt& y)
    return r;
    }
 
+void vartime_divide_word(const BigInt& x, const word y, BigInt& q_out, BigInt& r_out)
+   {
+   if(y == 0)
+      throw Invalid_Argument("vartime_divide_word: cannot divide by zero");
+
+   // It might be worthwhile to specialize vartime_divide for y with 1 word
+
+   // until then:
+   vartime_divide(x, BigInt::from_word(y), q_out, r_out);
+   }
+
 /*
 * Solve x = q * y + r
 *
@@ -168,7 +179,7 @@ void vartime_divide(const BigInt& x, const BigInt& y_arg, BigInt& q_out, BigInt&
    BigInt y = y_arg;
 
    BigInt r = x;
-   BigInt q = 0;
+   BigInt q = BigInt::zero();
    secure_vector<word> ws;
 
    r.set_sign(BigInt::Positive);
diff --git a/src/lib/math/bigint/divide.h b/src/lib/math/bigint/divide.h
index cd98ca3eb..26468bda1 100644
--- a/src/lib/math/bigint/divide.h
+++ b/src/lib/math/bigint/divide.h
@@ -25,6 +25,19 @@ void vartime_divide(const BigInt& x,
                     BigInt& q,
                     BigInt& r);
 
+/**
+* BigInt/word Division
+* @param x an integer
+* @param y a non-zero integer
+* @param q will be set to x / y
+* @param r will be set to x % y
+*/
+BOTAN_TEST_API
+void vartime_divide_word(const BigInt& x,
+                         word y,
+                         BigInt& q,
+                         BigInt& r);
+
 /**
 * BigInt division, const time variant
 *
diff --git a/src/lib/math/bigint/info.txt b/src/lib/math/bigint/info.txt
index c358299eb..d4dadfac4 100644
--- a/src/lib/math/bigint/info.txt
+++ b/src/lib/math/bigint/info.txt
@@ -1,5 +1,5 @@
 <defines>
-BIGINT -> 20131128
+BIGINT -> 20210423
 </defines>
 
 <header:public>
diff --git a/src/lib/math/numbertheory/make_prm.cpp b/src/lib/math/numbertheory/make_prm.cpp
index 760e916e2..c5536b790 100644
--- a/src/lib/math/numbertheory/make_prm.cpp
+++ b/src/lib/math/numbertheory/make_prm.cpp
@@ -136,15 +136,15 @@ BigInt random_prime(RandomNumberGenerator& rng,
 
       if(bits == 2)
          {
-         return ((rng.next_byte() % 2) ? 2 : 3);
+         return BigInt::from_word(((rng.next_byte() % 2) ? 2 : 3));
          }
       else if(bits == 3)
          {
-         return ((rng.next_byte() % 2) ? 5 : 7);
+         return BigInt::from_word(((rng.next_byte() % 2) ? 5 : 7));
          }
       else if(bits == 4)
          {
-         return ((rng.next_byte() % 2) ? 11 : 13);
+         return BigInt::from_word(((rng.next_byte() % 2) ? 11 : 13));
          }
       else
          {
@@ -157,7 +157,7 @@ BigInt random_prime(RandomNumberGenerator& rng,
             const uint16_t small_prime = PRIMES[idx];
 
             if(high_bit(small_prime) == bits)
-               return small_prime;
+               return BigInt::from_word(small_prime);
             }
          }
       }
@@ -320,7 +320,7 @@ BigInt random_safe_prime(RandomNumberGenerator& rng, size_t bits)
       Generate q == 2 (mod 3), since otherwise [in the case of q == 1 (mod 3)],
       2*q+1 == 3 (mod 3) and so certainly not prime.
       */
-      q = random_prime(rng, bits - 1, 0, 2, 3, error_bound);
+      q = random_prime(rng, bits - 1, BigInt::zero(), 2, 3, error_bound);
       p = (q << 1) + 1;
 
       if(is_prime(p, rng, error_bound, true))
diff --git a/src/lib/math/numbertheory/mod_inv.cpp b/src/lib/math/numbertheory/mod_inv.cpp
index 1c07c125f..a50861d8e 100644
--- a/src/lib/math/numbertheory/mod_inv.cpp
+++ b/src/lib/math/numbertheory/mod_inv.cpp
@@ -135,15 +135,15 @@ BigInt inverse_mod_pow2(const BigInt& a1, size_t k)
    */
 
    if(a1.is_even() || k == 0)
-      return 0;
+      return BigInt::zero();
    if(k == 1)
-      return 1;
+      return BigInt::one();
 
    BigInt a = a1;
    a.mask_bits(k);
 
-   BigInt b = 1;
-   BigInt X = 0;
+   BigInt b = BigInt::one();
+   BigInt X = BigInt::zero();
    BigInt newb;
 
    const size_t a_words = a.sig_words();
@@ -181,7 +181,7 @@ BigInt inverse_mod(const BigInt& n, const BigInt& mod)
    if(mod.is_negative() || n.is_negative())
       throw Invalid_Argument("inverse_mod: arguments must be non-negative");
    if(n.is_zero() || (n.is_even() && mod.is_even()))
-      return 0;
+      return BigInt::zero();
 
    if(mod.is_odd())
       {
@@ -232,7 +232,7 @@ BigInt inverse_mod(const BigInt& n, const BigInt& mod)
 
       // No modular inverse in this case:
       if(inv_o == 0)
-         return 0;
+         return BigInt::zero();
 
       BigInt h = inv_o;
       h.ct_cond_add(!inv_o.get_bit(0), o);
@@ -253,7 +253,7 @@ BigInt inverse_mod(const BigInt& n, const BigInt& mod)
 
    // No modular inverse in this case:
    if(inv_o == 0 || inv_2k == 0)
-      return 0;
+      return BigInt::zero();
 
    const BigInt m2k = BigInt::power_of_2(mod_lz);
    // Compute the CRT parameter
diff --git a/src/lib/math/numbertheory/monty.cpp b/src/lib/math/numbertheory/monty.cpp
index a6e22c9b7..9021db1f0 100644
--- a/src/lib/math/numbertheory/monty.cpp
+++ b/src/lib/math/numbertheory/monty.cpp
@@ -109,7 +109,7 @@ BigInt Montgomery_Params::mul(const BigInt& x, const BigInt& y,
    BOTAN_DEBUG_ASSERT(x.sig_words() <= m_p_words);
    BOTAN_DEBUG_ASSERT(y.sig_words() <= m_p_words);
 
-   BigInt z(BigInt::Positive, output_size);
+   BigInt z = BigInt::with_capacity(output_size);
    bigint_mul(z.mutable_data(), z.size(),
               x.data(), x.size(), std::min(m_p_words, x.size()),
               y.data(), y.size(), std::min(m_p_words, y.size()),
@@ -129,7 +129,7 @@ BigInt Montgomery_Params::mul(const BigInt& x,
    const size_t output_size = 2*m_p_words + 2;
    if(ws.size() < output_size)
       ws.resize(output_size);
-   BigInt z(BigInt::Positive, output_size);
+   BigInt z = BigInt::with_capacity(output_size);
 
    BOTAN_DEBUG_ASSERT(x.sig_words() <= m_p_words);
 
@@ -208,7 +208,7 @@ BigInt Montgomery_Params::sqr(const BigInt& x, secure_vector<word>& ws) const
    if(ws.size() < output_size)
       ws.resize(output_size);
 
-   BigInt z(BigInt::Positive, output_size);
+   BigInt z = BigInt::with_capacity(output_size);
 
    BOTAN_DEBUG_ASSERT(x.sig_words() <= m_p_words);
 
@@ -283,9 +283,10 @@ Montgomery_Int::Montgomery_Int(std::shared_ptr<const Montgomery_Params> params,
 Montgomery_Int::Montgomery_Int(std::shared_ptr<const Montgomery_Params> params,
                                const word words[], size_t len,
                                bool redc_needed) :
-   m_params(params),
-   m_v(words, len)
+   m_params(params)
    {
+   m_v.set_words(words, len);
+
    if(redc_needed)
       {
       BOTAN_ASSERT_NOMSG(m_v < m_params->p());
diff --git a/src/lib/math/numbertheory/monty_exp.cpp b/src/lib/math/numbertheory/monty_exp.cpp
index 112041be2..0c17bc2bd 100644
--- a/src/lib/math/numbertheory/monty_exp.cpp
+++ b/src/lib/math/numbertheory/monty_exp.cpp
@@ -106,7 +106,7 @@ BigInt Montgomery_Exponentation_State::exponentiation(const BigInt& scalar, size
    const size_t exp_nibbles = (max_k_bits + m_window_bits - 1) / m_window_bits;
 
    if(exp_nibbles == 0)
-      return 1;
+      return BigInt::one();
 
    secure_vector<word> e_bits(m_params->p_words());
    secure_vector<word> ws;
@@ -132,7 +132,7 @@ BigInt Montgomery_Exponentation_State::exponentiation_vartime(const BigInt& scal
    secure_vector<word> ws;
 
    if(exp_nibbles == 0)
-      return 1;
+      return BigInt::one();
 
    Montgomery_Int x = m_g[scalar.get_substring(m_window_bits*(exp_nibbles-1), m_window_bits)];
 
diff --git a/src/lib/math/numbertheory/numthry.cpp b/src/lib/math/numbertheory/numthry.cpp
index 96fe37756..528b5e851 100644
--- a/src/lib/math/numbertheory/numthry.cpp
+++ b/src/lib/math/numbertheory/numthry.cpp
@@ -43,7 +43,7 @@ BigInt ressol(const BigInt& a, const BigInt& p)
       throw Invalid_Argument("ressol: invalid prime");
 
    if(a == 0)
-      return 0;
+      return BigInt::zero();
    else if(a < 0)
       throw Invalid_Argument("ressol: value to solve for must be positive");
    else if(a >= p)
@@ -53,7 +53,7 @@ BigInt ressol(const BigInt& a, const BigInt& p)
       return a;
 
    if(jacobi(a, p) != 1) // not a quadratic residue
-      return -BigInt(1);
+      return BigInt::from_s32(-1);
 
    Modular_Reducer mod_p(p);
    auto monty_p = std::make_shared<Montgomery_Params>(p, mod_p);
@@ -80,7 +80,7 @@ BigInt ressol(const BigInt& a, const BigInt& p)
    word z = 2;
    for(;;)
       {
-      if(jacobi(z, p) == -1) // found one
+      if(jacobi(BigInt::from_word(z), p) == -1) // found one
          break;
 
       z += 1; // try next z
@@ -91,10 +91,10 @@ BigInt ressol(const BigInt& a, const BigInt& p)
       * certainly we have been given a non-prime p.
       */
       if(z >= 256)
-         return -BigInt(1);
+         return BigInt::from_s32(-1);
       }
 
-   BigInt c = monty_exp_vartime(monty_p, z, (q << 1) + 1);
+   BigInt c = monty_exp_vartime(monty_p, BigInt::from_word(z), (q << 1) + 1);
 
    while(n > 1)
       {
@@ -108,7 +108,7 @@ BigInt ressol(const BigInt& a, const BigInt& p)
 
          if(i >= s)
             {
-            return -BigInt(1);
+            return BigInt::from_s32(-1);
             }
          }
 
@@ -201,7 +201,7 @@ size_t low_zero_bits(const BigInt& n)
       }
 
    // if we saw no words with x > 0 then n == 0 and the value we have
-   // computed is meaningless. Instead return 0 in that case.
+   // computed is meaningless. Instead return BigInt::zero() in that case.
    return seen_nonempty_word.if_set_return(low_zero);
    }
 
@@ -230,7 +230,7 @@ BigInt gcd(const BigInt& a, const BigInt& b)
    if(b.is_zero())
       return abs(a);
    if(a == 1 || b == 1)
-      return 1;
+      return BigInt::one();
 
    // See https://gcd.cr.yp.to/safegcd-20190413.pdf fig 1.2
 
@@ -297,14 +297,14 @@ BigInt power_mod(const BigInt& base, const BigInt& exp, const BigInt& mod)
    {
    if(mod.is_negative() || mod == 1)
       {
-      return 0;
+      return BigInt::zero();
       }
 
    if(base.is_zero() || mod.is_zero())
       {
       if(exp.is_zero())
-         return 1;
-      return 0;
+         return BigInt::one();
+      return BigInt::zero();
       }
 
    Modular_Reducer reduce_mod(mod);
@@ -321,7 +321,7 @@ BigInt power_mod(const BigInt& base, const BigInt& exp, const BigInt& mod)
    Support for even modulus is just a convenience and not considered
    cryptographically important, so this implementation is slow ...
    */
-   BigInt accum = 1;
+   BigInt accum = BigInt::one();
    BigInt g = reduce_mod.reduce(base);
    BigInt t;
 
@@ -340,7 +340,7 @@ BigInt is_perfect_square(const BigInt& C)
    if(C < 1)
       throw Invalid_Argument("is_perfect_square requires C >= 1");
    if(C == 1)
-      return 1;
+      return BigInt::one();
 
    const size_t n = C.bits();
    const size_t m = (n + 1) / 2;
@@ -361,7 +361,7 @@ BigInt is_perfect_square(const BigInt& C)
    if(X2 == C)
       return X;
    else
-      return 0;
+      return BigInt::zero();
    }
 
 /*
diff --git a/src/lib/math/numbertheory/numthry.h b/src/lib/math/numbertheory/numthry.h
index 684022a1c..92a99418b 100644
--- a/src/lib/math/numbertheory/numthry.h
+++ b/src/lib/math/numbertheory/numthry.h
@@ -136,7 +136,7 @@ BigInt BOTAN_PUBLIC_API(2,8) is_perfect_square(const BigInt& x);
 */
 BigInt BOTAN_PUBLIC_API(2,0) random_prime(RandomNumberGenerator& rng,
                                           size_t bits,
-                                          const BigInt& coprime = 0,
+                                          const BigInt& coprime = BigInt::from_u64(0),
                                           size_t equiv = 1,
                                           size_t equiv_mod = 2,
                                           size_t prob = 128);
diff --git a/src/lib/math/numbertheory/primality.cpp b/src/lib/math/numbertheory/primality.cpp
index 779677ef8..d980a8a57 100644
--- a/src/lib/math/numbertheory/primality.cpp
+++ b/src/lib/math/numbertheory/primality.cpp
@@ -25,7 +25,7 @@ bool is_lucas_probable_prime(const BigInt& C, const Modular_Reducer& mod_C)
    else if(C == 3 || C == 5 || C == 7 || C == 11 || C == 13)
       return true;
 
-   BigInt D = 5;
+   BigInt D = BigInt::from_word(5);
 
    for(;;)
       {
@@ -55,8 +55,8 @@ bool is_lucas_probable_prime(const BigInt& C, const Modular_Reducer& mod_C)
    const BigInt K = C + 1;
    const size_t K_bits = K.bits() - 1;
 
-   BigInt U = 1;
-   BigInt V = 1;
+   BigInt U = BigInt::one();
+   BigInt V = BigInt::one();
 
    BigInt Ut, Vt, U2, V2;
 
@@ -95,7 +95,8 @@ bool is_bailie_psw_probable_prime(const BigInt& n, const Modular_Reducer& mod_n)
       return false;
 
    auto monty_n = std::make_shared<Montgomery_Params>(n, mod_n);
-   return passes_miller_rabin_test(n, mod_n, monty_n, 2) && is_lucas_probable_prime(n, mod_n);
+   const auto base = BigInt::from_word(2);
+   return passes_miller_rabin_test(n, mod_n, monty_n, base) && is_lucas_probable_prime(n, mod_n);
    }
 
 bool is_bailie_psw_probable_prime(const BigInt& n)
@@ -158,7 +159,7 @@ bool is_miller_rabin_probable_prime(const BigInt& n,
 
    for(size_t i = 0; i != test_iterations; ++i)
       {
-      const BigInt a = BigInt::random_integer(rng, 2, n);
+      const BigInt a = BigInt::random_integer(rng, BigInt::from_word(2), n);
 
       if(!passes_miller_rabin_test(n, mod_n, monty_n, a))
          return false;
diff --git a/src/lib/misc/fpe_fe1/fpe_fe1.cpp b/src/lib/misc/fpe_fe1/fpe_fe1.cpp
index ab6d073c1..895ca11a0 100644
--- a/src/lib/misc/fpe_fe1/fpe_fe1.cpp
+++ b/src/lib/misc/fpe_fe1/fpe_fe1.cpp
@@ -26,8 +26,8 @@ const size_t MAX_N_BYTES = 128/8;
 */
 void factor(BigInt n, BigInt& a, BigInt& b)
    {
-   a = 1;
-   b = 1;
+   a = BigInt::one();
+   b = BigInt::one();
 
    size_t n_low_zero = low_zero_bits(n);
 
@@ -42,7 +42,7 @@ void factor(BigInt n, BigInt& a, BigInt& b)
          a *= PRIMES[i];
          if(a > b)
             std::swap(a, b);
-         n /= PRIMES[i];
+         n /= BigInt::from_word(PRIMES[i]);
          }
       }
 
diff --git a/src/lib/prov/pkcs11/p11_rsa.h b/src/lib/prov/pkcs11/p11_rsa.h
index e3b557f94..50bb688e6 100644
--- a/src/lib/prov/pkcs11/p11_rsa.h
+++ b/src/lib/prov/pkcs11/p11_rsa.h
@@ -29,7 +29,7 @@ class BOTAN_PUBLIC_API(2,0) RSA_PublicKeyGenerationProperties final : public Pub
       explicit RSA_PublicKeyGenerationProperties(Ulong bits);
 
       /// @param pub_exponent public exponent e
-      inline void set_pub_exponent(const BigInt& pub_exponent = BigInt(0x10001))
+      inline void set_pub_exponent(const BigInt& pub_exponent = BigInt::from_word(0x10001))
          {
          add_binary(AttributeType::PublicExponent, BigInt::encode(pub_exponent));
          }
diff --git a/src/lib/pubkey/dh/dh.h b/src/lib/pubkey/dh/dh.h
index 3b81bbf5d..e4c9c937d 100644
--- a/src/lib/pubkey/dh/dh.h
+++ b/src/lib/pubkey/dh/dh.h
@@ -68,7 +68,7 @@ class BOTAN_PUBLIC_API(2,0) DH_PrivateKey final : public DH_PublicKey,
       * @param x the key's secret value (or if zero, generate a new key)
       */
       DH_PrivateKey(RandomNumberGenerator& rng, const DL_Group& grp,
-                    const BigInt& x = 0);
+                    const BigInt& x = BigInt::zero());
 
       std::unique_ptr<Public_Key> public_key() const override;
 
diff --git a/src/lib/pubkey/dl_group/dl_group.cpp b/src/lib/pubkey/dl_group/dl_group.cpp
index 26ea39f17..288000b53 100644
--- a/src/lib/pubkey/dl_group/dl_group.cpp
+++ b/src/lib/pubkey/dl_group/dl_group.cpp
@@ -240,7 +240,7 @@ BigInt make_dsa_generator(const BigInt& p, const BigInt& q)
    for(size_t i = 0; i != PRIME_TABLE_SIZE; ++i)
       {
       // TODO precompute!
-      BigInt g = power_mod(PRIMES[i], e, p);
+      BigInt g = power_mod(BigInt::from_word(PRIMES[i]), e, p);
       if(g > 1)
          return g;
       }
@@ -271,13 +271,13 @@ DL_Group::DL_Group(RandomNumberGenerator& rng,
       Always choose a generator that is quadratic reside mod p,
       this forces g to be a generator of the subgroup of size q.
       */
-      BigInt g = 2;
+      BigInt g = BigInt::from_word(2);
       if(jacobi(g, p) != 1)
          {
          // prime table does not contain 2
          for(size_t i = 0; i < PRIME_TABLE_SIZE; ++i)
             {
-            g = PRIMES[i];
+            g = BigInt::from_word(PRIMES[i]);
             if(jacobi(g, p) == 1)
                break;
             }
@@ -341,7 +341,7 @@ DL_Group::DL_Group(RandomNumberGenerator& rng,
 */
 DL_Group::DL_Group(const BigInt& p, const BigInt& g)
    {
-   m_data = std::make_shared<DL_Group_Data>(p, 0, g, DL_Group_Source::ExternalSource);
+   m_data = std::make_shared<DL_Group_Data>(p, BigInt::zero(), g, DL_Group_Source::ExternalSource);
    }
 
 /*
@@ -442,7 +442,7 @@ bool DL_Group::verify_group(RandomNumberGenerator& rng,
 
          for(size_t i = 2; i != upper_bound; ++i)
             {
-            if(data().power_g_p_vartime(i) == 1)
+            if(data().power_g_p_vartime(BigInt::from_word(i)) == 1)
                {
                return false;
                }
diff --git a/src/lib/pubkey/dsa/dsa.cpp b/src/lib/pubkey/dsa/dsa.cpp
index a9cfb34f2..616b1e287 100644
--- a/src/lib/pubkey/dsa/dsa.cpp
+++ b/src/lib/pubkey/dsa/dsa.cpp
@@ -108,7 +108,7 @@ DSA_Signature_Operation::raw_sign(const uint8_t msg[], size_t msg_len,
    {
    const BigInt& q = m_group.get_q();
 
-   BigInt m(msg, msg_len, m_group.q_bits());
+   BigInt m = BigInt::from_bytes_with_max_bits(msg, msg_len, m_group.q_bits());
 
    while(m >= q)
       m -= q;
@@ -187,7 +187,7 @@ bool DSA_Verification_Operation::verify(const uint8_t msg[], size_t msg_len,
 
    BigInt r(sig, q_bytes);
    BigInt s(sig + q_bytes, q_bytes);
-   BigInt i(msg, msg_len, q.bits());
+   BigInt i = BigInt::from_bytes_with_max_bits(msg, msg_len, m_group.q_bits());
 
    if(r <= 0 || r >= q || s <= 0 || s >= q)
       return false;
diff --git a/src/lib/pubkey/dsa/dsa.h b/src/lib/pubkey/dsa/dsa.h
index 75513a78d..e2722383a 100644
--- a/src/lib/pubkey/dsa/dsa.h
+++ b/src/lib/pubkey/dsa/dsa.h
@@ -72,7 +72,7 @@ class BOTAN_PUBLIC_API(2,0) DSA_PrivateKey final : public DSA_PublicKey,
       */
       DSA_PrivateKey(RandomNumberGenerator& rng,
                      const DL_Group& group,
-                     const BigInt& private_key = 0);
+                     const BigInt& private_key = BigInt::zero());
 
       std::unique_ptr<Public_Key> public_key() const override;
 
diff --git a/src/lib/pubkey/ec_group/ec_group.cpp b/src/lib/pubkey/ec_group/ec_group.cpp
index b253f56ab..0236e6272 100644
--- a/src/lib/pubkey/ec_group/ec_group.cpp
+++ b/src/lib/pubkey/ec_group/ec_group.cpp
@@ -637,13 +637,13 @@ BigInt EC_Group::blinded_base_point_multiply_x(const BigInt& k,
    const PointGFp pt = data().blinded_base_point_multiply(k, rng, ws);
 
    if(pt.is_zero())
-      return 0;
+      return BigInt::zero();
    return pt.get_affine_x();
    }
 
 BigInt EC_Group::random_scalar(RandomNumberGenerator& rng) const
    {
-   return BigInt::random_integer(rng, 1, get_order());
+   return BigInt::random_integer(rng, BigInt::one(), get_order());
    }
 
 PointGFp EC_Group::blinded_var_point_multiply(const PointGFp& point,
diff --git a/src/lib/pubkey/ecdh/ecdh.h b/src/lib/pubkey/ecdh/ecdh.h
index 4be7e656c..4a6061e1a 100644
--- a/src/lib/pubkey/ecdh/ecdh.h
+++ b/src/lib/pubkey/ecdh/ecdh.h
@@ -86,7 +86,7 @@ class BOTAN_PUBLIC_API(2,0) ECDH_PrivateKey final : public ECDH_PublicKey,
       */
       ECDH_PrivateKey(RandomNumberGenerator& rng,
                       const EC_Group& domain,
-                      const BigInt& x = 0) :
+                      const BigInt& x = BigInt::zero()) :
          EC_PrivateKey(rng, domain, x) {}
 
       std::unique_ptr<Public_Key> public_key() const override;
diff --git a/src/lib/pubkey/ecdsa/ecdsa.cpp b/src/lib/pubkey/ecdsa/ecdsa.cpp
index 490364f8b..2324edf85 100644
--- a/src/lib/pubkey/ecdsa/ecdsa.cpp
+++ b/src/lib/pubkey/ecdsa/ecdsa.cpp
@@ -52,7 +52,7 @@ PointGFp recover_ecdsa_public_key(const EC_Group& group,
 
    try
       {
-      const BigInt e(msg.data(), msg.size(), group.get_order_bits());
+      const BigInt e = BigInt::from_bytes_with_max_bits(msg.data(), msg.size(), group.get_order_bits());
       const BigInt r_inv = group.inverse_mod_order(r);
 
       BigInt x = r + add_order*group_order;
@@ -179,7 +179,7 @@ secure_vector<uint8_t>
 ECDSA_Signature_Operation::raw_sign(const uint8_t msg[], size_t msg_len,
                                     RandomNumberGenerator& rng)
    {
-   BigInt m(msg, msg_len, m_group.get_order_bits());
+   BigInt m = BigInt::from_bytes_with_max_bits(msg, msg_len, m_group.get_order_bits());
 
 #if defined(BOTAN_HAS_RFC6979_GENERATOR)
    const BigInt k = m_rfc6979->nonce_for(m);
@@ -241,7 +241,7 @@ bool ECDSA_Verification_Operation::verify(const uint8_t msg[], size_t msg_len,
    if(sig_len != m_group.get_order_bytes() * 2)
       return false;
 
-   const BigInt e(msg, msg_len, m_group.get_order_bits());
+   const BigInt e = BigInt::from_bytes_with_max_bits(msg, msg_len, m_group.get_order_bits());
 
    const BigInt r(sig, sig_len / 2);
    const BigInt s(sig + sig_len / 2, sig_len / 2);
diff --git a/src/lib/pubkey/ecdsa/ecdsa.h b/src/lib/pubkey/ecdsa/ecdsa.h
index 2bdb9e79b..581d024e9 100644
--- a/src/lib/pubkey/ecdsa/ecdsa.h
+++ b/src/lib/pubkey/ecdsa/ecdsa.h
@@ -101,7 +101,7 @@ class BOTAN_PUBLIC_API(2,0) ECDSA_PrivateKey final : public ECDSA_PublicKey,
       */
       ECDSA_PrivateKey(RandomNumberGenerator& rng,
                        const EC_Group& domain,
-                       const BigInt& x = 0) :
+                       const BigInt& x = BigInt::zero()) :
          EC_PrivateKey(rng, domain, x) {}
 
       bool check_key(RandomNumberGenerator& rng, bool) const override;
diff --git a/src/lib/pubkey/ecgdsa/ecgdsa.cpp b/src/lib/pubkey/ecgdsa/ecgdsa.cpp
index 0fe87d14a..073f4e91a 100644
--- a/src/lib/pubkey/ecgdsa/ecgdsa.cpp
+++ b/src/lib/pubkey/ecgdsa/ecgdsa.cpp
@@ -65,7 +65,7 @@ secure_vector<uint8_t>
 ECGDSA_Signature_Operation::raw_sign(const uint8_t msg[], size_t msg_len,
                                      RandomNumberGenerator& rng)
    {
-   const BigInt m(msg, msg_len, m_group.get_order_bits());
+   const BigInt m = BigInt::from_bytes_with_max_bits(msg, msg_len, m_group.get_order_bits());
 
    const BigInt k = m_group.random_scalar(rng);
 
@@ -115,7 +115,7 @@ bool ECGDSA_Verification_Operation::verify(const uint8_t msg[], size_t msg_len,
    if(sig_len != m_group.get_order_bytes() * 2)
       return false;
 
-   const BigInt e(msg, msg_len, m_group.get_order_bits());
+   const BigInt e = BigInt::from_bytes_with_max_bits(msg, msg_len, m_group.get_order_bits());
 
    const BigInt r(sig, sig_len / 2);
    const BigInt s(sig + sig_len / 2, sig_len / 2);
diff --git a/src/lib/pubkey/ecgdsa/ecgdsa.h b/src/lib/pubkey/ecgdsa/ecgdsa.h
index cf9f09de2..ea8e912a3 100644
--- a/src/lib/pubkey/ecgdsa/ecgdsa.h
+++ b/src/lib/pubkey/ecgdsa/ecgdsa.h
@@ -79,8 +79,8 @@ class BOTAN_PUBLIC_API(2,0) ECGDSA_PrivateKey final : public ECGDSA_PublicKey,
       * @param x the private key (if zero, generate a new random key)
       */
       ECGDSA_PrivateKey(RandomNumberGenerator& rng,
-                       const EC_Group& domain,
-                       const BigInt& x = 0) :
+                        const EC_Group& domain,
+                        const BigInt& x = BigInt::zero()) :
          EC_PrivateKey(rng, domain, x, true) {}
 
       std::unique_ptr<Public_Key> public_key() const override;
diff --git a/src/lib/pubkey/eckcdsa/eckcdsa.h b/src/lib/pubkey/eckcdsa/eckcdsa.h
index 924f56c4c..ebf5ada30 100644
--- a/src/lib/pubkey/eckcdsa/eckcdsa.h
+++ b/src/lib/pubkey/eckcdsa/eckcdsa.h
@@ -79,8 +79,8 @@ class BOTAN_PUBLIC_API(2,0) ECKCDSA_PrivateKey final : public ECKCDSA_PublicKey,
       * @param x the private key (if zero, generate a new random key)
       */
       ECKCDSA_PrivateKey(RandomNumberGenerator& rng,
-                       const EC_Group& domain,
-                       const BigInt& x = 0) :
+                         const EC_Group& domain,
+                         const BigInt& x = BigInt::zero()) :
          EC_PrivateKey(rng, domain, x, true) {}
 
       bool check_key(RandomNumberGenerator& rng, bool) const override;
diff --git a/src/lib/pubkey/elgamal/elgamal.h b/src/lib/pubkey/elgamal/elgamal.h
index 0c440df00..a316d9c50 100644
--- a/src/lib/pubkey/elgamal/elgamal.h
+++ b/src/lib/pubkey/elgamal/elgamal.h
@@ -72,7 +72,7 @@ class BOTAN_PUBLIC_API(2,0) ElGamal_PrivateKey final : public ElGamal_PublicKey,
       */
       ElGamal_PrivateKey(RandomNumberGenerator& rng,
                          const DL_Group& group,
-                         const BigInt& priv_key = 0);
+                         const BigInt& priv_key = BigInt::zero());
 
       std::unique_ptr<Public_Key> public_key() const override;
 
diff --git a/src/lib/pubkey/gost_3410/gost_3410.cpp b/src/lib/pubkey/gost_3410/gost_3410.cpp
index 6ec46f3b6..cfa03fe46 100644
--- a/src/lib/pubkey/gost_3410/gost_3410.cpp
+++ b/src/lib/pubkey/gost_3410/gost_3410.cpp
@@ -161,8 +161,8 @@ GOST_3410_Signature_Operation::raw_sign(const uint8_t msg[], size_t msg_len,
    BigInt e = decode_le(msg, msg_len);
 
    e = m_group.mod_order(e);
-   if(e == 0)
-      e = 1;
+   if(e.is_zero())
+      e = BigInt::one();
 
    const BigInt r = m_group.mod_order(
       m_group.blinded_base_point_multiply_x(k, rng, m_ws));
@@ -218,8 +218,8 @@ bool GOST_3410_Verification_Operation::verify(const uint8_t msg[], size_t msg_le
 
    BigInt e = decode_le(msg, msg_len);
    e = m_group.mod_order(e);
-   if(e == 0)
-      e = 1;
+   if(e.is_zero())
+      e = BigInt::one();
 
    const BigInt v = m_group.inverse_mod_order(e);
 
diff --git a/src/lib/pubkey/gost_3410/gost_3410.h b/src/lib/pubkey/gost_3410/gost_3410.h
index ffce3ef97..ed16aeebf 100644
--- a/src/lib/pubkey/gost_3410/gost_3410.h
+++ b/src/lib/pubkey/gost_3410/gost_3410.h
@@ -88,7 +88,7 @@ class BOTAN_PUBLIC_API(2,0) GOST_3410_PrivateKey final :
       */
       GOST_3410_PrivateKey(RandomNumberGenerator& rng,
                            const EC_Group& domain,
-                           const BigInt& x = 0);
+                           const BigInt& x = BigInt::zero());
 
       std::unique_ptr<Public_Key> public_key() const override;
 
diff --git a/src/lib/pubkey/rsa/rsa.h b/src/lib/pubkey/rsa/rsa.h
index ccea7c310..99a83f820 100644
--- a/src/lib/pubkey/rsa/rsa.h
+++ b/src/lib/pubkey/rsa/rsa.h
@@ -111,9 +111,9 @@ class BOTAN_PUBLIC_API(2,0) RSA_PrivateKey final : public Private_Key, public RS
       * @param n if specified, this must be n = p * q. Leave it as 0
       * if you wish to the constructor to calculate it.
       */
-      RSA_PrivateKey(const BigInt& p, const BigInt& q,
-                     const BigInt& e, const BigInt& d = 0,
-                     const BigInt& n = 0);
+      RSA_PrivateKey(const BigInt& p, const BigInt& q, const BigInt& e,
+                     const BigInt& d = BigInt::zero(),
+                     const BigInt& n = BigInt::zero());
 
       /**
       * Create a new private key with the specified bit length
diff --git a/src/lib/pubkey/sm2/sm2.h b/src/lib/pubkey/sm2/sm2.h
index 2341ed861..d2edf3d6f 100644
--- a/src/lib/pubkey/sm2/sm2.h
+++ b/src/lib/pubkey/sm2/sm2.h
@@ -85,7 +85,7 @@ class BOTAN_PUBLIC_API(2,2) SM2_PrivateKey final :
       */
       SM2_PrivateKey(RandomNumberGenerator& rng,
                      const EC_Group& domain,
-                     const BigInt& x = 0);
+                     const BigInt& x = BigInt::zero());
 
       bool check_key(RandomNumberGenerator& rng, bool) const override;
 


Test patch:
diff --git a/src/tests/test_tests.cpp b/src/tests/test_tests.cpp
index c3cf83645..dce916008 100644
--- a/src/tests/test_tests.cpp
+++ b/src/tests/test_tests.cpp
@@ -164,14 +164,16 @@ class Test_Tests final : public Test
 #if defined(BOTAN_HAS_BIGINT)
             {
             Test::Result test_result(testcase_name);
-            Botan::BigInt x = 5, y = 6;
+            const auto x = Botan::BigInt::from_word(5);
+            const auto y = Botan::BigInt::from_word(6);
             test_result.test_eq("test ints equal", x, y);
             verify_failure("test ints equal", result, test_result);
             }
 
             {
             Test::Result test_result(testcase_name);
-            Botan::BigInt x = 5, y = 5;
+            const auto x = Botan::BigInt::from_word(5);
+            const auto y = Botan::BigInt::from_word(5);
             test_result.test_ne("test ints not equal", x, y);
             verify_failure("test ints not equal", result, test_result);
             }
diff --git a/src/tests/unit_ecdsa.cpp b/src/tests/unit_ecdsa.cpp
index ad53f00db..83e6e3a3e 100644
--- a/src/tests/unit_ecdsa.cpp
+++ b/src/tests/unit_ecdsa.cpp
@@ -237,7 +237,7 @@ Test::Result test_unusual_curve()
    const Botan::BigInt a("0x0a377dede6b523333d36c78e9b0eaa3bf48ce93041f6d4fc34014d08f6833807498deedd4290101c5866e8dfb589485d13357b9e78c2d7fbe9fe");
    const Botan::BigInt b("0x0a9acf8c8ba617777e248509bcb4717d4db346202bf9e352cd5633731dd92a51b72a4dc3b3d17c823fcc8fbda4da08f25dea89046087342595a7");
    const Botan::BigInt order_g("0x0e1a16196e6000000000bc7f1618d867b15bb86474418f");
-   const Botan::BigInt cofactor = 1;
+   const Botan::BigInt cofactor = Botan::BigInt::one();
 
    const BigInt Gx("1503931002566715881584977704503341991763310127581173321974500299341775226206001860606586625324214456299149080935147329869147994265934715820");
    const BigInt Gy("1774988776970033741491814582357926984496972046739476148938345272681378523636129776486407268230155403536112014267092770854858769258781598199");