2 *****************************************************************************
3 Implementation of bigint wrapper class around GMP's MPZ long integers.
4 *****************************************************************************
5 * @author This file is part of libsnark, developed by SCIPR Lab
6 * and contributors (see AUTHORS).
7 * @copyright MIT license (see LICENSE file)
8 *****************************************************************************/
20 bigint<n>::bigint(const unsigned long x) /// Initalize from a small integer
22 static_assert(ULONG_MAX <= GMP_NUMB_MAX, "unsigned long does not fit in a GMP limb");
27 bigint<n>::bigint(const char* s) /// Initialize from a string containing an integer in decimal notation
30 unsigned char* s_copy = new unsigned char[l];
32 for (size_t i = 0; i < l; ++i)
34 assert(s[i] >= '0' && s[i] <= '9');
35 s_copy[i] = s[i] - '0';
38 mp_size_t limbs_written = mpn_set_str(this->data, s_copy, l, 10);
39 assert(limbs_written <= n);
45 bigint<n>::bigint(const mpz_t r) /// Initialize from MPZ element
50 for (size_t i = 0; i < n; ++i)
52 data[i] = mpz_get_ui(k);
53 mpz_fdiv_q_2exp(k, k, GMP_NUMB_BITS);
56 assert(mpz_sgn(k) == 0);
61 void bigint<n>::print() const
63 gmp_printf("%Nd\n", this->data, n);
67 void bigint<n>::print_hex() const
69 gmp_printf("%Nx\n", this->data, n);
73 bool bigint<n>::operator==(const bigint<n>& other) const
75 return (mpn_cmp(this->data, other.data, n) == 0);
79 bool bigint<n>::operator!=(const bigint<n>& other) const
81 return !(operator==(other));
85 void bigint<n>::clear()
87 mpn_zero(this->data, n);
91 bool bigint<n>::is_zero() const
93 for (mp_size_t i = 0; i < n; ++i)
104 template<mp_size_t n>
105 size_t bigint<n>::num_bits() const
108 for (long i = max_bits(); i >= 0; --i)
110 if (this->test_bit(i))
118 for (long i = n-1; i >= 0; --i)
120 mp_limb_t x = this->data[i];
127 return ((i+1) * GMP_NUMB_BITS) - __builtin_clzl(x);
133 template<mp_size_t n>
134 unsigned long bigint<n>::as_ulong() const
136 return this->data[0];
139 template<mp_size_t n>
140 void bigint<n>::to_mpz(mpz_t r) const
144 for (int i = n-1; i >= 0; --i)
146 mpz_mul_2exp(r, r, GMP_NUMB_BITS);
147 mpz_add_ui(r, r, this->data[i]);
151 template<mp_size_t n>
152 bool bigint<n>::test_bit(const std::size_t bitno) const
154 if (bitno >= n * GMP_NUMB_BITS)
160 const std::size_t part = bitno/GMP_NUMB_BITS;
161 const std::size_t bit = bitno - (GMP_NUMB_BITS*part);
162 const mp_limb_t one = 1;
163 return (this->data[part] & (one<<bit));
168 template<mp_size_t n> template<mp_size_t m>
169 inline void bigint<n>::operator+=(const bigint<m>& other)
171 static_assert(n >= m, "first arg must not be smaller than second arg for bigint in-place add");
172 mpn_add(data, data, n, other.data, m);
175 template<mp_size_t n> template<mp_size_t m>
176 inline bigint<n+m> bigint<n>::operator*(const bigint<m>& other) const
178 static_assert(n >= m, "first arg must not be smaller than second arg for bigint mul");
180 mpn_mul(res.data, data, n, other.data, m);
184 template<mp_size_t n> template<mp_size_t d>
185 inline void bigint<n>::div_qr(bigint<n-d+1>& quotient, bigint<d>& remainder,
186 const bigint<n>& dividend, const bigint<d>& divisor)
188 static_assert(n >= d, "dividend must not be smaller than divisor for bigint::div_qr");
189 assert(divisor.data[d-1] != 0);
190 mpn_tdiv_qr(quotient.data, remainder.data, 0, dividend.data, n, divisor.data, d);
193 // Return a copy shortened to m limbs provided it is less than limit, throwing std::domain_error if not in range.
194 template<mp_size_t n> template<mp_size_t m>
195 inline bigint<m> bigint<n>::shorten(const bigint<m>& q, const char *msg) const
197 static_assert(m <= n, "number of limbs must not increase for bigint::shorten");
198 for (mp_size_t i = m; i < n; i++) { // high-order limbs
200 throw std::domain_error(msg);
204 mpn_copyi(res.data, data, m);
209 template<mp_size_t n>
210 inline void bigint<n>::limit(const bigint<n>& q, const char *msg) const
213 throw std::domain_error(msg);
217 template<mp_size_t n>
218 inline bool bigint<n>::operator>(const bigint<n>& other) const
220 return mpn_cmp(this->data, other.data, n) > 0;
223 template<mp_size_t n>
224 bigint<n>& bigint<n>::randomize()
226 assert(GMP_NUMB_BITS == sizeof(mp_limb_t) * 8);
228 randombytes_buf(this->data, sizeof(mp_limb_t) * n);
234 template<mp_size_t n>
235 std::ostream& operator<<(std::ostream &out, const bigint<n> &b)
238 out.write((char*)b.data, sizeof(b.data[0]) * n);
251 template<mp_size_t n>
252 std::istream& operator>>(std::istream &in, bigint<n> &b)
255 in.read((char*)b.data, sizeof(b.data[0]) * n);
261 unsigned char* s_copy = new unsigned char[l];
263 for (size_t i = 0; i < l; ++i)
265 assert(s[i] >= '0' && s[i] <= '9');
266 s_copy[i] = s[i] - '0';
269 mp_size_t limbs_written = mpn_set_str(b.data, s_copy, l, 10);
270 assert(limbs_written <= n);
278 #endif // BIGINT_TCC_