upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/bignum.h
diff options
context:
space:
mode:
authorBitflash-sh <btf01@proton.me>2026-07-24 11:18:11 -0300
committerBitflash-sh <btf01@proton.me>2026-07-24 11:18:11 -0300
commit51d617e70f90a972185917ea0096c1ecef2bfa8b (patch)
tree9fbbcd867de9de9d0776afdd02f594ba312c46eb /src/bignum.h
Bitflash: fair-launch release
Satoshi's bitcoin-0.1.0 reborn with RandomX CPU proof of work, anonymous .btf addressing over Nostr with CGNAT rendezvous, automatic peer discovery, a headless Linux node, and Windows GUI wallet. Fair launch, no premine, 21M cap.
Diffstat (limited to 'src/bignum.h')
-rw-r--r--src/bignum.h525
1 files changed, 525 insertions, 0 deletions
diff --git a/src/bignum.h b/src/bignum.h
new file mode 100644
index 0000000..9da104b
--- /dev/null
+++ b/src/bignum.h
@@ -0,0 +1,525 @@
1// Copyright (c) 2009 Satoshi Nakamoto
2// Distributed under the MIT/X11 software license, see the accompanying
3// file license.txt or http://www.opensource.org/licenses/mit-license.php.
4//
5// Ported to OpenSSL 1.1+/3.x: BIGNUM became an opaque type, so CBigNum now
6// wraps a BIGNUM* instead of inheriting from BIGNUM. Identical semantics.
7
8#include <stdexcept>
9#include <vector>
10#include <openssl/bn.h>
11
12
13
14
15
16class bignum_error : public std::runtime_error
17{
18public:
19 explicit bignum_error(const std::string& str) : std::runtime_error(str) {}
20};
21
22
23
24class CAutoBN_CTX
25{
26protected:
27 BN_CTX* pctx;
28 BN_CTX* operator=(BN_CTX* pnew) { return pctx = pnew; }
29
30public:
31 CAutoBN_CTX()
32 {
33 pctx = BN_CTX_new();
34 if (pctx == NULL)
35 throw bignum_error("CAutoBN_CTX : BN_CTX_new() returned NULL");
36 }
37
38 ~CAutoBN_CTX()
39 {
40 if (pctx != NULL)
41 BN_CTX_free(pctx);
42 }
43
44 operator BN_CTX*() { return pctx; }
45 BN_CTX& operator*() { return *pctx; }
46 BN_CTX** operator&() { return &pctx; }
47 bool operator!() { return (pctx == NULL); }
48};
49
50
51
52class CBigNum
53{
54protected:
55 BIGNUM* bn;
56
57 void init()
58 {
59 bn = BN_new();
60 if (bn == NULL)
61 throw bignum_error("CBigNum : BN_new failed");
62 }
63
64public:
65 BIGNUM* get() { return bn; }
66 const BIGNUM* get() const { return bn; }
67
68 CBigNum()
69 {
70 init();
71 }
72
73 CBigNum(const CBigNum& b)
74 {
75 init();
76 if (!BN_copy(bn, b.bn))
77 {
78 BN_clear_free(bn);
79 throw bignum_error("CBigNum::CBigNum(const CBigNum&) : BN_copy failed");
80 }
81 }
82
83 explicit CBigNum(const std::string& str)
84 {
85 init();
86 SetHex(str);
87 }
88
89 CBigNum& operator=(const CBigNum& b)
90 {
91 if (!BN_copy(bn, b.bn))
92 throw bignum_error("CBigNum::operator= : BN_copy failed");
93 return (*this);
94 }
95
96 ~CBigNum()
97 {
98 BN_clear_free(bn);
99 }
100
101 CBigNum(char n) { init(); if (n >= 0) setulong(n); else setint64(n); }
102 CBigNum(short n) { init(); if (n >= 0) setulong(n); else setint64(n); }
103 CBigNum(int n) { init(); if (n >= 0) setulong(n); else setint64(n); }
104 CBigNum(long n) { init(); if (n >= 0) setulong(n); else setint64(n); }
105 CBigNum(int64 n) { init(); setint64(n); }
106 CBigNum(unsigned char n) { init(); setulong(n); }
107 CBigNum(unsigned short n) { init(); setulong(n); }
108 CBigNum(unsigned int n) { init(); setulong(n); }
109 CBigNum(unsigned long n) { init(); setulong(n); }
110 CBigNum(uint64 n) { init(); setuint64(n); }
111 explicit CBigNum(uint256 n) { init(); setuint256(n); }
112
113 explicit CBigNum(const std::vector<unsigned char>& vch)
114 {
115 init();
116 setvch(vch);
117 }
118
119 void setulong(unsigned long n)
120 {
121 if (!BN_set_word(bn, n))
122 throw bignum_error("CBigNum conversion from unsigned long : BN_set_word failed");
123 }
124
125 unsigned long getulong() const
126 {
127 return BN_get_word(bn);
128 }
129
130 unsigned int getuint() const
131 {
132 return BN_get_word(bn);
133 }
134
135 int getint() const
136 {
137 unsigned long n = BN_get_word(bn);
138 if (!BN_is_negative(bn))
139 return (n > INT_MAX ? INT_MAX : n);
140 else
141 return (n > INT_MAX ? INT_MIN : -(int)n);
142 }
143
144 void setint64(int64 n)
145 {
146 unsigned char pch[sizeof(n) + 6];
147 unsigned char* p = pch + 4;
148 bool fNegative = false;
149 if (n < (int64)0)
150 {
151 n = -n;
152 fNegative = true;
153 }
154 bool fLeadingZeroes = true;
155 for (int i = 0; i < 8; i++)
156 {
157 unsigned char c = (n >> 56) & 0xff;
158 n <<= 8;
159 if (fLeadingZeroes)
160 {
161 if (c == 0)
162 continue;
163 if (c & 0x80)
164 *p++ = (fNegative ? 0x80 : 0);
165 else if (fNegative)
166 c |= 0x80;
167 fLeadingZeroes = false;
168 }
169 *p++ = c;
170 }
171 unsigned int nSize = p - (pch + 4);
172 pch[0] = (nSize >> 24) & 0xff;
173 pch[1] = (nSize >> 16) & 0xff;
174 pch[2] = (nSize >> 8) & 0xff;
175 pch[3] = (nSize) & 0xff;
176 BN_mpi2bn(pch, p - pch, bn);
177 }
178
179 void setuint64(uint64 n)
180 {
181 unsigned char pch[sizeof(n) + 6];
182 unsigned char* p = pch + 4;
183 bool fLeadingZeroes = true;
184 for (int i = 0; i < 8; i++)
185 {
186 unsigned char c = (n >> 56) & 0xff;
187 n <<= 8;
188 if (fLeadingZeroes)
189 {
190 if (c == 0)
191 continue;
192 if (c & 0x80)
193 *p++ = 0;
194 fLeadingZeroes = false;
195 }
196 *p++ = c;
197 }
198 unsigned int nSize = p - (pch + 4);
199 pch[0] = (nSize >> 24) & 0xff;
200 pch[1] = (nSize >> 16) & 0xff;
201 pch[2] = (nSize >> 8) & 0xff;
202 pch[3] = (nSize) & 0xff;
203 BN_mpi2bn(pch, p - pch, bn);
204 }
205
206 void setuint256(uint256 n)
207 {
208 unsigned char pch[sizeof(n) + 6];
209 unsigned char* p = pch + 4;
210 bool fLeadingZeroes = true;
211 unsigned char* pbegin = (unsigned char*)&n;
212 unsigned char* psrc = pbegin + sizeof(n);
213 while (psrc != pbegin)
214 {
215 unsigned char c = *(--psrc);
216 if (fLeadingZeroes)
217 {
218 if (c == 0)
219 continue;
220 if (c & 0x80)
221 *p++ = 0;
222 fLeadingZeroes = false;
223 }
224 *p++ = c;
225 }
226 unsigned int nSize = p - (pch + 4);
227 pch[0] = (nSize >> 24) & 0xff;
228 pch[1] = (nSize >> 16) & 0xff;
229 pch[2] = (nSize >> 8) & 0xff;
230 pch[3] = (nSize >> 0) & 0xff;
231 BN_mpi2bn(pch, p - pch, bn);
232 }
233
234 uint256 getuint256()
235 {
236 unsigned int nSize = BN_bn2mpi(bn, NULL);
237 if (nSize < 4)
238 return 0;
239 std::vector<unsigned char> vch(nSize);
240 BN_bn2mpi(bn, &vch[0]);
241 if (vch.size() > 4)
242 vch[4] &= 0x7f;
243 uint256 n = 0;
244 for (int i = 0, j = vch.size()-1; i < sizeof(n) && j >= 4; i++, j--)
245 ((unsigned char*)&n)[i] = vch[j];
246 return n;
247 }
248
249 void setvch(const std::vector<unsigned char>& vch)
250 {
251 std::vector<unsigned char> vch2(vch.size() + 4);
252 unsigned int nSize = vch.size();
253 vch2[0] = (nSize >> 24) & 0xff;
254 vch2[1] = (nSize >> 16) & 0xff;
255 vch2[2] = (nSize >> 8) & 0xff;
256 vch2[3] = (nSize >> 0) & 0xff;
257 reverse_copy(vch.begin(), vch.end(), vch2.begin() + 4);
258 BN_mpi2bn(&vch2[0], vch2.size(), bn);
259 }
260
261 std::vector<unsigned char> getvch() const
262 {
263 unsigned int nSize = BN_bn2mpi(bn, NULL);
264 if (nSize < 4)
265 return std::vector<unsigned char>();
266 std::vector<unsigned char> vch(nSize);
267 BN_bn2mpi(bn, &vch[0]);
268 vch.erase(vch.begin(), vch.begin() + 4);
269 reverse(vch.begin(), vch.end());
270 return vch;
271 }
272
273 CBigNum& SetCompact(unsigned int nCompact)
274 {
275 unsigned int nSize = nCompact >> 24;
276 std::vector<unsigned char> vch(4 + nSize);
277 vch[3] = nSize;
278 if (nSize >= 1) vch[4] = (nCompact >> 16) & 0xff;
279 if (nSize >= 2) vch[5] = (nCompact >> 8) & 0xff;
280 if (nSize >= 3) vch[6] = (nCompact >> 0) & 0xff;
281 BN_mpi2bn(&vch[0], vch.size(), bn);
282 return *this;
283 }
284
285 unsigned int GetCompact() const
286 {
287 unsigned int nSize = BN_bn2mpi(bn, NULL);
288 std::vector<unsigned char> vch(nSize);
289 nSize -= 4;
290 BN_bn2mpi(bn, &vch[0]);
291 unsigned int nCompact = nSize << 24;
292 if (nSize >= 1) nCompact |= (vch[4] << 16);
293 if (nSize >= 2) nCompact |= (vch[5] << 8);
294 if (nSize >= 3) nCompact |= (vch[6] << 0);
295 return nCompact;
296 }
297
298 void SetHex(const std::string& str)
299 {
300 // skip 0x
301 const char* psz = str.c_str();
302 while (isspace(*psz))
303 psz++;
304 bool fNegative = false;
305 if (*psz == '-')
306 {
307 fNegative = true;
308 psz++;
309 }
310 if (psz[0] == '0' && tolower(psz[1]) == 'x')
311 psz += 2;
312 while (isspace(*psz))
313 psz++;
314
315 // hex string to bignum
316 static char phexdigit[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0 };
317 *this = 0;
318 while (isxdigit(*psz))
319 {
320 *this <<= 4;
321 int n = phexdigit[(unsigned char)*psz++];
322 *this += n;
323 }
324 if (fNegative)
325 *this = 0 - *this;
326 }
327
328 unsigned int GetSerializeSize(int nType=0, int nVersion=VERSION) const
329 {
330 return ::GetSerializeSize(getvch(), nType, nVersion);
331 }
332
333 template<typename Stream>
334 void Serialize(Stream& s, int nType=0, int nVersion=VERSION) const
335 {
336 ::Serialize(s, getvch(), nType, nVersion);
337 }
338
339 template<typename Stream>
340 void Unserialize(Stream& s, int nType=0, int nVersion=VERSION)
341 {
342 vector<unsigned char> vch;
343 ::Unserialize(s, vch, nType, nVersion);
344 setvch(vch);
345 }
346
347
348 bool operator!() const
349 {
350 return BN_is_zero(bn);
351 }
352
353 CBigNum& operator+=(const CBigNum& b)
354 {
355 if (!BN_add(bn, bn, b.bn))
356 throw bignum_error("CBigNum::operator+= : BN_add failed");
357 return *this;
358 }
359
360 CBigNum& operator-=(const CBigNum& b)
361 {
362 *this = *this - b;
363 return *this;
364 }
365
366 CBigNum& operator*=(const CBigNum& b)
367 {
368 CAutoBN_CTX pctx;
369 if (!BN_mul(bn, bn, b.bn, pctx))
370 throw bignum_error("CBigNum::operator*= : BN_mul failed");
371 return *this;
372 }
373
374 CBigNum& operator/=(const CBigNum& b)
375 {
376 *this = *this / b;
377 return *this;
378 }
379
380 CBigNum& operator%=(const CBigNum& b)
381 {
382 *this = *this % b;
383 return *this;
384 }
385
386 CBigNum& operator<<=(unsigned int shift)
387 {
388 if (!BN_lshift(bn, bn, shift))
389 throw bignum_error("CBigNum:operator<<= : BN_lshift failed");
390 return *this;
391 }
392
393 CBigNum& operator>>=(unsigned int shift)
394 {
395 if (!BN_rshift(bn, bn, shift))
396 throw bignum_error("CBigNum:operator>>= : BN_rshift failed");
397 return *this;
398 }
399
400
401 CBigNum& operator++()
402 {
403 // prefix operator
404 if (!BN_add(bn, bn, BN_value_one()))
405 throw bignum_error("CBigNum::operator++ : BN_add failed");
406 return *this;
407 }
408
409 const CBigNum operator++(int)
410 {
411 // postfix operator
412 const CBigNum ret = *this;
413 ++(*this);
414 return ret;
415 }
416
417 CBigNum& operator--()
418 {
419 // prefix operator
420 CBigNum r;
421 if (!BN_sub(r.bn, bn, BN_value_one()))
422 throw bignum_error("CBigNum::operator-- : BN_sub failed");
423 *this = r;
424 return *this;
425 }
426
427 const CBigNum operator--(int)
428 {
429 // postfix operator
430 const CBigNum ret = *this;
431 --(*this);
432 return ret;
433 }
434
435
436 friend inline const CBigNum operator+(const CBigNum& a, const CBigNum& b);
437 friend inline const CBigNum operator-(const CBigNum& a, const CBigNum& b);
438 friend inline const CBigNum operator-(const CBigNum& a);
439 friend inline const CBigNum operator*(const CBigNum& a, const CBigNum& b);
440 friend inline const CBigNum operator/(const CBigNum& a, const CBigNum& b);
441 friend inline const CBigNum operator%(const CBigNum& a, const CBigNum& b);
442 friend inline const CBigNum operator<<(const CBigNum& a, unsigned int shift);
443 friend inline const CBigNum operator>>(const CBigNum& a, unsigned int shift);
444 friend inline bool operator==(const CBigNum& a, const CBigNum& b);
445 friend inline bool operator!=(const CBigNum& a, const CBigNum& b);
446 friend inline bool operator<=(const CBigNum& a, const CBigNum& b);
447 friend inline bool operator>=(const CBigNum& a, const CBigNum& b);
448 friend inline bool operator<(const CBigNum& a, const CBigNum& b);
449 friend inline bool operator>(const CBigNum& a, const CBigNum& b);
450};
451
452
453
454inline const CBigNum operator+(const CBigNum& a, const CBigNum& b)
455{
456 CBigNum r;
457 if (!BN_add(r.bn, a.bn, b.bn))
458 throw bignum_error("CBigNum::operator+ : BN_add failed");
459 return r;
460}
461
462inline const CBigNum operator-(const CBigNum& a, const CBigNum& b)
463{
464 CBigNum r;
465 if (!BN_sub(r.bn, a.bn, b.bn))
466 throw bignum_error("CBigNum::operator- : BN_sub failed");
467 return r;
468}
469
470inline const CBigNum operator-(const CBigNum& a)
471{
472 CBigNum r(a);
473 BN_set_negative(r.bn, !BN_is_negative(r.bn));
474 return r;
475}
476
477inline const CBigNum operator*(const CBigNum& a, const CBigNum& b)
478{
479 CAutoBN_CTX pctx;
480 CBigNum r;
481 if (!BN_mul(r.bn, a.bn, b.bn, pctx))
482 throw bignum_error("CBigNum::operator* : BN_mul failed");
483 return r;
484}
485
486inline const CBigNum operator/(const CBigNum& a, const CBigNum& b)
487{
488 CAutoBN_CTX pctx;
489 CBigNum r;
490 if (!BN_div(r.bn, NULL, a.bn, b.bn, pctx))
491 throw bignum_error("CBigNum::operator/ : BN_div failed");
492 return r;
493}
494
495inline const CBigNum operator%(const CBigNum& a, const CBigNum& b)
496{
497 CAutoBN_CTX pctx;
498 CBigNum r;
499 if (!BN_mod(r.bn, a.bn, b.bn, pctx))
500 throw bignum_error("CBigNum::operator% : BN_div failed");
501 return r;
502}
503
504inline const CBigNum operator<<(const CBigNum& a, unsigned int shift)
505{
506 CBigNum r;
507 if (!BN_lshift(r.bn, a.bn, shift))
508 throw bignum_error("CBigNum:operator<< : BN_lshift failed");
509 return r;
510}
511
512inline const CBigNum operator>>(const CBigNum& a, unsigned int shift)
513{
514 CBigNum r;
515 if (!BN_rshift(r.bn, a.bn, shift))
516 throw bignum_error("CBigNum:operator>> : BN_rshift failed");
517 return r;
518}
519
520inline bool operator==(const CBigNum& a, const CBigNum& b) { return (BN_cmp(a.bn, b.bn) == 0); }
521inline bool operator!=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(a.bn, b.bn) != 0); }
522inline bool operator<=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(a.bn, b.bn) <= 0); }
523inline bool operator>=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(a.bn, b.bn) >= 0); }
524inline bool operator<(const CBigNum& a, const CBigNum& b) { return (BN_cmp(a.bn, b.bn) < 0); }
525inline bool operator>(const CBigNum& a, const CBigNum& b) { return (BN_cmp(a.bn, b.bn) > 0); }