bitcoinrb 0.2.5 → 0.2.6
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.
- 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."
|