bitcoin-ruby 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -1
- data/Gemfile +21 -0
- data/README.rdoc +85 -25
- data/Rakefile +7 -3
- data/bin/bitcoin_node +39 -42
- data/bin/bitcoin_shell +1 -0
- data/bin/bitcoin_wallet +129 -53
- data/bitcoin-ruby.gemspec +4 -7
- data/concept-examples/blockchain-pow.rb +1 -1
- data/doc/CONFIG.rdoc +5 -5
- data/doc/EXAMPLES.rdoc +9 -5
- data/doc/NAMECOIN.rdoc +34 -0
- data/doc/NODE.rdoc +147 -10
- data/examples/balance.rb +10 -4
- data/examples/bbe_verify_tx.rb +7 -2
- data/examples/forwarder.rb +73 -0
- data/examples/generate_tx.rb +34 -0
- data/examples/simple_network_monitor_and_util.rb +187 -0
- data/examples/verify_tx.rb +1 -1
- data/lib/bitcoin.rb +308 -18
- data/lib/bitcoin/builder.rb +62 -36
- data/lib/bitcoin/config.rb +2 -0
- data/lib/bitcoin/connection.rb +11 -8
- data/lib/bitcoin/electrum/mnemonic.rb +162 -0
- data/lib/bitcoin/ffi/openssl.rb +187 -21
- data/lib/bitcoin/gui/addr_view.rb +2 -0
- data/lib/bitcoin/gui/conn_view.rb +2 -0
- data/lib/bitcoin/gui/connection.rb +2 -0
- data/lib/bitcoin/gui/em_gtk.rb +2 -0
- data/lib/bitcoin/gui/gui.rb +2 -0
- data/lib/bitcoin/gui/helpers.rb +2 -0
- data/lib/bitcoin/gui/tree_view.rb +2 -0
- data/lib/bitcoin/gui/tx_view.rb +2 -0
- data/lib/bitcoin/key.rb +77 -11
- data/lib/bitcoin/litecoin.rb +81 -0
- data/lib/bitcoin/logger.rb +20 -1
- data/lib/bitcoin/namecoin.rb +279 -0
- data/lib/bitcoin/network/command_client.rb +7 -6
- data/lib/bitcoin/network/command_handler.rb +229 -43
- data/lib/bitcoin/network/connection_handler.rb +182 -70
- data/lib/bitcoin/network/node.rb +231 -106
- data/lib/bitcoin/protocol.rb +44 -23
- data/lib/bitcoin/protocol/address.rb +5 -3
- data/lib/bitcoin/protocol/alert.rb +3 -4
- data/lib/bitcoin/protocol/aux_pow.rb +123 -0
- data/lib/bitcoin/protocol/block.rb +98 -18
- data/lib/bitcoin/protocol/handler.rb +6 -5
- data/lib/bitcoin/protocol/parser.rb +44 -19
- data/lib/bitcoin/protocol/tx.rb +105 -52
- data/lib/bitcoin/protocol/txin.rb +39 -19
- data/lib/bitcoin/protocol/txout.rb +28 -13
- data/lib/bitcoin/protocol/version.rb +16 -7
- data/lib/bitcoin/script.rb +579 -122
- data/lib/bitcoin/storage/{dummy.rb → dummy/dummy_store.rb} +8 -14
- data/lib/bitcoin/storage/models.rb +20 -7
- data/lib/bitcoin/storage/{sequel_store/sequel_migrations.rb → sequel/migrations.rb} +22 -7
- data/lib/bitcoin/storage/sequel/migrations/001_base_schema.rb +52 -0
- data/lib/bitcoin/storage/sequel/migrations/002_tx.rb +50 -0
- data/lib/bitcoin/storage/sequel/migrations/003_change_txin_script_sig_to_blob.rb +18 -0
- data/lib/bitcoin/storage/sequel/sequel_store.rb +436 -0
- data/lib/bitcoin/storage/storage.rb +233 -28
- data/lib/bitcoin/storage/utxo/migrations/001_base_schema.rb +52 -0
- data/lib/bitcoin/storage/utxo/migrations/002_utxo.rb +18 -0
- data/lib/bitcoin/storage/utxo/utxo_store.rb +361 -0
- data/lib/bitcoin/validation.rb +369 -0
- data/lib/bitcoin/version.rb +1 -1
- data/lib/bitcoin/wallet/coinselector.rb +3 -0
- data/lib/bitcoin/wallet/keygenerator.rb +3 -1
- data/lib/bitcoin/wallet/keystore.rb +6 -2
- data/lib/bitcoin/wallet/txdp.rb +6 -4
- data/lib/bitcoin/wallet/wallet.rb +54 -16
- data/spec/bitcoin/bitcoin_spec.rb +48 -3
- data/spec/bitcoin/builder_spec.rb +40 -17
- data/spec/bitcoin/fixtures/000000000000056b1a3d84a1e2b33cde8915a4b61c0cae14fca6d3e1490b4f98.json +3697 -0
- data/spec/bitcoin/fixtures/03d7e1fa4d5fefa169431f24f7798552861b255cd55d377066fedcd088fb0e99.json +23 -0
- data/spec/bitcoin/fixtures/0961c660358478829505e16a1f028757e54b5bbf9758341a7546573738f31429.json +24 -0
- data/spec/bitcoin/fixtures/0f24294a1d23efbb49c1765cf443fba7930702752aba6d765870082fe4f13cae.json +37 -0
- data/spec/bitcoin/fixtures/315ac7d4c26d69668129cc352851d9389b4a6868f1509c6c8b66bead11e2619f.json +31 -0
- data/spec/bitcoin/fixtures/35e2001b428891fefa0bfb73167c7360669d3cbd7b3aa78e7cad125ddfc51131.json +27 -0
- data/spec/bitcoin/fixtures/3a17dace09ffb919ed627a93f1873220f4c975c1248558b18d16bce25d38c4b7.json +72 -0
- data/spec/bitcoin/fixtures/3e58b7eed0fdb599019af08578effea25c8666bbe8e200845453cacce6314477.json +27 -0
- data/spec/bitcoin/fixtures/514c46f0b61714092f15c8dfcb576c9f79b3f959989b98de3944b19d98832b58.json +24 -0
- data/spec/bitcoin/fixtures/51bf528ecf3c161e7c021224197dbe84f9a8564212f6207baa014c01a1668e1e.json +30 -0
- data/spec/bitcoin/fixtures/69216b8aaa35b76d6613e5f527f4858640d986e1046238583bdad79b35e938dc.json +28 -0
- data/spec/bitcoin/fixtures/7208e5edf525f04e705fb3390194e316205b8f995c8c9fcd8c6093abe04fa27d.json +27 -0
- data/spec/bitcoin/fixtures/761d8c5210fdfd505f6dff38f740ae3728eb93d7d0971fb433f685d40a4c04f6.json +27 -0
- data/spec/bitcoin/fixtures/aea682d68a3ea5e3583e088dcbd699a5d44d4b083f02ad0aaf2598fe1fa4dfd4.json +27 -0
- data/spec/bitcoin/fixtures/bd1715f1abfdc62bea3f605bdb461b3ba1f2cca6ec0d73a18a548b7717ca8531.json +34 -0
- data/spec/bitcoin/fixtures/block-testnet-0000000000ac85bb2530a05a4214a387e6be02b22d3348abc5e7a5d9c4ce8dab.bin +0 -0
- data/spec/bitcoin/fixtures/cd874fa8cb0e2ec2d385735d5e1fd482c4fe648533efb4c50ee53bda58e15ae2.json +24 -0
- data/spec/bitcoin/fixtures/ce5fad9b4ef094d8f4937b0707edaf0a6e6ceeaf67d5edbfd51f660eac8f398b.json +41 -0
- data/spec/bitcoin/fixtures/f003f0c1193019db2497a675fd05d9f2edddf9b67c59e677c48d3dbd4ed5f00b.json +23 -0
- data/spec/bitcoin/fixtures/freicoin-block-000000005d231b285e63af83edae2d8f5e50e70d396468643092b9239fd3be3c.bin +0 -0
- data/spec/bitcoin/fixtures/freicoin-block-000000005d231b285e63af83edae2d8f5e50e70d396468643092b9239fd3be3c.json +43 -0
- data/spec/bitcoin/fixtures/freicoin-genesis-block-000000005b1e3d23ecfd2dd4a6e1a35238aa0392c0a8528c40df52376d7efe2c.bin +0 -0
- data/spec/bitcoin/fixtures/freicoin-genesis-block-000000005b1e3d23ecfd2dd4a6e1a35238aa0392c0a8528c40df52376d7efe2c.json +67 -0
- data/spec/bitcoin/fixtures/litecoin-block-80ca095ed10b02e53d769eb6eaf92cd04e9e0759e5be4a8477b42911ba49c78f.bin +0 -0
- data/spec/bitcoin/fixtures/litecoin-block-80ca095ed10b02e53d769eb6eaf92cd04e9e0759e5be4a8477b42911ba49c78f.json +39 -0
- data/spec/bitcoin/fixtures/litecoin-genesis-block-12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2.bin +0 -0
- data/spec/bitcoin/fixtures/litecoin-genesis-block-12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2.json +39 -0
- data/spec/bitcoin/fixtures/rawblock-auxpow.bin +0 -0
- data/spec/bitcoin/fixtures/tx-313897799b1e37e9ecae15010e56156dddde4e683c96b0e713af95272c38aee0.json +30 -0
- data/spec/bitcoin/fixtures/tx-3da75972766f0ad13319b0b461fd16823a731e44f6e9de4eb3c52d6a6fb6c8ae.json +23 -0
- data/spec/bitcoin/fixtures/tx-44b833074e671120ba33106877b49e86ece510824b9af477a3853972bcd8d06a.json +30 -0
- data/spec/bitcoin/fixtures/tx-d3d77d63709e47d9ef58f0b557800115a6b676c6a423012fbb96f45d8fcef830.json +28 -0
- data/spec/bitcoin/key_spec.rb +128 -3
- data/spec/bitcoin/namecoin_spec.rb +182 -0
- data/spec/bitcoin/network_spec.rb +5 -3
- data/spec/bitcoin/node/command_api_spec.rb +376 -0
- data/spec/bitcoin/protocol/addr_spec.rb +2 -0
- data/spec/bitcoin/protocol/alert_spec.rb +2 -0
- data/spec/bitcoin/protocol/aux_pow_spec.rb +44 -0
- data/spec/bitcoin/protocol/block_spec.rb +134 -39
- data/spec/bitcoin/protocol/getblocks_spec.rb +32 -0
- data/spec/bitcoin/protocol/inv_spec.rb +10 -8
- data/spec/bitcoin/protocol/notfound_spec.rb +31 -0
- data/spec/bitcoin/protocol/ping_spec.rb +2 -0
- data/spec/bitcoin/protocol/tx_spec.rb +83 -17
- data/spec/bitcoin/protocol/version_spec.rb +7 -5
- data/spec/bitcoin/script/opcodes_spec.rb +412 -133
- data/spec/bitcoin/script/script_spec.rb +112 -13
- data/spec/bitcoin/spec_helper.rb +68 -0
- data/spec/bitcoin/storage/reorg_spec.rb +199 -0
- data/spec/bitcoin/storage/storage_spec.rb +337 -0
- data/spec/bitcoin/storage/validation_spec.rb +261 -0
- data/spec/bitcoin/wallet/coinselector_spec.rb +10 -7
- data/spec/bitcoin/wallet/keygenerator_spec.rb +2 -0
- data/spec/bitcoin/wallet/keystore_spec.rb +2 -0
- data/spec/bitcoin/wallet/txdp_spec.rb +2 -0
- data/spec/bitcoin/wallet/wallet_spec.rb +91 -58
- metadata +105 -51
- data/lib/bitcoin/storage/sequel.rb +0 -335
- data/spec/bitcoin/fixtures/0d0affb5964abe804ffe85e53f1dbb9f29e406aa3046e2db04fba240e63c7fdd.json +0 -27
- data/spec/bitcoin/fixtures/477fff140b363ec2cc51f3a65c0c58eda38f4d41f04a295bbd62babf25e4c590.json +0 -27
- data/spec/bitcoin/reorg_spec.rb +0 -129
- data/spec/bitcoin/storage_spec.rb +0 -229
data/lib/bitcoin/builder.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
|
1
3
|
module Bitcoin
|
2
4
|
|
3
5
|
# Optional DSL to help create blocks and transactions.
|
@@ -7,19 +9,21 @@ module Bitcoin
|
|
7
9
|
|
8
10
|
# build a Bitcoin::Protocol::Block matching the given +target+.
|
9
11
|
# see BlockBuilder for details.
|
10
|
-
def
|
12
|
+
def build_block(target = "00".ljust(64, 'f'))
|
11
13
|
c = BlockBuilder.new
|
12
14
|
yield c
|
13
15
|
c.block(target)
|
14
16
|
end
|
17
|
+
alias :blk :build_block
|
15
18
|
|
16
19
|
# build a Bitcoin::Protocol::Tx.
|
17
20
|
# see TxBuilder for details.
|
18
|
-
def
|
21
|
+
def build_tx
|
19
22
|
c = TxBuilder.new
|
20
23
|
yield c
|
21
24
|
c.tx
|
22
25
|
end
|
26
|
+
alias :tx :build_tx
|
23
27
|
|
24
28
|
# build a Bitcoin::Script.
|
25
29
|
# see ScriptBuilder for details.
|
@@ -29,7 +33,7 @@ module Bitcoin
|
|
29
33
|
c.script
|
30
34
|
end
|
31
35
|
|
32
|
-
# DSL to create a Bitcoin::Protocol::Block used by Builder#
|
36
|
+
# DSL to create a Bitcoin::Protocol::Block used by Builder#create_block.
|
33
37
|
# block = blk("00".ljust(32, 'f')) do |b|
|
34
38
|
# b.prev_block "\x00"*32
|
35
39
|
# b.tx do |t|
|
@@ -46,7 +50,7 @@ module Bitcoin
|
|
46
50
|
class BlockBuilder
|
47
51
|
|
48
52
|
def initialize
|
49
|
-
@block =
|
53
|
+
@block = P::Block.new(nil)
|
50
54
|
end
|
51
55
|
|
52
56
|
# specify block version. this is usually not necessary. defaults to 1.
|
@@ -59,6 +63,11 @@ module Bitcoin
|
|
59
63
|
@prev_block = hash
|
60
64
|
end
|
61
65
|
|
66
|
+
# set the block timestamp (defaults to current time).
|
67
|
+
def time time
|
68
|
+
@time = time
|
69
|
+
end
|
70
|
+
|
62
71
|
# add transactions to the block (see TxBuilder).
|
63
72
|
def tx
|
64
73
|
c = TxBuilder.new
|
@@ -69,14 +78,15 @@ module Bitcoin
|
|
69
78
|
# create the block according to values specified via DSL.
|
70
79
|
def block target
|
71
80
|
@block.ver = @version || 1
|
72
|
-
@block.prev_block =
|
81
|
+
@block.prev_block = @prev_block.htb.reverse
|
73
82
|
@block.mrkl_root = @mrkl_root
|
74
|
-
@block.time = Time.now.to_i
|
83
|
+
@block.time = @time || Time.now.to_i
|
75
84
|
@block.nonce = 0
|
76
|
-
@block.mrkl_root =
|
77
|
-
t.hash }).last].pack("H*")
|
85
|
+
@block.mrkl_root = Bitcoin.hash_mrkl_tree(@block.tx.map(&:hash)).last.htb.reverse
|
78
86
|
find_hash(target)
|
79
|
-
|
87
|
+
block = P::Block.new(@block.to_payload)
|
88
|
+
raise "Payload Error" unless block.to_payload == @block.to_payload
|
89
|
+
block
|
80
90
|
end
|
81
91
|
|
82
92
|
private
|
@@ -104,22 +114,25 @@ module Bitcoin
|
|
104
114
|
|
105
115
|
end
|
106
116
|
|
107
|
-
# DSL to create Bitcoin::Protocol::Tx used by Builder#
|
108
|
-
#
|
109
|
-
#
|
110
|
-
#
|
111
|
-
#
|
112
|
-
#
|
113
|
-
#
|
114
|
-
#
|
115
|
-
#
|
116
|
-
#
|
117
|
-
#
|
118
|
-
#
|
117
|
+
# DSL to create Bitcoin::Protocol::Tx used by Builder#build_tx.
|
118
|
+
# tx = tx do |t|
|
119
|
+
# t.input do |i|
|
120
|
+
# i.prev_out prev_tx # previous transaction
|
121
|
+
# i.prev_out_index 0 # index of previous output
|
122
|
+
# i.signature_key key # Bitcoin::Key used to sign the input
|
123
|
+
# end
|
124
|
+
# t.output do |o|
|
125
|
+
# o.value 12345 # 0.00012345 BTC
|
126
|
+
# o.script {|s| s.type :address; s.recipient key.addr }
|
127
|
+
# end
|
128
|
+
# end
|
129
|
+
#
|
130
|
+
# signs every input that has a signature key. if the signature key is
|
131
|
+
# not specified, the input will include the #sig_hash that needs to be signed.
|
119
132
|
class TxBuilder
|
120
133
|
|
121
134
|
def initialize
|
122
|
-
@tx =
|
135
|
+
@tx = P::Tx.new(nil)
|
123
136
|
@tx.ver, @tx.lock_time = 1, 0
|
124
137
|
@ins, @outs = [], []
|
125
138
|
end
|
@@ -148,7 +161,10 @@ module Bitcoin
|
|
148
161
|
@outs << c
|
149
162
|
end
|
150
163
|
|
151
|
-
# create the transaction according to values specified via DSL
|
164
|
+
# create the transaction according to values specified via DSL.
|
165
|
+
# sign each input that has a signature key specified. if there is
|
166
|
+
# no key, store the sig_hash in the input, so it can easily be
|
167
|
+
# signed later.
|
152
168
|
def tx
|
153
169
|
@ins.each {|i| @tx.add_in(i.txin) }
|
154
170
|
@outs.each {|o| @tx.add_out(o.txout) }
|
@@ -160,26 +176,36 @@ module Bitcoin
|
|
160
176
|
next
|
161
177
|
end
|
162
178
|
prev_tx = inc.instance_variable_get(:@prev_out)
|
163
|
-
sig_hash = @tx.signature_hash_for_input(i, prev_tx)
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
179
|
+
@sig_hash = @tx.signature_hash_for_input(i, prev_tx)
|
180
|
+
if inc.key && inc.key.priv
|
181
|
+
sig = inc.key.sign(@sig_hash)
|
182
|
+
script_sig = Script.to_signature_pubkey_script(sig, [inc.key.pub].pack("H*"))
|
183
|
+
@tx.in[i].script_sig_length = script_sig.bytesize
|
184
|
+
@tx.in[i].script_sig = script_sig
|
185
|
+
raise "Signature error" unless @tx.verify_input_signature(i, prev_tx)
|
186
|
+
else
|
187
|
+
@tx.in[i].script_sig_length = 0
|
188
|
+
@tx.in[i].script_sig = ""
|
189
|
+
@tx.in[i].sig_hash = @sig_hash
|
190
|
+
@tx.in[i].sig_address = Script.new(prev_tx.out[@tx.in[i].prev_out_index].pk_script).get_address
|
191
|
+
end
|
169
192
|
end
|
170
|
-
|
193
|
+
data = @tx.in.map {|i| [i.sig_hash, i.sig_address] }
|
194
|
+
tx = P::Tx.new(@tx.to_payload)
|
195
|
+
data.each.with_index {|d, i| i = tx.in[i]; i.sig_hash = d[0]; i.sig_address = d[1] }
|
196
|
+
raise "Payload Error" unless tx.to_payload == @tx.to_payload
|
197
|
+
tx
|
171
198
|
end
|
172
199
|
end
|
173
200
|
|
174
201
|
# create a Bitcoin::Protocol::TxIn used by TxBuilder#input.
|
175
202
|
#
|
176
|
-
# inputs
|
177
|
-
# or they have to define a #prev_out, #prev_out_index and #signature key.
|
203
|
+
# inputs need a #prev_out tx and #prev_out_index of the output they spend.
|
178
204
|
class TxInBuilder
|
179
205
|
attr_reader :key, :coinbase_data
|
180
206
|
|
181
207
|
def initialize
|
182
|
-
@txin =
|
208
|
+
@txin = P::TxIn.new
|
183
209
|
end
|
184
210
|
|
185
211
|
# previous transaction that contains the output we want to use.
|
@@ -224,7 +250,7 @@ module Bitcoin
|
|
224
250
|
attr_reader :script
|
225
251
|
|
226
252
|
def initialize
|
227
|
-
@type =
|
253
|
+
@type = :address
|
228
254
|
@script = nil
|
229
255
|
end
|
230
256
|
|
@@ -236,7 +262,7 @@ module Bitcoin
|
|
236
262
|
# recipient(s) of the script.
|
237
263
|
# depending on the #type, either an address, hash160 pubkey, etc.
|
238
264
|
def recipient *data
|
239
|
-
@script =
|
265
|
+
@script = Script.send("to_#{@type}_script", *data)
|
240
266
|
end
|
241
267
|
end
|
242
268
|
|
@@ -245,7 +271,7 @@ module Bitcoin
|
|
245
271
|
attr_reader :txout
|
246
272
|
|
247
273
|
def initialize
|
248
|
-
@txout =
|
274
|
+
@txout = P::TxOut.new
|
249
275
|
end
|
250
276
|
|
251
277
|
# set output value (in base units / "satoshis")
|
data/lib/bitcoin/config.rb
CHANGED
data/lib/bitcoin/connection.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
|
1
3
|
require 'socket'
|
2
4
|
require 'eventmachine'
|
3
5
|
require 'bitcoin'
|
@@ -5,27 +7,24 @@ require 'bitcoin'
|
|
5
7
|
module Bitcoin
|
6
8
|
|
7
9
|
module ConnectionHandler
|
8
|
-
def hth(h); h.unpack("H*")[0]; end
|
9
|
-
def htb(h); [h].pack("H*"); end
|
10
|
-
|
11
10
|
def on_inv_transaction(hash)
|
12
|
-
p ['inv transaction', hth
|
11
|
+
p ['inv transaction', hash.hth]
|
13
12
|
pkt = Protocol.getdata_pkt(:tx, [hash])
|
14
13
|
send_data(pkt)
|
15
14
|
end
|
16
15
|
|
17
16
|
def on_inv_block(hash)
|
18
|
-
p ['inv block', hth
|
17
|
+
p ['inv block', hash.hth]
|
19
18
|
pkt = Protocol.getdata_pkt(:block, [hash])
|
20
19
|
send_data(pkt)
|
21
20
|
end
|
22
21
|
|
23
22
|
def on_get_transaction(hash)
|
24
|
-
p ['get transaction', hth
|
23
|
+
p ['get transaction', hash.hth]
|
25
24
|
end
|
26
25
|
|
27
26
|
def on_get_block(hash)
|
28
|
-
p ['get block', hth
|
27
|
+
p ['get block', hash.hth]
|
29
28
|
end
|
30
29
|
|
31
30
|
def on_addr(addr)
|
@@ -43,10 +42,14 @@ module Bitcoin
|
|
43
42
|
end
|
44
43
|
|
45
44
|
def on_version(version)
|
46
|
-
p [@sockaddr, 'version', version, version.
|
45
|
+
p [@sockaddr, 'version', version, version.time - Time.now.to_i]
|
47
46
|
send_data( Protocol.verack_pkt )
|
48
47
|
end
|
49
48
|
|
49
|
+
def on_verack
|
50
|
+
on_handshake_complete
|
51
|
+
end
|
52
|
+
|
50
53
|
def on_handshake_complete
|
51
54
|
p [@sockaddr, 'handshake complete']
|
52
55
|
@connected = true
|
@@ -0,0 +1,162 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
|
3
|
+
class Mnemonic
|
4
|
+
# ruby version of: https://github.com/spesmilo/electrum/blob/master/lib/mnemonic.py
|
5
|
+
|
6
|
+
# list of words from http://en.wiktionary.org/wiki/Wiktionary:Frequency_lists/Contemporary_poetry
|
7
|
+
Words = (<<-TEXT).split
|
8
|
+
like just love know never want time out there make look eye down only think
|
9
|
+
heart back then into about more away still them take thing even through long always
|
10
|
+
world too friend tell try hand thought over here other need smile again much cry
|
11
|
+
been night ever little said end some those around mind people girl leave dream left
|
12
|
+
turn myself give nothing really off before something find walk wish good once place ask
|
13
|
+
stop keep watch seem everything wait got yet made remember start alone run hope maybe
|
14
|
+
believe body hate after close talk stand own each hurt help home god soul new
|
15
|
+
many two inside should true first fear mean better play another gone change use wonder
|
16
|
+
someone hair cold open best any behind happen water dark laugh stay forever name work
|
17
|
+
show sky break came deep door put black together upon happy such great white matter
|
18
|
+
fill past please burn cause enough touch moment soon voice scream anything stare sound red
|
19
|
+
everyone hide kiss truth death beautiful mine blood broken very pass next forget tree wrong
|
20
|
+
air mother understand lip hit wall memory sleep free high realize school might skin sweet
|
21
|
+
perfect blue kill breath dance against fly between grow strong under listen bring sometimes speak
|
22
|
+
pull person become family begin ground real small father sure feet rest young finally land
|
23
|
+
across today different guy line fire reason reach second slowly write eat smell mouth step
|
24
|
+
learn three floor promise breathe darkness push earth guess save song above along both color
|
25
|
+
house almost sorry anymore brother okay dear game fade already apart warm beauty heard notice
|
26
|
+
question shine began piece whole shadow secret street within finger point morning whisper child moon
|
27
|
+
green story glass kid silence since soft yourself empty shall angel answer baby bright dad
|
28
|
+
path worry hour drop follow power war half flow heaven act chance fact least tired
|
29
|
+
children near quite afraid rise sea taste window cover nice trust lot sad cool force
|
30
|
+
peace return blind easy ready roll rose drive held music beneath hang mom paint emotion
|
31
|
+
quiet clear cloud few pretty bird outside paper picture front rock simple anyone meant reality
|
32
|
+
road sense waste bit leaf thank happiness meet men smoke truly decide self age book
|
33
|
+
form alive carry escape damn instead able ice minute throw catch leg ring course goodbye
|
34
|
+
lead poem sick corner desire known problem remind shoulder suppose toward wave drink jump woman
|
35
|
+
pretend sister week human joy crack grey pray surprise dry knee less search bleed caught
|
36
|
+
clean embrace future king son sorrow chest hug remain sat worth blow daddy final parent
|
37
|
+
tight also create lonely safe cross dress evil silent bone fate perhaps anger class scar
|
38
|
+
snow tiny tonight continue control dog edge mirror month suddenly comfort given loud quickly gaze
|
39
|
+
plan rush stone town battle ignore spirit stood stupid yours brown build dust hey kept
|
40
|
+
pay phone twist although ball beyond hidden nose taken fail float pure somehow wash wrap
|
41
|
+
angry cheek creature forgotten heat rip single space special weak whatever yell anyway blame job
|
42
|
+
choose country curse drift echo figure grew laughter neck suffer worse yeah disappear foot forward
|
43
|
+
knife mess somewhere stomach storm beg idea lift offer breeze field five often simply stuck
|
44
|
+
win allow confuse enjoy except flower seek strength calm grin gun heavy hill large ocean
|
45
|
+
shoe sigh straight summer tongue accept crazy everyday exist grass mistake sent shut surround table
|
46
|
+
ache brain destroy heal nature shout sign stain choice doubt glance glow mountain queen stranger
|
47
|
+
throat tomorrow city either fish flame rather shape spin spread ash distance finish image imagine
|
48
|
+
important nobody shatter warmth became feed flesh funny lust shirt trouble yellow attention bare bite
|
49
|
+
money protect amaze appear born choke completely daughter fresh friendship gentle probably six deserve expect
|
50
|
+
grab middle nightmare river thousand weight worst wound barely bottle cream regret relationship stick test
|
51
|
+
crush endless fault itself rule spill art circle join kick mask master passion quick raise
|
52
|
+
smooth unless wander actually broke chair deal favorite gift note number sweat box chill clothes
|
53
|
+
lady mark park poor sadness tie animal belong brush consume dawn forest innocent pen pride
|
54
|
+
stream thick clay complete count draw faith press silver struggle surface taught teach wet bless
|
55
|
+
chase climb enter letter melt metal movie stretch swing vision wife beside crash forgot guide
|
56
|
+
haunt joke knock plant pour prove reveal steal stuff trip wood wrist bother bottom crawl
|
57
|
+
crowd fix forgive frown grace loose lucky party release surely survive teacher gently grip speed
|
58
|
+
suicide travel treat vein written cage chain conversation date enemy however interest million page pink
|
59
|
+
proud sway themselves winter church cruel cup demon experience freedom pair pop purpose respect shoot
|
60
|
+
softly state strange bar birth curl dirt excuse lord lovely monster order pack pants pool
|
61
|
+
scene seven shame slide ugly among blade blonde closet creek deny drug eternity gain grade
|
62
|
+
handle key linger pale prepare swallow swim tremble wheel won cast cigarette claim college direction
|
63
|
+
dirty gather ghost hundred loss lung orange present swear swirl twice wild bitter blanket doctor
|
64
|
+
everywhere flash grown knowledge numb pressure radio repeat ruin spend unknown buy clock devil early
|
65
|
+
false fantasy pound precious refuse sheet teeth welcome add ahead block bury caress content depth
|
66
|
+
despite distant marry purple threw whenever bomb dull easily grasp hospital innocence normal receive reply
|
67
|
+
rhyme shade someday sword toe visit asleep bought center consider flat hero history ink insane
|
68
|
+
muscle mystery pocket reflection shove silently smart soldier spot stress train type view whether bus
|
69
|
+
energy explain holy hunger inch magic mix noise nowhere prayer presence shock snap spider study
|
70
|
+
thunder trail admit agree bag bang bound butterfly cute exactly explode familiar fold further pierce
|
71
|
+
reflect scent selfish sharp sink spring stumble universe weep women wonderful action ancient attempt avoid
|
72
|
+
birthday branch chocolate core depress drunk especially focus fruit honest match palm perfectly pillow pity
|
73
|
+
poison roar shift slightly thump truck tune twenty unable wipe wrote coat constant dinner drove
|
74
|
+
egg eternal flight flood frame freak gasp glad hollow motion peer plastic root screen season
|
75
|
+
sting strike team unlike victim volume warn weird attack await awake built charm crave despair
|
76
|
+
fought grant grief horse limit message ripple sanity scatter serve split string trick annoy blur
|
77
|
+
boat brave clearly cling connect fist forth imagination iron jock judge lesson milk misery nail
|
78
|
+
naked ourselves poet possible princess sail size snake society stroke torture toss trace wise bloom
|
79
|
+
bullet cell check cost darling during footstep fragile hallway hardly horizon invisible journey midnight mud
|
80
|
+
nod pause relax shiver sudden value youth abuse admire blink breast bruise constantly couple creep
|
81
|
+
curve difference dumb emptiness gotta honor plain planet recall rub ship slam soar somebody tightly
|
82
|
+
weather adore approach bond bread burst candle coffee cousin crime desert flutter frozen grand heel
|
83
|
+
hello language level movement pleasure powerful random rhythm settle silly slap sort spoken steel threaten
|
84
|
+
tumble upset aside awkward bee blank board button card carefully complain crap deeply discover drag
|
85
|
+
dread effort entire fairy giant gotten greet illusion jeans leap liquid march mend nervous nine
|
86
|
+
replace rope spine stole terror accident apple balance boom childhood collect demand depression eventually faint
|
87
|
+
glare goal group honey kitchen laid limb machine mere mold murder nerve painful poetry prince
|
88
|
+
rabbit shelter shore shower soothe stair steady sunlight tangle tease treasure uncle begun bliss canvas
|
89
|
+
cheer claw clutch commit crimson crystal delight doll existence express fog football gay goose guard
|
90
|
+
hatred illuminate mass math mourn rich rough skip stir student style support thorn tough yard
|
91
|
+
yearn yesterday advice appreciate autumn bank beam bowl capture carve collapse confusion creation dove feather
|
92
|
+
girlfriend glory government harsh hop inner loser moonlight neighbor neither peach pig praise screw shield
|
93
|
+
shimmer sneak stab subject throughout thrown tower twirl wow army arrive bathroom bump cease cookie
|
94
|
+
couch courage dim guilt howl hum husband insult led lunch mock mostly natural nearly needle
|
95
|
+
nerd peaceful perfection pile price remove roam sanctuary serious shiny shook sob stolen tap vain
|
96
|
+
void warrior wrinkle affection apologize blossom bounce bridge cheap crumble decision descend desperately dig dot
|
97
|
+
flip frighten heartbeat huge lazy lick odd opinion process puzzle quietly retreat score sentence separate
|
98
|
+
situation skill soak square stray taint task tide underneath veil whistle anywhere bedroom bid bloody
|
99
|
+
burden careful compare concern curtain decay defeat describe double dreamer driver dwell evening flare flicker
|
100
|
+
grandma guitar harm horrible hungry indeed lace melody monkey nation object obviously rainbow salt scratch
|
101
|
+
shown shy stage stun third tickle useless weakness worship worthless afternoon beard boyfriend bubble busy
|
102
|
+
certain chin concrete desk diamond doom drawn due felicity freeze frost garden glide harmony hopefully
|
103
|
+
hunt jealous lightning mama mercy peel physical position pulse punch quit rant respond salty sane
|
104
|
+
satisfy savior sheep slept social sport tuck utter valley wolf aim alas alter arrow awaken
|
105
|
+
beaten belief brand ceiling cheese clue confidence connection daily disguise eager erase essence everytime expression
|
106
|
+
fan flag flirt foul fur giggle glorious ignorance law lifeless measure mighty muse north opposite
|
107
|
+
paradise patience patient pencil petal plate ponder possibly practice slice spell stock strife strip suffocate
|
108
|
+
suit tender tool trade velvet verse waist witch aunt bench bold cap certainly click companion
|
109
|
+
creator dart delicate determine dish dragon drama drum dude everybody feast forehead former fright fully
|
110
|
+
gas hook hurl invite juice manage moral possess raw rebel royal scale scary several slight
|
111
|
+
stubborn swell talent tea terrible thread torment trickle usually vast violence weave acid agony ashamed
|
112
|
+
awe belly blend blush character cheat common company coward creak danger deadly defense define depend
|
113
|
+
desperate destination dew duck dusty embarrass engine example explore foe freely frustrate generation glove guilty
|
114
|
+
health hurry idiot impossible inhale jaw kingdom mention mist moan mumble mutter observe ode pathetic
|
115
|
+
pattern pie prefer puff rape rare revenge rude scrape spiral squeeze strain sunset suspend sympathy
|
116
|
+
thigh throne total unseen weapon weary
|
117
|
+
TEXT
|
118
|
+
|
119
|
+
def self.encode(hex, words=Words)
|
120
|
+
n = words.size
|
121
|
+
[hex].pack("H*").unpack("N*").map{|x|
|
122
|
+
w1 = x % n
|
123
|
+
w2 = ((x / n) + w1) % n
|
124
|
+
w3 = ((x / n / n) + w2) % n
|
125
|
+
[ words[w1], words[w2], words[w3] ]
|
126
|
+
}.flatten
|
127
|
+
end
|
128
|
+
|
129
|
+
def self.decode(word_list, words=Words)
|
130
|
+
n = words.size
|
131
|
+
word_list.each_slice(3).map{|three_words|
|
132
|
+
w1, w2, w3 = three_words.map{|word| words.index(word) % n }
|
133
|
+
'%08x' % ( w1 + n*((w2-w1)%n) + n*n*((w3-w2)%n) )
|
134
|
+
}.join
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
|
140
|
+
|
141
|
+
if $0 == __FILE__
|
142
|
+
hex = "4c7d10656aa55383a5d88e3f63300af5e169918f4058bf349d99b20239909b61"
|
143
|
+
expected_words = ['horse', 'love', 'nose', 'speak', 'diamond', 'gaze', 'wash', 'drag', 'glance',
|
144
|
+
'money', 'cease', 'soft', 'complete', 'huge', 'aside', 'confusion', 'touch',
|
145
|
+
'grass', 'pie', 'play', 'bread', 'exactly', 'bubble', 'great']
|
146
|
+
|
147
|
+
# from http://brainwallet.org/#chains
|
148
|
+
hex = "ff64b72c431f75799f0c5ebe438e46dd"
|
149
|
+
expected_words = %w[muscle lot sea got revenge crack wait yeah gas study embrace spend]
|
150
|
+
hex = "18cfaf96961750c7a4e4e39c861d1415"
|
151
|
+
expected_words = %w[example poor twice expect decision master blame rub forward easy jump carve]
|
152
|
+
|
153
|
+
# from https://en.bitcoin.it/wiki/Electrum#Brain_Wallet
|
154
|
+
hex = "431a62f1c86555d3c45e5c4d9e10c8c7"
|
155
|
+
expected_words = %w[constant forest adore false green weave stop guy fur freeze giggle clock]
|
156
|
+
|
157
|
+
#p Mnemonic.encode(hex)
|
158
|
+
p Mnemonic.encode(hex) == expected_words
|
159
|
+
#p Mnemonic.decode(expected_words)
|
160
|
+
p Mnemonic.decode(expected_words) == hex
|
161
|
+
end
|
162
|
+
|
data/lib/bitcoin/ffi/openssl.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
|
1
3
|
# autoload when you need to re-generate a public_key from only its private_key.
|
2
4
|
# ported from: https://github.com/sipa/bitcoin/blob/2d40fe4da9ea82af4b652b691a4185431d6e47a8/key.h
|
3
5
|
|
4
|
-
Bitcoin.require_dependency :ffi, exit: false, message:
|
5
|
-
"Skipping FFI needed for OpenSSL_EC.regenerate_key."
|
6
|
+
Bitcoin.require_dependency :ffi, exit: false, message: "Skipping FFI needed for OpenSSL_EC methods."
|
6
7
|
|
7
8
|
module Bitcoin
|
8
9
|
module OpenSSL_EC
|
@@ -10,32 +11,54 @@ module OpenSSL_EC
|
|
10
11
|
ffi_lib 'ssl'
|
11
12
|
|
12
13
|
NID_secp256k1 = 714
|
14
|
+
POINT_CONVERSION_COMPRESSED = 2
|
15
|
+
POINT_CONVERSION_UNCOMPRESSED = 4
|
13
16
|
|
14
17
|
attach_function :SSL_library_init, [], :int
|
15
18
|
attach_function :ERR_load_crypto_strings, [], :void
|
16
19
|
attach_function :SSL_load_error_strings, [], :void
|
17
20
|
attach_function :RAND_poll, [], :int
|
18
21
|
|
19
|
-
|
22
|
+
attach_function :BN_CTX_free, [:pointer], :int
|
23
|
+
attach_function :BN_CTX_new, [], :pointer
|
24
|
+
attach_function :BN_add, [:pointer, :pointer, :pointer], :int
|
20
25
|
attach_function :BN_bin2bn, [:pointer, :int, :pointer], :pointer
|
21
|
-
attach_function :
|
22
|
-
attach_function :
|
26
|
+
attach_function :BN_bn2bin, [:pointer, :pointer], :void
|
27
|
+
attach_function :BN_cmp, [:pointer, :pointer], :int
|
28
|
+
attach_function :BN_copy, [:pointer, :pointer], :pointer
|
29
|
+
attach_function :BN_dup, [:pointer], :pointer
|
30
|
+
attach_function :BN_free, [:pointer], :int
|
31
|
+
attach_function :BN_mod_inverse, [:pointer, :pointer, :pointer, :pointer], :pointer
|
32
|
+
attach_function :BN_mod_mul, [:pointer, :pointer, :pointer, :pointer, :pointer], :int
|
33
|
+
attach_function :BN_mod_sub, [:pointer, :pointer, :pointer, :pointer, :pointer], :int
|
34
|
+
attach_function :BN_mul_word, [:pointer, :int], :int
|
23
35
|
attach_function :BN_new, [], :pointer
|
24
|
-
attach_function :
|
36
|
+
attach_function :BN_rshift, [:pointer, :pointer, :int], :int
|
37
|
+
attach_function :BN_set_word, [:pointer, :int], :int
|
38
|
+
attach_function :EC_GROUP_get_curve_GFp, [:pointer, :pointer, :pointer, :pointer, :pointer], :int
|
39
|
+
attach_function :EC_GROUP_get_degree, [:pointer], :int
|
25
40
|
attach_function :EC_GROUP_get_order, [:pointer, :pointer, :pointer], :int
|
26
|
-
attach_function :
|
27
|
-
attach_function :
|
41
|
+
attach_function :EC_KEY_free, [:pointer], :int
|
42
|
+
attach_function :EC_KEY_get0_group, [:pointer], :pointer
|
43
|
+
attach_function :EC_KEY_get0_private_key, [:pointer], :pointer
|
44
|
+
attach_function :EC_KEY_new_by_curve_name, [:int], :pointer
|
45
|
+
attach_function :EC_KEY_set_conv_form, [:pointer, :int], :void
|
28
46
|
attach_function :EC_KEY_set_private_key, [:pointer, :pointer], :int
|
29
47
|
attach_function :EC_KEY_set_public_key, [:pointer, :pointer], :int
|
30
|
-
attach_function :BN_free, [:pointer], :int
|
31
48
|
attach_function :EC_POINT_free, [:pointer], :int
|
32
|
-
attach_function :
|
33
|
-
attach_function :
|
34
|
-
attach_function :
|
35
|
-
attach_function :
|
49
|
+
attach_function :EC_POINT_is_at_infinity, [:pointer, :pointer], :int
|
50
|
+
attach_function :EC_POINT_mul, [:pointer, :pointer, :pointer, :pointer, :pointer, :pointer], :int
|
51
|
+
attach_function :EC_POINT_new, [:pointer], :pointer
|
52
|
+
attach_function :EC_POINT_set_compressed_coordinates_GFp, [:pointer, :pointer, :pointer, :int, :pointer], :int
|
36
53
|
attach_function :d2i_ECPrivateKey, [:pointer, :pointer, :long], :pointer
|
37
|
-
attach_function :
|
38
|
-
attach_function :
|
54
|
+
attach_function :i2d_ECPrivateKey, [:pointer, :pointer], :int
|
55
|
+
attach_function :i2o_ECPublicKey, [:pointer, :pointer], :uint
|
56
|
+
attach_function :EC_KEY_check_key, [:pointer], :uint
|
57
|
+
attach_function :ECDSA_do_sign, [:pointer, :uint, :pointer], :pointer
|
58
|
+
attach_function :BN_num_bits, [:pointer], :int
|
59
|
+
attach_function :ECDSA_SIG_free, [:pointer], :void
|
60
|
+
|
61
|
+
def self.BN_num_bytes(ptr); (BN_num_bits(ptr) + 7) / 8; end
|
39
62
|
|
40
63
|
|
41
64
|
# resolve public from private key, using ffi and libssl.so
|
@@ -48,7 +71,7 @@ module OpenSSL_EC
|
|
48
71
|
#private_key = FFI::MemoryPointer.new(:uint8, private_key.bytesize)
|
49
72
|
# .put_bytes(0, private_key, 0, private_key.bytesize)
|
50
73
|
private_key = FFI::MemoryPointer.from_string(private_key)
|
51
|
-
|
74
|
+
|
52
75
|
init_ffi_ssl
|
53
76
|
eckey = EC_KEY_new_by_curve_name(NID_secp256k1)
|
54
77
|
#priv_key = BN_bin2bn(private_key, private_key.size, BN_new())
|
@@ -69,10 +92,11 @@ module OpenSSL_EC
|
|
69
92
|
|
70
93
|
|
71
94
|
length = i2d_ECPrivateKey(eckey, nil)
|
72
|
-
|
95
|
+
buf = FFI::MemoryPointer.new(:uint8, length)
|
96
|
+
ptr = FFI::MemoryPointer.new(:pointer).put_pointer(0, buf)
|
73
97
|
priv_hex = if i2d_ECPrivateKey(eckey, ptr) == length
|
74
|
-
size =
|
75
|
-
|
98
|
+
size = buf.get_array_of_uint8(8, 1)[0]
|
99
|
+
buf.get_array_of_uint8(9, size).pack("C*").rjust(32, "\x00").unpack("H*")[0]
|
76
100
|
#der_to_private_key( ptr.read_pointer.read_string(length).unpack("H*")[0] )
|
77
101
|
end
|
78
102
|
|
@@ -82,9 +106,10 @@ module OpenSSL_EC
|
|
82
106
|
|
83
107
|
|
84
108
|
length = i2o_ECPublicKey(eckey, nil)
|
85
|
-
|
109
|
+
buf = FFI::MemoryPointer.new(:uint8, length)
|
110
|
+
ptr = FFI::MemoryPointer.new(:pointer).put_pointer(0, buf)
|
86
111
|
pub_hex = if i2o_ECPublicKey(eckey, ptr) == length
|
87
|
-
|
112
|
+
buf.read_string(length).unpack("H*")[0]
|
88
113
|
end
|
89
114
|
|
90
115
|
EC_KEY_free(eckey)
|
@@ -109,6 +134,147 @@ module OpenSSL_EC
|
|
109
134
|
buf.read_string(32).unpack("H*")[0]
|
110
135
|
end
|
111
136
|
|
137
|
+
# Given the components of a signature and a selector value, recover and
|
138
|
+
# return the public key that generated the signature according to the
|
139
|
+
# algorithm in SEC1v2 section 4.1.6.
|
140
|
+
#
|
141
|
+
# rec_id is an index from 0 to 3 that indicates which of the 4 possible
|
142
|
+
# keys is the correct one. Because the key recovery operation yields
|
143
|
+
# multiple potential keys, the correct key must either be stored alongside
|
144
|
+
# the signature, or you must be willing to try each rec_id in turn until
|
145
|
+
# you find one that outputs the key you are expecting.
|
146
|
+
#
|
147
|
+
# If this method returns nil, it means recovery was not possible and rec_id
|
148
|
+
# should be iterated.
|
149
|
+
#
|
150
|
+
# Given the above two points, a correct usage of this method is inside a
|
151
|
+
# for loop from 0 to 3, and if the output is nil OR a key that is not the
|
152
|
+
# one you expect, you try again with the next rec_id.
|
153
|
+
#
|
154
|
+
# message_hash = hash of the signed message.
|
155
|
+
# signature = the R and S components of the signature, wrapped.
|
156
|
+
# rec_id = which possible key to recover.
|
157
|
+
# is_compressed = whether or not the original pubkey was compressed.
|
158
|
+
def self.recover_public_key_from_signature(message_hash, signature, rec_id, is_compressed)
|
159
|
+
return nil if rec_id < 0 or signature.bytesize != 65
|
160
|
+
init_ffi_ssl
|
161
|
+
|
162
|
+
signature = FFI::MemoryPointer.from_string(signature)
|
163
|
+
#signature_bn = BN_bin2bn(signature, 65, BN_new())
|
164
|
+
r = BN_bin2bn(signature[1], 32, BN_new())
|
165
|
+
s = BN_bin2bn(signature[33], 32, BN_new())
|
166
|
+
|
167
|
+
n, i = 0, rec_id / 2
|
168
|
+
eckey = EC_KEY_new_by_curve_name(NID_secp256k1)
|
169
|
+
|
170
|
+
EC_KEY_set_conv_form(eckey, POINT_CONVERSION_COMPRESSED) if is_compressed
|
171
|
+
|
172
|
+
group = EC_KEY_get0_group(eckey)
|
173
|
+
order = BN_new()
|
174
|
+
EC_GROUP_get_order(group, order, nil)
|
175
|
+
x = BN_dup(order)
|
176
|
+
BN_mul_word(x, i)
|
177
|
+
BN_add(x, x, r)
|
178
|
+
|
179
|
+
field = BN_new()
|
180
|
+
EC_GROUP_get_curve_GFp(group, field, nil, nil, nil)
|
181
|
+
|
182
|
+
if BN_cmp(x, field) >= 0
|
183
|
+
[r, s, order, x, field].each{|i| BN_free(i) }
|
184
|
+
EC_KEY_free(eckey)
|
185
|
+
return nil
|
186
|
+
end
|
187
|
+
|
188
|
+
big_r = EC_POINT_new(group)
|
189
|
+
EC_POINT_set_compressed_coordinates_GFp(group, big_r, x, rec_id % 2, nil)
|
190
|
+
|
191
|
+
big_q = EC_POINT_new(group)
|
192
|
+
n = EC_GROUP_get_degree(group)
|
193
|
+
e = BN_bin2bn(message_hash, message_hash.bytesize, BN_new())
|
194
|
+
BN_rshift(e, e, 8 - (n & 7)) if 8 * message_hash.bytesize > n
|
195
|
+
|
196
|
+
ctx = BN_CTX_new()
|
197
|
+
zero, rr, sor, eor = BN_new(), BN_new(), BN_new(), BN_new()
|
198
|
+
BN_set_word(zero, 0)
|
199
|
+
BN_mod_sub(e, zero, e, order, ctx)
|
200
|
+
BN_mod_inverse(rr, r, order, ctx)
|
201
|
+
BN_mod_mul(sor, s, rr, order, ctx)
|
202
|
+
BN_mod_mul(eor, e, rr, order, ctx)
|
203
|
+
EC_POINT_mul(group, big_q, eor, big_r, sor, ctx)
|
204
|
+
EC_KEY_set_public_key(eckey, big_q)
|
205
|
+
BN_CTX_free(ctx)
|
206
|
+
|
207
|
+
[r, s, order, x, field, e, zero, rr, sor, eor].each{|i| BN_free(i) }
|
208
|
+
[big_r, big_q].each{|i| EC_POINT_free(i) }
|
209
|
+
|
210
|
+
length = i2o_ECPublicKey(eckey, nil)
|
211
|
+
buf = FFI::MemoryPointer.new(:uint8, length)
|
212
|
+
ptr = FFI::MemoryPointer.new(:pointer).put_pointer(0, buf)
|
213
|
+
pub_hex = if i2o_ECPublicKey(eckey, ptr) == length
|
214
|
+
buf.read_string(length).unpack("H*")[0]
|
215
|
+
end
|
216
|
+
|
217
|
+
EC_KEY_free(eckey)
|
218
|
+
|
219
|
+
pub_hex
|
220
|
+
end
|
221
|
+
|
222
|
+
def self.sign_compact(hash, private_key, public_key_hex = nil, pubkey_compressed = nil)
|
223
|
+
private_key = [private_key].pack("H*") if private_key.bytesize >= 64
|
224
|
+
private_key_hex = private_key.unpack("H*")[0]
|
225
|
+
|
226
|
+
public_key_hex = regenerate_key(private_key_hex).last unless public_key_hex
|
227
|
+
pubkey_compressed = (public_key_hex[0..1] == "04" ? false : true) unless pubkey_compressed
|
228
|
+
|
229
|
+
init_ffi_ssl
|
230
|
+
eckey = EC_KEY_new_by_curve_name(NID_secp256k1)
|
231
|
+
priv_key = BN_bin2bn(private_key, private_key.bytesize, BN_new())
|
232
|
+
|
233
|
+
group, order, ctx = EC_KEY_get0_group(eckey), BN_new(), BN_CTX_new()
|
234
|
+
EC_GROUP_get_order(group, order, ctx)
|
235
|
+
|
236
|
+
pub_key = EC_POINT_new(group)
|
237
|
+
EC_POINT_mul(group, pub_key, priv_key, nil, nil, ctx)
|
238
|
+
EC_KEY_set_private_key(eckey, priv_key)
|
239
|
+
EC_KEY_set_public_key(eckey, pub_key)
|
240
|
+
|
241
|
+
signature = ECDSA_do_sign(hash, hash.bytesize, eckey)
|
242
|
+
|
243
|
+
BN_free(order)
|
244
|
+
BN_CTX_free(ctx)
|
245
|
+
EC_POINT_free(pub_key)
|
246
|
+
BN_free(priv_key)
|
247
|
+
EC_KEY_free(eckey)
|
248
|
+
|
249
|
+
buf, rec_id, head = FFI::MemoryPointer.new(:uint8, 32), nil, nil
|
250
|
+
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") }
|
251
|
+
|
252
|
+
if signature.get_array_of_pointer(0, 2).all?{|i| BN_num_bits(i) <= 256 }
|
253
|
+
4.times{|i|
|
254
|
+
head = [ 27 + i + (pubkey_compressed ? 4 : 0) ].pack("C")
|
255
|
+
if public_key_hex == recover_public_key_from_signature(hash, [head, r, s].join, i, pubkey_compressed)
|
256
|
+
rec_id = i; break
|
257
|
+
end
|
258
|
+
}
|
259
|
+
end
|
260
|
+
|
261
|
+
ECDSA_SIG_free(signature)
|
262
|
+
|
263
|
+
[ head, [r,s] ].join if rec_id
|
264
|
+
end
|
265
|
+
|
266
|
+
def self.recover_compact(hash, signature)
|
267
|
+
return false if signature.bytesize != 65
|
268
|
+
#i = signature.unpack("C")[0] - 27
|
269
|
+
#pubkey = recover_public_key_from_signature(hash, signature, (i & ~4), i >= 4)
|
270
|
+
|
271
|
+
version = signature.unpack('C')[0]
|
272
|
+
return false if version < 27 or version > 34
|
273
|
+
|
274
|
+
compressed = (version >= 31) ? (version -= 4; true) : false
|
275
|
+
pubkey = recover_public_key_from_signature(hash, signature, version-27, compressed)
|
276
|
+
end
|
277
|
+
|
112
278
|
def self.init_ffi_ssl
|
113
279
|
return if @ssl_loaded
|
114
280
|
SSL_library_init()
|