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 ÷nd, 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