1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2012 The Bitcoin developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 #ifndef BITCOIN_BIGNUM_H
6 #define BITCOIN_BIGNUM_H
10 #include <openssl/bn.h>
12 #include "util.h" // for uint64
14 /** Errors thrown by the bignum class */
15 class bignum_error
: public std::runtime_error
18 explicit bignum_error(const std::string
& str
) : std::runtime_error(str
) {}
22 /** RAII encapsulated BN_CTX (OpenSSL bignum context) */
27 BN_CTX
* operator=(BN_CTX
* pnew
) { return pctx
= pnew
; }
34 throw bignum_error("CAutoBN_CTX : BN_CTX_new() returned NULL");
43 operator BN_CTX
*() { return pctx
; }
44 BN_CTX
& operator*() { return *pctx
; }
45 BN_CTX
** operator&() { return &pctx
; }
46 bool operator!() { return (pctx
== NULL
); }
50 /** C++ wrapper for BIGNUM (OpenSSL bignum) */
51 class CBigNum
: public BIGNUM
59 CBigNum(const CBigNum
& b
)
62 if (!BN_copy(this, &b
))
65 throw bignum_error("CBigNum::CBigNum(const CBigNum&) : BN_copy failed");
69 CBigNum
& operator=(const CBigNum
& b
)
71 if (!BN_copy(this, &b
))
72 throw bignum_error("CBigNum::operator= : BN_copy failed");
81 //CBigNum(char n) is not portable. Use 'signed char' or 'unsigned char'.
82 CBigNum(signed char n
) { BN_init(this); if (n
>= 0) setulong(n
); else setint64(n
); }
83 CBigNum(short n
) { BN_init(this); if (n
>= 0) setulong(n
); else setint64(n
); }
84 CBigNum(int n
) { BN_init(this); if (n
>= 0) setulong(n
); else setint64(n
); }
85 CBigNum(long n
) { BN_init(this); if (n
>= 0) setulong(n
); else setint64(n
); }
86 CBigNum(int64 n
) { BN_init(this); setint64(n
); }
87 CBigNum(unsigned char n
) { BN_init(this); setulong(n
); }
88 CBigNum(unsigned short n
) { BN_init(this); setulong(n
); }
89 CBigNum(unsigned int n
) { BN_init(this); setulong(n
); }
90 CBigNum(unsigned long n
) { BN_init(this); setulong(n
); }
91 CBigNum(uint64 n
) { BN_init(this); setuint64(n
); }
92 explicit CBigNum(uint256 n
) { BN_init(this); setuint256(n
); }
94 explicit CBigNum(const std::vector
<unsigned char>& vch
)
100 void setulong(unsigned long n
)
102 if (!BN_set_word(this, n
))
103 throw bignum_error("CBigNum conversion from unsigned long : BN_set_word failed");
106 unsigned long getulong() const
108 return BN_get_word(this);
111 unsigned int getuint() const
113 return BN_get_word(this);
118 unsigned long n
= BN_get_word(this);
119 if (!BN_is_negative(this))
120 return (n
> (unsigned long)std::numeric_limits
<int>::max() ? std::numeric_limits
<int>::max() : n
);
122 return (n
> (unsigned long)std::numeric_limits
<int>::max() ? std::numeric_limits
<int>::min() : -(int)n
);
125 void setint64(int64 sn
)
127 unsigned char pch
[sizeof(sn
) + 6];
128 unsigned char* p
= pch
+ 4;
134 // Since the minimum signed integer cannot be represented as positive so long as its type is signed, and it's not well-defined what happens if you make it unsigned before negating it, we instead increment the negative integer by 1, convert it, then increment the (now positive) unsigned integer by 1 to compensate
143 bool fLeadingZeroes
= true;
144 for (int i
= 0; i
< 8; i
++)
146 unsigned char c
= (n
>> 56) & 0xff;
153 *p
++ = (fNegative
? 0x80 : 0);
156 fLeadingZeroes
= false;
160 unsigned int nSize
= p
- (pch
+ 4);
161 pch
[0] = (nSize
>> 24) & 0xff;
162 pch
[1] = (nSize
>> 16) & 0xff;
163 pch
[2] = (nSize
>> 8) & 0xff;
164 pch
[3] = (nSize
) & 0xff;
165 BN_mpi2bn(pch
, p
- pch
, this);
168 void setuint64(uint64 n
)
170 unsigned char pch
[sizeof(n
) + 6];
171 unsigned char* p
= pch
+ 4;
172 bool fLeadingZeroes
= true;
173 for (int i
= 0; i
< 8; i
++)
175 unsigned char c
= (n
>> 56) & 0xff;
183 fLeadingZeroes
= false;
187 unsigned int nSize
= p
- (pch
+ 4);
188 pch
[0] = (nSize
>> 24) & 0xff;
189 pch
[1] = (nSize
>> 16) & 0xff;
190 pch
[2] = (nSize
>> 8) & 0xff;
191 pch
[3] = (nSize
) & 0xff;
192 BN_mpi2bn(pch
, p
- pch
, this);
195 void setuint256(uint256 n
)
197 unsigned char pch
[sizeof(n
) + 6];
198 unsigned char* p
= pch
+ 4;
199 bool fLeadingZeroes
= true;
200 unsigned char* pbegin
= (unsigned char*)&n
;
201 unsigned char* psrc
= pbegin
+ sizeof(n
);
202 while (psrc
!= pbegin
)
204 unsigned char c
= *(--psrc
);
211 fLeadingZeroes
= false;
215 unsigned int nSize
= p
- (pch
+ 4);
216 pch
[0] = (nSize
>> 24) & 0xff;
217 pch
[1] = (nSize
>> 16) & 0xff;
218 pch
[2] = (nSize
>> 8) & 0xff;
219 pch
[3] = (nSize
>> 0) & 0xff;
220 BN_mpi2bn(pch
, p
- pch
, this);
225 unsigned int nSize
= BN_bn2mpi(this, NULL
);
228 std::vector
<unsigned char> vch(nSize
);
229 BN_bn2mpi(this, &vch
[0]);
233 for (unsigned int i
= 0, j
= vch
.size()-1; i
< sizeof(n
) && j
>= 4; i
++, j
--)
234 ((unsigned char*)&n
)[i
] = vch
[j
];
238 void setvch(const std::vector
<unsigned char>& vch
)
240 std::vector
<unsigned char> vch2(vch
.size() + 4);
241 unsigned int nSize
= vch
.size();
242 // BIGNUM's byte stream format expects 4 bytes of
243 // big endian size data info at the front
244 vch2
[0] = (nSize
>> 24) & 0xff;
245 vch2
[1] = (nSize
>> 16) & 0xff;
246 vch2
[2] = (nSize
>> 8) & 0xff;
247 vch2
[3] = (nSize
>> 0) & 0xff;
248 // swap data to big endian
249 reverse_copy(vch
.begin(), vch
.end(), vch2
.begin() + 4);
250 BN_mpi2bn(&vch2
[0], vch2
.size(), this);
253 std::vector
<unsigned char> getvch() const
255 unsigned int nSize
= BN_bn2mpi(this, NULL
);
257 return std::vector
<unsigned char>();
258 std::vector
<unsigned char> vch(nSize
);
259 BN_bn2mpi(this, &vch
[0]);
260 vch
.erase(vch
.begin(), vch
.begin() + 4);
261 reverse(vch
.begin(), vch
.end());
265 CBigNum
& SetCompact(unsigned int nCompact
)
267 unsigned int nSize
= nCompact
>> 24;
268 std::vector
<unsigned char> vch(4 + nSize
);
270 if (nSize
>= 1) vch
[4] = (nCompact
>> 16) & 0xff;
271 if (nSize
>= 2) vch
[5] = (nCompact
>> 8) & 0xff;
272 if (nSize
>= 3) vch
[6] = (nCompact
>> 0) & 0xff;
273 BN_mpi2bn(&vch
[0], vch
.size(), this);
277 unsigned int GetCompact() const
279 unsigned int nSize
= BN_bn2mpi(this, NULL
);
280 std::vector
<unsigned char> vch(nSize
);
282 BN_bn2mpi(this, &vch
[0]);
283 unsigned int nCompact
= nSize
<< 24;
284 if (nSize
>= 1) nCompact
|= (vch
[4] << 16);
285 if (nSize
>= 2) nCompact
|= (vch
[5] << 8);
286 if (nSize
>= 3) nCompact
|= (vch
[6] << 0);
290 void SetHex(const std::string
& str
)
293 const char* psz
= str
.c_str();
294 while (isspace(*psz
))
296 bool fNegative
= false;
302 if (psz
[0] == '0' && tolower(psz
[1]) == 'x')
304 while (isspace(*psz
))
307 // hex string to bignum
308 static signed 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 };
310 while (isxdigit(*psz
))
313 int n
= phexdigit
[(unsigned char)*psz
++];
320 std::string
ToString(int nBase
=10) const
323 CBigNum bnBase
= nBase
;
327 BN_set_negative(&bn
, false);
330 if (BN_cmp(&bn
, &bn0
) == 0)
332 while (BN_cmp(&bn
, &bn0
) > 0)
334 if (!BN_div(&dv
, &rem
, &bn
, &bnBase
, pctx
))
335 throw bignum_error("CBigNum::ToString() : BN_div failed");
337 unsigned int c
= rem
.getulong();
338 str
+= "0123456789abcdef"[c
];
340 if (BN_is_negative(this))
342 reverse(str
.begin(), str
.end());
346 std::string
GetHex() const
351 unsigned int GetSerializeSize(int nType
=0, int nVersion
=PROTOCOL_VERSION
) const
353 return ::GetSerializeSize(getvch(), nType
, nVersion
);
356 template<typename Stream
>
357 void Serialize(Stream
& s
, int nType
=0, int nVersion
=PROTOCOL_VERSION
) const
359 ::Serialize(s
, getvch(), nType
, nVersion
);
362 template<typename Stream
>
363 void Unserialize(Stream
& s
, int nType
=0, int nVersion
=PROTOCOL_VERSION
)
365 std::vector
<unsigned char> vch
;
366 ::Unserialize(s
, vch
, nType
, nVersion
);
371 bool operator!() const
373 return BN_is_zero(this);
376 CBigNum
& operator+=(const CBigNum
& b
)
378 if (!BN_add(this, this, &b
))
379 throw bignum_error("CBigNum::operator+= : BN_add failed");
383 CBigNum
& operator-=(const CBigNum
& b
)
389 CBigNum
& operator*=(const CBigNum
& b
)
392 if (!BN_mul(this, this, &b
, pctx
))
393 throw bignum_error("CBigNum::operator*= : BN_mul failed");
397 CBigNum
& operator/=(const CBigNum
& b
)
403 CBigNum
& operator%=(const CBigNum
& b
)
409 CBigNum
& operator<<=(unsigned int shift
)
411 if (!BN_lshift(this, this, shift
))
412 throw bignum_error("CBigNum:operator<<= : BN_lshift failed");
416 CBigNum
& operator>>=(unsigned int shift
)
418 // Note: BN_rshift segfaults on 64-bit if 2^shift is greater than the number
419 // if built on ubuntu 9.04 or 9.10, probably depends on version of OpenSSL
422 if (BN_cmp(&a
, this) > 0)
428 if (!BN_rshift(this, this, shift
))
429 throw bignum_error("CBigNum:operator>>= : BN_rshift failed");
434 CBigNum
& operator++()
437 if (!BN_add(this, this, BN_value_one()))
438 throw bignum_error("CBigNum::operator++ : BN_add failed");
442 const CBigNum
operator++(int)
445 const CBigNum ret
= *this;
450 CBigNum
& operator--()
454 if (!BN_sub(&r
, this, BN_value_one()))
455 throw bignum_error("CBigNum::operator-- : BN_sub failed");
460 const CBigNum
operator--(int)
463 const CBigNum ret
= *this;
469 friend inline const CBigNum
operator-(const CBigNum
& a
, const CBigNum
& b
);
470 friend inline const CBigNum
operator/(const CBigNum
& a
, const CBigNum
& b
);
471 friend inline const CBigNum
operator%(const CBigNum
& a
, const CBigNum
& b
);
476 inline const CBigNum
operator+(const CBigNum
& a
, const CBigNum
& b
)
479 if (!BN_add(&r
, &a
, &b
))
480 throw bignum_error("CBigNum::operator+ : BN_add failed");
484 inline const CBigNum
operator-(const CBigNum
& a
, const CBigNum
& b
)
487 if (!BN_sub(&r
, &a
, &b
))
488 throw bignum_error("CBigNum::operator- : BN_sub failed");
492 inline const CBigNum
operator-(const CBigNum
& a
)
495 BN_set_negative(&r
, !BN_is_negative(&r
));
499 inline const CBigNum
operator*(const CBigNum
& a
, const CBigNum
& b
)
503 if (!BN_mul(&r
, &a
, &b
, pctx
))
504 throw bignum_error("CBigNum::operator* : BN_mul failed");
508 inline const CBigNum
operator/(const CBigNum
& a
, const CBigNum
& b
)
512 if (!BN_div(&r
, NULL
, &a
, &b
, pctx
))
513 throw bignum_error("CBigNum::operator/ : BN_div failed");
517 inline const CBigNum
operator%(const CBigNum
& a
, const CBigNum
& b
)
521 if (!BN_mod(&r
, &a
, &b
, pctx
))
522 throw bignum_error("CBigNum::operator% : BN_div failed");
526 inline const CBigNum
operator<<(const CBigNum
& a
, unsigned int shift
)
529 if (!BN_lshift(&r
, &a
, shift
))
530 throw bignum_error("CBigNum:operator<< : BN_lshift failed");
534 inline const CBigNum
operator>>(const CBigNum
& a
, unsigned int shift
)
541 inline bool operator==(const CBigNum
& a
, const CBigNum
& b
) { return (BN_cmp(&a
, &b
) == 0); }
542 inline bool operator!=(const CBigNum
& a
, const CBigNum
& b
) { return (BN_cmp(&a
, &b
) != 0); }
543 inline bool operator<=(const CBigNum
& a
, const CBigNum
& b
) { return (BN_cmp(&a
, &b
) <= 0); }
544 inline bool operator>=(const CBigNum
& a
, const CBigNum
& b
) { return (BN_cmp(&a
, &b
) >= 0); }
545 inline bool operator<(const CBigNum
& a
, const CBigNum
& b
) { return (BN_cmp(&a
, &b
) < 0); }
546 inline bool operator>(const CBigNum
& a
, const CBigNum
& b
) { return (BN_cmp(&a
, &b
) > 0); }