bitcoin-ruby 0.0.14 → 0.0.15
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +4 -3
- data/COPYING +1 -1
- data/Gemfile.lock +1 -1
- data/README.rdoc +11 -29
- data/lib/bitcoin.rb +83 -11
- data/lib/bitcoin/bech32.rb +172 -0
- data/lib/bitcoin/builder.rb +25 -7
- data/lib/bitcoin/ffi/secp256k1.rb +12 -12
- data/lib/bitcoin/protocol/txout.rb +7 -1
- data/lib/bitcoin/script.rb +25 -8
- data/lib/bitcoin/version.rb +1 -1
- data/spec/bitcoin/bech32_spec.rb +160 -0
- data/spec/bitcoin/bitcoin_spec.rb +60 -0
- data/spec/bitcoin/builder_spec.rb +33 -0
- data/spec/bitcoin/fixtures/base58_keys_invalid.json +182 -0
- data/spec/bitcoin/fixtures/base58_keys_valid.json +488 -0
- data/spec/bitcoin/protocol/txout_spec.rb +6 -0
- data/spec/bitcoin/script/script_spec.rb +4 -0
- data/spec/bitcoin/secp256k1_spec.rb +1 -1
- metadata +9 -2
data/lib/bitcoin/builder.rb
CHANGED
@@ -237,7 +237,7 @@ module Bitcoin
|
|
237
237
|
@tx.in[i].sig_address = Script.new(@prev_script).get_address if @prev_script
|
238
238
|
end
|
239
239
|
|
240
|
-
def get_script_sig(inc)
|
240
|
+
def get_script_sig(inc, hash_type)
|
241
241
|
if inc.has_multiple_keys?
|
242
242
|
# multiple keys given, generate signature for each one
|
243
243
|
sigs = inc.sign(@sig_hash)
|
@@ -251,7 +251,7 @@ module Bitcoin
|
|
251
251
|
else
|
252
252
|
# only one key given, generate signature and script_sig
|
253
253
|
sig = inc.sign(@sig_hash)
|
254
|
-
script_sig = Script.to_signature_pubkey_script(sig, [inc.key.pub].pack("H*"))
|
254
|
+
script_sig = Script.to_signature_pubkey_script(sig, [inc.key.pub].pack("H*"), hash_type)
|
255
255
|
end
|
256
256
|
return script_sig
|
257
257
|
end
|
@@ -268,13 +268,28 @@ module Bitcoin
|
|
268
268
|
sig_script = inc.instance_eval { @redeem_script }
|
269
269
|
sig_script ||= @prev_script
|
270
270
|
|
271
|
+
hash_type = if inc.prev_out_forkid
|
272
|
+
Script::SIGHASH_TYPE[:all] | Script::SIGHASH_TYPE[:forkid]
|
273
|
+
else
|
274
|
+
Script::SIGHASH_TYPE[:all]
|
275
|
+
end
|
276
|
+
|
271
277
|
# when a sig_script was found, generate the sig_hash to be signed
|
272
278
|
if sig_script
|
273
279
|
script = Script.new(sig_script)
|
274
280
|
if script.is_witness_v0_keyhash?
|
275
281
|
@sig_hash = @tx.signature_hash_for_witness_input(i, sig_script, inc.value)
|
276
282
|
else
|
277
|
-
@sig_hash =
|
283
|
+
@sig_hash = if inc.prev_out_forkid
|
284
|
+
@tx.signature_hash_for_input(
|
285
|
+
i,
|
286
|
+
sig_script,
|
287
|
+
hash_type,
|
288
|
+
inc.value,
|
289
|
+
inc.prev_out_forkid)
|
290
|
+
else
|
291
|
+
@tx.signature_hash_for_input(i, sig_script)
|
292
|
+
end
|
278
293
|
end
|
279
294
|
end
|
280
295
|
|
@@ -285,10 +300,12 @@ module Bitcoin
|
|
285
300
|
@tx.in[i].script_witness.stack << inc.sign(@sig_hash) + [Script::SIGHASH_TYPE[:all]].pack("C")
|
286
301
|
@tx.in[i].script_witness.stack << inc.key.pub.htb
|
287
302
|
else
|
288
|
-
@tx.in[i].script_sig = get_script_sig(inc)
|
303
|
+
@tx.in[i].script_sig = get_script_sig(inc, hash_type)
|
289
304
|
end
|
290
305
|
# double-check that the script_sig is valid to spend the given prev_script
|
291
|
-
|
306
|
+
if @prev_script && !inc.prev_out_forkid && !@tx.verify_input_signature(i, @prev_script)
|
307
|
+
raise "Signature error"
|
308
|
+
end
|
292
309
|
elsif inc.has_multiple_keys?
|
293
310
|
raise "Keys missing for multisig signing"
|
294
311
|
else
|
@@ -329,7 +346,7 @@ module Bitcoin
|
|
329
346
|
#
|
330
347
|
# If you want to spend a multisig output, just provide an array of keys to #signature_key.
|
331
348
|
class TxInBuilder
|
332
|
-
attr_reader :prev_tx, :prev_script, :redeem_script, :key, :coinbase_data, :prev_out_value
|
349
|
+
attr_reader :prev_tx, :prev_script, :redeem_script, :key, :coinbase_data, :prev_out_value, :prev_out_forkid
|
333
350
|
|
334
351
|
def initialize
|
335
352
|
@txin = P::TxIn.new
|
@@ -341,7 +358,8 @@ module Bitcoin
|
|
341
358
|
# You can either pass the transaction, or just the tx hash.
|
342
359
|
# If you pass only the hash, you need to pass the previous outputs
|
343
360
|
# +script+ separately if you want the txin to be signed.
|
344
|
-
def prev_out tx, idx = nil, script = nil, prev_value = nil
|
361
|
+
def prev_out tx, idx = nil, script = nil, prev_value = nil, prev_forkid = nil
|
362
|
+
@prev_out_forkid = prev_forkid
|
345
363
|
if tx.is_a?(Bitcoin::P::Tx)
|
346
364
|
@prev_tx = tx
|
347
365
|
@prev_out_hash = tx.binary_hash
|
@@ -134,7 +134,7 @@ module Bitcoin
|
|
134
134
|
|
135
135
|
internal_pubkey = FFI::MemoryPointer.new(:uchar, 64)
|
136
136
|
result = secp256k1_ec_pubkey_create(context, internal_pubkey, seckey)
|
137
|
-
raise "error creating pubkey" unless result
|
137
|
+
raise "error creating pubkey" unless result == 1
|
138
138
|
|
139
139
|
pubkey, pubkey_len = FFI::MemoryPointer.new(:uchar, 65), FFI::MemoryPointer.new(:uint64)
|
140
140
|
result = if compressed
|
@@ -144,7 +144,7 @@ module Bitcoin
|
|
144
144
|
pubkey_len.put_uint64(0, 65)
|
145
145
|
secp256k1_ec_pubkey_serialize(context, pubkey, pubkey_len, internal_pubkey, SECP256K1_EC_UNCOMPRESSED)
|
146
146
|
end
|
147
|
-
raise "error serialize pubkey" unless result || pubkey_len.read_uint64 > 0
|
147
|
+
raise "error serialize pubkey" unless (result == 1) || pubkey_len.read_uint64 > 0
|
148
148
|
|
149
149
|
[ seckey.read_string(32), pubkey.read_string(pubkey_len.read_uint64) ]
|
150
150
|
end
|
@@ -158,7 +158,7 @@ module Bitcoin
|
|
158
158
|
def self.sign(data, priv_key)
|
159
159
|
with_context do |context|
|
160
160
|
seckey = FFI::MemoryPointer.new(:uchar, priv_key.bytesize).put_bytes(0, priv_key)
|
161
|
-
raise "priv_key invalid" unless secp256k1_ec_seckey_verify(context, seckey)
|
161
|
+
raise "priv_key invalid" unless secp256k1_ec_seckey_verify(context, seckey) == 1
|
162
162
|
|
163
163
|
internal_signature = FFI::MemoryPointer.new(:uchar, 64)
|
164
164
|
msg32 = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, data)
|
@@ -173,7 +173,7 @@ module Bitcoin
|
|
173
173
|
|
174
174
|
signature, signature_len = FFI::MemoryPointer.new(:uchar, 72), FFI::MemoryPointer.new(:uint64).put_uint64(0, 72)
|
175
175
|
result = secp256k1_ecdsa_signature_serialize_der(context, signature, signature_len, internal_signature)
|
176
|
-
raise "secp256k1_ecdsa_signature_serialize_der failed" unless result
|
176
|
+
raise "secp256k1_ecdsa_signature_serialize_der failed" unless result == 1
|
177
177
|
|
178
178
|
signature.read_string(signature_len.read_uint64)
|
179
179
|
end
|
@@ -186,13 +186,13 @@ module Bitcoin
|
|
186
186
|
pubkey = FFI::MemoryPointer.new(:uchar, pub_key.bytesize).put_bytes(0, pub_key)
|
187
187
|
internal_pubkey = FFI::MemoryPointer.new(:uchar, 64)
|
188
188
|
result = secp256k1_ec_pubkey_parse(context, internal_pubkey, pubkey, pubkey.size)
|
189
|
-
return false unless result
|
189
|
+
return false unless result == 1
|
190
190
|
|
191
191
|
signature = FFI::MemoryPointer.new(:uchar, sig.bytesize).put_bytes(0, sig)
|
192
192
|
internal_signature = FFI::MemoryPointer.new(:uchar, 64)
|
193
193
|
result = secp256k1_ecdsa_signature_parse_der(context, internal_signature, signature, signature.size)
|
194
194
|
#result = ecdsa_signature_parse_der_lax(context, internal_signature, signature, signature.size)
|
195
|
-
return false unless result
|
195
|
+
return false unless result == 1
|
196
196
|
|
197
197
|
# libsecp256k1's ECDSA verification requires lower-S signatures, which have not historically been enforced in Bitcoin, so normalize them first.
|
198
198
|
secp256k1_ecdsa_signature_normalize(context, internal_signature, internal_signature)
|
@@ -200,14 +200,14 @@ module Bitcoin
|
|
200
200
|
msg32 = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, data)
|
201
201
|
result = secp256k1_ecdsa_verify(context, internal_signature, msg32, internal_pubkey)
|
202
202
|
|
203
|
-
return result
|
203
|
+
return result == 1
|
204
204
|
end
|
205
205
|
end
|
206
206
|
|
207
207
|
def self.sign_compact(message, priv_key, compressed=true)
|
208
208
|
with_context do |context|
|
209
209
|
seckey = FFI::MemoryPointer.new(:uchar, priv_key.bytesize).put_bytes(0, priv_key)
|
210
|
-
raise "priv_key invalid" unless secp256k1_ec_seckey_verify(context, seckey)
|
210
|
+
raise "priv_key invalid" unless secp256k1_ec_seckey_verify(context, seckey) == 1
|
211
211
|
|
212
212
|
msg32 = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, message)
|
213
213
|
internal_recoverable_signature = FFI::MemoryPointer.new(:uchar, 65)
|
@@ -223,7 +223,7 @@ module Bitcoin
|
|
223
223
|
|
224
224
|
recoverable_signature = FFI::MemoryPointer.new(:uchar, 64)
|
225
225
|
result = secp256k1_ecdsa_recoverable_signature_serialize_compact(context, recoverable_signature, rec_id, internal_recoverable_signature)
|
226
|
-
raise "secp256k1_ecdsa_recoverable_signature_serialize_compact failed" unless result
|
226
|
+
raise "secp256k1_ecdsa_recoverable_signature_serialize_compact failed" unless result == 1
|
227
227
|
raise "secp256k1_ecdsa_recoverable_signature_serialize_compact failed" unless rec_id.read_int != -1
|
228
228
|
|
229
229
|
header = [27 + rec_id.read_int + (compressed ? 4 : 0)].pack("C")
|
@@ -248,15 +248,15 @@ module Bitcoin
|
|
248
248
|
|
249
249
|
internal_recoverable_signature = FFI::MemoryPointer.new(:uchar, 65)
|
250
250
|
result = secp256k1_ecdsa_recoverable_signature_parse_compact(context, internal_recoverable_signature, recoverable_signature, recid)
|
251
|
-
return nil unless result
|
251
|
+
return nil unless result == 1
|
252
252
|
|
253
253
|
internal_pubkey = FFI::MemoryPointer.new(:uchar, 64)
|
254
254
|
result = secp256k1_ecdsa_recover(context, internal_pubkey, internal_recoverable_signature, msg32)
|
255
|
-
return nil unless result
|
255
|
+
return nil unless result == 1
|
256
256
|
|
257
257
|
pubkey, pubkey_len = FFI::MemoryPointer.new(:uchar, 65), FFI::MemoryPointer.new(:uint64).put_uint64(0, 65)
|
258
258
|
result = secp256k1_ec_pubkey_serialize(context, pubkey, pubkey_len, internal_pubkey, flag)
|
259
|
-
raise "error serialize pubkey" unless result || pubkey_len.read_uint64 > 0
|
259
|
+
raise "error serialize pubkey" unless (result == 1) || pubkey_len.read_uint64 > 0
|
260
260
|
|
261
261
|
pubkey.read_string(pubkey_len.read_uint64)
|
262
262
|
end
|
@@ -9,7 +9,7 @@ module Bitcoin
|
|
9
9
|
attr_accessor :value
|
10
10
|
|
11
11
|
# pk_script output Script
|
12
|
-
|
12
|
+
attr_reader :pk_script, :pk_script_length
|
13
13
|
|
14
14
|
# p2sh redeem script (optional, not included in the serialized binary format)
|
15
15
|
attr_accessor :redeem_script
|
@@ -39,6 +39,7 @@ module Bitcoin
|
|
39
39
|
|
40
40
|
# parse raw binary data for transaction output
|
41
41
|
def parse_data_from_io(buf)
|
42
|
+
clear_parsed_script_cache
|
42
43
|
@value = buf.read(8).unpack("Q")[0]
|
43
44
|
@pk_script_length = Protocol.unpack_var_int_from_io(buf)
|
44
45
|
@pk_script = buf.read(@pk_script_length)
|
@@ -50,6 +51,10 @@ module Bitcoin
|
|
50
51
|
@parsed_script ||= Bitcoin::Script.new(pk_script)
|
51
52
|
end
|
52
53
|
|
54
|
+
def clear_parsed_script_cache
|
55
|
+
remove_instance_variable(:@parsed_script) if defined?(@parsed_script)
|
56
|
+
end
|
57
|
+
|
53
58
|
def to_payload
|
54
59
|
[@value].pack("Q") << Protocol.pack_var_int(@pk_script_length) << @pk_script
|
55
60
|
end
|
@@ -73,6 +78,7 @@ module Bitcoin
|
|
73
78
|
|
74
79
|
# set pk_script and pk_script_length
|
75
80
|
def pk_script=(pk_script)
|
81
|
+
clear_parsed_script_cache
|
76
82
|
@pk_script_length, @pk_script = pk_script.bytesize, pk_script
|
77
83
|
end
|
78
84
|
|
data/lib/bitcoin/script.rb
CHANGED
@@ -599,19 +599,19 @@ class Bitcoin::Script
|
|
599
599
|
@chunks[0] == OP_RETURN && @chunks.size <= 2
|
600
600
|
end
|
601
601
|
|
602
|
-
# is this a witness script
|
602
|
+
# is this a witness script
|
603
603
|
def is_witness?
|
604
|
-
|
604
|
+
@chunks.length == 2 && (0..16).include?(@chunks[0]) && @chunks[1].is_a?(String)
|
605
605
|
end
|
606
606
|
|
607
607
|
# is this a witness pubkey script
|
608
608
|
def is_witness_v0_keyhash?
|
609
|
-
|
609
|
+
is_witness? && @chunks[0] == 0 && @chunks[1].bytesize == 20
|
610
610
|
end
|
611
611
|
|
612
612
|
# is this a witness script hash
|
613
613
|
def is_witness_v0_scripthash?
|
614
|
-
|
614
|
+
is_witness? && @chunks[0] == 0 && @chunks[1].bytesize == 32
|
615
615
|
end
|
616
616
|
|
617
617
|
# Verify the script is only pushing data onto the stack
|
@@ -731,6 +731,12 @@ class Bitcoin::Script
|
|
731
731
|
return [get_hash160_address] if is_hash160?
|
732
732
|
return get_multisig_addresses if is_multisig?
|
733
733
|
return [get_p2sh_address] if is_p2sh?
|
734
|
+
|
735
|
+
if is_witness_v0_keyhash? || is_witness_v0_scripthash?
|
736
|
+
program_hex = chunks[1].unpack("H*").first
|
737
|
+
return Bitcoin.encode_segwit_address(0, program_hex)
|
738
|
+
end
|
739
|
+
|
734
740
|
[]
|
735
741
|
end
|
736
742
|
|
@@ -762,20 +768,28 @@ class Bitcoin::Script
|
|
762
768
|
[ ["a9", "14", p2sh, "87"].join ].pack("H*")
|
763
769
|
end
|
764
770
|
|
771
|
+
# generate pay-to-witness output script for given +witness_version+ and
|
772
|
+
# +witness_program+. returns a raw binary script of the form:
|
773
|
+
# <witness_version> <witness_program>
|
774
|
+
def self.to_witness_script(witness_version, witness_program_hex)
|
775
|
+
return nil unless (0..16).include?(witness_version)
|
776
|
+
return nil unless witness_program_hex
|
777
|
+
version = witness_version != 0 ? 0x50 + witness_version : 0 # 0x50 for OP_1.. codes
|
778
|
+
[version].pack('C') + pack_pushdata(witness_program_hex.htb)
|
779
|
+
end
|
780
|
+
|
765
781
|
# generate p2wpkh tx for given +address+. returns a raw binary script of the form:
|
766
782
|
# 0 <hash160>
|
767
783
|
def self.to_witness_hash160_script(hash160)
|
768
784
|
return nil unless hash160
|
769
|
-
|
770
|
-
[ ["00", "14", hash160].join ].pack("H*")
|
785
|
+
to_witness_script(0, hash160)
|
771
786
|
end
|
772
787
|
|
773
788
|
# generate p2wsh output script for given +p2sh+ sha256. returns a raw binary script of the form:
|
774
789
|
# 0 <p2sh>
|
775
790
|
def self.to_witness_p2sh_script(p2sh)
|
776
791
|
return nil unless p2sh
|
777
|
-
|
778
|
-
[ [ "00", "20", p2sh].join].pack("H*")
|
792
|
+
to_witness_script(0, p2sh)
|
779
793
|
end
|
780
794
|
|
781
795
|
# generate hash160 or p2sh output script, depending on the type of the given +address+.
|
@@ -785,6 +799,9 @@ class Bitcoin::Script
|
|
785
799
|
case Bitcoin.address_type(address)
|
786
800
|
when :hash160; to_hash160_script(hash160)
|
787
801
|
when :p2sh; to_p2sh_script(hash160)
|
802
|
+
when :witness_v0_keyhash, :witness_v0_scripthash
|
803
|
+
witness_version, witness_program_hex = Bitcoin.decode_segwit_address(address)
|
804
|
+
to_witness_script(witness_version, witness_program_hex)
|
788
805
|
end
|
789
806
|
end
|
790
807
|
|
data/lib/bitcoin/version.rb
CHANGED
@@ -0,0 +1,160 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
|
3
|
+
require_relative 'spec_helper'
|
4
|
+
|
5
|
+
describe Bitcoin::Bech32 do
|
6
|
+
before do
|
7
|
+
Bitcoin.network = :bitcoin
|
8
|
+
|
9
|
+
@invalid_address_enc = [
|
10
|
+
["BC", 0, 20],
|
11
|
+
["bc", 0, 21],
|
12
|
+
["bc", 17, 32],
|
13
|
+
["bc", 1, 1],
|
14
|
+
["bc", 16, 41],
|
15
|
+
]
|
16
|
+
|
17
|
+
@valid_address = [
|
18
|
+
[
|
19
|
+
"BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4",
|
20
|
+
22, [
|
21
|
+
0x00, 0x14, 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54,
|
22
|
+
0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6
|
23
|
+
]
|
24
|
+
],
|
25
|
+
[
|
26
|
+
"tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7",
|
27
|
+
34, [
|
28
|
+
0x00, 0x20, 0x18, 0x63, 0x14, 0x3c, 0x14, 0xc5, 0x16, 0x68, 0x04,
|
29
|
+
0xbd, 0x19, 0x20, 0x33, 0x56, 0xda, 0x13, 0x6c, 0x98, 0x56, 0x78,
|
30
|
+
0xcd, 0x4d, 0x27, 0xa1, 0xb8, 0xc6, 0x32, 0x96, 0x04, 0x90, 0x32,
|
31
|
+
0x62
|
32
|
+
]
|
33
|
+
],
|
34
|
+
[
|
35
|
+
"bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx",
|
36
|
+
42, [
|
37
|
+
0x51, 0x28, 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54,
|
38
|
+
0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6,
|
39
|
+
0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94, 0x1c,
|
40
|
+
0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6
|
41
|
+
]
|
42
|
+
],
|
43
|
+
[
|
44
|
+
"BC1SW50QA3JX3S",
|
45
|
+
4, [
|
46
|
+
0x60, 0x02, 0x75, 0x1e
|
47
|
+
]
|
48
|
+
],
|
49
|
+
[
|
50
|
+
"bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj",
|
51
|
+
18, [
|
52
|
+
0x52, 0x10, 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54,
|
53
|
+
0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23
|
54
|
+
]
|
55
|
+
],
|
56
|
+
[
|
57
|
+
"tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy",
|
58
|
+
34, [
|
59
|
+
0x00, 0x20, 0x00, 0x00, 0x00, 0xc4, 0xa5, 0xca, 0xd4, 0x62, 0x21,
|
60
|
+
0xb2, 0xa1, 0x87, 0x90, 0x5e, 0x52, 0x66, 0x36, 0x2b, 0x99, 0xd5,
|
61
|
+
0xe9, 0x1c, 0x6c, 0xe2, 0x4d, 0x16, 0x5d, 0xab, 0x93, 0xe8, 0x64,
|
62
|
+
0x33
|
63
|
+
]
|
64
|
+
]
|
65
|
+
]
|
66
|
+
|
67
|
+
@valid_checksum = [
|
68
|
+
"A12UEL5L",
|
69
|
+
"an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1tt5tgs",
|
70
|
+
"abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw",
|
71
|
+
"11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j",
|
72
|
+
"split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w",
|
73
|
+
]
|
74
|
+
|
75
|
+
@invalid_checksum = [
|
76
|
+
" 1nwldj5",
|
77
|
+
"\x7f""1axkwrx",
|
78
|
+
"an84characterslonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1569pvx",
|
79
|
+
"pzry9x0s0muk",
|
80
|
+
"1pzry9x0s0muk",
|
81
|
+
"x1b4n0q5v",
|
82
|
+
"li1dgmt3",
|
83
|
+
"de1lg7wt\xff",
|
84
|
+
]
|
85
|
+
|
86
|
+
@invalid_address = [
|
87
|
+
"tc1qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty",
|
88
|
+
"bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5",
|
89
|
+
"BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2",
|
90
|
+
"bc1rw5uspcuh",
|
91
|
+
"bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5rljs90",
|
92
|
+
"BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P",
|
93
|
+
"tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7",
|
94
|
+
"bc1zw508d6qejxtdg4y5r3zarvaryvqyzf3du",
|
95
|
+
"tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv",
|
96
|
+
"bc1gmk9yu",
|
97
|
+
]
|
98
|
+
end
|
99
|
+
|
100
|
+
describe '#decode and #encode' do
|
101
|
+
it "test vectors" do
|
102
|
+
@valid_checksum.each do |testdata|
|
103
|
+
hrp, data = Bitcoin::Bech32.decode(testdata)
|
104
|
+
newdata = Bitcoin::Bech32.encode(hrp, data)
|
105
|
+
newdata.should == testdata.downcase
|
106
|
+
end
|
107
|
+
|
108
|
+
@invalid_checksum.each do |testdata|
|
109
|
+
hrp, data = Bitcoin::Bech32.decode(testdata)
|
110
|
+
hrp.should == nil
|
111
|
+
end
|
112
|
+
|
113
|
+
@valid_address.each do |testdata, _, _|
|
114
|
+
hrp, data = Bitcoin::Bech32.decode(testdata)
|
115
|
+
newdata = Bitcoin::Bech32.encode(hrp, data)
|
116
|
+
newdata.should == testdata.downcase
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
describe '#decode_segwit_address and #encode_segwit_address' do
|
122
|
+
it "test vectors" do
|
123
|
+
@valid_address.each do |testaddress, _, testscript|
|
124
|
+
Bitcoin.network = :bitcoin
|
125
|
+
version, program = Bitcoin.decode_segwit_address(testaddress)
|
126
|
+
if version.nil?
|
127
|
+
Bitcoin.network = :testnet3
|
128
|
+
version, program = Bitcoin.decode_segwit_address(testaddress)
|
129
|
+
end
|
130
|
+
version.should != nil
|
131
|
+
|
132
|
+
script = Bitcoin::Script.to_witness_script(version, program)
|
133
|
+
script.should == testscript.pack("C*")
|
134
|
+
|
135
|
+
newaddress = Bitcoin.encode_segwit_address(version, program)
|
136
|
+
newaddress.should != nil
|
137
|
+
newaddress.should == testaddress.downcase
|
138
|
+
end
|
139
|
+
|
140
|
+
@invalid_address.each do |testaddress|
|
141
|
+
Bitcoin.network = :bitcoin
|
142
|
+
version, program = Bitcoin.decode_segwit_address(testaddress)
|
143
|
+
if version.nil?
|
144
|
+
Bitcoin.network = :testnet3
|
145
|
+
version, program = Bitcoin.decode_segwit_address(testaddress)
|
146
|
+
end
|
147
|
+
version.should == nil
|
148
|
+
end
|
149
|
+
|
150
|
+
Bitcoin.network = :bitcoin
|
151
|
+
@invalid_address_enc.each do |testhrp, testversion, testlength|
|
152
|
+
Bitcoin.network[:bech32_hrp] = testhrp
|
153
|
+
program_hex = Array.new(testlength){ 0 }.pack("C*").unpack("H*").first
|
154
|
+
newaddress = Bitcoin.encode_segwit_address(testversion, program_hex)
|
155
|
+
newaddress.should == nil
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
end
|