Commit | Line | Data |
---|---|---|
8bd66202 | 1 | // Copyright (c) 2009-2010 Satoshi Nakamoto |
f914f1a7 | 2 | // Copyright (c) 2009-2013 The Bitcoin Core developers |
78253fcb | 3 | // Distributed under the MIT software license, see the accompanying |
3a25a2b9 | 4 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. |
51ed9ec9 | 5 | |
84738627 PJ |
6 | #ifndef BITCOIN_TEST_BIGNUM_H |
7 | #define BITCOIN_TEST_BIGNUM_H | |
8bd66202 | 8 | |
ccc84e09 PW |
9 | #include <algorithm> |
10 | #include <limits> | |
8bd66202 | 11 | #include <stdexcept> |
51ed9ec9 | 12 | #include <stdint.h> |
f25e3adf | 13 | #include <string> |
8bd66202 | 14 | #include <vector> |
8bd66202 | 15 | |
51ed9ec9 | 16 | #include <openssl/bn.h> |
8bd66202 GA |
17 | |
18 | class bignum_error : public std::runtime_error | |
19 | { | |
20 | public: | |
21 | explicit bignum_error(const std::string& str) : std::runtime_error(str) {} | |
22 | }; | |
23 | ||
24 | ||
7e05b972 | 25 | /** C++ wrapper for BIGNUM (OpenSSL bignum) */ |
fa318aa9 | 26 | class CBigNum |
8bd66202 | 27 | { |
fa318aa9 | 28 | BIGNUM* bn; |
8bd66202 GA |
29 | public: |
30 | CBigNum() | |
31 | { | |
fa318aa9 | 32 | bn = BN_new(); |
8bd66202 GA |
33 | } |
34 | ||
35 | CBigNum(const CBigNum& b) | |
36 | { | |
fa318aa9 JG |
37 | bn = BN_new(); |
38 | if (!BN_copy(bn, b.bn)) | |
8bd66202 | 39 | { |
fa318aa9 | 40 | BN_clear_free(bn); |
5262fde0 | 41 | throw bignum_error("CBigNum::CBigNum(const CBigNum&): BN_copy failed"); |
8bd66202 GA |
42 | } |
43 | } | |
44 | ||
45 | CBigNum& operator=(const CBigNum& b) | |
46 | { | |
fa318aa9 | 47 | if (!BN_copy(bn, b.bn)) |
5262fde0 | 48 | throw bignum_error("CBigNum::operator=: BN_copy failed"); |
8bd66202 GA |
49 | return (*this); |
50 | } | |
51 | ||
52 | ~CBigNum() | |
53 | { | |
fa318aa9 | 54 | BN_clear_free(bn); |
8bd66202 GA |
55 | } |
56 | ||
fa318aa9 | 57 | CBigNum(long long n) { bn = BN_new(); setint64(n); } |
8bd66202 GA |
58 | |
59 | explicit CBigNum(const std::vector<unsigned char>& vch) | |
60 | { | |
fa318aa9 | 61 | bn = BN_new(); |
8bd66202 GA |
62 | setvch(vch); |
63 | } | |
64 | ||
8bd66202 GA |
65 | int getint() const |
66 | { | |
fa318aa9 JG |
67 | BN_ULONG n = BN_get_word(bn); |
68 | if (!BN_is_negative(bn)) | |
63c17613 | 69 | return (n > (BN_ULONG)std::numeric_limits<int>::max() ? std::numeric_limits<int>::max() : n); |
8bd66202 | 70 | else |
63c17613 | 71 | return (n > (BN_ULONG)std::numeric_limits<int>::max() ? std::numeric_limits<int>::min() : -(int)n); |
8bd66202 GA |
72 | } |
73 | ||
51ed9ec9 | 74 | void setint64(int64_t sn) |
8bd66202 | 75 | { |
fe78c9ae | 76 | unsigned char pch[sizeof(sn) + 6]; |
8bd66202 | 77 | unsigned char* p = pch + 4; |
fe78c9ae | 78 | bool fNegative; |
51ed9ec9 | 79 | uint64_t n; |
fe78c9ae | 80 | |
51ed9ec9 | 81 | if (sn < (int64_t)0) |
8bd66202 | 82 | { |
f0bf5fb2 | 83 | // Since the minimum signed integer cannot be represented as positive so long as its type is signed, |
84 | // and it's not well-defined what happens if you make it unsigned before negating it, | |
85 | // we instead increment the negative integer by 1, convert it, then increment the (now positive) unsigned integer by 1 to compensate | |
0f5a2a82 LD |
86 | n = -(sn + 1); |
87 | ++n; | |
8bd66202 | 88 | fNegative = true; |
fe78c9ae RC |
89 | } else { |
90 | n = sn; | |
91 | fNegative = false; | |
8bd66202 | 92 | } |
fe78c9ae | 93 | |
8bd66202 GA |
94 | bool fLeadingZeroes = true; |
95 | for (int i = 0; i < 8; i++) | |
96 | { | |
97 | unsigned char c = (n >> 56) & 0xff; | |
98 | n <<= 8; | |
99 | if (fLeadingZeroes) | |
100 | { | |
101 | if (c == 0) | |
102 | continue; | |
103 | if (c & 0x80) | |
104 | *p++ = (fNegative ? 0x80 : 0); | |
105 | else if (fNegative) | |
106 | c |= 0x80; | |
107 | fLeadingZeroes = false; | |
108 | } | |
109 | *p++ = c; | |
110 | } | |
111 | unsigned int nSize = p - (pch + 4); | |
112 | pch[0] = (nSize >> 24) & 0xff; | |
113 | pch[1] = (nSize >> 16) & 0xff; | |
114 | pch[2] = (nSize >> 8) & 0xff; | |
115 | pch[3] = (nSize) & 0xff; | |
fa318aa9 | 116 | BN_mpi2bn(pch, p - pch, bn); |
8bd66202 GA |
117 | } |
118 | ||
8bd66202 GA |
119 | void setvch(const std::vector<unsigned char>& vch) |
120 | { | |
121 | std::vector<unsigned char> vch2(vch.size() + 4); | |
122 | unsigned int nSize = vch.size(); | |
a9d3af88 DH |
123 | // BIGNUM's byte stream format expects 4 bytes of |
124 | // big endian size data info at the front | |
8bd66202 GA |
125 | vch2[0] = (nSize >> 24) & 0xff; |
126 | vch2[1] = (nSize >> 16) & 0xff; | |
127 | vch2[2] = (nSize >> 8) & 0xff; | |
128 | vch2[3] = (nSize >> 0) & 0xff; | |
a9d3af88 | 129 | // swap data to big endian |
8bd66202 | 130 | reverse_copy(vch.begin(), vch.end(), vch2.begin() + 4); |
fa318aa9 | 131 | BN_mpi2bn(&vch2[0], vch2.size(), bn); |
8bd66202 GA |
132 | } |
133 | ||
134 | std::vector<unsigned char> getvch() const | |
135 | { | |
fa318aa9 | 136 | unsigned int nSize = BN_bn2mpi(bn, NULL); |
a06113b0 | 137 | if (nSize <= 4) |
8bd66202 GA |
138 | return std::vector<unsigned char>(); |
139 | std::vector<unsigned char> vch(nSize); | |
fa318aa9 | 140 | BN_bn2mpi(bn, &vch[0]); |
8bd66202 GA |
141 | vch.erase(vch.begin(), vch.begin() + 4); |
142 | reverse(vch.begin(), vch.end()); | |
143 | return vch; | |
144 | } | |
145 | ||
fa318aa9 | 146 | friend inline const CBigNum operator+(const CBigNum& a, const CBigNum& b); |
8bd66202 | 147 | friend inline const CBigNum operator-(const CBigNum& a, const CBigNum& b); |
fa318aa9 JG |
148 | friend inline const CBigNum operator-(const CBigNum& a); |
149 | friend inline bool operator==(const CBigNum& a, const CBigNum& b); | |
150 | friend inline bool operator!=(const CBigNum& a, const CBigNum& b); | |
151 | friend inline bool operator<=(const CBigNum& a, const CBigNum& b); | |
152 | friend inline bool operator>=(const CBigNum& a, const CBigNum& b); | |
153 | friend inline bool operator<(const CBigNum& a, const CBigNum& b); | |
154 | friend inline bool operator>(const CBigNum& a, const CBigNum& b); | |
8bd66202 GA |
155 | }; |
156 | ||
157 | ||
158 | ||
159 | inline const CBigNum operator+(const CBigNum& a, const CBigNum& b) | |
160 | { | |
161 | CBigNum r; | |
fa318aa9 | 162 | if (!BN_add(r.bn, a.bn, b.bn)) |
5262fde0 | 163 | throw bignum_error("CBigNum::operator+: BN_add failed"); |
8bd66202 GA |
164 | return r; |
165 | } | |
166 | ||
167 | inline const CBigNum operator-(const CBigNum& a, const CBigNum& b) | |
168 | { | |
169 | CBigNum r; | |
fa318aa9 | 170 | if (!BN_sub(r.bn, a.bn, b.bn)) |
5262fde0 | 171 | throw bignum_error("CBigNum::operator-: BN_sub failed"); |
8bd66202 GA |
172 | return r; |
173 | } | |
174 | ||
175 | inline const CBigNum operator-(const CBigNum& a) | |
176 | { | |
177 | CBigNum r(a); | |
fa318aa9 | 178 | BN_set_negative(r.bn, !BN_is_negative(r.bn)); |
8bd66202 GA |
179 | return r; |
180 | } | |
181 | ||
fa318aa9 JG |
182 | inline bool operator==(const CBigNum& a, const CBigNum& b) { return (BN_cmp(a.bn, b.bn) == 0); } |
183 | inline bool operator!=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(a.bn, b.bn) != 0); } | |
184 | inline bool operator<=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(a.bn, b.bn) <= 0); } | |
185 | inline bool operator>=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(a.bn, b.bn) >= 0); } | |
186 | inline bool operator<(const CBigNum& a, const CBigNum& b) { return (BN_cmp(a.bn, b.bn) < 0); } | |
187 | inline bool operator>(const CBigNum& a, const CBigNum& b) { return (BN_cmp(a.bn, b.bn) > 0); } | |
223b6f1b | 188 | |
84738627 | 189 | #endif // BITCOIN_TEST_BIGNUM_H |