1 //
2 // Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 #include "td/utils/BigNum.h"
8 
9 char disable_linker_warning_about_empty_file_bignum_cpp TD_UNUSED;
10 
11 #if TD_HAVE_OPENSSL
12 
13 #include "td/utils/logging.h"
14 #include "td/utils/misc.h"
15 #include "td/utils/SliceBuilder.h"
16 
17 #include <openssl/bn.h>
18 #include <openssl/crypto.h>
19 
20 #include <algorithm>
21 
22 namespace td {
23 
24 class BigNumContext::Impl {
25  public:
26   BN_CTX *big_num_context;
27 
Impl()28   Impl() : big_num_context(BN_CTX_new()) {
29     LOG_IF(FATAL, big_num_context == nullptr);
30   }
31   Impl(const Impl &other) = delete;
32   Impl &operator=(const Impl &other) = delete;
33   Impl(Impl &&other) = delete;
34   Impl &operator=(Impl &&other) = delete;
~Impl()35   ~Impl() {
36     BN_CTX_free(big_num_context);
37   }
38 };
39 
BigNumContext()40 BigNumContext::BigNumContext() : impl_(make_unique<Impl>()) {
41 }
42 
43 BigNumContext::BigNumContext(BigNumContext &&other) noexcept = default;
44 BigNumContext &BigNumContext::operator=(BigNumContext &&other) noexcept = default;
45 BigNumContext::~BigNumContext() = default;
46 
47 class BigNum::Impl {
48  public:
49   BIGNUM *big_num;
50 
Impl()51   Impl() : Impl(BN_new()) {
52   }
Impl(BIGNUM * big_num)53   explicit Impl(BIGNUM *big_num) : big_num(big_num) {
54     LOG_IF(FATAL, big_num == nullptr);
55   }
56   Impl(const Impl &other) = delete;
57   Impl &operator=(const Impl &other) = delete;
58   Impl(Impl &&other) = delete;
59   Impl &operator=(Impl &&other) = delete;
~Impl()60   ~Impl() {
61     BN_clear_free(big_num);
62   }
63 };
64 
BigNum()65 BigNum::BigNum() : impl_(make_unique<Impl>()) {
66 }
67 
BigNum(const BigNum & other)68 BigNum::BigNum(const BigNum &other) : BigNum() {
69   *this = other;
70 }
71 
operator =(const BigNum & other)72 BigNum &BigNum::operator=(const BigNum &other) {
73   if (this == &other) {
74     return *this;
75   }
76   CHECK(impl_ != nullptr);
77   CHECK(other.impl_ != nullptr);
78   BIGNUM *result = BN_copy(impl_->big_num, other.impl_->big_num);
79   LOG_IF(FATAL, result == nullptr);
80   return *this;
81 }
82 
83 BigNum::BigNum(BigNum &&other) noexcept = default;
84 BigNum &BigNum::operator=(BigNum &&other) noexcept = default;
85 BigNum::~BigNum() = default;
86 
from_binary(Slice str)87 BigNum BigNum::from_binary(Slice str) {
88   return BigNum(make_unique<Impl>(BN_bin2bn(str.ubegin(), narrow_cast<int>(str.size()), nullptr)));
89 }
90 
from_le_binary(Slice str)91 BigNum BigNum::from_le_binary(Slice str) {
92 #if defined(OPENSSL_IS_BORINGSSL)
93   return BigNum(make_unique<Impl>(BN_le2bn(str.ubegin(), narrow_cast<int>(str.size()), nullptr)));
94 #elif OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
95   return BigNum(make_unique<Impl>(BN_lebin2bn(str.ubegin(), narrow_cast<int>(str.size()), nullptr)));
96 #else
97   string str_copy = str.str();
98   std::reverse(str_copy.begin(), str_copy.end());
99   return from_binary(str_copy);
100 #endif
101 }
102 
from_decimal(CSlice str)103 Result<BigNum> BigNum::from_decimal(CSlice str) {
104   BigNum result;
105   int res = BN_dec2bn(&result.impl_->big_num, str.c_str());
106   if (res == 0 || static_cast<size_t>(res) != str.size()) {
107     return Status::Error(PSLICE() << "Failed to parse \"" << str << "\" as BigNum");
108   }
109   return result;
110 }
111 
from_hex(CSlice str)112 Result<BigNum> BigNum::from_hex(CSlice str) {
113   BigNum result;
114   int res = BN_hex2bn(&result.impl_->big_num, str.c_str());
115   if (res == 0 || static_cast<size_t>(res) != str.size()) {
116     return Status::Error(PSLICE() << "Failed to parse \"" << str << "\" as hexadecimal BigNum");
117   }
118   return result;
119 }
120 
from_raw(void * openssl_big_num)121 BigNum BigNum::from_raw(void *openssl_big_num) {
122   return BigNum(make_unique<Impl>(static_cast<BIGNUM *>(openssl_big_num)));
123 }
124 
BigNum(unique_ptr<Impl> && impl)125 BigNum::BigNum(unique_ptr<Impl> &&impl) : impl_(std::move(impl)) {
126 }
127 
get_num_bits() const128 int BigNum::get_num_bits() const {
129   return BN_num_bits(impl_->big_num);
130 }
131 
get_num_bytes() const132 int BigNum::get_num_bytes() const {
133   return BN_num_bytes(impl_->big_num);
134 }
135 
set_bit(int num)136 void BigNum::set_bit(int num) {
137   int result = BN_set_bit(impl_->big_num, num);
138   LOG_IF(FATAL, result != 1);
139 }
140 
clear_bit(int num)141 void BigNum::clear_bit(int num) {
142   int result = BN_clear_bit(impl_->big_num, num);
143   LOG_IF(FATAL, result != 1);
144 }
145 
is_bit_set(int num) const146 bool BigNum::is_bit_set(int num) const {
147   return BN_is_bit_set(impl_->big_num, num) != 0;
148 }
149 
is_prime(BigNumContext & context) const150 bool BigNum::is_prime(BigNumContext &context) const {
151 #if OPENSSL_VERSION_NUMBER >= 0x30000000L && !defined(LIBRESSL_VERSION_NUMBER)
152   int result = BN_check_prime(impl_->big_num, context.impl_->big_num_context, nullptr);
153 #else
154   int result =
155       BN_is_prime_ex(impl_->big_num, get_num_bits() > 2048 ? 128 : 64, context.impl_->big_num_context, nullptr);
156 #endif
157   LOG_IF(FATAL, result == -1);
158   return result == 1;
159 }
160 
operator +=(uint32 value)161 void BigNum::operator+=(uint32 value) {
162   int result = BN_add_word(impl_->big_num, value);
163   LOG_IF(FATAL, result != 1);
164 }
165 
operator -=(uint32 value)166 void BigNum::operator-=(uint32 value) {
167   int result = BN_sub_word(impl_->big_num, value);
168   LOG_IF(FATAL, result != 1);
169 }
170 
operator *=(uint32 value)171 void BigNum::operator*=(uint32 value) {
172   int result = BN_mul_word(impl_->big_num, value);
173   LOG_IF(FATAL, result != 1);
174 }
175 
operator /=(uint32 value)176 void BigNum::operator/=(uint32 value) {
177   BN_ULONG result = BN_div_word(impl_->big_num, value);
178   LOG_IF(FATAL, result == static_cast<BN_ULONG>(-1));
179 }
180 
operator %(uint32 value) const181 uint32 BigNum::operator%(uint32 value) const {
182   BN_ULONG result = BN_mod_word(impl_->big_num, value);
183   LOG_IF(FATAL, result == static_cast<BN_ULONG>(-1));
184   return narrow_cast<uint32>(result);
185 }
186 
set_value(uint32 new_value)187 void BigNum::set_value(uint32 new_value) {
188   if (new_value == 0) {
189     BN_zero(impl_->big_num);
190   } else {
191     int result = BN_set_word(impl_->big_num, new_value);
192     LOG_IF(FATAL, result != 1);
193   }
194 }
195 
clone() const196 BigNum BigNum::clone() const {
197   BIGNUM *result = BN_dup(impl_->big_num);
198   LOG_IF(FATAL, result == nullptr);
199   return BigNum(make_unique<Impl>(result));
200 }
201 
to_binary(int exact_size) const202 string BigNum::to_binary(int exact_size) const {
203   int num_size = get_num_bytes();
204   if (exact_size == -1) {
205     exact_size = num_size;
206   } else {
207     CHECK(exact_size >= num_size);
208   }
209   string res(exact_size, '\0');
210   BN_bn2bin(impl_->big_num, MutableSlice(res).ubegin() + (exact_size - num_size));
211   return res;
212 }
213 
to_le_binary(int exact_size) const214 string BigNum::to_le_binary(int exact_size) const {
215 #if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) || defined(OPENSSL_IS_BORINGSSL)
216   int num_size = get_num_bytes();
217   if (exact_size == -1) {
218     exact_size = num_size;
219   } else {
220     CHECK(exact_size >= num_size);
221   }
222   string result(exact_size, '\0');
223 #if defined(OPENSSL_IS_BORINGSSL)
224   BN_bn2le_padded(MutableSlice(result).ubegin(), exact_size, impl_->big_num);
225 #else
226   BN_bn2lebinpad(impl_->big_num, MutableSlice(result).ubegin(), exact_size);
227 #endif
228   return result;
229 #else
230   string result = to_binary(exact_size);
231   std::reverse(result.begin(), result.end());
232   return result;
233 #endif
234 }
235 
to_decimal() const236 string BigNum::to_decimal() const {
237   char *result = BN_bn2dec(impl_->big_num);
238   CHECK(result != nullptr);
239   string res(result);
240   OPENSSL_free(result);
241   return res;
242 }
243 
random(BigNum & r,int bits,int top,int bottom)244 void BigNum::random(BigNum &r, int bits, int top, int bottom) {
245   int result = BN_rand(r.impl_->big_num, bits, top, bottom);
246   LOG_IF(FATAL, result != 1);
247 }
248 
add(BigNum & r,const BigNum & a,const BigNum & b)249 void BigNum::add(BigNum &r, const BigNum &a, const BigNum &b) {
250   int result = BN_add(r.impl_->big_num, a.impl_->big_num, b.impl_->big_num);
251   LOG_IF(FATAL, result != 1);
252 }
253 
sub(BigNum & r,const BigNum & a,const BigNum & b)254 void BigNum::sub(BigNum &r, const BigNum &a, const BigNum &b) {
255   CHECK(r.impl_->big_num != a.impl_->big_num);
256   CHECK(r.impl_->big_num != b.impl_->big_num);
257   int result = BN_sub(r.impl_->big_num, a.impl_->big_num, b.impl_->big_num);
258   LOG_IF(FATAL, result != 1);
259 }
260 
mul(BigNum & r,BigNum & a,BigNum & b,BigNumContext & context)261 void BigNum::mul(BigNum &r, BigNum &a, BigNum &b, BigNumContext &context) {
262   int result = BN_mul(r.impl_->big_num, a.impl_->big_num, b.impl_->big_num, context.impl_->big_num_context);
263   LOG_IF(FATAL, result != 1);
264 }
265 
mod_add(BigNum & r,BigNum & a,BigNum & b,const BigNum & m,BigNumContext & context)266 void BigNum::mod_add(BigNum &r, BigNum &a, BigNum &b, const BigNum &m, BigNumContext &context) {
267   int result = BN_mod_add(r.impl_->big_num, a.impl_->big_num, b.impl_->big_num, m.impl_->big_num,
268                           context.impl_->big_num_context);
269   LOG_IF(FATAL, result != 1);
270 }
271 
mod_sub(BigNum & r,BigNum & a,BigNum & b,const BigNum & m,BigNumContext & context)272 void BigNum::mod_sub(BigNum &r, BigNum &a, BigNum &b, const BigNum &m, BigNumContext &context) {
273   int result = BN_mod_sub(r.impl_->big_num, a.impl_->big_num, b.impl_->big_num, m.impl_->big_num,
274                           context.impl_->big_num_context);
275   LOG_IF(FATAL, result != 1);
276 }
277 
mod_mul(BigNum & r,BigNum & a,BigNum & b,const BigNum & m,BigNumContext & context)278 void BigNum::mod_mul(BigNum &r, BigNum &a, BigNum &b, const BigNum &m, BigNumContext &context) {
279   int result = BN_mod_mul(r.impl_->big_num, a.impl_->big_num, b.impl_->big_num, m.impl_->big_num,
280                           context.impl_->big_num_context);
281   LOG_IF(FATAL, result != 1);
282 }
283 
mod_inverse(BigNum & r,BigNum & a,const BigNum & m,BigNumContext & context)284 void BigNum::mod_inverse(BigNum &r, BigNum &a, const BigNum &m, BigNumContext &context) {
285   auto result = BN_mod_inverse(r.impl_->big_num, a.impl_->big_num, m.impl_->big_num, context.impl_->big_num_context);
286   LOG_IF(FATAL, result != r.impl_->big_num);
287 }
288 
div(BigNum * quotient,BigNum * remainder,const BigNum & dividend,const BigNum & divisor,BigNumContext & context)289 void BigNum::div(BigNum *quotient, BigNum *remainder, const BigNum &dividend, const BigNum &divisor,
290                  BigNumContext &context) {
291   auto q = quotient == nullptr ? nullptr : quotient->impl_->big_num;
292   auto r = remainder == nullptr ? nullptr : remainder->impl_->big_num;
293   if (q == nullptr && r == nullptr) {
294     return;
295   }
296 
297   auto result = BN_div(q, r, dividend.impl_->big_num, divisor.impl_->big_num, context.impl_->big_num_context);
298   LOG_IF(FATAL, result != 1);
299 }
300 
mod_exp(BigNum & r,const BigNum & a,const BigNum & p,const BigNum & m,BigNumContext & context)301 void BigNum::mod_exp(BigNum &r, const BigNum &a, const BigNum &p, const BigNum &m, BigNumContext &context) {
302   int result = BN_mod_exp(r.impl_->big_num, a.impl_->big_num, p.impl_->big_num, m.impl_->big_num,
303                           context.impl_->big_num_context);
304   LOG_IF(FATAL, result != 1);
305 }
306 
gcd(BigNum & r,BigNum & a,BigNum & b,BigNumContext & context)307 void BigNum::gcd(BigNum &r, BigNum &a, BigNum &b, BigNumContext &context) {
308   int result = BN_gcd(r.impl_->big_num, a.impl_->big_num, b.impl_->big_num, context.impl_->big_num_context);
309   LOG_IF(FATAL, result != 1);
310 }
311 
compare(const BigNum & a,const BigNum & b)312 int BigNum::compare(const BigNum &a, const BigNum &b) {
313   return BN_cmp(a.impl_->big_num, b.impl_->big_num);
314 }
315 
operator <<(StringBuilder & sb,const BigNum & bn)316 StringBuilder &operator<<(StringBuilder &sb, const BigNum &bn) {
317   return sb << bn.to_decimal();
318 }
319 
320 }  // namespace td
321 #endif
322