bitcoinrb 0.2.5 → 0.2.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.ruby-version +1 -1
- data/.travis.yml +2 -3
- data/README.md +4 -1
- data/bitcoinrb.gemspec +2 -2
- data/lib/bitcoin/base58.rb +1 -1
- data/lib/bitcoin/bit_stream.rb +2 -2
- data/lib/bitcoin/block_header.rb +1 -1
- data/lib/bitcoin/ext_key.rb +9 -7
- data/lib/bitcoin/gcs_filter.rb +3 -1
- data/lib/bitcoin/key.rb +3 -5
- data/lib/bitcoin/psbt/input.rb +30 -2
- data/lib/bitcoin/psbt/output.rb +2 -2
- data/lib/bitcoin/psbt/tx.rb +14 -3
- data/lib/bitcoin/psbt.rb +1 -1
- data/lib/bitcoin/rpc/request_handler.rb +1 -0
- data/lib/bitcoin/secp256k1/native.rb +27 -18
- data/lib/bitcoin/secp256k1/ruby.rb +5 -0
- data/lib/bitcoin/store/spv_chain.rb +1 -0
- data/lib/bitcoin/util.rb +6 -4
- data/lib/bitcoin/version.rb +1 -1
- data/lib/bitcoin/wallet/account.rb +2 -2
- data/lib/bitcoin/wallet/master_key.rb +1 -1
- data/lib/bitcoin.rb +4 -0
- data/lib/openassets/payload.rb +6 -1
- metadata +11 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2dea1d2e52223f2754f748f612c5d3df9606988476ee0c1f5b1ad03e71ba0ead
|
4
|
+
data.tar.gz: baedfcc44fdacd0c2c46766a360fb76404630bd01dbaf034664d358f5564d5b8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 851b762a403ebd8a0f175171e000650b76b5380522c174cbea3c03817477aa89e98b8a3e204c0cc3c223fb281dfbc75ae936cd1b1fe6e6f6b06ae5aeca74b335
|
7
|
+
data.tar.gz: 75fd1e350ab651a01b1eae0d0b6885ca933a60efcfc237ad75de55002777806aaf805c4a724430535521c421a10111871838d97bfaf94d93766f93e433e33160
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.6.
|
1
|
+
2.6.2
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -46,7 +46,7 @@ gem leveldb-ruby
|
|
46
46
|
Add this line to your application's Gemfile:
|
47
47
|
|
48
48
|
```ruby
|
49
|
-
gem 'bitcoinrb'
|
49
|
+
gem 'bitcoinrb', require: 'bitcoin'
|
50
50
|
```
|
51
51
|
|
52
52
|
And then execute:
|
@@ -57,6 +57,9 @@ Or install it yourself as:
|
|
57
57
|
|
58
58
|
$ gem install bitcoinrb
|
59
59
|
|
60
|
+
And then add to your .rb file:
|
61
|
+
|
62
|
+
require 'bitcoin'
|
60
63
|
|
61
64
|
## Usage
|
62
65
|
|
data/bitcoinrb.gemspec
CHANGED
@@ -32,13 +32,13 @@ Gem::Specification.new do |spec|
|
|
32
32
|
spec.add_runtime_dependency 'rest-client'
|
33
33
|
spec.add_runtime_dependency 'iniparse'
|
34
34
|
spec.add_runtime_dependency 'siphash'
|
35
|
-
spec.add_runtime_dependency 'protobuf'
|
35
|
+
spec.add_runtime_dependency 'protobuf', '3.8.5'
|
36
36
|
spec.add_runtime_dependency 'scrypt'
|
37
37
|
|
38
38
|
# for options
|
39
39
|
spec.add_development_dependency 'leveldb-ruby'
|
40
40
|
|
41
|
-
spec.add_development_dependency 'bundler'
|
41
|
+
spec.add_development_dependency 'bundler'
|
42
42
|
spec.add_development_dependency 'rake', '~> 10.0'
|
43
43
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
44
44
|
spec.add_development_dependency 'timecop'
|
data/lib/bitcoin/base58.rb
CHANGED
@@ -25,7 +25,7 @@ module Bitcoin
|
|
25
25
|
int_val = 0
|
26
26
|
base58_val.reverse.split(//).each_with_index do |char,index|
|
27
27
|
raise ArgumentError, 'Value passed not a valid Base58 String.' if (char_index = ALPHABET.index(char)).nil?
|
28
|
-
int_val += char_index * (SIZE**index)
|
28
|
+
int_val += char_index * (SIZE ** index)
|
29
29
|
end
|
30
30
|
s = int_val.to_even_length_hex
|
31
31
|
s = '' if s == '00'
|
data/lib/bitcoin/bit_stream.rb
CHANGED
@@ -2,7 +2,7 @@ module Bitcoin
|
|
2
2
|
|
3
3
|
class BitStreamWriter
|
4
4
|
|
5
|
-
MAX_BIT = 2**64
|
5
|
+
MAX_BIT = 4611686018427387904 # 2**64
|
6
6
|
|
7
7
|
attr_reader :stream
|
8
8
|
attr_accessor :buffer
|
@@ -28,7 +28,7 @@ module Bitcoin
|
|
28
28
|
|
29
29
|
def flush
|
30
30
|
return if offset == 0
|
31
|
-
self.stream <<
|
31
|
+
self.stream << buffer.itb
|
32
32
|
self.offset = 0
|
33
33
|
self.buffer = 0
|
34
34
|
end
|
data/lib/bitcoin/block_header.rb
CHANGED
@@ -70,7 +70,7 @@ module Bitcoin
|
|
70
70
|
def work
|
71
71
|
target = difficulty_target
|
72
72
|
return 0 if target < 1
|
73
|
-
(
|
73
|
+
115792089237316195423570985008687907853269984665640564039457584007913129639936.div(target + 1) # 115792089237316195423570985008687907853269984665640564039457584007913129639936 is 2**256
|
74
74
|
end
|
75
75
|
|
76
76
|
def ==(other)
|
data/lib/bitcoin/ext_key.rb
CHANGED
@@ -3,6 +3,8 @@ module Bitcoin
|
|
3
3
|
# Integers modulo the order of the curve(secp256k1)
|
4
4
|
CURVE_ORDER = ECDSA::Group::Secp256k1.order
|
5
5
|
|
6
|
+
HARDENED_THRESHOLD = 2147483648 # 2**31
|
7
|
+
|
6
8
|
# BIP32 Extended private key
|
7
9
|
class ExtKey
|
8
10
|
|
@@ -83,7 +85,7 @@ module Bitcoin
|
|
83
85
|
|
84
86
|
# whether hardened key.
|
85
87
|
def hardened?
|
86
|
-
number >=
|
88
|
+
number >= HARDENED_THRESHOLD
|
87
89
|
end
|
88
90
|
|
89
91
|
# derive new key
|
@@ -91,12 +93,12 @@ module Bitcoin
|
|
91
93
|
# @param [Boolean] harden whether hardened key or not. If true, 2^31 is added to +number+.
|
92
94
|
# @return [Bitcoin::ExtKey] derived new key.
|
93
95
|
def derive(number, harden = false)
|
94
|
-
number +=
|
96
|
+
number += HARDENED_THRESHOLD if harden
|
95
97
|
new_key = ExtKey.new
|
96
98
|
new_key.depth = depth + 1
|
97
99
|
new_key.number = number
|
98
100
|
new_key.parent_fingerprint = fingerprint
|
99
|
-
if number > (
|
101
|
+
if number > (HARDENED_THRESHOLD - 1)
|
100
102
|
data = [0x00].pack('C') << key.priv_key.htb << [number].pack('N')
|
101
103
|
else
|
102
104
|
data = key.pubkey.htb << [number].pack('N')
|
@@ -153,7 +155,7 @@ module Bitcoin
|
|
153
155
|
|
154
156
|
# get version bytes from purpose' value.
|
155
157
|
def self.version_from_purpose(purpose)
|
156
|
-
v = purpose -
|
158
|
+
v = purpose - HARDENED_THRESHOLD
|
157
159
|
case v
|
158
160
|
when 49
|
159
161
|
Bitcoin.chain_params.bip49_privkey_p2wpkh_p2sh_version
|
@@ -245,7 +247,7 @@ module Bitcoin
|
|
245
247
|
|
246
248
|
# whether hardened key.
|
247
249
|
def hardened?
|
248
|
-
number >=
|
250
|
+
number >= HARDENED_THRESHOLD
|
249
251
|
end
|
250
252
|
|
251
253
|
# derive child key
|
@@ -254,7 +256,7 @@ module Bitcoin
|
|
254
256
|
new_key.depth = depth + 1
|
255
257
|
new_key.number = number
|
256
258
|
new_key.parent_fingerprint = fingerprint
|
257
|
-
raise 'hardened key is not support' if number > (
|
259
|
+
raise 'hardened key is not support' if number > (HARDENED_THRESHOLD - 1)
|
258
260
|
data = pub.htb << [number].pack('N')
|
259
261
|
l = Bitcoin.hmac_sha512(chain_code, data)
|
260
262
|
left = l[0..31].bth.to_i(16)
|
@@ -306,7 +308,7 @@ module Bitcoin
|
|
306
308
|
|
307
309
|
# get version bytes from purpose' value.
|
308
310
|
def self.version_from_purpose(purpose)
|
309
|
-
v = purpose -
|
311
|
+
v = purpose - HARDENED_THRESHOLD
|
310
312
|
case v
|
311
313
|
when 49
|
312
314
|
Bitcoin.chain_params.bip49_pubkey_p2wpkh_p2sh_version
|
data/lib/bitcoin/gcs_filter.rb
CHANGED
@@ -6,6 +6,8 @@ module Bitcoin
|
|
6
6
|
# see https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki
|
7
7
|
class GCSFilter
|
8
8
|
|
9
|
+
MAX_ELEMENTS_SIZE = 4294967296 # 2**32
|
10
|
+
|
9
11
|
attr_reader :p # Golomb-Rice coding parameter
|
10
12
|
attr_reader :m # Inverse false positive rate
|
11
13
|
attr_reader :n # Number of elements in the filter
|
@@ -26,7 +28,7 @@ module Bitcoin
|
|
26
28
|
@p = p
|
27
29
|
@m = m
|
28
30
|
if elements
|
29
|
-
raise 'elements size must be < 2**32.' if elements.size >=
|
31
|
+
raise 'elements size must be < 2**32.' if elements.size >= MAX_ELEMENTS_SIZE
|
30
32
|
@n = elements.size
|
31
33
|
encoded = Bitcoin.pack_var_int(@n)
|
32
34
|
bit_writer = Bitcoin::BitStreamWriter.new
|
data/lib/bitcoin/key.rb
CHANGED
@@ -18,7 +18,7 @@ module Bitcoin
|
|
18
18
|
|
19
19
|
TYPES = {uncompressed: 0x00, compressed: 0x01, p2pkh: 0x10, p2wpkh: 0x11, pw2pkh_p2sh: 0x12}
|
20
20
|
|
21
|
-
|
21
|
+
MIN_PRIV_KEY_MOD_ORDER = 0x01
|
22
22
|
# Order of secp256k1's generator minus 1.
|
23
23
|
MAX_PRIV_KEY_MOD_ORDER = ECDSA::Group::Secp256k1.order - 1
|
24
24
|
|
@@ -253,15 +253,13 @@ module Bitcoin
|
|
253
253
|
# @param [Boolean] compressed pubkey compressed?
|
254
254
|
# @return [String] a pubkey which generate from privkey
|
255
255
|
def generate_pubkey(privkey, compressed: true)
|
256
|
-
|
257
|
-
pubkey = ECDSA::Format::PointOctetString.encode(public_key, compression: compressed)
|
258
|
-
pubkey.bth
|
256
|
+
@secp256k1_module.generate_pubkey(privkey, compressed: compressed)
|
259
257
|
end
|
260
258
|
|
261
259
|
# check private key range.
|
262
260
|
def validate_private_key_range(private_key)
|
263
261
|
value = private_key.to_i(16)
|
264
|
-
|
262
|
+
MIN_PRIV_KEY_MOD_ORDER <= value && value <= MAX_PRIV_KEY_MOD_ORDER
|
265
263
|
end
|
266
264
|
|
267
265
|
# Supported violations include negative integers, excessive padding, garbage
|
data/lib/bitcoin/psbt/input.rb
CHANGED
@@ -100,11 +100,12 @@ module Bitcoin
|
|
100
100
|
payload << PSBT.serialize_to_vector(PSBT_IN_TYPES[:script_sig], value: final_script_sig.to_payload) if final_script_sig
|
101
101
|
payload << PSBT.serialize_to_vector(PSBT_IN_TYPES[:script_witness], value: final_script_witness.to_payload) if final_script_witness
|
102
102
|
payload << unknowns.map {|k,v|Bitcoin.pack_var_int(k.htb.bytesize) << k.htb << Bitcoin.pack_var_int(v.bytesize) << v}.join
|
103
|
-
payload << PSBT_SEPARATOR.
|
103
|
+
payload << PSBT_SEPARATOR.itb
|
104
104
|
payload
|
105
105
|
end
|
106
106
|
|
107
107
|
# Sanity check
|
108
|
+
# @return [Boolean]
|
108
109
|
def sane?
|
109
110
|
return false if non_witness_utxo && witness_utxo
|
110
111
|
return false if witness_script && witness_utxo.nil?
|
@@ -112,6 +113,33 @@ module Bitcoin
|
|
112
113
|
true
|
113
114
|
end
|
114
115
|
|
116
|
+
# Check whether input's scriptPubkey is correct witness.
|
117
|
+
# @return [Boolean]
|
118
|
+
def valid_witness_input?
|
119
|
+
return true if witness_utxo.script_pubkey.p2wpkh? # P2WPKH
|
120
|
+
return true if witness_utxo.script_pubkey.p2wsh? && witness_utxo.script_pubkey == redeem_script.to_p2wsh # P2WSH
|
121
|
+
return true if witness_utxo.script_pubkey.p2sh? && redeem_script&.witness_program? && # segwit nested in P2SH
|
122
|
+
redeem_script.to_p2sh == witness_utxo.script_pubkey && witness_script&.to_sha256 == redeem_script.witness_data[1].bth
|
123
|
+
false
|
124
|
+
end
|
125
|
+
|
126
|
+
# Check whether input's scriptPubkey is correct witness.
|
127
|
+
# @return [Boolean]
|
128
|
+
def valid_non_witness_input?
|
129
|
+
non_witness_utxo.outputs.each do |o|
|
130
|
+
return true if o.script_pubkey.p2sh? && redeem_script.to_p2sh == o.script_pubkey
|
131
|
+
end
|
132
|
+
false
|
133
|
+
end
|
134
|
+
|
135
|
+
# Check whether the signer can sign this input.
|
136
|
+
# @return [Boolean]
|
137
|
+
def ready_to_sign?
|
138
|
+
return false unless sane?
|
139
|
+
return valid_witness_input? if witness_utxo
|
140
|
+
valid_non_witness_input? # non_witness_utxo
|
141
|
+
end
|
142
|
+
|
115
143
|
# add signature as partial sig.
|
116
144
|
# @param [String] pubkey a public key with hex format.
|
117
145
|
# @param [String] sig a signature.
|
@@ -132,7 +160,7 @@ module Bitcoin
|
|
132
160
|
raise ArgumentError, 'The Partially Signed Input\'s redeem_script are different.' unless redeem_script == psbi.redeem_script
|
133
161
|
raise ArgumentError, 'The Partially Signed Input\'s witness_script are different.' unless witness_script == psbi.witness_script
|
134
162
|
combined = Bitcoin::PSBT::Input.new(non_witness_utxo: non_witness_utxo, witness_utxo: witness_utxo)
|
135
|
-
combined.unknowns = unknowns.merge(psbi.unknowns)
|
163
|
+
combined.unknowns = Hash[unknowns.merge(psbi.unknowns).sort]
|
136
164
|
combined.redeem_script = redeem_script
|
137
165
|
combined.witness_script = witness_script
|
138
166
|
combined.sighash_type = sighash_type
|
data/lib/bitcoin/psbt/output.rb
CHANGED
@@ -52,7 +52,7 @@ module Bitcoin
|
|
52
52
|
payload << PSBT.serialize_to_vector(PSBT_OUT_TYPES[:witness_script], value: witness_script) if witness_script
|
53
53
|
payload << hd_key_paths.values.map{|v|v.to_payload(PSBT_OUT_TYPES[:bip32_derivation])}.join
|
54
54
|
payload << unknowns.map {|k,v|Bitcoin.pack_var_int(k.htb.bytesize) << k.htb << Bitcoin.pack_var_int(v.bytesize) << v}.join
|
55
|
-
payload << PSBT_SEPARATOR.
|
55
|
+
payload << PSBT_SEPARATOR.itb
|
56
56
|
payload
|
57
57
|
end
|
58
58
|
|
@@ -66,7 +66,7 @@ module Bitcoin
|
|
66
66
|
combined = Bitcoin::PSBT::Output.new
|
67
67
|
combined.redeem_script = redeem_script
|
68
68
|
combined.witness_script = witness_script
|
69
|
-
combined.unknowns = unknowns.merge(psbo.unknowns)
|
69
|
+
combined.unknowns = Hash[unknowns.merge(psbo.unknowns).sort]
|
70
70
|
combined.hd_key_paths = hd_key_paths.merge(psbo.hd_key_paths)
|
71
71
|
combined
|
72
72
|
end
|
data/lib/bitcoin/psbt/tx.rb
CHANGED
@@ -86,13 +86,13 @@ module Bitcoin
|
|
86
86
|
# generate payload.
|
87
87
|
# @return [String] a payload with binary format.
|
88
88
|
def to_payload
|
89
|
-
payload = PSBT_MAGIC_BYTES.
|
89
|
+
payload = PSBT_MAGIC_BYTES.itb << 0xff.itb
|
90
90
|
|
91
91
|
payload << PSBT.serialize_to_vector(PSBT_GLOBAL_TYPES[:unsigned_tx], value: tx.to_payload)
|
92
92
|
|
93
93
|
payload << unknowns.map {|k,v|Bitcoin.pack_var_int(k.htb.bytesize) << k.htb << Bitcoin.pack_var_int(v.bytesize) << v}.join
|
94
94
|
|
95
|
-
payload << PSBT_SEPARATOR.
|
95
|
+
payload << PSBT_SEPARATOR.itb
|
96
96
|
|
97
97
|
payload << inputs.map(&:to_payload).join
|
98
98
|
payload << outputs.map(&:to_payload).join
|
@@ -129,6 +129,16 @@ module Bitcoin
|
|
129
129
|
end
|
130
130
|
end
|
131
131
|
|
132
|
+
# Check whether the signer can sign. Specifically, check the following.
|
133
|
+
# * If a non-witness UTXO is provided, its hash must match the hash specified in the prevout
|
134
|
+
# * If a witness UTXO is provided, no non-witness signature may be created
|
135
|
+
# * If a redeemScript is provided, the scriptPubKey must be for that redeemScript
|
136
|
+
# * If a witnessScript is provided, the scriptPubKey or the redeemScript must be for that witnessScript
|
137
|
+
# @return [Boolean]
|
138
|
+
def ready_to_sign?
|
139
|
+
inputs.all?(&:ready_to_sign?)
|
140
|
+
end
|
141
|
+
|
132
142
|
# get signature script of input specified by +index+
|
133
143
|
# @param [Integer] index input index.
|
134
144
|
# @return [Bitcoin::Script]
|
@@ -158,7 +168,8 @@ module Bitcoin
|
|
158
168
|
outputs.each_with_index do |o, index|
|
159
169
|
combined.outputs[index] = o.merge(psbt.outputs[index])
|
160
170
|
end
|
161
|
-
|
171
|
+
|
172
|
+
combined.unknowns = Hash[unknowns.merge(psbt.unknowns).sort]
|
162
173
|
combined
|
163
174
|
end
|
164
175
|
|
data/lib/bitcoin/psbt.rb
CHANGED
@@ -21,7 +21,7 @@ module Bitcoin
|
|
21
21
|
module_function
|
22
22
|
|
23
23
|
def self.serialize_to_vector(key_type, key: nil, value: nil)
|
24
|
-
key_len = key_type.
|
24
|
+
key_len = key_type.itb.bytesize
|
25
25
|
key_len += key.bytesize if key
|
26
26
|
s = Bitcoin.pack_var_int(key_len) << Bitcoin.pack_var_int(key_type)
|
27
27
|
s << key if key
|
@@ -78,23 +78,8 @@ module Bitcoin
|
|
78
78
|
priv_key = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, SecureRandom.random_bytes(32))
|
79
79
|
ret = secp256k1_ec_seckey_verify(context, priv_key)
|
80
80
|
end
|
81
|
-
|
82
|
-
|
83
|
-
result = secp256k1_ec_pubkey_create(context, internal_pubkey, priv_key)
|
84
|
-
raise 'error creating pubkey' unless result
|
85
|
-
|
86
|
-
pubkey = FFI::MemoryPointer.new(:uchar, 65)
|
87
|
-
pubkey_len = FFI::MemoryPointer.new(:uint64)
|
88
|
-
result = if compressed
|
89
|
-
pubkey_len.put_uint64(0, 33)
|
90
|
-
secp256k1_ec_pubkey_serialize(context, pubkey, pubkey_len, internal_pubkey, SECP256K1_EC_COMPRESSED)
|
91
|
-
else
|
92
|
-
pubkey_len.put_uint64(0, 65)
|
93
|
-
secp256k1_ec_pubkey_serialize(context, pubkey, pubkey_len, internal_pubkey, SECP256K1_EC_UNCOMPRESSED)
|
94
|
-
end
|
95
|
-
raise 'error serialize pubkey' unless result || pubkey_len.read_uint64 > 0
|
96
|
-
|
97
|
-
[ priv_key.read_string(32).bth, pubkey.read_string(pubkey_len.read_uint64).bth ]
|
81
|
+
private_key = priv_key.read_string(32).bth
|
82
|
+
[private_key , generate_pubkey_in_context(context, private_key, compressed: compressed) ]
|
98
83
|
end
|
99
84
|
end
|
100
85
|
|
@@ -104,6 +89,12 @@ module Bitcoin
|
|
104
89
|
Bitcoin::Key.new(priv_key: privkey, pubkey: pubkey, compressed: compressed)
|
105
90
|
end
|
106
91
|
|
92
|
+
def generate_pubkey(priv_key, compressed: true)
|
93
|
+
with_context do |context|
|
94
|
+
generate_pubkey_in_context(context, priv_key, compressed: compressed)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
107
98
|
# sign data.
|
108
99
|
# @param [String] data a data to be signed with binary format
|
109
100
|
# @param [String] privkey a private key using sign
|
@@ -159,7 +150,25 @@ module Bitcoin
|
|
159
150
|
end
|
160
151
|
end
|
161
152
|
|
153
|
+
private
|
154
|
+
|
155
|
+
def generate_pubkey_in_context(context, privkey, compressed: true)
|
156
|
+
internal_pubkey = FFI::MemoryPointer.new(:uchar, 64)
|
157
|
+
result = secp256k1_ec_pubkey_create(context, internal_pubkey, privkey.htb)
|
158
|
+
raise 'error creating pubkey' unless result
|
159
|
+
|
160
|
+
pubkey = FFI::MemoryPointer.new(:uchar, 65)
|
161
|
+
pubkey_len = FFI::MemoryPointer.new(:uint64)
|
162
|
+
result = if compressed
|
163
|
+
pubkey_len.put_uint64(0, 33)
|
164
|
+
secp256k1_ec_pubkey_serialize(context, pubkey, pubkey_len, internal_pubkey, SECP256K1_EC_COMPRESSED)
|
165
|
+
else
|
166
|
+
pubkey_len.put_uint64(0, 65)
|
167
|
+
secp256k1_ec_pubkey_serialize(context, pubkey, pubkey_len, internal_pubkey, SECP256K1_EC_UNCOMPRESSED)
|
168
|
+
end
|
169
|
+
raise 'error serialize pubkey' unless result || pubkey_len.read_uint64 > 0
|
170
|
+
pubkey.read_string(pubkey_len.read_uint64).bth
|
171
|
+
end
|
162
172
|
end
|
163
|
-
|
164
173
|
end
|
165
174
|
end
|
@@ -22,6 +22,11 @@ module Bitcoin
|
|
22
22
|
Bitcoin::Key.new(priv_key: privkey, pubkey: pubkey, compressed: compressed)
|
23
23
|
end
|
24
24
|
|
25
|
+
def generate_pubkey(privkey, compressed: true)
|
26
|
+
public_key = ECDSA::Group::Secp256k1.generator.multiply_by_scalar(privkey.to_i(16))
|
27
|
+
ECDSA::Format::PointOctetString.encode(public_key, compression: compressed).bth
|
28
|
+
end
|
29
|
+
|
25
30
|
# sign data.
|
26
31
|
# @param [String] data a data to be signed with binary format
|
27
32
|
# @param [String] privkey a private key using sign
|
data/lib/bitcoin/util.rb
CHANGED
@@ -31,6 +31,7 @@ module Bitcoin
|
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
|
+
# @return an integer for a valid payload, otherwise nil
|
34
35
|
def unpack_var_int(payload)
|
35
36
|
case payload.unpack('C').first
|
36
37
|
when 0xfd
|
@@ -44,15 +45,16 @@ module Bitcoin
|
|
44
45
|
end
|
45
46
|
end
|
46
47
|
|
48
|
+
# @return an integer for a valid payload, otherwise nil
|
47
49
|
def unpack_var_int_from_io(buf)
|
48
|
-
uchar = buf.read(1)
|
50
|
+
uchar = buf.read(1)&.unpack('C')&.first
|
49
51
|
case uchar
|
50
52
|
when 0xfd
|
51
|
-
buf.read(2)
|
53
|
+
buf.read(2)&.unpack('v')&.first
|
52
54
|
when 0xfe
|
53
|
-
buf.read(4)
|
55
|
+
buf.read(4)&.unpack('V')&.first
|
54
56
|
when 0xff
|
55
|
-
buf.read(8)
|
57
|
+
buf.read(8)&.unpack('Q')&.first
|
56
58
|
else
|
57
59
|
uchar
|
58
60
|
end
|
data/lib/bitcoin/version.rb
CHANGED
@@ -140,8 +140,8 @@ module Bitcoin
|
|
140
140
|
|
141
141
|
def validate_params!(account_key, purpose, index)
|
142
142
|
raise 'account_key must be an instance of Bitcoin::ExtPubkey.' unless account_key.is_a?(Bitcoin::ExtPubkey)
|
143
|
-
raise 'Account key and index does not match.' unless account_key.number == (index +
|
144
|
-
version_bytes = Bitcoin::ExtPubkey.version_from_purpose(purpose +
|
143
|
+
raise 'Account key and index does not match.' unless account_key.number == (index + Bitcoin::HARDENED_THRESHOLD)
|
144
|
+
version_bytes = Bitcoin::ExtPubkey.version_from_purpose(purpose + Bitcoin::HARDENED_THRESHOLD)
|
145
145
|
raise 'The purpose and the account key do not match.' unless account_key.version == version_bytes
|
146
146
|
end
|
147
147
|
|
@@ -71,7 +71,7 @@ module Bitcoin
|
|
71
71
|
next
|
72
72
|
end
|
73
73
|
raise ArgumentError.new("#{path} is invalid format.") unless p.delete("'") =~ /^[0-9]+$/
|
74
|
-
num = (p[-1] == "'" ? p.delete("'").to_i +
|
74
|
+
num = (p[-1] == "'" ? p.delete("'").to_i + Bitcoin::HARDENED_THRESHOLD : p.to_i)
|
75
75
|
derived_key = derived_key.derive(num)
|
76
76
|
end
|
77
77
|
derived_key
|
data/lib/bitcoin.rb
CHANGED
data/lib/openassets/payload.rb
CHANGED
@@ -24,14 +24,19 @@ module OpenAssets
|
|
24
24
|
version = buf.read(2)
|
25
25
|
return nil if marker != MARKER || version != VERSION
|
26
26
|
count = Bitcoin.unpack_var_int_from_io(buf)
|
27
|
+
return nil unless count
|
27
28
|
quantities = []
|
28
29
|
count.times do
|
29
30
|
quantities << LEB128.decode_unsigned(buf, buf.pos)
|
30
31
|
end
|
31
32
|
metadata_length = Bitcoin.unpack_var_int_from_io(buf)
|
32
|
-
return nil if buf.length < metadata_length + buf.pos
|
33
|
+
return nil if metadata_length.nil? || buf.length < metadata_length + buf.pos
|
33
34
|
metadata = buf.read(metadata_length).each_byte.map(&:chr).join
|
34
35
|
new(quantities, metadata)
|
36
|
+
rescue
|
37
|
+
# LEB128#decode_unsigned raise 'undefined method `unpack' for nil:NilClass'
|
38
|
+
# for invalid format such as "018f8f" (the most significant bit of the last byte should be 0)
|
39
|
+
nil
|
35
40
|
end
|
36
41
|
|
37
42
|
# generate binary payload
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bitcoinrb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- azuchi
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-04-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ecdsa
|
@@ -182,16 +182,16 @@ dependencies:
|
|
182
182
|
name: protobuf
|
183
183
|
requirement: !ruby/object:Gem::Requirement
|
184
184
|
requirements:
|
185
|
-
- -
|
185
|
+
- - '='
|
186
186
|
- !ruby/object:Gem::Version
|
187
|
-
version:
|
187
|
+
version: 3.8.5
|
188
188
|
type: :runtime
|
189
189
|
prerelease: false
|
190
190
|
version_requirements: !ruby/object:Gem::Requirement
|
191
191
|
requirements:
|
192
|
-
- -
|
192
|
+
- - '='
|
193
193
|
- !ruby/object:Gem::Version
|
194
|
-
version:
|
194
|
+
version: 3.8.5
|
195
195
|
- !ruby/object:Gem::Dependency
|
196
196
|
name: scrypt
|
197
197
|
requirement: !ruby/object:Gem::Requirement
|
@@ -224,16 +224,16 @@ dependencies:
|
|
224
224
|
name: bundler
|
225
225
|
requirement: !ruby/object:Gem::Requirement
|
226
226
|
requirements:
|
227
|
-
- - "
|
227
|
+
- - ">="
|
228
228
|
- !ruby/object:Gem::Version
|
229
|
-
version: '
|
229
|
+
version: '0'
|
230
230
|
type: :development
|
231
231
|
prerelease: false
|
232
232
|
version_requirements: !ruby/object:Gem::Requirement
|
233
233
|
requirements:
|
234
|
-
- - "
|
234
|
+
- - ">="
|
235
235
|
- !ruby/object:Gem::Version
|
236
|
-
version: '
|
236
|
+
version: '0'
|
237
237
|
- !ruby/object:Gem::Dependency
|
238
238
|
name: rake
|
239
239
|
requirement: !ruby/object:Gem::Requirement
|
@@ -439,7 +439,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
439
439
|
- !ruby/object:Gem::Version
|
440
440
|
version: '0'
|
441
441
|
requirements: []
|
442
|
-
rubygems_version: 3.0.
|
442
|
+
rubygems_version: 3.0.3
|
443
443
|
signing_key:
|
444
444
|
specification_version: 4
|
445
445
|
summary: "[WIP]The implementation of Bitcoin Protocol for Ruby."
|