PageRenderTime 55ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/include/coin/BigNum.h

https://github.com/libcoin/libcoin
C Header | 590 lines | 500 code | 72 blank | 18 comment | 80 complexity | 031b36b88f0e5967092ced5056a25217 MD5 | raw file
  1. // Copyright (c) 2009-2010 Satoshi Nakamoto
  2. // Copyright (c) 2011 The Bitcoin developers
  3. // Distributed under the MIT/X11 software license, see the accompanying
  4. // file license.txt or http://www.opensource.org/licenses/mit-license.php.
  5. #ifndef BITCOIN_BIGNUM_H
  6. #define BITCOIN_BIGNUM_H
  7. #include <stdexcept>
  8. #include <vector>
  9. #include <openssl/bn.h>
  10. #include <coin/util.h>
  11. //#include <coin/serialize.h>
  12. class bignum_error : public std::runtime_error
  13. {
  14. public:
  15. explicit bignum_error(const std::string& str) : std::runtime_error(str) {}
  16. };
  17. class CAutoBN_CTX
  18. {
  19. protected:
  20. BN_CTX* pctx;
  21. BN_CTX* operator=(BN_CTX* pnew) { return pctx = pnew; }
  22. public:
  23. CAutoBN_CTX()
  24. {
  25. pctx = BN_CTX_new();
  26. if (pctx == NULL)
  27. throw bignum_error("CAutoBN_CTX : BN_CTX_new() returned NULL");
  28. }
  29. ~CAutoBN_CTX()
  30. {
  31. if (pctx != NULL)
  32. BN_CTX_free(pctx);
  33. }
  34. operator BN_CTX*() { return pctx; }
  35. BN_CTX& operator*() { return *pctx; }
  36. BN_CTX** operator&() { return &pctx; }
  37. bool operator!() { return (pctx == NULL); }
  38. };
  39. class CBigNum : public BIGNUM
  40. {
  41. public:
  42. CBigNum()
  43. {
  44. BN_init(this);
  45. }
  46. CBigNum(const CBigNum& b)
  47. {
  48. BN_init(this);
  49. if (!BN_copy(this, &b))
  50. {
  51. BN_clear_free(this);
  52. throw bignum_error("CBigNum::CBigNum(const CBigNum&) : BN_copy failed");
  53. }
  54. }
  55. CBigNum(const BIGNUM* bn) {
  56. BN_init(this);
  57. if (!BN_copy(this, bn)) {
  58. BN_clear_free(this);
  59. throw bignum_error("CBigNum::CBigNum(const BIGNUM* bn) : BN_copy failed");
  60. }
  61. }
  62. CBigNum& operator=(const CBigNum& b)
  63. {
  64. if (!BN_copy(this, &b))
  65. throw bignum_error("CBigNum::operator= : BN_copy failed");
  66. return (*this);
  67. }
  68. ~CBigNum()
  69. {
  70. BN_clear_free(this);
  71. }
  72. CBigNum(char n) { BN_init(this); if (n >= 0) setulong(n); else setint64(n); }
  73. CBigNum(int16_t n) { BN_init(this); if (n >= 0) setulong(n); else setint64(n); }
  74. // CBigNum(int n) { BN_init(this); if (n >= 0) setulong(n); else setint64(n); }
  75. CBigNum(int32_t n) { BN_init(this); if (n >= 0) setulong(n); else setint64(n); }
  76. CBigNum(int64_t n) { BN_init(this); setint64(n); }
  77. CBigNum(unsigned char n) { BN_init(this); setulong(n); }
  78. CBigNum(uint16_t n) { BN_init(this); setulong(n); }
  79. CBigNum(uint32_t n) { BN_init(this); setulong(n); }
  80. // CBigNum(size_t n) { BN_init(this); setulong(n); }
  81. CBigNum(uint64_t n) { BN_init(this); setuint64(n); }
  82. explicit CBigNum(uint256 n) { BN_init(this); setuint256(n); }
  83. explicit CBigNum(const std::vector<unsigned char>& vch)
  84. {
  85. BN_init(this);
  86. setvch(vch);
  87. }
  88. int bits() const {
  89. return BN_num_bits(this);
  90. }
  91. void setulong(unsigned long n)
  92. {
  93. if (!BN_set_word(this, n))
  94. throw bignum_error("CBigNum conversion from unsigned long : BN_set_word failed");
  95. }
  96. unsigned long getulong() const
  97. {
  98. return BN_get_word(this);
  99. }
  100. void setuint(unsigned int n) {
  101. setulong(static_cast<unsigned long>(n));
  102. }
  103. unsigned int getuint() const
  104. {
  105. return BN_get_word(this);
  106. }
  107. int getint() const
  108. {
  109. unsigned long n = BN_get_word(this);
  110. if (!BN_is_negative(this))
  111. return (n > INT_MAX ? INT_MAX : n);
  112. else
  113. return (n > INT_MAX ? INT_MIN : -(int)n);
  114. }
  115. void setint64(int64_t n)
  116. {
  117. unsigned char pch[sizeof(n) + 6];
  118. unsigned char* p = pch + 4;
  119. bool fNegative = false;
  120. if (n < (int64_t)0)
  121. {
  122. n = -n;
  123. fNegative = true;
  124. }
  125. bool fLeadingZeroes = true;
  126. for (int i = 0; i < 8; i++)
  127. {
  128. unsigned char c = (n >> 56) & 0xff;
  129. n <<= 8;
  130. if (fLeadingZeroes)
  131. {
  132. if (c == 0)
  133. continue;
  134. if (c & 0x80)
  135. *p++ = (fNegative ? 0x80 : 0);
  136. else if (fNegative)
  137. c |= 0x80;
  138. fLeadingZeroes = false;
  139. }
  140. *p++ = c;
  141. }
  142. unsigned int nSize = p - (pch + 4);
  143. pch[0] = (nSize >> 24) & 0xff;
  144. pch[1] = (nSize >> 16) & 0xff;
  145. pch[2] = (nSize >> 8) & 0xff;
  146. pch[3] = (nSize) & 0xff;
  147. BN_mpi2bn(pch, p - pch, this);
  148. }
  149. uint64_t getuint64() const {
  150. #if (ULONG_MAX > UINT_MAX)
  151. return static_cast<uint64_t>(getulong());
  152. #else
  153. int len = BN_num_bytes(this);
  154. if (len > 8)
  155. throw std::runtime_error("BN getuint64 overflow");
  156. unsigned char buf[8];
  157. memset(buf, 0, sizeof(buf));
  158. BN_bn2bin(this, buf + 8 - len);
  159. return
  160. static_cast<uint64_t>(buf[0]) << 56 | static_cast<uint64_t>(buf[1]) << 48 |
  161. static_cast<uint64_t>(buf[2]) << 40 | static_cast<uint64_t>(buf[3]) << 32 |
  162. static_cast<uint64_t>(buf[4]) << 24 | static_cast<uint64_t>(buf[5]) << 16 |
  163. static_cast<uint64_t>(buf[6]) << 8 | static_cast<uint64_t>(buf[7]);
  164. #endif
  165. }
  166. void setuint64(uint64_t n)
  167. {
  168. unsigned char pch[sizeof(n) + 6];
  169. unsigned char* p = pch + 4;
  170. bool fLeadingZeroes = true;
  171. for (int i = 0; i < 8; i++)
  172. {
  173. unsigned char c = (n >> 56) & 0xff;
  174. n <<= 8;
  175. if (fLeadingZeroes)
  176. {
  177. if (c == 0)
  178. continue;
  179. if (c & 0x80)
  180. *p++ = 0;
  181. fLeadingZeroes = false;
  182. }
  183. *p++ = c;
  184. }
  185. unsigned int nSize = p - (pch + 4);
  186. pch[0] = (nSize >> 24) & 0xff;
  187. pch[1] = (nSize >> 16) & 0xff;
  188. pch[2] = (nSize >> 8) & 0xff;
  189. pch[3] = (nSize) & 0xff;
  190. BN_mpi2bn(pch, p - pch, this);
  191. }
  192. void setuint256(uint256 n)
  193. {
  194. unsigned char pch[sizeof(n) + 6];
  195. unsigned char* p = pch + 4;
  196. bool fLeadingZeroes = true;
  197. unsigned char* pbegin = (unsigned char*)&n;
  198. unsigned char* psrc = pbegin + sizeof(n);
  199. while (psrc != pbegin)
  200. {
  201. unsigned char c = *(--psrc);
  202. if (fLeadingZeroes)
  203. {
  204. if (c == 0)
  205. continue;
  206. if (c & 0x80)
  207. *p++ = 0;
  208. fLeadingZeroes = false;
  209. }
  210. *p++ = c;
  211. }
  212. unsigned int nSize = p - (pch + 4);
  213. pch[0] = (nSize >> 24) & 0xff;
  214. pch[1] = (nSize >> 16) & 0xff;
  215. pch[2] = (nSize >> 8) & 0xff;
  216. pch[3] = (nSize >> 0) & 0xff;
  217. BN_mpi2bn(pch, p - pch, this);
  218. }
  219. uint256 getuint256()
  220. {
  221. unsigned int nSize = BN_bn2mpi(this, NULL);
  222. if (nSize < 4)
  223. return uint256(0);
  224. std::vector<unsigned char> vch(nSize);
  225. BN_bn2mpi(this, &vch[0]);
  226. if (vch.size() > 4)
  227. vch[4] &= 0x7f;
  228. uint256 n = uint256(0);
  229. for (unsigned int i = 0, j = vch.size()-1; i < sizeof(n) && j >= 4; i++, j--)
  230. ((unsigned char*)&n)[i] = vch[j];
  231. return n;
  232. }
  233. void setvch(const std::vector<unsigned char>& vch)
  234. {
  235. std::vector<unsigned char> vch2(vch.size() + 4);
  236. unsigned int nSize = vch.size();
  237. // BIGNUM's byte stream format expects 4 bytes of
  238. // big endian size data info at the front
  239. vch2[0] = (nSize >> 24) & 0xff;
  240. vch2[1] = (nSize >> 16) & 0xff;
  241. vch2[2] = (nSize >> 8) & 0xff;
  242. vch2[3] = (nSize >> 0) & 0xff;
  243. // swap data to big endian
  244. reverse_copy(vch.begin(), vch.end(), vch2.begin() + 4);
  245. BN_mpi2bn(&vch2[0], vch2.size(), this);
  246. }
  247. std::vector<unsigned char> getvch() const
  248. {
  249. unsigned int nSize = BN_bn2mpi(this, NULL);
  250. if (nSize < 4)
  251. return std::vector<unsigned char>();
  252. std::vector<unsigned char> vch(nSize);
  253. BN_bn2mpi(this, &vch[0]);
  254. vch.erase(vch.begin(), vch.begin() + 4);
  255. reverse(vch.begin(), vch.end());
  256. return vch;
  257. }
  258. CBigNum& SetCompact(int nCompact)
  259. {
  260. unsigned int nSize = nCompact >> 24;
  261. std::vector<unsigned char> vch(4 + nSize);
  262. vch[3] = nSize;
  263. if (nSize >= 1) vch[4] = (nCompact >> 16) & 0xff;
  264. if (nSize >= 2) vch[5] = (nCompact >> 8) & 0xff;
  265. if (nSize >= 3) vch[6] = (nCompact >> 0) & 0xff;
  266. BN_mpi2bn(&vch[0], vch.size(), this);
  267. return *this;
  268. }
  269. int GetCompact() const
  270. {
  271. unsigned int nSize = BN_bn2mpi(this, NULL);
  272. std::vector<unsigned char> vch(nSize);
  273. nSize -= 4;
  274. BN_bn2mpi(this, &vch[0]);
  275. unsigned int nCompact = nSize << 24;
  276. if (nSize >= 1) nCompact |= (vch[4] << 16);
  277. if (nSize >= 2) nCompact |= (vch[5] << 8);
  278. if (nSize >= 3) nCompact |= (vch[6] << 0);
  279. return nCompact;
  280. }
  281. void SetHex(const std::string& str)
  282. {
  283. // skip 0x
  284. const char* psz = str.c_str();
  285. while (isspace(*psz))
  286. psz++;
  287. bool fNegative = false;
  288. if (*psz == '-')
  289. {
  290. fNegative = true;
  291. psz++;
  292. }
  293. if (psz[0] == '0' && tolower(psz[1]) == 'x')
  294. psz += 2;
  295. while (isspace(*psz))
  296. psz++;
  297. // hex string to bignum
  298. 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 };
  299. *this = 0;
  300. while (isxdigit(*psz))
  301. {
  302. *this <<= 4;
  303. int n = phexdigit[(int)*psz++];
  304. *this += n;
  305. }
  306. if (fNegative)
  307. *this = 0 - *this;
  308. }
  309. std::string toString(int nBase=10) const
  310. {
  311. CAutoBN_CTX pctx;
  312. CBigNum bnBase = nBase;
  313. CBigNum bn0 = 0;
  314. std::string str;
  315. CBigNum bn = *this;
  316. BN_set_negative(&bn, false);
  317. CBigNum dv;
  318. CBigNum rem;
  319. if (BN_cmp(&bn, &bn0) == 0)
  320. return "0";
  321. while (BN_cmp(&bn, &bn0) > 0)
  322. {
  323. if (!BN_div(&dv, &rem, &bn, &bnBase, pctx))
  324. throw bignum_error("CBigNum::toString() : BN_div failed");
  325. bn = dv;
  326. unsigned int c = rem.getulong();
  327. str += "0123456789abcdef"[c];
  328. }
  329. if (BN_is_negative(this))
  330. str += "-";
  331. reverse(str.begin(), str.end());
  332. return str;
  333. }
  334. std::string GetHex() const
  335. {
  336. return toString(16);
  337. }
  338. bool operator!() const
  339. {
  340. return BN_is_zero(this);
  341. }
  342. CBigNum& operator+=(const CBigNum& b)
  343. {
  344. if (!BN_add(this, this, &b))
  345. throw bignum_error("CBigNum::operator+= : BN_add failed");
  346. return *this;
  347. }
  348. CBigNum& operator-=(const CBigNum& b)
  349. {
  350. *this = *this - b;
  351. return *this;
  352. }
  353. CBigNum& operator*=(const CBigNum& b)
  354. {
  355. CAutoBN_CTX pctx;
  356. if (!BN_mul(this, this, &b, pctx))
  357. throw bignum_error("CBigNum::operator*= : BN_mul failed");
  358. return *this;
  359. }
  360. CBigNum& operator/=(const CBigNum& b)
  361. {
  362. *this = *this / b;
  363. return *this;
  364. }
  365. CBigNum& operator%=(const CBigNum& b)
  366. {
  367. *this = *this % b;
  368. return *this;
  369. }
  370. CBigNum& operator<<=(unsigned int shift)
  371. {
  372. if (!BN_lshift(this, this, shift))
  373. throw bignum_error("CBigNum:operator<<= : BN_lshift failed");
  374. return *this;
  375. }
  376. CBigNum& operator>>=(unsigned int shift)
  377. {
  378. // Note: BN_rshift segfaults on 64-bit if 2^shift is greater than the number
  379. // if built on ubuntu 9.04 or 9.10, probably depends on version of openssl
  380. CBigNum a = 1;
  381. a <<= shift;
  382. if (BN_cmp(&a, this) > 0)
  383. {
  384. *this = 0;
  385. return *this;
  386. }
  387. if (!BN_rshift(this, this, shift))
  388. throw bignum_error("CBigNum:operator>>= : BN_rshift failed");
  389. return *this;
  390. }
  391. CBigNum& operator++()
  392. {
  393. // prefix operator
  394. if (!BN_add(this, this, BN_value_one()))
  395. throw bignum_error("CBigNum::operator++ : BN_add failed");
  396. return *this;
  397. }
  398. const CBigNum operator++(int)
  399. {
  400. // postfix operator
  401. const CBigNum ret = *this;
  402. ++(*this);
  403. return ret;
  404. }
  405. CBigNum& operator--()
  406. {
  407. // prefix operator
  408. CBigNum r;
  409. if (!BN_sub(&r, this, BN_value_one()))
  410. throw bignum_error("CBigNum::operator-- : BN_sub failed");
  411. *this = r;
  412. return *this;
  413. }
  414. const CBigNum operator--(int)
  415. {
  416. // postfix operator
  417. const CBigNum ret = *this;
  418. --(*this);
  419. return ret;
  420. }
  421. friend inline const CBigNum operator-(const CBigNum& a, const CBigNum& b);
  422. friend inline const CBigNum operator/(const CBigNum& a, const CBigNum& b);
  423. friend inline const CBigNum operator%(const CBigNum& a, const CBigNum& b);
  424. };
  425. inline const CBigNum operator+(const CBigNum& a, const CBigNum& b)
  426. {
  427. CBigNum r;
  428. if (!BN_add(&r, &a, &b))
  429. throw bignum_error("CBigNum::operator+ : BN_add failed");
  430. return r;
  431. }
  432. inline const CBigNum operator-(const CBigNum& a, const CBigNum& b)
  433. {
  434. CBigNum r;
  435. if (!BN_sub(&r, &a, &b))
  436. throw bignum_error("CBigNum::operator- : BN_sub failed");
  437. return r;
  438. }
  439. inline const CBigNum operator-(const CBigNum& a)
  440. {
  441. CBigNum r(a);
  442. BN_set_negative(&r, !BN_is_negative(&r));
  443. return r;
  444. }
  445. inline const CBigNum operator*(const CBigNum& a, const CBigNum& b)
  446. {
  447. CAutoBN_CTX pctx;
  448. CBigNum r;
  449. if (!BN_mul(&r, &a, &b, pctx))
  450. throw bignum_error("CBigNum::operator* : BN_mul failed");
  451. return r;
  452. }
  453. inline const CBigNum operator/(const CBigNum& a, const CBigNum& b)
  454. {
  455. CAutoBN_CTX pctx;
  456. CBigNum r;
  457. if (!BN_div(&r, NULL, &a, &b, pctx))
  458. throw bignum_error("CBigNum::operator/ : BN_div failed");
  459. return r;
  460. }
  461. inline const CBigNum operator%(const CBigNum& a, const CBigNum& b)
  462. {
  463. CAutoBN_CTX pctx;
  464. CBigNum r;
  465. if (!BN_mod(&r, &a, &b, pctx))
  466. throw bignum_error("CBigNum::operator% : BN_div failed");
  467. return r;
  468. }
  469. inline const CBigNum operator<<(const CBigNum& a, unsigned int shift)
  470. {
  471. CBigNum r;
  472. if (!BN_lshift(&r, &a, shift))
  473. throw bignum_error("CBigNum:operator<< : BN_lshift failed");
  474. return r;
  475. }
  476. inline const CBigNum operator>>(const CBigNum& a, unsigned int shift)
  477. {
  478. CBigNum r = a;
  479. r >>= shift;
  480. return r;
  481. }
  482. inline const CBigNum GCD(const CBigNum& a, const CBigNum& b) {
  483. CAutoBN_CTX pctx;
  484. CBigNum r;
  485. if (!BN_gcd(&r, &a, &b, pctx))
  486. throw bignum_error("CBigNum::GCD : BN_gcd failed");
  487. return r;
  488. }
  489. inline const CBigNum ModPow(const CBigNum& a, const CBigNum& p, const CBigNum& m) {
  490. CAutoBN_CTX pctx;
  491. CBigNum r;
  492. if (!BN_mod_exp(&r, &a, &p, &m, pctx))
  493. throw bignum_error("CBigNum::GCD : BN_gcd failed");
  494. return r;
  495. }
  496. inline const CBigNum ModInverse(const CBigNum& a, const CBigNum& n) {
  497. CAutoBN_CTX pctx;
  498. CBigNum r;
  499. if (!BN_mod_inverse(&r, &a, &n, pctx))
  500. throw bignum_error("CBigNum::GCD : BN_gcd failed");
  501. return r;
  502. }
  503. inline bool operator==(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) == 0); }
  504. inline bool operator!=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) != 0); }
  505. inline bool operator<=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) <= 0); }
  506. inline bool operator>=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) >= 0); }
  507. inline bool operator<(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) < 0); }
  508. inline bool operator>(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) > 0); }
  509. inline std::ostream& operator<<(std::ostream& os, const CBigNum& bn) {
  510. return os << bn.getvch();
  511. }
  512. inline std::istream& operator>>(std::istream& is, CBigNum& bn) {
  513. std::vector<unsigned char> vch;
  514. is >> vch;
  515. bn.setvch(vch);
  516. return is;
  517. }
  518. #endif