1 // Copyright (c) 2009-2010 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.
7 #include <openssl/bn.h>
13 class bignum_error
: public std::runtime_error
16 explicit bignum_error(const std::string
& str
) : std::runtime_error(str
) {}
25 BN_CTX
* operator=(BN_CTX
* pnew
) { return pctx
= pnew
; }
32 throw bignum_error("CAutoBN_CTX : BN_CTX_new() returned NULL");
41 operator BN_CTX
*() { return pctx
; }
42 BN_CTX
& operator*() { return *pctx
; }
43 BN_CTX
** operator&() { return &pctx
; }
44 bool operator!() { return (pctx
== NULL
); }
49 class CBigNum
: public BIGNUM
57 CBigNum(const CBigNum
& b
)
60 if (!BN_copy(this, &b
))
63 throw bignum_error("CBigNum::CBigNum(const CBigNum&) : BN_copy failed");
67 CBigNum
& operator=(const CBigNum
& b
)
69 if (!BN_copy(this, &b
))
70 throw bignum_error("CBigNum::operator= : BN_copy failed");
79 CBigNum(char n
) { BN_init(this); if (n
>= 0) setulong(n
); else setint64(n
); }
80 CBigNum(short n
) { BN_init(this); if (n
>= 0) setulong(n
); else setint64(n
); }
81 CBigNum(int n
) { BN_init(this); if (n
>= 0) setulong(n
); else setint64(n
); }
82 CBigNum(long n
) { BN_init(this); if (n
>= 0) setulong(n
); else setint64(n
); }
83 CBigNum(int64 n
) { BN_init(this); setint64(n
); }
84 CBigNum(unsigned char n
) { BN_init(this); setulong(n
); }
85 CBigNum(unsigned short n
) { BN_init(this); setulong(n
); }
86 CBigNum(unsigned int n
) { BN_init(this); setulong(n
); }
87 CBigNum(unsigned long n
) { BN_init(this); setulong(n
); }
88 CBigNum(uint64 n
) { BN_init(this); setuint64(n
); }
89 explicit CBigNum(uint256 n
) { BN_init(this); setuint256(n
); }
91 explicit CBigNum(const std::vector
<unsigned char>& vch
)
97 void setulong(unsigned long n
)
99 if (!BN_set_word(this, n
))
100 throw bignum_error("CBigNum conversion from unsigned long : BN_set_word failed");
103 unsigned long getulong() const
105 return BN_get_word(this);
108 unsigned int getuint() const
110 return BN_get_word(this);
115 unsigned long n
= BN_get_word(this);
116 if (!BN_is_negative(this))
117 return (n
> INT_MAX
? INT_MAX
: n
);
119 return (n
> INT_MAX
? INT_MIN
: -(int)n
);
122 void setint64(int64 n
)
124 unsigned char pch
[sizeof(n
) + 6];
125 unsigned char* p
= pch
+ 4;
126 bool fNegative
= false;
132 bool fLeadingZeroes
= true;
133 for (int i
= 0; i
< 8; i
++)
135 unsigned char c
= (n
>> 56) & 0xff;
142 *p
++ = (fNegative
? 0x80 : 0);
145 fLeadingZeroes
= false;
149 unsigned int nSize
= p
- (pch
+ 4);
150 pch
[0] = (nSize
>> 24) & 0xff;
151 pch
[1] = (nSize
>> 16) & 0xff;
152 pch
[2] = (nSize
>> 8) & 0xff;
153 pch
[3] = (nSize
) & 0xff;
154 BN_mpi2bn(pch
, p
- pch
, this);
157 void setuint64(uint64 n
)
159 unsigned char pch
[sizeof(n
) + 6];
160 unsigned char* p
= pch
+ 4;
161 bool fLeadingZeroes
= true;
162 for (int i
= 0; i
< 8; i
++)
164 unsigned char c
= (n
>> 56) & 0xff;
172 fLeadingZeroes
= false;
176 unsigned int nSize
= p
- (pch
+ 4);
177 pch
[0] = (nSize
>> 24) & 0xff;
178 pch
[1] = (nSize
>> 16) & 0xff;
179 pch
[2] = (nSize
>> 8) & 0xff;
180 pch
[3] = (nSize
) & 0xff;
181 BN_mpi2bn(pch
, p
- pch
, this);
184 void setuint256(uint256 n
)
186 unsigned char pch
[sizeof(n
) + 6];
187 unsigned char* p
= pch
+ 4;
188 bool fLeadingZeroes
= true;
189 unsigned char* pbegin
= (unsigned char*)&n
;
190 unsigned char* psrc
= pbegin
+ sizeof(n
);
191 while (psrc
!= pbegin
)
193 unsigned char c
= *(--psrc
);
200 fLeadingZeroes
= false;
204 unsigned int nSize
= p
- (pch
+ 4);
205 pch
[0] = (nSize
>> 24) & 0xff;
206 pch
[1] = (nSize
>> 16) & 0xff;
207 pch
[2] = (nSize
>> 8) & 0xff;
208 pch
[3] = (nSize
>> 0) & 0xff;
209 BN_mpi2bn(pch
, p
- pch
, this);
214 unsigned int nSize
= BN_bn2mpi(this, NULL
);
217 std::vector
<unsigned char> vch(nSize
);
218 BN_bn2mpi(this, &vch
[0]);
222 for (int i
= 0, j
= vch
.size()-1; i
< sizeof(n
) && j
>= 4; i
++, j
--)
223 ((unsigned char*)&n
)[i
] = vch
[j
];
227 void setvch(const std::vector
<unsigned char>& vch
)
229 std::vector
<unsigned char> vch2(vch
.size() + 4);
230 unsigned int nSize
= vch
.size();
231 vch2
[0] = (nSize
>> 24) & 0xff;
232 vch2
[1] = (nSize
>> 16) & 0xff;
233 vch2
[2] = (nSize
>> 8) & 0xff;
234 vch2
[3] = (nSize
>> 0) & 0xff;
235 reverse_copy(vch
.begin(), vch
.end(), vch2
.begin() + 4);
236 BN_mpi2bn(&vch2
[0], vch2
.size(), this);
239 std::vector
<unsigned char> getvch() const
241 unsigned int nSize
= BN_bn2mpi(this, NULL
);
243 return std::vector
<unsigned char>();
244 std::vector
<unsigned char> vch(nSize
);
245 BN_bn2mpi(this, &vch
[0]);
246 vch
.erase(vch
.begin(), vch
.begin() + 4);
247 reverse(vch
.begin(), vch
.end());
251 CBigNum
& SetCompact(unsigned int nCompact
)
253 unsigned int nSize
= nCompact
>> 24;
254 std::vector
<unsigned char> vch(4 + nSize
);
256 if (nSize
>= 1) vch
[4] = (nCompact
>> 16) & 0xff;
257 if (nSize
>= 2) vch
[5] = (nCompact
>> 8) & 0xff;
258 if (nSize
>= 3) vch
[6] = (nCompact
>> 0) & 0xff;
259 BN_mpi2bn(&vch
[0], vch
.size(), this);
263 unsigned int GetCompact() const
265 unsigned int nSize
= BN_bn2mpi(this, NULL
);
266 std::vector
<unsigned char> vch(nSize
);
268 BN_bn2mpi(this, &vch
[0]);
269 unsigned int nCompact
= nSize
<< 24;
270 if (nSize
>= 1) nCompact
|= (vch
[4] << 16);
271 if (nSize
>= 2) nCompact
|= (vch
[5] << 8);
272 if (nSize
>= 3) nCompact
|= (vch
[6] << 0);
276 void SetHex(const std::string
& str
)
279 const char* psz
= str
.c_str();
280 while (isspace(*psz
))
282 bool fNegative
= false;
288 if (psz
[0] == '0' && tolower(psz
[1]) == 'x')
290 while (isspace(*psz
))
293 // hex string to bignum
294 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 };
296 while (isxdigit(*psz
))
299 int n
= phexdigit
[*psz
++];
306 std::string
ToString(int nBase
=10) const
309 CBigNum bnBase
= nBase
;
313 BN_set_negative(&bn
, false);
316 if (BN_cmp(&bn
, &bn0
) == 0)
318 while (BN_cmp(&bn
, &bn0
) > 0)
320 if (!BN_div(&dv
, &rem
, &bn
, &bnBase
, pctx
))
321 throw bignum_error("CBigNum::ToString() : BN_div failed");
323 unsigned int c
= rem
.getulong();
324 str
+= "0123456789abcdef"[c
];
326 if (BN_is_negative(this))
328 reverse(str
.begin(), str
.end());
332 std::string
GetHex() const
337 unsigned int GetSerializeSize(int nType
=0, int nVersion
=VERSION
) const
339 return ::GetSerializeSize(getvch(), nType
, nVersion
);
342 template<typename Stream
>
343 void Serialize(Stream
& s
, int nType
=0, int nVersion
=VERSION
) const
345 ::Serialize(s
, getvch(), nType
, nVersion
);
348 template<typename Stream
>
349 void Unserialize(Stream
& s
, int nType
=0, int nVersion
=VERSION
)
351 vector
<unsigned char> vch
;
352 ::Unserialize(s
, vch
, nType
, nVersion
);
357 bool operator!() const
359 return BN_is_zero(this);
362 CBigNum
& operator+=(const CBigNum
& b
)
364 if (!BN_add(this, this, &b
))
365 throw bignum_error("CBigNum::operator+= : BN_add failed");
369 CBigNum
& operator-=(const CBigNum
& b
)
375 CBigNum
& operator*=(const CBigNum
& b
)
378 if (!BN_mul(this, this, &b
, pctx
))
379 throw bignum_error("CBigNum::operator*= : BN_mul failed");
383 CBigNum
& operator/=(const CBigNum
& b
)
389 CBigNum
& operator%=(const CBigNum
& b
)
395 CBigNum
& operator<<=(unsigned int shift
)
397 if (!BN_lshift(this, this, shift
))
398 throw bignum_error("CBigNum:operator<<= : BN_lshift failed");
402 CBigNum
& operator>>=(unsigned int shift
)
404 // Note: BN_rshift segfaults on 64-bit if 2^shift is greater than the number
405 // if built on ubuntu 9.04 or 9.10, probably depends on version of openssl
408 if (BN_cmp(&a
, this) > 0)
414 if (!BN_rshift(this, this, shift
))
415 throw bignum_error("CBigNum:operator>>= : BN_rshift failed");
420 CBigNum
& operator++()
423 if (!BN_add(this, this, BN_value_one()))
424 throw bignum_error("CBigNum::operator++ : BN_add failed");
428 const CBigNum
operator++(int)
431 const CBigNum ret
= *this;
436 CBigNum
& operator--()
440 if (!BN_sub(&r
, this, BN_value_one()))
441 throw bignum_error("CBigNum::operator-- : BN_sub failed");
446 const CBigNum
operator--(int)
449 const CBigNum ret
= *this;
455 friend inline const CBigNum
operator-(const CBigNum
& a
, const CBigNum
& b
);
456 friend inline const CBigNum
operator/(const CBigNum
& a
, const CBigNum
& b
);
457 friend inline const CBigNum
operator%(const CBigNum
& a
, const CBigNum
& b
);
462 inline const CBigNum
operator+(const CBigNum
& a
, const CBigNum
& b
)
465 if (!BN_add(&r
, &a
, &b
))
466 throw bignum_error("CBigNum::operator+ : BN_add failed");
470 inline const CBigNum
operator-(const CBigNum
& a
, const CBigNum
& b
)
473 if (!BN_sub(&r
, &a
, &b
))
474 throw bignum_error("CBigNum::operator- : BN_sub failed");
478 inline const CBigNum
operator-(const CBigNum
& a
)
481 BN_set_negative(&r
, !BN_is_negative(&r
));
485 inline const CBigNum
operator*(const CBigNum
& a
, const CBigNum
& b
)
489 if (!BN_mul(&r
, &a
, &b
, pctx
))
490 throw bignum_error("CBigNum::operator* : BN_mul failed");
494 inline const CBigNum
operator/(const CBigNum
& a
, const CBigNum
& b
)
498 if (!BN_div(&r
, NULL
, &a
, &b
, pctx
))
499 throw bignum_error("CBigNum::operator/ : BN_div failed");
503 inline const CBigNum
operator%(const CBigNum
& a
, const CBigNum
& b
)
507 if (!BN_mod(&r
, &a
, &b
, pctx
))
508 throw bignum_error("CBigNum::operator% : BN_div failed");
512 inline const CBigNum
operator<<(const CBigNum
& a
, unsigned int shift
)
515 if (!BN_lshift(&r
, &a
, shift
))
516 throw bignum_error("CBigNum:operator<< : BN_lshift failed");
520 inline const CBigNum
operator>>(const CBigNum
& a
, unsigned int shift
)
527 inline bool operator==(const CBigNum
& a
, const CBigNum
& b
) { return (BN_cmp(&a
, &b
) == 0); }
528 inline bool operator!=(const CBigNum
& a
, const CBigNum
& b
) { return (BN_cmp(&a
, &b
) != 0); }
529 inline bool operator<=(const CBigNum
& a
, const CBigNum
& b
) { return (BN_cmp(&a
, &b
) <= 0); }
530 inline bool operator>=(const CBigNum
& a
, const CBigNum
& b
) { return (BN_cmp(&a
, &b
) >= 0); }
531 inline bool operator<(const CBigNum
& a
, const CBigNum
& b
) { return (BN_cmp(&a
, &b
) < 0); }
532 inline bool operator>(const CBigNum
& a
, const CBigNum
& b
) { return (BN_cmp(&a
, &b
) > 0); }