From 51d617e70f90a972185917ea0096c1ecef2bfa8b Mon Sep 17 00:00:00 2001 From: Bitflash-sh Date: Fri, 24 Jul 2026 11:18:11 -0300 Subject: 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. --- src/bignum.h | 525 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 525 insertions(+) create mode 100644 src/bignum.h (limited to 'src/bignum.h') 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 @@ +// Copyright (c) 2009 Satoshi Nakamoto +// Distributed under the MIT/X11 software license, see the accompanying +// file license.txt or http://www.opensource.org/licenses/mit-license.php. +// +// Ported to OpenSSL 1.1+/3.x: BIGNUM became an opaque type, so CBigNum now +// wraps a BIGNUM* instead of inheriting from BIGNUM. Identical semantics. + +#include +#include +#include + + + + + +class bignum_error : public std::runtime_error +{ +public: + explicit bignum_error(const std::string& str) : std::runtime_error(str) {} +}; + + + +class CAutoBN_CTX +{ +protected: + BN_CTX* pctx; + BN_CTX* operator=(BN_CTX* pnew) { return pctx = pnew; } + +public: + CAutoBN_CTX() + { + pctx = BN_CTX_new(); + if (pctx == NULL) + throw bignum_error("CAutoBN_CTX : BN_CTX_new() returned NULL"); + } + + ~CAutoBN_CTX() + { + if (pctx != NULL) + BN_CTX_free(pctx); + } + + operator BN_CTX*() { return pctx; } + BN_CTX& operator*() { return *pctx; } + BN_CTX** operator&() { return &pctx; } + bool operator!() { return (pctx == NULL); } +}; + + + +class CBigNum +{ +protected: + BIGNUM* bn; + + void init() + { + bn = BN_new(); + if (bn == NULL) + throw bignum_error("CBigNum : BN_new failed"); + } + +public: + BIGNUM* get() { return bn; } + const BIGNUM* get() const { return bn; } + + CBigNum() + { + init(); + } + + CBigNum(const CBigNum& b) + { + init(); + if (!BN_copy(bn, b.bn)) + { + BN_clear_free(bn); + throw bignum_error("CBigNum::CBigNum(const CBigNum&) : BN_copy failed"); + } + } + + explicit CBigNum(const std::string& str) + { + init(); + SetHex(str); + } + + CBigNum& operator=(const CBigNum& b) + { + if (!BN_copy(bn, b.bn)) + throw bignum_error("CBigNum::operator= : BN_copy failed"); + return (*this); + } + + ~CBigNum() + { + BN_clear_free(bn); + } + + CBigNum(char n) { init(); if (n >= 0) setulong(n); else setint64(n); } + CBigNum(short n) { init(); if (n >= 0) setulong(n); else setint64(n); } + CBigNum(int n) { init(); if (n >= 0) setulong(n); else setint64(n); } + CBigNum(long n) { init(); if (n >= 0) setulong(n); else setint64(n); } + CBigNum(int64 n) { init(); setint64(n); } + CBigNum(unsigned char n) { init(); setulong(n); } + CBigNum(unsigned short n) { init(); setulong(n); } + CBigNum(unsigned int n) { init(); setulong(n); } + CBigNum(unsigned long n) { init(); setulong(n); } + CBigNum(uint64 n) { init(); setuint64(n); } + explicit CBigNum(uint256 n) { init(); setuint256(n); } + + explicit CBigNum(const std::vector& vch) + { + init(); + setvch(vch); + } + + void setulong(unsigned long n) + { + if (!BN_set_word(bn, n)) + throw bignum_error("CBigNum conversion from unsigned long : BN_set_word failed"); + } + + unsigned long getulong() const + { + return BN_get_word(bn); + } + + unsigned int getuint() const + { + return BN_get_word(bn); + } + + int getint() const + { + unsigned long n = BN_get_word(bn); + if (!BN_is_negative(bn)) + return (n > INT_MAX ? INT_MAX : n); + else + return (n > INT_MAX ? INT_MIN : -(int)n); + } + + void setint64(int64 n) + { + unsigned char pch[sizeof(n) + 6]; + unsigned char* p = pch + 4; + bool fNegative = false; + if (n < (int64)0) + { + n = -n; + fNegative = true; + } + bool fLeadingZeroes = true; + for (int i = 0; i < 8; i++) + { + unsigned char c = (n >> 56) & 0xff; + n <<= 8; + if (fLeadingZeroes) + { + if (c == 0) + continue; + if (c & 0x80) + *p++ = (fNegative ? 0x80 : 0); + else if (fNegative) + c |= 0x80; + fLeadingZeroes = false; + } + *p++ = c; + } + unsigned int nSize = p - (pch + 4); + pch[0] = (nSize >> 24) & 0xff; + pch[1] = (nSize >> 16) & 0xff; + pch[2] = (nSize >> 8) & 0xff; + pch[3] = (nSize) & 0xff; + BN_mpi2bn(pch, p - pch, bn); + } + + void setuint64(uint64 n) + { + unsigned char pch[sizeof(n) + 6]; + unsigned char* p = pch + 4; + bool fLeadingZeroes = true; + for (int i = 0; i < 8; i++) + { + unsigned char c = (n >> 56) & 0xff; + n <<= 8; + if (fLeadingZeroes) + { + if (c == 0) + continue; + if (c & 0x80) + *p++ = 0; + fLeadingZeroes = false; + } + *p++ = c; + } + unsigned int nSize = p - (pch + 4); + pch[0] = (nSize >> 24) & 0xff; + pch[1] = (nSize >> 16) & 0xff; + pch[2] = (nSize >> 8) & 0xff; + pch[3] = (nSize) & 0xff; + BN_mpi2bn(pch, p - pch, bn); + } + + void setuint256(uint256 n) + { + unsigned char pch[sizeof(n) + 6]; + unsigned char* p = pch + 4; + bool fLeadingZeroes = true; + unsigned char* pbegin = (unsigned char*)&n; + unsigned char* psrc = pbegin + sizeof(n); + while (psrc != pbegin) + { + unsigned char c = *(--psrc); + if (fLeadingZeroes) + { + if (c == 0) + continue; + if (c & 0x80) + *p++ = 0; + fLeadingZeroes = false; + } + *p++ = c; + } + unsigned int nSize = p - (pch + 4); + pch[0] = (nSize >> 24) & 0xff; + pch[1] = (nSize >> 16) & 0xff; + pch[2] = (nSize >> 8) & 0xff; + pch[3] = (nSize >> 0) & 0xff; + BN_mpi2bn(pch, p - pch, bn); + } + + uint256 getuint256() + { + unsigned int nSize = BN_bn2mpi(bn, NULL); + if (nSize < 4) + return 0; + std::vector vch(nSize); + BN_bn2mpi(bn, &vch[0]); + if (vch.size() > 4) + vch[4] &= 0x7f; + uint256 n = 0; + for (int i = 0, j = vch.size()-1; i < sizeof(n) && j >= 4; i++, j--) + ((unsigned char*)&n)[i] = vch[j]; + return n; + } + + void setvch(const std::vector& vch) + { + std::vector vch2(vch.size() + 4); + unsigned int nSize = vch.size(); + vch2[0] = (nSize >> 24) & 0xff; + vch2[1] = (nSize >> 16) & 0xff; + vch2[2] = (nSize >> 8) & 0xff; + vch2[3] = (nSize >> 0) & 0xff; + reverse_copy(vch.begin(), vch.end(), vch2.begin() + 4); + BN_mpi2bn(&vch2[0], vch2.size(), bn); + } + + std::vector getvch() const + { + unsigned int nSize = BN_bn2mpi(bn, NULL); + if (nSize < 4) + return std::vector(); + std::vector vch(nSize); + BN_bn2mpi(bn, &vch[0]); + vch.erase(vch.begin(), vch.begin() + 4); + reverse(vch.begin(), vch.end()); + return vch; + } + + CBigNum& SetCompact(unsigned int nCompact) + { + unsigned int nSize = nCompact >> 24; + std::vector vch(4 + nSize); + vch[3] = nSize; + if (nSize >= 1) vch[4] = (nCompact >> 16) & 0xff; + if (nSize >= 2) vch[5] = (nCompact >> 8) & 0xff; + if (nSize >= 3) vch[6] = (nCompact >> 0) & 0xff; + BN_mpi2bn(&vch[0], vch.size(), bn); + return *this; + } + + unsigned int GetCompact() const + { + unsigned int nSize = BN_bn2mpi(bn, NULL); + std::vector vch(nSize); + nSize -= 4; + BN_bn2mpi(bn, &vch[0]); + unsigned int nCompact = nSize << 24; + if (nSize >= 1) nCompact |= (vch[4] << 16); + if (nSize >= 2) nCompact |= (vch[5] << 8); + if (nSize >= 3) nCompact |= (vch[6] << 0); + return nCompact; + } + + void SetHex(const std::string& str) + { + // skip 0x + const char* psz = str.c_str(); + while (isspace(*psz)) + psz++; + bool fNegative = false; + if (*psz == '-') + { + fNegative = true; + psz++; + } + if (psz[0] == '0' && tolower(psz[1]) == 'x') + psz += 2; + while (isspace(*psz)) + psz++; + + // hex string to bignum + 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 }; + *this = 0; + while (isxdigit(*psz)) + { + *this <<= 4; + int n = phexdigit[(unsigned char)*psz++]; + *this += n; + } + if (fNegative) + *this = 0 - *this; + } + + unsigned int GetSerializeSize(int nType=0, int nVersion=VERSION) const + { + return ::GetSerializeSize(getvch(), nType, nVersion); + } + + template + void Serialize(Stream& s, int nType=0, int nVersion=VERSION) const + { + ::Serialize(s, getvch(), nType, nVersion); + } + + template + void Unserialize(Stream& s, int nType=0, int nVersion=VERSION) + { + vector vch; + ::Unserialize(s, vch, nType, nVersion); + setvch(vch); + } + + + bool operator!() const + { + return BN_is_zero(bn); + } + + CBigNum& operator+=(const CBigNum& b) + { + if (!BN_add(bn, bn, b.bn)) + throw bignum_error("CBigNum::operator+= : BN_add failed"); + return *this; + } + + CBigNum& operator-=(const CBigNum& b) + { + *this = *this - b; + return *this; + } + + CBigNum& operator*=(const CBigNum& b) + { + CAutoBN_CTX pctx; + if (!BN_mul(bn, bn, b.bn, pctx)) + throw bignum_error("CBigNum::operator*= : BN_mul failed"); + return *this; + } + + CBigNum& operator/=(const CBigNum& b) + { + *this = *this / b; + return *this; + } + + CBigNum& operator%=(const CBigNum& b) + { + *this = *this % b; + return *this; + } + + CBigNum& operator<<=(unsigned int shift) + { + if (!BN_lshift(bn, bn, shift)) + throw bignum_error("CBigNum:operator<<= : BN_lshift failed"); + return *this; + } + + CBigNum& operator>>=(unsigned int shift) + { + if (!BN_rshift(bn, bn, shift)) + throw bignum_error("CBigNum:operator>>= : BN_rshift failed"); + return *this; + } + + + CBigNum& operator++() + { + // prefix operator + if (!BN_add(bn, bn, BN_value_one())) + throw bignum_error("CBigNum::operator++ : BN_add failed"); + return *this; + } + + const CBigNum operator++(int) + { + // postfix operator + const CBigNum ret = *this; + ++(*this); + return ret; + } + + CBigNum& operator--() + { + // prefix operator + CBigNum r; + if (!BN_sub(r.bn, bn, BN_value_one())) + throw bignum_error("CBigNum::operator-- : BN_sub failed"); + *this = r; + return *this; + } + + const CBigNum operator--(int) + { + // postfix operator + const CBigNum ret = *this; + --(*this); + return ret; + } + + + friend inline const CBigNum operator+(const CBigNum& a, const CBigNum& b); + friend inline const CBigNum operator-(const CBigNum& a, const CBigNum& b); + friend inline const CBigNum operator-(const CBigNum& a); + friend inline const CBigNum operator*(const CBigNum& a, const CBigNum& b); + friend inline const CBigNum operator/(const CBigNum& a, const CBigNum& b); + friend inline const CBigNum operator%(const CBigNum& a, const CBigNum& b); + friend inline const CBigNum operator<<(const CBigNum& a, unsigned int shift); + friend inline const CBigNum operator>>(const CBigNum& a, unsigned int shift); + friend inline bool operator==(const CBigNum& a, const CBigNum& b); + friend inline bool operator!=(const CBigNum& a, const CBigNum& b); + friend inline bool operator<=(const CBigNum& a, const CBigNum& b); + friend inline bool operator>=(const CBigNum& a, const CBigNum& b); + friend inline bool operator<(const CBigNum& a, const CBigNum& b); + friend inline bool operator>(const CBigNum& a, const CBigNum& b); +}; + + + +inline const CBigNum operator+(const CBigNum& a, const CBigNum& b) +{ + CBigNum r; + if (!BN_add(r.bn, a.bn, b.bn)) + throw bignum_error("CBigNum::operator+ : BN_add failed"); + return r; +} + +inline const CBigNum operator-(const CBigNum& a, const CBigNum& b) +{ + CBigNum r; + if (!BN_sub(r.bn, a.bn, b.bn)) + throw bignum_error("CBigNum::operator- : BN_sub failed"); + return r; +} + +inline const CBigNum operator-(const CBigNum& a) +{ + CBigNum r(a); + BN_set_negative(r.bn, !BN_is_negative(r.bn)); + return r; +} + +inline const CBigNum operator*(const CBigNum& a, const CBigNum& b) +{ + CAutoBN_CTX pctx; + CBigNum r; + if (!BN_mul(r.bn, a.bn, b.bn, pctx)) + throw bignum_error("CBigNum::operator* : BN_mul failed"); + return r; +} + +inline const CBigNum operator/(const CBigNum& a, const CBigNum& b) +{ + CAutoBN_CTX pctx; + CBigNum r; + if (!BN_div(r.bn, NULL, a.bn, b.bn, pctx)) + throw bignum_error("CBigNum::operator/ : BN_div failed"); + return r; +} + +inline const CBigNum operator%(const CBigNum& a, const CBigNum& b) +{ + CAutoBN_CTX pctx; + CBigNum r; + if (!BN_mod(r.bn, a.bn, b.bn, pctx)) + throw bignum_error("CBigNum::operator% : BN_div failed"); + return r; +} + +inline const CBigNum operator<<(const CBigNum& a, unsigned int shift) +{ + CBigNum r; + if (!BN_lshift(r.bn, a.bn, shift)) + throw bignum_error("CBigNum:operator<< : BN_lshift failed"); + return r; +} + +inline const CBigNum operator>>(const CBigNum& a, unsigned int shift) +{ + CBigNum r; + if (!BN_rshift(r.bn, a.bn, shift)) + throw bignum_error("CBigNum:operator>> : BN_rshift failed"); + return r; +} + +inline bool operator==(const CBigNum& a, const CBigNum& b) { return (BN_cmp(a.bn, b.bn) == 0); } +inline bool operator!=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(a.bn, b.bn) != 0); } +inline bool operator<=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(a.bn, b.bn) <= 0); } +inline bool operator>=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(a.bn, b.bn) >= 0); } +inline bool operator<(const CBigNum& a, const CBigNum& b) { return (BN_cmp(a.bn, b.bn) < 0); } +inline bool operator>(const CBigNum& a, const CBigNum& b) { return (BN_cmp(a.bn, b.bn) > 0); } -- cgit v1.2.3 From 060a37de4a1f08ffb5939c8fc47a805c5d0d0024 Mon Sep 17 00:00:00 2001 From: Bitflash Date: Fri, 7 Aug 2026 16:46:15 -0300 Subject: bignum: shift setint64 in unsigned space to avoid signed overflow UB setint64() extracted big-endian bytes with a signed left shift (n <<= 8). When the top byte is set that overflows int64 -- undefined behaviour, which the script fuzzer flagged under UBSan (bignum.h:158). The result was correct on two's-complement hardware, so this is a latent UB inherited from the original 0.1 code, not a behaviour change. Do the shift on a uint64. --- src/bignum.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/bignum.h') diff --git a/src/bignum.h b/src/bignum.h index 9da104b..6a295b2 100644 --- a/src/bignum.h +++ b/src/bignum.h @@ -155,7 +155,9 @@ public: for (int i = 0; i < 8; i++) { unsigned char c = (n >> 56) & 0xff; - n <<= 8; + n = (int64)((uint64)n << 8); // shift in unsigned space; <<= on a + // signed int64 with the top byte set + // is overflow UB (fuzzer/UBSan finding) if (fLeadingZeroes) { if (c == 0) -- cgit v1.2.3