bitcoin-ruby 0.0.18 → 0.0.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (255) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +8 -0
  3. data/.rspec +1 -0
  4. data/.rubocop.yml +46 -0
  5. data/.travis.yml +5 -1
  6. data/Gemfile +11 -9
  7. data/Gemfile.lock +64 -12
  8. data/README.rdoc +17 -4
  9. data/Rakefile +58 -83
  10. data/bitcoin-ruby.gemspec +5 -2
  11. data/lib/bitcoin.rb +31 -14
  12. data/lib/bitcoin/bech32.rb +126 -132
  13. data/lib/bitcoin/bloom_filter.rb +24 -21
  14. data/lib/bitcoin/builder.rb +168 -126
  15. data/lib/bitcoin/connection.rb +21 -24
  16. data/lib/bitcoin/contracthash.rb +20 -24
  17. data/lib/bitcoin/dogecoin.rb +79 -77
  18. data/lib/bitcoin/electrum/mnemonic.rb +28 -25
  19. data/lib/bitcoin/ext_key.rb +3 -3
  20. data/lib/bitcoin/ffi/bitcoinconsensus.rb +17 -13
  21. data/lib/bitcoin/ffi/openssl.rb +355 -338
  22. data/lib/bitcoin/ffi/secp256k1.rb +97 -64
  23. data/lib/bitcoin/protocol.rb +6 -3
  24. data/lib/bitcoin/protocol/address.rb +15 -13
  25. data/lib/bitcoin/protocol/aux_pow.rb +12 -15
  26. data/lib/bitcoin/protocol/block.rb +102 -76
  27. data/lib/bitcoin/protocol/handler.rb +2 -4
  28. data/lib/bitcoin/protocol/parser.rb +108 -92
  29. data/lib/bitcoin/protocol/partial_merkle_tree.rb +59 -47
  30. data/lib/bitcoin/protocol/reject.rb +26 -28
  31. data/lib/bitcoin/protocol/script_witness.rb +3 -8
  32. data/lib/bitcoin/protocol/tx.rb +250 -137
  33. data/lib/bitcoin/protocol/txin.rb +44 -38
  34. data/lib/bitcoin/protocol/txout.rb +27 -20
  35. data/lib/bitcoin/protocol/version.rb +47 -34
  36. data/lib/bitcoin/script.rb +18 -17
  37. data/lib/bitcoin/trezor/mnemonic.rb +113 -98
  38. data/lib/bitcoin/version.rb +1 -1
  39. data/spec/examples.txt +399 -0
  40. data/spec/{bitcoin/fixtures → fixtures}/000000000000056b1a3d84a1e2b33cde8915a4b61c0cae14fca6d3e1490b4f98.json +0 -0
  41. data/spec/{bitcoin/fixtures → fixtures}/03d7e1fa4d5fefa169431f24f7798552861b255cd55d377066fedcd088fb0e99.json +0 -0
  42. data/spec/{bitcoin/fixtures → fixtures}/0961c660358478829505e16a1f028757e54b5bbf9758341a7546573738f31429.json +0 -0
  43. data/spec/{bitcoin/fixtures → fixtures}/0f24294a1d23efbb49c1765cf443fba7930702752aba6d765870082fe4f13cae.json +0 -0
  44. data/spec/{bitcoin/fixtures → fixtures}/156e6e1b84c5c3bd3a0927b25e4119fadce6e6d5186f363317511d1d680fae9a.json +0 -0
  45. data/spec/{bitcoin/fixtures → fixtures}/23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63.json +0 -0
  46. data/spec/{bitcoin/fixtures → fixtures}/315ac7d4c26d69668129cc352851d9389b4a6868f1509c6c8b66bead11e2619f.json +0 -0
  47. data/spec/{bitcoin/fixtures → fixtures}/35e2001b428891fefa0bfb73167c7360669d3cbd7b3aa78e7cad125ddfc51131.json +0 -0
  48. data/spec/{bitcoin/fixtures → fixtures}/3a17dace09ffb919ed627a93f1873220f4c975c1248558b18d16bce25d38c4b7.json +0 -0
  49. data/spec/{bitcoin/fixtures → fixtures}/3e58b7eed0fdb599019af08578effea25c8666bbe8e200845453cacce6314477.json +0 -0
  50. data/spec/{bitcoin/fixtures → fixtures}/514c46f0b61714092f15c8dfcb576c9f79b3f959989b98de3944b19d98832b58.json +0 -0
  51. data/spec/{bitcoin/fixtures → fixtures}/51bf528ecf3c161e7c021224197dbe84f9a8564212f6207baa014c01a1668e1e.json +0 -0
  52. data/spec/{bitcoin/fixtures → fixtures}/60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1.json +0 -0
  53. data/spec/{bitcoin/fixtures → fixtures}/69216b8aaa35b76d6613e5f527f4858640d986e1046238583bdad79b35e938dc.json +0 -0
  54. data/spec/{bitcoin/fixtures → fixtures}/7208e5edf525f04e705fb3390194e316205b8f995c8c9fcd8c6093abe04fa27d.json +0 -0
  55. data/spec/{bitcoin/fixtures → fixtures}/761d8c5210fdfd505f6dff38f740ae3728eb93d7d0971fb433f685d40a4c04f6.json +0 -0
  56. data/spec/{bitcoin/fixtures → fixtures}/8d0b238a06b5a70be75d543902d02d7a514d68d3252a949a513865ac3538874c.json +0 -0
  57. data/spec/{bitcoin/fixtures → fixtures}/aea682d68a3ea5e3583e088dcbd699a5d44d4b083f02ad0aaf2598fe1fa4dfd4.json +0 -0
  58. data/spec/{bitcoin/fixtures → fixtures}/base58_keys_invalid.json +0 -0
  59. data/spec/{bitcoin/fixtures → fixtures}/base58_keys_valid.json +0 -0
  60. data/spec/{bitcoin/fixtures → fixtures}/bc179baab547b7d7c1d5d8d6f8b0cc6318eaa4b0dd0a093ad6ac7f5a1cb6b3ba.json +0 -0
  61. data/spec/{bitcoin/fixtures → fixtures}/bd1715f1abfdc62bea3f605bdb461b3ba1f2cca6ec0d73a18a548b7717ca8531.json +0 -0
  62. data/spec/{bitcoin/fixtures → fixtures}/block-testnet-0000000000ac85bb2530a05a4214a387e6be02b22d3348abc5e7a5d9c4ce8dab.bin +0 -0
  63. data/spec/{bitcoin/fixtures → fixtures}/cd874fa8cb0e2ec2d385735d5e1fd482c4fe648533efb4c50ee53bda58e15ae2.json +0 -0
  64. data/spec/{bitcoin/fixtures → fixtures}/ce5fad9b4ef094d8f4937b0707edaf0a6e6ceeaf67d5edbfd51f660eac8f398b.json +0 -0
  65. data/spec/{bitcoin/fixtures → fixtures}/coinbase-toshi.json +0 -0
  66. data/spec/{bitcoin/fixtures → fixtures}/coinbase.json +0 -0
  67. data/spec/{bitcoin/fixtures → fixtures}/dogecoin-block-60323982f9c5ff1b5a954eac9dc1269352835f47c2c5222691d80f0d50dcf053.bin +0 -0
  68. data/spec/{bitcoin/fixtures → fixtures}/f003f0c1193019db2497a675fd05d9f2edddf9b67c59e677c48d3dbd4ed5f00b.json +0 -0
  69. data/spec/{bitcoin/fixtures → fixtures}/filteredblock-0.bin +0 -0
  70. data/spec/{bitcoin/fixtures → fixtures}/litecoin-block-80ca095ed10b02e53d769eb6eaf92cd04e9e0759e5be4a8477b42911ba49c78f.bin +0 -0
  71. data/spec/{bitcoin/fixtures → fixtures}/litecoin-block-80ca095ed10b02e53d769eb6eaf92cd04e9e0759e5be4a8477b42911ba49c78f.json +0 -0
  72. data/spec/{bitcoin/fixtures → fixtures}/litecoin-genesis-block-12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2.bin +0 -0
  73. data/spec/{bitcoin/fixtures → fixtures}/litecoin-genesis-block-12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2.json +0 -0
  74. data/spec/{bitcoin/fixtures → fixtures}/litecoin-tx-f5aa30f574e3b6f1a3d99c07a6356ba812aabb9661e1d5f71edff828cbd5c996.json +0 -0
  75. data/spec/{bitcoin/fixtures → fixtures}/rawblock-0.bin +0 -0
  76. data/spec/{bitcoin/fixtures → fixtures}/rawblock-0.json +0 -0
  77. data/spec/{bitcoin/fixtures → fixtures}/rawblock-1.bin +0 -0
  78. data/spec/{bitcoin/fixtures → fixtures}/rawblock-1.json +0 -0
  79. data/spec/{bitcoin/fixtures → fixtures}/rawblock-131025.bin +0 -0
  80. data/spec/{bitcoin/fixtures → fixtures}/rawblock-131025.json +0 -0
  81. data/spec/{bitcoin/fixtures → fixtures}/rawblock-170.bin +0 -0
  82. data/spec/{bitcoin/fixtures → fixtures}/rawblock-9.bin +0 -0
  83. data/spec/{bitcoin/fixtures → fixtures}/rawblock-auxpow.bin +0 -0
  84. data/spec/{bitcoin/fixtures → fixtures}/rawblock-testnet-1151351.bin +0 -0
  85. data/spec/{bitcoin/fixtures → fixtures}/rawblock-testnet-26478.bin +0 -0
  86. data/spec/{bitcoin/fixtures → fixtures}/rawblock-testnet-26478.json +0 -0
  87. data/spec/{bitcoin/fixtures → fixtures}/rawblock-testnet-265322.bin +0 -0
  88. data/spec/{bitcoin/fixtures → fixtures}/rawtx-01-toshi.json +0 -0
  89. data/spec/{bitcoin/fixtures → fixtures}/rawtx-01.bin +0 -0
  90. data/spec/{bitcoin/fixtures → fixtures}/rawtx-01.json +0 -0
  91. data/spec/{bitcoin/fixtures → fixtures}/rawtx-02-toshi.json +0 -0
  92. data/spec/{bitcoin/fixtures → fixtures}/rawtx-02.bin +0 -0
  93. data/spec/{bitcoin/fixtures → fixtures}/rawtx-02.json +0 -0
  94. data/spec/{bitcoin/fixtures → fixtures}/rawtx-03-toshi.json +0 -0
  95. data/spec/{bitcoin/fixtures → fixtures}/rawtx-03.bin +0 -0
  96. data/spec/{bitcoin/fixtures → fixtures}/rawtx-03.json +0 -0
  97. data/spec/{bitcoin/fixtures → fixtures}/rawtx-04.json +0 -0
  98. data/spec/{bitcoin/fixtures → fixtures}/rawtx-0437cd7f8525ceed2324359c2d0ba26006d92d856a9c20fa0241106ee5a597c9.bin +0 -0
  99. data/spec/{bitcoin/fixtures → fixtures}/rawtx-05.json +0 -0
  100. data/spec/{bitcoin/fixtures → fixtures}/rawtx-14be6fff8c6014f7c9493b4a6e4a741699173f39d74431b6b844fcb41ebb9984.bin +0 -0
  101. data/spec/{bitcoin/fixtures → fixtures}/rawtx-2f4a2717ec8c9f077a87dde6cbe0274d5238793a3f3f492b63c744837285e58a.bin +0 -0
  102. data/spec/{bitcoin/fixtures → fixtures}/rawtx-2f4a2717ec8c9f077a87dde6cbe0274d5238793a3f3f492b63c744837285e58a.json +0 -0
  103. data/spec/{bitcoin/fixtures → fixtures}/rawtx-406b2b06bcd34d3c8733e6b79f7a394c8a431fbf4ff5ac705c93f4076bb77602.json +0 -0
  104. data/spec/{bitcoin/fixtures → fixtures}/rawtx-52250a162c7d03d2e1fbc5ebd1801a88612463314b55102171c5b5d817d2d7b2.bin +0 -0
  105. data/spec/{bitcoin/fixtures → fixtures}/rawtx-b5d4e8883533f99e5903ea2cf001a133a322fa6b1370b18a16c57c946a40823d.bin +0 -0
  106. data/spec/{bitcoin/fixtures → fixtures}/rawtx-ba1ff5cd66713133c062a871a8adab92416f1e38d17786b2bf56ac5f6ffdfdf5.json +0 -0
  107. data/spec/{bitcoin/fixtures → fixtures}/rawtx-c99c49da4c38af669dea436d3e73780dfdb6c1ecf9958baa52960e8baee30e73.json +0 -0
  108. data/spec/{bitcoin/fixtures → fixtures}/rawtx-de35d060663750b3975b7997bde7fb76307cec5b270d12fcd9c4ad98b279c28c.json +0 -0
  109. data/spec/{bitcoin/fixtures → fixtures}/rawtx-f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16.bin +0 -0
  110. data/spec/{bitcoin/fixtures → fixtures}/rawtx-p2wpkh.bin +0 -0
  111. data/spec/{bitcoin/fixtures → fixtures}/rawtx-p2wpkh.json +0 -0
  112. data/spec/{bitcoin/fixtures → fixtures}/rawtx-testnet-04fdc38d6722ab4b12d79113fc4b2896bdcc5169710690ee4e78541b98e467b4.bin +0 -0
  113. data/spec/{bitcoin/fixtures → fixtures}/rawtx-testnet-0b294c7d11dd21bcccb8393e6744fed7d4d1981a08c00e3e88838cc421f33c9f.bin +0 -0
  114. data/spec/{bitcoin/fixtures → fixtures}/rawtx-testnet-3bc52ac063291ad92d95ddda5fd776a342083b95607ad32ed8bc6f8f7d30449e.bin +0 -0
  115. data/spec/{bitcoin/fixtures → fixtures}/rawtx-testnet-6f0bbdd4e71a8af4305018d738184df32dbb6f27284fdebd5b56d16947f7c181.bin +0 -0
  116. data/spec/{bitcoin/fixtures → fixtures}/rawtx-testnet-a220adf1902c46a39db25a24bc4178b6a88440f977a7e2cabfdd8b5c1dd35cfb.json +0 -0
  117. data/spec/{bitcoin/fixtures → fixtures}/rawtx-testnet-a7c9b06e275e8674cc19a5f7d3e557c72c6d93576e635b33212dbe08ab7cdb60.bin +0 -0
  118. data/spec/{bitcoin/fixtures → fixtures}/rawtx-testnet-e232e0055dbdca88bbaa79458683195a0b7c17c5b6c524a8d146721d4d4d652f.bin +0 -0
  119. data/spec/{bitcoin/fixtures → fixtures}/rawtx-testnet-e232e0055dbdca88bbaa79458683195a0b7c17c5b6c524a8d146721d4d4d652f.json +0 -0
  120. data/spec/{bitcoin/fixtures → fixtures}/rawtx-testnet-f80acbd2f594d04ddb0e1cacba662132104909157dff526935a3c88abe9201a5.bin +0 -0
  121. data/spec/{bitcoin/fixtures → fixtures}/script_tests.json +0 -0
  122. data/spec/{bitcoin/fixtures → fixtures}/sighash.json +0 -0
  123. data/spec/{bitcoin/fixtures → fixtures}/tx-0295028ef826b2a188409cb905b631faebb9bb3cdf14510571c5f4bd8591338f.json +0 -0
  124. data/spec/{bitcoin/fixtures → fixtures}/tx-03339a725007a279484fb6f5361f522dd1cf4d0923d30e6b973290dba4275f92.json +0 -0
  125. data/spec/{bitcoin/fixtures → fixtures}/tx-0a6a357e2f7796444e02638749d9611c008b253fb55f5dc88b739b230ed0c4c3.json +0 -0
  126. data/spec/{bitcoin/fixtures → fixtures}/tx-0ce7e5238fbdb6c086cf1b384b21b827e91cc23f360417265874a5a0d86ce367.json +0 -0
  127. data/spec/{bitcoin/fixtures → fixtures}/tx-0ef34c49f630aea17df0080728b0fc67bf5f87fbda936934a4b11b4a69d7821e.json +0 -0
  128. data/spec/{bitcoin/fixtures → fixtures}/tx-1129d2a8bd5bb3a81e54dc96a90f1f6b2544575748caa17243470935c5dd91b7.json +0 -0
  129. data/spec/{bitcoin/fixtures → fixtures}/tx-19aa42fee0fa57c45d3b16488198b27caaacc4ff5794510d0c17f173f05587ff.json +0 -0
  130. data/spec/{bitcoin/fixtures → fixtures}/tx-1a4f3b9dc4494aeedeb39f30dd37e60541b2abe3ed4977992017cc0ad4f44956.json +0 -0
  131. data/spec/{bitcoin/fixtures → fixtures}/tx-1f9191dcf2b1844ca28c6ef4b969e1d5fab70a5e3c56b7007949e55851cb0c4f.json +0 -0
  132. data/spec/{bitcoin/fixtures → fixtures}/tx-22cd5fef23684d7b304e119bedffde6f54538d3d54a5bfa237e20dc2d9b4b5ad.json +0 -0
  133. data/spec/{bitcoin/fixtures → fixtures}/tx-28204cad1d7fc1d199e8ef4fa22f182de6258a3eaafe1bbe56ebdcacd3069a5f.json +0 -0
  134. data/spec/{bitcoin/fixtures → fixtures}/tx-2958fb00b4fd6fe0353503b886eb9a193d502f4fd5fc042d5e03216ba918bbd6.json +0 -0
  135. data/spec/{bitcoin/fixtures → fixtures}/tx-29f277145749ad6efbed3ae6ce301f8d33c585ec26b7c044ad93c2f866e9e942.json +0 -0
  136. data/spec/{bitcoin/fixtures → fixtures}/tx-2c5e5376c20e9cc78d0fb771730e5d840cc2096eff0ef045b599fe92475ace1c.json +0 -0
  137. data/spec/{bitcoin/fixtures → fixtures}/tx-2c63aa814701cef5dbd4bbaddab3fea9117028f2434dddcdab8339141e9b14d1.json +0 -0
  138. data/spec/{bitcoin/fixtures → fixtures}/tx-313897799b1e37e9ecae15010e56156dddde4e683c96b0e713af95272c38aee0.json +0 -0
  139. data/spec/{bitcoin/fixtures → fixtures}/tx-326882a7f22b5191f1a0cc9962ca4b878cd969cf3b3a70887aece4d801a0ba5e.json +0 -0
  140. data/spec/{bitcoin/fixtures → fixtures}/tx-345bed8785c3282a264ffb0dbee61cde54854f10e16f1b3e75b7f2d9f62946f2.json +0 -0
  141. data/spec/{bitcoin/fixtures → fixtures}/tx-39ba7440b7103557560cc8ce258009936796485aaf8b478e66ab4cb97c66e31b.json +0 -0
  142. data/spec/{bitcoin/fixtures → fixtures}/tx-3a04d57a833367f1655cc5ec3beb587888ef4977a86caa8c8ad4ba7cc717eae7.json +0 -0
  143. data/spec/{bitcoin/fixtures → fixtures}/tx-3da75972766f0ad13319b0b461fd16823a731e44f6e9de4eb3c52d6a6fb6c8ae.json +0 -0
  144. data/spec/{bitcoin/fixtures → fixtures}/tx-4142ee4877eb116abf955a7ec6ef2dc38133b793df762b76d75e3d7d4d8badc9.json +0 -0
  145. data/spec/{bitcoin/fixtures → fixtures}/tx-44b833074e671120ba33106877b49e86ece510824b9af477a3853972bcd8d06a.json +0 -0
  146. data/spec/{bitcoin/fixtures → fixtures}/tx-46224764c7870f95b58f155bce1e38d4da8e99d42dbb632d0dd7c07e092ee5aa.json +0 -0
  147. data/spec/{bitcoin/fixtures → fixtures}/tx-5df1375ffe61ac35ca178ebb0cab9ea26dedbd0e96005dfcee7e379fa513232f.json +0 -0
  148. data/spec/{bitcoin/fixtures → fixtures}/tx-62d9a565bd7b5344c5352e3e9e5f40fa4bbd467fa19c87357216ec8777ba1cce.json +0 -0
  149. data/spec/{bitcoin/fixtures → fixtures}/tx-6327783a064d4e350c454ad5cd90201aedf65b1fc524e73709c52f0163739190.json +0 -0
  150. data/spec/{bitcoin/fixtures → fixtures}/tx-6606c366a487bff9e412d0b6c09c14916319932db5954bf5d8719f43f828a3ba.json +0 -0
  151. data/spec/{bitcoin/fixtures → fixtures}/tx-6aaf18b9f1283b939d8e5d40ff5f8a435229f4178372659cc3a0bce4e262bf78.json +0 -0
  152. data/spec/{bitcoin/fixtures → fixtures}/tx-6b48bba6f6d2286d7ec0883c0fc3085955090813a4c94980466611c798b868cc.json +0 -0
  153. data/spec/{bitcoin/fixtures → fixtures}/tx-70cfbc6690f9ab46712db44e3079ac227962b2771a9341d4233d898b521619ef.json +0 -0
  154. data/spec/{bitcoin/fixtures → fixtures}/tx-7a1a9db42f065f75110fcdb1bc415549c8ef7670417ba1d35a67f1b8adc562c1.json +0 -0
  155. data/spec/{bitcoin/fixtures → fixtures}/tx-9a768fc7d0c4bdc86e25154357ef7c0063ca21310e5740a2f12f90b7455184a7.json +0 -0
  156. data/spec/{bitcoin/fixtures → fixtures}/tx-9cad8d523a0694f2509d092c39cebc8046adae62b4e4297102d568191d9478d8.json +0 -0
  157. data/spec/{bitcoin/fixtures → fixtures}/tx-9e052eb694bd7e15906433f064dff0161a12fd325c1124537766377004023c6f.json +0 -0
  158. data/spec/{bitcoin/fixtures → fixtures}/tx-9fb65b7304aaa77ac9580823c2c06b259cc42591e5cce66d76a81b6f51cc5c28.json +0 -0
  159. data/spec/{bitcoin/fixtures → fixtures}/tx-a6ce7081addade7676cd2af75c4129eba6bf5e179a19c40c7d4cf6a5fe595954.json +0 -0
  160. data/spec/{bitcoin/fixtures → fixtures}/tx-a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944.json +0 -0
  161. data/spec/{bitcoin/fixtures → fixtures}/tx-aab7ef280abbb9cc6fbaf524d2645c3daf4fcca2b3f53370e618d9cedf65f1f8.json +0 -0
  162. data/spec/{bitcoin/fixtures → fixtures}/tx-ab9805c6d57d7070d9a42c5176e47bb705023e6b67249fb6760880548298e742.json +0 -0
  163. data/spec/{bitcoin/fixtures → fixtures}/tx-ad4bcf3241e5d2ad140564e20db3567d41594cf4c2012433fe46a2b70e0d87b8.json +0 -0
  164. data/spec/{bitcoin/fixtures → fixtures}/tx-b5b598de91787439afd5938116654e0b16b7a0d0f82742ba37564219c5afcbf9.json +0 -0
  165. data/spec/{bitcoin/fixtures → fixtures}/tx-b8fd633e7713a43d5ac87266adc78444669b987a56b3a65fb92d58c2c4b0e84d.json +0 -0
  166. data/spec/{bitcoin/fixtures → fixtures}/tx-bbca0628c42cb8bf7c3f4b2ad688fa56da5308dd2a10255da89fb1f46e6e413d.json +0 -0
  167. data/spec/{bitcoin/fixtures → fixtures}/tx-bc7fd132fcf817918334822ee6d9bd95c889099c96e07ca2c1eb2cc70db63224.json +0 -0
  168. data/spec/{bitcoin/fixtures → fixtures}/tx-c192b74844e4837a34c4a5a97b438f1c111405b01b99e2d12b7c96d07fc74c04.json +0 -0
  169. data/spec/{bitcoin/fixtures → fixtures}/tx-d3d77d63709e47d9ef58f0b557800115a6b676c6a423012fbb96f45d8fcef830.json +0 -0
  170. data/spec/{bitcoin/fixtures → fixtures}/tx-e335562f7e297aadeed88e5954bc4eeb8dc00b31d829eedb232e39d672b0c009.json +0 -0
  171. data/spec/{bitcoin/fixtures → fixtures}/tx-eb3b82c0884e3efa6d8b0be55b4915eb20be124c9766245bcc7f34fdac32bccb.json +0 -0
  172. data/spec/{bitcoin/fixtures → fixtures}/tx-fee1b9b85531c8fb6cd7831f83490c7f2aa768b6eefe29854ef5e89ce7b9ecb1.json +0 -0
  173. data/spec/{bitcoin/fixtures → fixtures}/txscript-invalid-too-many-sigops-followed-by-invalid-pushdata.bin +0 -0
  174. data/spec/helpers/block_helpers.rb +58 -0
  175. data/spec/helpers/fixture_helpers.rb +20 -0
  176. data/spec/helpers/library_helpers.rb +15 -0
  177. data/spec/spec_helper.rb +109 -0
  178. data/spec/unit/bitcoin/bech32_spec.rb +187 -0
  179. data/spec/unit/bitcoin/bitcoin_spec.rb +1079 -0
  180. data/spec/unit/bitcoin/bloom_filter_spec.rb +33 -0
  181. data/spec/unit/bitcoin/builder_spec.rb +559 -0
  182. data/spec/unit/bitcoin/contracthash_spec.rb +52 -0
  183. data/spec/unit/bitcoin/ext_key_spec.rb +281 -0
  184. data/spec/unit/bitcoin/key_spec.rb +457 -0
  185. data/spec/unit/bitcoin/network_spec.rb +71 -0
  186. data/spec/unit/bitcoin/protocol/addr_spec.rb +90 -0
  187. data/spec/unit/bitcoin/protocol/aux_pow_spec.rb +45 -0
  188. data/spec/unit/bitcoin/protocol/bip143_spec.rb +334 -0
  189. data/spec/unit/bitcoin/protocol/block_spec.rb +280 -0
  190. data/spec/unit/bitcoin/protocol/getblocks_spec.rb +44 -0
  191. data/spec/unit/bitcoin/protocol/inv_spec.rb +166 -0
  192. data/spec/unit/bitcoin/protocol/notfound_spec.rb +44 -0
  193. data/spec/unit/bitcoin/protocol/parser_spec.rb +69 -0
  194. data/spec/unit/bitcoin/protocol/partial_merkle_tree_spec.rb +47 -0
  195. data/spec/unit/bitcoin/protocol/ping_spec.rb +62 -0
  196. data/spec/unit/bitcoin/protocol/tx_spec.rb +1515 -0
  197. data/spec/unit/bitcoin/protocol/txin_spec.rb +47 -0
  198. data/spec/unit/bitcoin/protocol/txout_spec.rb +36 -0
  199. data/spec/unit/bitcoin/protocol/version_spec.rb +121 -0
  200. data/spec/unit/bitcoin/script/opcodes_spec.rb +864 -0
  201. data/spec/unit/bitcoin/script/script_spec.rb +1610 -0
  202. data/spec/unit/bitcoin/secp256k1_spec.rb +138 -0
  203. data/spec/unit/bitcoin/trezor/mnemonic_spec.rb +193 -0
  204. data/spec/unit/integrations/dogecoin_spec.rb +215 -0
  205. metadata +381 -372
  206. data/lib/bitcoin/logger.rb +0 -86
  207. data/lib/bitcoin/protocol/alert.rb +0 -46
  208. data/spec/bitcoin/bech32_spec.rb +0 -160
  209. data/spec/bitcoin/bitcoin_spec.rb +0 -666
  210. data/spec/bitcoin/bloom_filter_spec.rb +0 -23
  211. data/spec/bitcoin/builder_spec.rb +0 -375
  212. data/spec/bitcoin/contracthash_spec.rb +0 -45
  213. data/spec/bitcoin/dogecoin_spec.rb +0 -176
  214. data/spec/bitcoin/ext_key_spec.rb +0 -180
  215. data/spec/bitcoin/ffi_openssl.rb +0 -45
  216. data/spec/bitcoin/fixtures/rawblock-170.json +0 -68
  217. data/spec/bitcoin/fixtures/rawblock-9.json +0 -39
  218. data/spec/bitcoin/fixtures/reorg/blk_0_to_4.dat +0 -0
  219. data/spec/bitcoin/fixtures/reorg/blk_3A.dat +0 -0
  220. data/spec/bitcoin/fixtures/reorg/blk_4A.dat +0 -0
  221. data/spec/bitcoin/fixtures/reorg/blk_5A.dat +0 -0
  222. data/spec/bitcoin/fixtures/testnet/block_0.bin +0 -0
  223. data/spec/bitcoin/fixtures/testnet/block_1.bin +0 -0
  224. data/spec/bitcoin/fixtures/testnet/block_2.bin +0 -0
  225. data/spec/bitcoin/fixtures/testnet/block_3.bin +0 -0
  226. data/spec/bitcoin/fixtures/testnet/block_4.bin +0 -0
  227. data/spec/bitcoin/fixtures/testnet/block_5.bin +0 -0
  228. data/spec/bitcoin/fixtures/txdp-1.txt +0 -32
  229. data/spec/bitcoin/fixtures/txdp-2-signed.txt +0 -19
  230. data/spec/bitcoin/fixtures/txdp-2-unsigned.txt +0 -14
  231. data/spec/bitcoin/helpers/fake_blockchain.rb +0 -183
  232. data/spec/bitcoin/key_spec.rb +0 -326
  233. data/spec/bitcoin/network_spec.rb +0 -50
  234. data/spec/bitcoin/performance/storage_spec.rb +0 -41
  235. data/spec/bitcoin/protocol/addr_spec.rb +0 -82
  236. data/spec/bitcoin/protocol/alert_spec.rb +0 -22
  237. data/spec/bitcoin/protocol/aux_pow_spec.rb +0 -45
  238. data/spec/bitcoin/protocol/bip143_spec.rb +0 -116
  239. data/spec/bitcoin/protocol/block_spec.rb +0 -208
  240. data/spec/bitcoin/protocol/getblocks_spec.rb +0 -32
  241. data/spec/bitcoin/protocol/inv_spec.rb +0 -134
  242. data/spec/bitcoin/protocol/notfound_spec.rb +0 -31
  243. data/spec/bitcoin/protocol/parser_spec.rb +0 -50
  244. data/spec/bitcoin/protocol/partial_merkle_tree_spec.rb +0 -38
  245. data/spec/bitcoin/protocol/ping_spec.rb +0 -51
  246. data/spec/bitcoin/protocol/reject.rb +0 -17
  247. data/spec/bitcoin/protocol/tx_spec.rb +0 -894
  248. data/spec/bitcoin/protocol/txin_spec.rb +0 -45
  249. data/spec/bitcoin/protocol/txout_spec.rb +0 -33
  250. data/spec/bitcoin/protocol/version_spec.rb +0 -110
  251. data/spec/bitcoin/script/opcodes_spec.rb +0 -773
  252. data/spec/bitcoin/script/script_spec.rb +0 -977
  253. data/spec/bitcoin/secp256k1_spec.rb +0 -78
  254. data/spec/bitcoin/spec_helper.rb +0 -108
  255. data/spec/bitcoin/trezor/mnemonic_spec.rb +0 -161
@@ -86,7 +86,7 @@ module Bitcoin
86
86
  new_key.depth = depth + 1
87
87
  new_key.number = number
88
88
  new_key.parent_fingerprint = fingerprint
89
- if number > (2**31 -1)
89
+ if number > (2**31 - 1)
90
90
  data = [0x00].pack('C') << priv_key.priv.htb << [number].pack('N')
91
91
  else
92
92
  data = priv_key.pub.htb << [number].pack('N')
@@ -164,7 +164,7 @@ module Bitcoin
164
164
  new_key.depth = depth + 1
165
165
  new_key.number = number
166
166
  new_key.parent_fingerprint = fingerprint
167
- raise 'hardened key is not support' if number > (2**31 -1)
167
+ raise 'hardened key is not support' if number > (2**31 - 1)
168
168
  data = pub.htb << [number].pack('N')
169
169
  l = Bitcoin.hmac_sha512(chain_code, data)
170
170
  left = OpenSSL::BN.from_hex(l[0..31].bth)
@@ -188,4 +188,4 @@ module Bitcoin
188
188
  end
189
189
  end
190
190
 
191
- end
191
+ end
@@ -2,11 +2,10 @@
2
2
 
3
3
  require 'ffi'
4
4
 
5
- # binding for src/.libs/bitcoinconsensus.so (https://github.com/bitcoin/bitcoin)
6
- # tag: v0.11.0
7
- # commit: d26f951802c762de04fb68e1a112d611929920ba
8
-
9
5
  module Bitcoin
6
+ # binding for src/.libs/bitcoinconsensus.so (https://github.com/bitcoin/bitcoin)
7
+ # tag: v0.11.0
8
+ # commit: d26f951802c762de04fb68e1a112d611929920ba
10
9
  module BitcoinConsensus
11
10
  extend FFI::Library
12
11
 
@@ -21,10 +20,10 @@ module Bitcoin
21
20
  SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS = (1 << 7)
22
21
  SCRIPT_VERIFY_CLEANSTACK = (1 << 8)
23
22
 
24
- ERR_CODES = { 0 => :ok, 1 => :tx_index, 2 => :tx_size_mismatch, 3 => :tx_deserialize }
23
+ ERR_CODES = { 0 => :ok, 1 => :tx_index, 2 => :tx_size_mismatch, 3 => :tx_deserialize }.freeze
25
24
 
26
25
  def self.ffi_load_functions(file)
27
- class_eval <<-RUBY
26
+ class_eval <<-RUBY # rubocop:disable Style/EvalWithLocation
28
27
  ffi_lib [ %[#{file}] ]
29
28
  attach_function :bitcoinconsensus_version, [], :uint
30
29
 
@@ -36,7 +35,9 @@ module Bitcoin
36
35
  end
37
36
 
38
37
  def self.lib_available?
39
- @__lib_path ||= [ ENV['BITCOINCONSENSUS_LIB_PATH'], 'vendor/bitcoin/src/.libs/libbitcoinconsensus.so' ].find{|f| File.exists?(f.to_s) }
38
+ @__lib_path ||= [ # rubocop:disable Naming/MemoizedInstanceVariableName
39
+ ENV['BITCOINCONSENSUS_LIB_PATH'], 'vendor/bitcoin/src/.libs/libbitcoinconsensus.so'
40
+ ].find { |f| File.exist?(f.to_s) }
40
41
  end
41
42
 
42
43
  def self.init
@@ -55,21 +56,24 @@ module Bitcoin
55
56
  def self.verify_script(input_index, script_pubkey, tx_payload, script_flags)
56
57
  init
57
58
 
58
- scriptPubKey = FFI::MemoryPointer.new(:uchar, script_pubkey.bytesize).put_bytes(0, script_pubkey)
59
- txTo = FFI::MemoryPointer.new(:uchar, tx_payload.bytesize).put_bytes(0, tx_payload)
59
+ script_pub_key = FFI::MemoryPointer.new(
60
+ :uchar, script_pubkey.bytesize
61
+ ).put_bytes(0, script_pubkey)
62
+ tx_to = FFI::MemoryPointer.new(:uchar, tx_payload.bytesize).put_bytes(0, tx_payload)
60
63
  error_ret = FFI::MemoryPointer.new(:uint)
61
64
 
62
- ret = bitcoinconsensus_verify_script(scriptPubKey, scriptPubKey.size, txTo, txTo.size, input_index, script_flags, error_ret)
65
+ ret = bitcoinconsensus_verify_script(
66
+ script_pub_key, script_pub_key.size, tx_to, tx_to.size, input_index, script_flags, error_ret
67
+ )
63
68
 
64
69
  case ret
65
70
  when 0
66
71
  false
67
72
  when 1
68
- (ERR_CODES[error_ret.read_int] == :ok) ? true : false
73
+ ERR_CODES[error_ret.read_int] == :ok
69
74
  else
70
- raise "error invalid result"
75
+ raise 'error invalid result'
71
76
  end
72
77
  end
73
-
74
78
  end
75
79
  end
@@ -1,388 +1,405 @@
1
1
  # encoding: ascii-8bit
2
2
 
3
- # autoload when you need to re-generate a public_key from only its private_key.
4
- # ported from: https://github.com/sipa/bitcoin/blob/2d40fe4da9ea82af4b652b691a4185431d6e47a8/key.h
5
-
6
3
  require 'ffi'
7
4
 
8
5
  module Bitcoin
9
- module OpenSSL_EC
10
- extend FFI::Library
11
- if FFI::Platform.windows?
12
- ffi_lib 'libeay32', 'ssleay32'
13
- else
14
- ffi_lib [ 'libssl.so.1.0.0', 'ssl' ]
15
- end
16
-
17
- NID_secp256k1 = 714
18
- POINT_CONVERSION_COMPRESSED = 2
19
- POINT_CONVERSION_UNCOMPRESSED = 4
20
-
21
- attach_function :SSL_library_init, [], :int
22
- attach_function :ERR_load_crypto_strings, [], :void
23
- attach_function :SSL_load_error_strings, [], :void
24
- attach_function :RAND_poll, [], :int
25
-
26
- attach_function :BN_CTX_free, [:pointer], :int
27
- attach_function :BN_CTX_new, [], :pointer
28
- attach_function :BN_add, [:pointer, :pointer, :pointer], :int
29
- attach_function :BN_bin2bn, [:pointer, :int, :pointer], :pointer
30
- attach_function :BN_bn2bin, [:pointer, :pointer], :int
31
- attach_function :BN_cmp, [:pointer, :pointer], :int
32
- attach_function :BN_copy, [:pointer, :pointer], :pointer
33
- attach_function :BN_dup, [:pointer], :pointer
34
- attach_function :BN_free, [:pointer], :int
35
- attach_function :BN_mod_inverse, [:pointer, :pointer, :pointer, :pointer], :pointer
36
- attach_function :BN_mod_mul, [:pointer, :pointer, :pointer, :pointer, :pointer], :int
37
- attach_function :BN_mod_sub, [:pointer, :pointer, :pointer, :pointer, :pointer], :int
38
- attach_function :BN_mul_word, [:pointer, :int], :int
39
- attach_function :BN_new, [], :pointer
40
- attach_function :BN_rshift, [:pointer, :pointer, :int], :int
41
- attach_function :BN_rshift1, [:pointer, :pointer], :int
42
- attach_function :BN_set_word, [:pointer, :int], :int
43
- attach_function :BN_sub, [:pointer, :pointer, :pointer], :int
44
- attach_function :EC_GROUP_get_curve_GFp, [:pointer, :pointer, :pointer, :pointer, :pointer], :int
45
- attach_function :EC_GROUP_get_degree, [:pointer], :int
46
- attach_function :EC_GROUP_get_order, [:pointer, :pointer, :pointer], :int
47
- attach_function :EC_KEY_free, [:pointer], :int
48
- attach_function :EC_KEY_get0_group, [:pointer], :pointer
49
- attach_function :EC_KEY_get0_private_key, [:pointer], :pointer
50
- attach_function :EC_KEY_new_by_curve_name, [:int], :pointer
51
- attach_function :EC_KEY_set_conv_form, [:pointer, :int], :void
52
- attach_function :EC_KEY_set_private_key, [:pointer, :pointer], :int
53
- attach_function :EC_KEY_set_public_key, [:pointer, :pointer], :int
54
- attach_function :EC_POINT_free, [:pointer], :int
55
- attach_function :EC_POINT_is_at_infinity, [:pointer, :pointer], :int
56
- attach_function :EC_POINT_mul, [:pointer, :pointer, :pointer, :pointer, :pointer, :pointer], :int
57
- attach_function :EC_POINT_new, [:pointer], :pointer
58
- attach_function :EC_POINT_set_compressed_coordinates_GFp, [:pointer, :pointer, :pointer, :int, :pointer], :int
59
- attach_function :d2i_ECPrivateKey, [:pointer, :pointer, :long], :pointer
60
- attach_function :i2d_ECPrivateKey, [:pointer, :pointer], :int
61
- attach_function :i2o_ECPublicKey, [:pointer, :pointer], :uint
62
- attach_function :EC_KEY_check_key, [:pointer], :uint
63
- attach_function :ECDSA_do_sign, [:pointer, :uint, :pointer], :pointer
64
- attach_function :BN_num_bits, [:pointer], :int
65
- attach_function :ECDSA_SIG_free, [:pointer], :void
66
- attach_function :EC_POINT_add, [:pointer, :pointer, :pointer, :pointer, :pointer], :int
67
- attach_function :EC_POINT_point2hex, [:pointer, :pointer, :int, :pointer], :string
68
- attach_function :EC_POINT_hex2point, [:pointer, :string, :pointer, :pointer], :pointer
69
- attach_function :ECDSA_SIG_new, [], :pointer
70
- attach_function :d2i_ECDSA_SIG, [:pointer, :pointer, :long], :pointer
71
- attach_function :i2d_ECDSA_SIG, [:pointer, :pointer], :int
72
- attach_function :OPENSSL_free, :CRYPTO_free, [:pointer], :void
73
-
74
- def self.BN_num_bytes(ptr); (BN_num_bits(ptr) + 7) / 8; end
75
-
76
-
77
- # resolve public from private key, using ffi and libssl.so
78
- # example:
79
- # keypair = Bitcoin.generate_key; Bitcoin::OpenSSL_EC.regenerate_key(keypair.first) == keypair
80
- def self.regenerate_key(private_key)
81
- private_key = [private_key].pack("H*") if private_key.bytesize >= (32*2)
82
- private_key_hex = private_key.unpack("H*")[0]
83
-
84
- #private_key = FFI::MemoryPointer.new(:uint8, private_key.bytesize)
85
- # .put_bytes(0, private_key, 0, private_key.bytesize)
86
- private_key = FFI::MemoryPointer.from_string(private_key)
87
-
88
- init_ffi_ssl
89
- eckey = EC_KEY_new_by_curve_name(NID_secp256k1)
90
- #priv_key = BN_bin2bn(private_key, private_key.size, BN_new())
91
- priv_key = BN_bin2bn(private_key, private_key.size-1, BN_new())
92
-
93
- group, order, ctx = EC_KEY_get0_group(eckey), BN_new(), BN_CTX_new()
94
- EC_GROUP_get_order(group, order, ctx)
95
-
96
- pub_key = EC_POINT_new(group)
97
- EC_POINT_mul(group, pub_key, priv_key, nil, nil, ctx)
98
- EC_KEY_set_private_key(eckey, priv_key)
99
- EC_KEY_set_public_key(eckey, pub_key)
100
-
101
- BN_free(order)
102
- BN_CTX_free(ctx)
103
- EC_POINT_free(pub_key)
104
- BN_free(priv_key)
105
-
106
-
107
- length = i2d_ECPrivateKey(eckey, nil)
108
- buf = FFI::MemoryPointer.new(:uint8, length)
109
- ptr = FFI::MemoryPointer.new(:pointer).put_pointer(0, buf)
110
- priv_hex = if i2d_ECPrivateKey(eckey, ptr) == length
111
- size = buf.get_array_of_uint8(8, 1)[0]
112
- buf.get_array_of_uint8(9, size).pack("C*").rjust(32, "\x00").unpack("H*")[0]
113
- #der_to_private_key( ptr.read_pointer.read_string(length).unpack("H*")[0] )
114
- end
115
-
116
- if priv_hex != private_key_hex
117
- raise "regenerated wrong private_key, raise here before generating a faulty public_key too!"
6
+ # autoload when you need to re-generate a public_key from only its private_key.
7
+ # ported from: https://github.com/sipa/bitcoin/blob/2d40fe4da9ea82af4b652b691a4185431d6e47a8/key.h
8
+ module OpenSSL_EC # rubocop:disable Naming/ClassAndModuleCamelCase
9
+ extend FFI::Library
10
+ if FFI::Platform.windows?
11
+ ffi_lib 'libeay32', 'ssleay32'
12
+ else
13
+ ffi_lib ['libssl.so.1.0.0', 'ssl']
118
14
  end
119
15
 
120
-
121
- length = i2o_ECPublicKey(eckey, nil)
122
- buf = FFI::MemoryPointer.new(:uint8, length)
123
- ptr = FFI::MemoryPointer.new(:pointer).put_pointer(0, buf)
124
- pub_hex = if i2o_ECPublicKey(eckey, ptr) == length
125
- buf.read_string(length).unpack("H*")[0]
16
+ NID_secp256k1 = 714 # rubocop:disable Naming/ConstantName
17
+ POINT_CONVERSION_COMPRESSED = 2
18
+ POINT_CONVERSION_UNCOMPRESSED = 4
19
+
20
+ attach_function :SSL_library_init, [], :int
21
+ attach_function :ERR_load_crypto_strings, [], :void
22
+ attach_function :SSL_load_error_strings, [], :void
23
+ attach_function :RAND_poll, [], :int
24
+
25
+ attach_function :BN_CTX_free, [:pointer], :int
26
+ attach_function :BN_CTX_new, [], :pointer
27
+ attach_function :BN_add, %i[pointer pointer pointer], :int
28
+ attach_function :BN_bin2bn, %i[pointer int pointer], :pointer
29
+ attach_function :BN_bn2bin, %i[pointer pointer], :int
30
+ attach_function :BN_cmp, %i[pointer pointer], :int
31
+ attach_function :BN_copy, %i[pointer pointer], :pointer
32
+ attach_function :BN_dup, [:pointer], :pointer
33
+ attach_function :BN_free, [:pointer], :int
34
+ attach_function :BN_mod_inverse, %i[pointer pointer pointer pointer], :pointer
35
+ attach_function :BN_mod_mul, %i[pointer pointer pointer pointer pointer], :int
36
+ attach_function :BN_mod_sub, %i[pointer pointer pointer pointer pointer], :int
37
+ attach_function :BN_mul_word, %i[pointer int], :int
38
+ attach_function :BN_new, [], :pointer
39
+ attach_function :BN_rshift, %i[pointer pointer int], :int
40
+ attach_function :BN_rshift1, %i[pointer pointer], :int
41
+ attach_function :BN_set_word, %i[pointer int], :int
42
+ attach_function :BN_sub, %i[pointer pointer pointer], :int
43
+ attach_function :EC_GROUP_get_curve_GFp, %i[pointer pointer pointer pointer pointer], :int
44
+ attach_function :EC_GROUP_get_degree, [:pointer], :int
45
+ attach_function :EC_GROUP_get_order, %i[pointer pointer pointer], :int
46
+ attach_function :EC_KEY_free, [:pointer], :int
47
+ attach_function :EC_KEY_get0_group, [:pointer], :pointer
48
+ attach_function :EC_KEY_get0_private_key, [:pointer], :pointer
49
+ attach_function :EC_KEY_new_by_curve_name, [:int], :pointer
50
+ attach_function :EC_KEY_set_conv_form, %i[pointer int], :void
51
+ attach_function :EC_KEY_set_private_key, %i[pointer pointer], :int
52
+ attach_function :EC_KEY_set_public_key, %i[pointer pointer], :int
53
+ attach_function :EC_POINT_free, [:pointer], :int
54
+ attach_function :EC_POINT_is_at_infinity, %i[pointer pointer], :int
55
+ attach_function :EC_POINT_mul, %i[pointer pointer pointer pointer pointer pointer], :int
56
+ attach_function :EC_POINT_new, [:pointer], :pointer
57
+ attach_function :EC_POINT_set_compressed_coordinates_GFp,
58
+ %i[pointer pointer pointer int pointer], :int
59
+ attach_function :d2i_ECPrivateKey, %i[pointer pointer long], :pointer
60
+ attach_function :i2d_ECPrivateKey, %i[pointer pointer], :int
61
+ attach_function :i2o_ECPublicKey, %i[pointer pointer], :uint
62
+ attach_function :EC_KEY_check_key, [:pointer], :uint
63
+ attach_function :ECDSA_do_sign, %i[pointer uint pointer], :pointer
64
+ attach_function :BN_num_bits, [:pointer], :int
65
+ attach_function :ECDSA_SIG_free, [:pointer], :void
66
+ attach_function :EC_POINT_add, %i[pointer pointer pointer pointer pointer], :int
67
+ attach_function :EC_POINT_point2hex, %i[pointer pointer int pointer], :string
68
+ attach_function :EC_POINT_hex2point, %i[pointer string pointer pointer], :pointer
69
+ attach_function :ECDSA_SIG_new, [], :pointer
70
+ attach_function :d2i_ECDSA_SIG, %i[pointer pointer long], :pointer
71
+ attach_function :i2d_ECDSA_SIG, %i[pointer pointer], :int
72
+ attach_function :OPENSSL_free, :CRYPTO_free, [:pointer], :void
73
+
74
+ def self.BN_num_bytes(ptr) # rubocop:disable Naming/MethodName
75
+ (BN_num_bits(ptr) + 7) / 8
126
76
  end
127
77
 
128
- EC_KEY_free(eckey)
129
-
130
- [ priv_hex, pub_hex ]
131
- end
132
-
133
- # extract private key from uncompressed DER format
134
- def self.der_to_private_key(der_hex)
135
- init_ffi_ssl
136
- #k = EC_KEY_new_by_curve_name(NID_secp256k1)
137
- #kp = FFI::MemoryPointer.new(:pointer).put_pointer(0, eckey)
138
-
139
- buf = FFI::MemoryPointer.from_string([der_hex].pack("H*"))
140
- ptr = FFI::MemoryPointer.new(:pointer).put_pointer(0, buf)
141
-
142
- #ec_key = d2i_ECPrivateKey(kp, ptr, buf.size-1)
143
- ec_key = d2i_ECPrivateKey(nil, ptr, buf.size-1)
144
- return nil if ec_key.null?
145
- bn = EC_KEY_get0_private_key(ec_key)
146
- BN_bn2bin(bn, buf)
147
- buf.read_string(32).unpack("H*")[0]
148
- end
78
+ # resolve public from private key, using ffi and libssl.so
79
+ # example:
80
+ # keypair = Bitcoin.generate_key; Bitcoin::OpenSSL_EC.regenerate_key(keypair.first) == keypair
81
+ def self.regenerate_key(private_key)
82
+ private_key = [private_key].pack('H*') if private_key.bytesize >= (32 * 2)
83
+ private_key_hex = private_key.unpack('H*')[0]
84
+
85
+ # private_key = FFI::MemoryPointer.new(:uint8, private_key.bytesize)
86
+ # .put_bytes(0, private_key, 0, private_key.bytesize)
87
+ private_key = FFI::MemoryPointer.from_string(private_key)
88
+
89
+ init_ffi_ssl
90
+ eckey = EC_KEY_new_by_curve_name(NID_secp256k1)
91
+ # priv_key = BN_bin2bn(private_key, private_key.size, BN_new())
92
+ priv_key = BN_bin2bn(private_key, private_key.size - 1, BN_new())
93
+
94
+ group = EC_KEY_get0_group(eckey)
95
+ order = BN_new()
96
+ ctx = BN_CTX_new()
97
+ EC_GROUP_get_order(group, order, ctx)
98
+
99
+ pub_key = EC_POINT_new(group)
100
+ EC_POINT_mul(group, pub_key, priv_key, nil, nil, ctx)
101
+ EC_KEY_set_private_key(eckey, priv_key)
102
+ EC_KEY_set_public_key(eckey, pub_key)
103
+
104
+ BN_free(order)
105
+ BN_CTX_free(ctx)
106
+ EC_POINT_free(pub_key)
107
+ BN_free(priv_key)
108
+
109
+ length = i2d_ECPrivateKey(eckey, nil)
110
+ buf = FFI::MemoryPointer.new(:uint8, length)
111
+ ptr = FFI::MemoryPointer.new(:pointer).put_pointer(0, buf)
112
+ priv_hex = if i2d_ECPrivateKey(eckey, ptr) == length
113
+ size = buf.get_array_of_uint8(8, 1)[0]
114
+ buf.get_array_of_uint8(9, size).pack('C*').rjust(32, "\x00").unpack('H*')[0]
115
+ # der_to_private_key( ptr.read_pointer.read_string(length).unpack("H*")[0] )
116
+ end
117
+
118
+ if priv_hex != private_key_hex
119
+ raise 'regenerated wrong private_key, raise here before generating a faulty public_key too!'
120
+ end
121
+
122
+ length = i2o_ECPublicKey(eckey, nil)
123
+ buf = FFI::MemoryPointer.new(:uint8, length)
124
+ ptr = FFI::MemoryPointer.new(:pointer).put_pointer(0, buf)
125
+ pub_hex = buf.read_string(length).unpack('H*')[0] if i2o_ECPublicKey(eckey, ptr) == length
149
126
 
150
- # Given the components of a signature and a selector value, recover and
151
- # return the public key that generated the signature according to the
152
- # algorithm in SEC1v2 section 4.1.6.
153
- #
154
- # rec_id is an index from 0 to 3 that indicates which of the 4 possible
155
- # keys is the correct one. Because the key recovery operation yields
156
- # multiple potential keys, the correct key must either be stored alongside
157
- # the signature, or you must be willing to try each rec_id in turn until
158
- # you find one that outputs the key you are expecting.
159
- #
160
- # If this method returns nil, it means recovery was not possible and rec_id
161
- # should be iterated.
162
- #
163
- # Given the above two points, a correct usage of this method is inside a
164
- # for loop from 0 to 3, and if the output is nil OR a key that is not the
165
- # one you expect, you try again with the next rec_id.
166
- #
167
- # message_hash = hash of the signed message.
168
- # signature = the R and S components of the signature, wrapped.
169
- # rec_id = which possible key to recover.
170
- # is_compressed = whether or not the original pubkey was compressed.
171
- def self.recover_public_key_from_signature(message_hash, signature, rec_id, is_compressed)
172
- return nil if rec_id < 0 or signature.bytesize != 65
173
- init_ffi_ssl
174
-
175
- signature = FFI::MemoryPointer.from_string(signature)
176
- #signature_bn = BN_bin2bn(signature, 65, BN_new())
177
- r = BN_bin2bn(signature[1], 32, BN_new())
178
- s = BN_bin2bn(signature[33], 32, BN_new())
179
-
180
- n, i = 0, rec_id / 2
181
- eckey = EC_KEY_new_by_curve_name(NID_secp256k1)
182
-
183
- EC_KEY_set_conv_form(eckey, POINT_CONVERSION_COMPRESSED) if is_compressed
184
-
185
- group = EC_KEY_get0_group(eckey)
186
- order = BN_new()
187
- EC_GROUP_get_order(group, order, nil)
188
- x = BN_dup(order)
189
- BN_mul_word(x, i)
190
- BN_add(x, x, r)
191
-
192
- field = BN_new()
193
- EC_GROUP_get_curve_GFp(group, field, nil, nil, nil)
194
-
195
- if BN_cmp(x, field) >= 0
196
- [r, s, order, x, field].each{|i| BN_free(i) }
197
127
  EC_KEY_free(eckey)
198
- return nil
128
+
129
+ [priv_hex, pub_hex]
199
130
  end
200
131
 
201
- big_r = EC_POINT_new(group)
202
- EC_POINT_set_compressed_coordinates_GFp(group, big_r, x, rec_id % 2, nil)
203
-
204
- big_q = EC_POINT_new(group)
205
- n = EC_GROUP_get_degree(group)
206
- e = BN_bin2bn(message_hash, message_hash.bytesize, BN_new())
207
- BN_rshift(e, e, 8 - (n & 7)) if 8 * message_hash.bytesize > n
208
-
209
- ctx = BN_CTX_new()
210
- zero, rr, sor, eor = BN_new(), BN_new(), BN_new(), BN_new()
211
- BN_set_word(zero, 0)
212
- BN_mod_sub(e, zero, e, order, ctx)
213
- BN_mod_inverse(rr, r, order, ctx)
214
- BN_mod_mul(sor, s, rr, order, ctx)
215
- BN_mod_mul(eor, e, rr, order, ctx)
216
- EC_POINT_mul(group, big_q, eor, big_r, sor, ctx)
217
- EC_KEY_set_public_key(eckey, big_q)
218
- BN_CTX_free(ctx)
219
-
220
- [r, s, order, x, field, e, zero, rr, sor, eor].each{|i| BN_free(i) }
221
- [big_r, big_q].each{|i| EC_POINT_free(i) }
222
-
223
- length = i2o_ECPublicKey(eckey, nil)
224
- buf = FFI::MemoryPointer.new(:uint8, length)
225
- ptr = FFI::MemoryPointer.new(:pointer).put_pointer(0, buf)
226
- pub_hex = if i2o_ECPublicKey(eckey, ptr) == length
227
- buf.read_string(length).unpack("H*")[0]
132
+ # extract private key from uncompressed DER format
133
+ def self.der_to_private_key(der_hex)
134
+ init_ffi_ssl
135
+ # k = EC_KEY_new_by_curve_name(NID_secp256k1)
136
+ # kp = FFI::MemoryPointer.new(:pointer).put_pointer(0, eckey)
137
+
138
+ buf = FFI::MemoryPointer.from_string([der_hex].pack('H*'))
139
+ ptr = FFI::MemoryPointer.new(:pointer).put_pointer(0, buf)
140
+
141
+ # ec_key = d2i_ECPrivateKey(kp, ptr, buf.size-1)
142
+ ec_key = d2i_ECPrivateKey(nil, ptr, buf.size - 1)
143
+ return nil if ec_key.null?
144
+ bn = EC_KEY_get0_private_key(ec_key)
145
+ BN_bn2bin(bn, buf)
146
+ buf.read_string(32).unpack('H*')[0]
228
147
  end
229
148
 
230
- EC_KEY_free(eckey)
149
+ # Given the components of a signature and a selector value, recover and
150
+ # return the public key that generated the signature according to the
151
+ # algorithm in SEC1v2 section 4.1.6.
152
+ #
153
+ # rec_id is an index from 0 to 3 that indicates which of the 4 possible
154
+ # keys is the correct one. Because the key recovery operation yields
155
+ # multiple potential keys, the correct key must either be stored alongside
156
+ # the signature, or you must be willing to try each rec_id in turn until
157
+ # you find one that outputs the key you are expecting.
158
+ #
159
+ # If this method returns nil, it means recovery was not possible and rec_id
160
+ # should be iterated.
161
+ #
162
+ # Given the above two points, a correct usage of this method is inside a
163
+ # for loop from 0 to 3, and if the output is nil OR a key that is not the
164
+ # one you expect, you try again with the next rec_id.
165
+ #
166
+ # message_hash = hash of the signed message.
167
+ # signature = the R and S components of the signature, wrapped.
168
+ # rec_id = which possible key to recover.
169
+ # is_compressed = whether or not the original pubkey was compressed.
170
+ def self.recover_public_key_from_signature(message_hash, signature, rec_id, is_compressed)
171
+ return nil if rec_id < 0 || signature.bytesize != 65
172
+ init_ffi_ssl
173
+
174
+ signature = FFI::MemoryPointer.from_string(signature)
175
+ # signature_bn = BN_bin2bn(signature, 65, BN_new())
176
+ r = BN_bin2bn(signature[1], 32, BN_new())
177
+ s = BN_bin2bn(signature[33], 32, BN_new())
178
+
179
+ i = rec_id / 2
180
+ eckey = EC_KEY_new_by_curve_name(NID_secp256k1)
181
+
182
+ EC_KEY_set_conv_form(eckey, POINT_CONVERSION_COMPRESSED) if is_compressed
183
+
184
+ group = EC_KEY_get0_group(eckey)
185
+ order = BN_new()
186
+ EC_GROUP_get_order(group, order, nil)
187
+ x = BN_dup(order)
188
+ BN_mul_word(x, i)
189
+ BN_add(x, x, r)
190
+
191
+ field = BN_new()
192
+ EC_GROUP_get_curve_GFp(group, field, nil, nil, nil)
193
+
194
+ if BN_cmp(x, field) >= 0
195
+ [r, s, order, x, field].each { |item| BN_free(item) }
196
+ EC_KEY_free(eckey)
197
+ return nil
198
+ end
199
+
200
+ big_r = EC_POINT_new(group)
201
+ EC_POINT_set_compressed_coordinates_GFp(group, big_r, x, rec_id % 2, nil)
202
+
203
+ big_q = EC_POINT_new(group)
204
+ n = EC_GROUP_get_degree(group)
205
+ e = BN_bin2bn(message_hash, message_hash.bytesize, BN_new())
206
+ BN_rshift(e, e, 8 - (n & 7)) if 8 * message_hash.bytesize > n
207
+
208
+ ctx = BN_CTX_new()
209
+ zero = BN_new()
210
+ rr = BN_new()
211
+ sor = BN_new()
212
+ eor = BN_new()
213
+ BN_set_word(zero, 0)
214
+ BN_mod_sub(e, zero, e, order, ctx)
215
+ BN_mod_inverse(rr, r, order, ctx)
216
+ BN_mod_mul(sor, s, rr, order, ctx)
217
+ BN_mod_mul(eor, e, rr, order, ctx)
218
+ EC_POINT_mul(group, big_q, eor, big_r, sor, ctx)
219
+ EC_KEY_set_public_key(eckey, big_q)
220
+ BN_CTX_free(ctx)
221
+
222
+ [r, s, order, x, field, e, zero, rr, sor, eor].each { |item| BN_free(item) }
223
+ [big_r, big_q].each { |item| EC_POINT_free(item) }
224
+
225
+ length = i2o_ECPublicKey(eckey, nil)
226
+ buf = FFI::MemoryPointer.new(:uint8, length)
227
+ ptr = FFI::MemoryPointer.new(:pointer).put_pointer(0, buf)
228
+ pub_hex = buf.read_string(length).unpack('H*')[0] if i2o_ECPublicKey(eckey, ptr) == length
231
229
 
232
- pub_hex
233
- end
230
+ EC_KEY_free(eckey)
234
231
 
235
- # Regenerate a DER-encoded signature such that the S-value complies with the BIP62
236
- # specification.
237
- #
238
- def self.signature_to_low_s(signature)
239
- init_ffi_ssl
240
-
241
- buf = FFI::MemoryPointer.new(:uint8, 34)
242
- temp = signature.unpack("C*")
243
- length_r = temp[3]
244
- length_s = temp[5+length_r]
245
- sig = FFI::MemoryPointer.from_string(signature)
246
-
247
- # Calculate the lower s value
248
- s = BN_bin2bn(sig[6 + length_r], length_s, BN_new())
249
- eckey = EC_KEY_new_by_curve_name(NID_secp256k1)
250
- group, order, halforder, ctx = EC_KEY_get0_group(eckey), BN_new(), BN_new(), BN_CTX_new()
251
-
252
- EC_GROUP_get_order(group, order, ctx)
253
- BN_rshift1(halforder, order)
254
- if BN_cmp(s, halforder) > 0
255
- BN_sub(s, order, s)
232
+ pub_hex
256
233
  end
257
234
 
258
- BN_free(halforder)
259
- BN_free(order)
260
- BN_CTX_free(ctx)
261
-
262
- length_s = BN_bn2bin(s, buf)
263
- # p buf.read_string(length_s).unpack("H*")
264
-
265
- # Re-encode the signature in DER format
266
- sig = [0x30, 0, 0x02, length_r]
267
- sig.concat(temp.slice(4, length_r))
268
- sig << 0x02
269
- sig << length_s
270
- sig.concat(buf.read_string(length_s).unpack("C*"))
271
- sig[1] = sig.size - 2
235
+ # Regenerate a DER-encoded signature such that the S-value complies with the BIP62
236
+ # specification.
237
+ #
238
+ def self.signature_to_low_s(signature)
239
+ init_ffi_ssl
240
+
241
+ buf = FFI::MemoryPointer.new(:uint8, 34)
242
+ temp = signature.unpack('C*')
243
+ length_r = temp[3]
244
+ length_s = temp[5 + length_r]
245
+ sig = FFI::MemoryPointer.from_string(signature)
246
+
247
+ # Calculate the lower s value
248
+ s = BN_bin2bn(sig[6 + length_r], length_s, BN_new())
249
+ eckey = EC_KEY_new_by_curve_name(NID_secp256k1)
250
+ group = EC_KEY_get0_group(eckey)
251
+ order = BN_new()
252
+ halforder = BN_new()
253
+ ctx = BN_CTX_new()
254
+
255
+ EC_GROUP_get_order(group, order, ctx)
256
+ BN_rshift1(halforder, order)
257
+ BN_sub(s, order, s) if BN_cmp(s, halforder) > 0
258
+
259
+ BN_free(halforder)
260
+ BN_free(order)
261
+ BN_CTX_free(ctx)
262
+
263
+ length_s = BN_bn2bin(s, buf)
264
+ # p buf.read_string(length_s).unpack("H*")
265
+
266
+ # Re-encode the signature in DER format
267
+ sig = [0x30, 0, 0x02, length_r]
268
+ sig.concat(temp.slice(4, length_r))
269
+ sig << 0x02
270
+ sig << length_s
271
+ sig.concat(buf.read_string(length_s).unpack('C*'))
272
+ sig[1] = sig.size - 2
273
+
274
+ BN_free(s)
275
+ EC_KEY_free(eckey)
272
276
 
273
- BN_free(s)
274
- EC_KEY_free(eckey)
277
+ sig.pack('C*')
278
+ end
275
279
 
276
- sig.pack("C*")
277
- end
280
+ def self.sign_compact(hash, private_key, public_key_hex = nil, pubkey_compressed = nil)
281
+ msg32 = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, hash)
278
282
 
279
- def self.sign_compact(hash, private_key, public_key_hex = nil, pubkey_compressed = nil)
280
- msg32 = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, hash)
283
+ private_key = [private_key].pack('H*') if private_key.bytesize >= 64
284
+ private_key_hex = private_key.unpack('H*')[0]
281
285
 
282
- private_key = [private_key].pack("H*") if private_key.bytesize >= 64
283
- private_key_hex = private_key.unpack("H*")[0]
286
+ public_key_hex ||= regenerate_key(private_key_hex).last
287
+ pubkey_compressed ||= public_key_hex[0..1] != '04'
284
288
 
285
- public_key_hex = regenerate_key(private_key_hex).last unless public_key_hex
286
- pubkey_compressed = (public_key_hex[0..1] == "04" ? false : true) unless pubkey_compressed
289
+ init_ffi_ssl
290
+ eckey = EC_KEY_new_by_curve_name(NID_secp256k1)
291
+ priv_key = BN_bin2bn(private_key, private_key.bytesize, BN_new())
287
292
 
288
- init_ffi_ssl
289
- eckey = EC_KEY_new_by_curve_name(NID_secp256k1)
290
- priv_key = BN_bin2bn(private_key, private_key.bytesize, BN_new())
293
+ group = EC_KEY_get0_group(eckey)
294
+ order = BN_new()
295
+ ctx = BN_CTX_new()
296
+ EC_GROUP_get_order(group, order, ctx)
291
297
 
292
- group, order, ctx = EC_KEY_get0_group(eckey), BN_new(), BN_CTX_new()
293
- EC_GROUP_get_order(group, order, ctx)
298
+ pub_key = EC_POINT_new(group)
299
+ EC_POINT_mul(group, pub_key, priv_key, nil, nil, ctx)
300
+ EC_KEY_set_private_key(eckey, priv_key)
301
+ EC_KEY_set_public_key(eckey, pub_key)
294
302
 
295
- pub_key = EC_POINT_new(group)
296
- EC_POINT_mul(group, pub_key, priv_key, nil, nil, ctx)
297
- EC_KEY_set_private_key(eckey, priv_key)
298
- EC_KEY_set_public_key(eckey, pub_key)
303
+ signature = ECDSA_do_sign(msg32, msg32.size, eckey)
299
304
 
300
- signature = ECDSA_do_sign(msg32, msg32.size, eckey)
305
+ BN_free(order)
306
+ BN_CTX_free(ctx)
307
+ EC_POINT_free(pub_key)
308
+ BN_free(priv_key)
309
+ EC_KEY_free(eckey)
301
310
 
302
- BN_free(order)
303
- BN_CTX_free(ctx)
304
- EC_POINT_free(pub_key)
305
- BN_free(priv_key)
306
- EC_KEY_free(eckey)
311
+ buf = FFI::MemoryPointer.new(:uint8, 32)
312
+ head = nil
313
+ r, s = signature.get_array_of_pointer(0, 2).map do |i|
314
+ BN_bn2bin(i, buf)
315
+ buf.read_string(BN_num_bytes(i)).rjust(32, "\x00")
316
+ end
317
+
318
+ rec_id = nil
319
+ if signature.get_array_of_pointer(0, 2).all? { |i| BN_num_bits(i) <= 256 }
320
+ 4.times do |i|
321
+ head = [27 + i + (pubkey_compressed ? 4 : 0)].pack('C')
322
+ recovered_key = recover_public_key_from_signature(
323
+ msg32.read_string(32), [head, r, s].join, i, pubkey_compressed
324
+ )
325
+ if public_key_hex == recovered_key
326
+ rec_id = i
327
+ break
328
+ end
329
+ end
330
+ end
307
331
 
308
- buf, rec_id, head = FFI::MemoryPointer.new(:uint8, 32), nil, nil
309
- r, s = signature.get_array_of_pointer(0, 2).map{|i| BN_bn2bin(i, buf); buf.read_string(BN_num_bytes(i)).rjust(32, "\x00") }
332
+ ECDSA_SIG_free(signature)
310
333
 
311
- if signature.get_array_of_pointer(0, 2).all?{|i| BN_num_bits(i) <= 256 }
312
- 4.times{|i|
313
- head = [ 27 + i + (pubkey_compressed ? 4 : 0) ].pack("C")
314
- if public_key_hex == recover_public_key_from_signature(msg32.read_string(32), [head, r, s].join, i, pubkey_compressed)
315
- rec_id = i; break
316
- end
317
- }
334
+ [head, [r, s]].join if rec_id
318
335
  end
319
336
 
320
- ECDSA_SIG_free(signature)
321
-
322
- [ head, [r,s] ].join if rec_id
323
- end
337
+ def self.recover_compact(hash, signature)
338
+ return false if signature.bytesize != 65
339
+ msg32 = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, hash)
324
340
 
325
- def self.recover_compact(hash, signature)
326
- return false if signature.bytesize != 65
327
- msg32 = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, hash)
341
+ version = signature.unpack('C')[0]
342
+ return false if version < 27 || version > 34
328
343
 
329
- version = signature.unpack('C')[0]
330
- return false if version < 27 or version > 34
344
+ compressed = version >= 31
345
+ version -= 4 if compressed
331
346
 
332
- compressed = (version >= 31) ? (version -= 4; true) : false
333
- pubkey = recover_public_key_from_signature(msg32.read_string(32), signature, version-27, compressed)
334
- end
347
+ recover_public_key_from_signature(msg32.read_string(32), signature, version - 27, compressed)
348
+ end
335
349
 
336
- # lifted from https://github.com/GemHQ/money-tree
337
- def self.ec_add(point_0, point_1)
338
- init_ffi_ssl
350
+ # lifted from https://github.com/GemHQ/money-tree
351
+ def self.ec_add(point0, point1)
352
+ init_ffi_ssl
339
353
 
340
- eckey = EC_KEY_new_by_curve_name(NID_secp256k1)
341
- group = EC_KEY_get0_group(eckey)
354
+ eckey = EC_KEY_new_by_curve_name(NID_secp256k1)
355
+ group = EC_KEY_get0_group(eckey)
342
356
 
343
- point_0_hex = point_0.to_bn.to_s(16)
344
- point_0_pt = EC_POINT_hex2point(group, point_0_hex, nil, nil)
345
- point_1_hex = point_1.to_bn.to_s(16)
346
- point_1_pt = EC_POINT_hex2point(group, point_1_hex, nil, nil)
357
+ point_0_hex = point0.to_bn.to_s(16)
358
+ point_0_pt = EC_POINT_hex2point(group, point_0_hex, nil, nil)
359
+ point_1_hex = point1.to_bn.to_s(16)
360
+ point_1_pt = EC_POINT_hex2point(group, point_1_hex, nil, nil)
347
361
 
348
- sum_point = EC_POINT_new(group)
349
- success = EC_POINT_add(group, sum_point, point_0_pt, point_1_pt, nil)
350
- hex = EC_POINT_point2hex(group, sum_point, POINT_CONVERSION_UNCOMPRESSED, nil)
351
- EC_KEY_free(eckey)
352
- EC_POINT_free(sum_point)
353
- hex
354
- end
362
+ sum_point = EC_POINT_new(group)
363
+ EC_POINT_add(group, sum_point, point_0_pt, point_1_pt, nil)
364
+ hex = EC_POINT_point2hex(group, sum_point, POINT_CONVERSION_UNCOMPRESSED, nil)
365
+ EC_KEY_free(eckey)
366
+ EC_POINT_free(sum_point)
367
+ hex
368
+ end
355
369
 
356
- # repack signature for OpenSSL 1.0.1k handling of DER signatures
357
- # https://github.com/bitcoin/bitcoin/pull/5634/files
358
- def self.repack_der_signature(signature)
359
- init_ffi_ssl
370
+ # repack signature for OpenSSL 1.0.1k handling of DER signatures
371
+ # https://github.com/bitcoin/bitcoin/pull/5634/files
372
+ def self.repack_der_signature(signature)
373
+ init_ffi_ssl
360
374
 
361
- return false if signature.empty?
375
+ return false if signature.empty?
362
376
 
363
- # New versions of OpenSSL will reject non-canonical DER signatures. de/re-serialize first.
364
- norm_der = FFI::MemoryPointer.new(:pointer)
365
- sig_ptr = FFI::MemoryPointer.new(:pointer).put_pointer(0, FFI::MemoryPointer.from_string(signature))
377
+ # New versions of OpenSSL will reject non-canonical DER signatures. de/re-serialize first.
378
+ norm_der = FFI::MemoryPointer.new(:pointer)
379
+ sig_ptr = FFI::MemoryPointer.new(:pointer).put_pointer(
380
+ 0, FFI::MemoryPointer.from_string(signature)
381
+ )
366
382
 
367
- norm_sig = d2i_ECDSA_SIG(nil, sig_ptr, signature.bytesize)
383
+ norm_sig = d2i_ECDSA_SIG(nil, sig_ptr, signature.bytesize)
368
384
 
369
- derlen = i2d_ECDSA_SIG(norm_sig, norm_der)
370
- ECDSA_SIG_free(norm_sig)
371
- return false if derlen <= 0
385
+ derlen = i2d_ECDSA_SIG(norm_sig, norm_der)
386
+ ECDSA_SIG_free(norm_sig)
387
+ return false if derlen <= 0
372
388
 
373
- ret = norm_der.read_pointer.read_string(derlen)
374
- OPENSSL_free(norm_der.read_pointer)
389
+ ret = norm_der.read_pointer.read_string(derlen)
390
+ OPENSSL_free(norm_der.read_pointer)
375
391
 
376
- ret
377
- end
392
+ ret
393
+ end
378
394
 
379
- def self.init_ffi_ssl
380
- return if @ssl_loaded
381
- SSL_library_init()
382
- ERR_load_crypto_strings()
383
- SSL_load_error_strings()
384
- RAND_poll()
385
- @ssl_loaded = true
395
+ def self.init_ffi_ssl
396
+ @ssl_loaded ||= false
397
+ return if @ssl_loaded
398
+ SSL_library_init()
399
+ ERR_load_crypto_strings()
400
+ SSL_load_error_strings()
401
+ RAND_poll()
402
+ @ssl_loaded = true
403
+ end
386
404
  end
387
405
  end
388
- end