bitcoinrb 0.2.6 → 0.2.7
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/.travis.yml +3 -1
- data/Gemfile +2 -0
- data/README.md +4 -3
- data/lib/bitcoin/psbt/input.rb +24 -12
- data/lib/bitcoin/psbt/output.rb +6 -1
- data/lib/bitcoin/psbt/tx.rb +20 -4
- data/lib/bitcoin/secp256k1/ruby.rb +9 -4
- data/lib/bitcoin/tx.rb +2 -2
- data/lib/bitcoin/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 14d06b76233959dbd16e89459a109982612c8ec6e91b746328fac54bb0d6ddae
|
4
|
+
data.tar.gz: ca60bd4fb4f1075335a0806bfdb5cd829da3f2a2d0b3794012e55ee17c7d417c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d49893ec5f8819dc78c19974bd74e1cf2545a787e8861b212a2801e40135b3c0f22650e46df9d5089bbae47dd9c6b74ce13320763a4107633fce5a1355cbbc5b
|
7
|
+
data.tar.gz: b2d422ecfc721e2e41b87d089dd2e6727f564f1346ae8a05b7e0d0b16247f8ca4b4113190c92d6e6abedb6180c8373289773ee6648963a10dbe9f3b0f726f471
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -9,13 +9,14 @@ NOTE: Bitcoinrb work in progress, and there is a possibility of incompatible cha
|
|
9
9
|
|
10
10
|
Bitcoinrb supports following feature:
|
11
11
|
|
12
|
-
* Bitcoin script interpreter
|
12
|
+
* Bitcoin script interpreter(including [BIP-65](https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki), [BIP-68](https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki), [BIP-112](https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki))
|
13
13
|
* De/serialization of Bitcoin protocol network messages
|
14
14
|
* De/serialization of blocks and transactions
|
15
15
|
* Key generation and verification for ECDSA, including [BIP-32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) and [BIP-39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) supports.
|
16
16
|
* ECDSA signature(RFC6979 -Deterministic ECDSA, LOW-S, LOW-R support)
|
17
|
-
* Segwit support (parsing segwit payload, Bech32 address, sign for segwit tx,
|
18
|
-
*
|
17
|
+
* Segwit support (parsing segwit payload, Bech32 address, sign for segwit tx, [BIP-141](https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki), [BIP-143](https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki), [BIP-144](https://github.com/bitcoin/bips/blob/master/bip-0144.mediawiki))
|
18
|
+
* [BIP-173](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki) Bech32 address support
|
19
|
+
* [BIP-174](https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki) PSBT(Partially Signed Bitcoin Transaction) support
|
19
20
|
* [WIP] SPV node
|
20
21
|
* [WIP] 0ff-chain protocol
|
21
22
|
|
data/lib/bitcoin/psbt/input.rb
CHANGED
@@ -29,9 +29,13 @@ module Bitcoin
|
|
29
29
|
# @return [Bitcoin::PSBTInput] psbt input.
|
30
30
|
def self.parse_from_buf(buf)
|
31
31
|
input = self.new
|
32
|
+
found_sep = false
|
32
33
|
until buf.eof?
|
33
34
|
key_len = Bitcoin.unpack_var_int_from_io(buf)
|
34
|
-
|
35
|
+
if key_len == 0
|
36
|
+
found_sep = true
|
37
|
+
break
|
38
|
+
end
|
35
39
|
key_type = buf.read(1).unpack('C').first
|
36
40
|
key = buf.read(key_len - 1)
|
37
41
|
value = buf.read(Bitcoin.unpack_var_int_from_io(buf))
|
@@ -83,6 +87,7 @@ module Bitcoin
|
|
83
87
|
input.unknowns[unknown_key] = value
|
84
88
|
end
|
85
89
|
end
|
90
|
+
raise ArgumentError, 'Separator is missing at the end of an input map.' unless found_sep
|
86
91
|
input
|
87
92
|
end
|
88
93
|
|
@@ -116,28 +121,35 @@ module Bitcoin
|
|
116
121
|
# Check whether input's scriptPubkey is correct witness.
|
117
122
|
# @return [Boolean]
|
118
123
|
def valid_witness_input?
|
119
|
-
return true if witness_utxo
|
120
|
-
return true if witness_utxo
|
121
|
-
|
122
|
-
|
124
|
+
return true if witness_utxo&.script_pubkey.p2wpkh? # P2WPKH
|
125
|
+
return true if witness_utxo&.script_pubkey.p2wsh? && witness_utxo&.script_pubkey == redeem_script.to_p2wsh # P2WSH
|
126
|
+
# segwit nested in P2SH
|
127
|
+
if witness_utxo&.script_pubkey.p2sh? && redeem_script&.witness_program? && redeem_script.to_p2sh == witness_utxo&.script_pubkey
|
128
|
+
return true if redeem_script.p2wpkh?# nested p2wpkh
|
129
|
+
return true if witness_script&.to_sha256 == redeem_script.witness_data[1].bth # nested p2wsh
|
130
|
+
end
|
123
131
|
false
|
124
132
|
end
|
125
133
|
|
126
134
|
# Check whether input's scriptPubkey is correct witness.
|
127
135
|
# @return [Boolean]
|
128
|
-
def valid_non_witness_input?
|
129
|
-
|
130
|
-
return true if o.script_pubkey.p2sh? && redeem_script.to_p2sh == o.script_pubkey
|
131
|
-
end
|
132
|
-
false
|
136
|
+
def valid_non_witness_input?(utxo)
|
137
|
+
utxo.script_pubkey.p2sh? && redeem_script.to_p2sh == utxo.script_pubkey
|
133
138
|
end
|
134
139
|
|
135
140
|
# Check whether the signer can sign this input.
|
141
|
+
# @param [Bitcoin::TxOut] utxo utxo object which input refers.
|
136
142
|
# @return [Boolean]
|
137
|
-
def ready_to_sign?
|
143
|
+
def ready_to_sign?(utxo)
|
138
144
|
return false unless sane?
|
139
145
|
return valid_witness_input? if witness_utxo
|
140
|
-
valid_non_witness_input? # non_witness_utxo
|
146
|
+
valid_non_witness_input?(utxo) # non_witness_utxo
|
147
|
+
end
|
148
|
+
|
149
|
+
# Checks whether a PSBTInput is already signed.
|
150
|
+
# @return [Boolean] return true if already signed.
|
151
|
+
def signed?
|
152
|
+
final_script_sig || final_script_witness
|
141
153
|
end
|
142
154
|
|
143
155
|
# add signature as partial sig.
|
data/lib/bitcoin/psbt/output.rb
CHANGED
@@ -19,9 +19,13 @@ module Bitcoin
|
|
19
19
|
# @return [Bitcoin::PSBTOutput] psbt output.
|
20
20
|
def self.parse_from_buf(buf)
|
21
21
|
output = self.new
|
22
|
+
found_sep = false
|
22
23
|
until buf.eof?
|
23
24
|
key_len = Bitcoin.unpack_var_int_from_io(buf)
|
24
|
-
|
25
|
+
if key_len == 0
|
26
|
+
found_sep = true
|
27
|
+
break
|
28
|
+
end
|
25
29
|
key_type = buf.read(1).unpack('C').first
|
26
30
|
key = buf.read(key_len - 1)
|
27
31
|
value = buf.read(Bitcoin.unpack_var_int_from_io(buf))
|
@@ -43,6 +47,7 @@ module Bitcoin
|
|
43
47
|
output.unknowns[unknown_key] = value
|
44
48
|
end
|
45
49
|
end
|
50
|
+
raise ArgumentError, 'Separator is missing at the end of an output map.' unless found_sep
|
46
51
|
output
|
47
52
|
end
|
48
53
|
|
data/lib/bitcoin/psbt/tx.rb
CHANGED
@@ -29,11 +29,14 @@ module Bitcoin
|
|
29
29
|
raise ArgumentError, 'Invalid PSBT magic bytes.' unless buf.read(4).unpack('N').first == PSBT_MAGIC_BYTES
|
30
30
|
raise ArgumentError, 'Invalid PSBT separator.' unless buf.read(1).bth.to_i(16) == 0xff
|
31
31
|
partial_tx = self.new
|
32
|
-
|
32
|
+
found_sep = false
|
33
33
|
# read global data.
|
34
34
|
until buf.eof?
|
35
35
|
key_len = Bitcoin.unpack_var_int_from_io(buf)
|
36
|
-
|
36
|
+
if key_len == 0
|
37
|
+
found_sep = true
|
38
|
+
break
|
39
|
+
end
|
37
40
|
key_type = buf.read(1).unpack('C').first
|
38
41
|
key = buf.read(key_len - 1)
|
39
42
|
value = buf.read(Bitcoin.unpack_var_int_from_io(buf))
|
@@ -42,7 +45,7 @@ module Bitcoin
|
|
42
45
|
when PSBT_GLOBAL_TYPES[:unsigned_tx]
|
43
46
|
raise ArgumentError, 'Invalid global transaction typed key.' unless key_len == 1
|
44
47
|
raise ArgumentError, 'Duplicate Key, unsigned tx already provided.' if partial_tx.tx
|
45
|
-
partial_tx.tx = Bitcoin::Tx.parse_from_payload(value)
|
48
|
+
partial_tx.tx = Bitcoin::Tx.parse_from_payload(value, non_witness: true)
|
46
49
|
partial_tx.tx.in.each do |tx_in|
|
47
50
|
raise ArgumentError, 'Unsigned tx does not have empty scriptSigs and scriptWitnesses.' if !tx_in.script_sig.empty? || !tx_in.script_witness.empty?
|
48
51
|
end
|
@@ -52,6 +55,7 @@ module Bitcoin
|
|
52
55
|
end
|
53
56
|
end
|
54
57
|
|
58
|
+
raise ArgumentError, 'Separator is missing at the end of an output map.' unless found_sep
|
55
59
|
raise ArgumentError, 'No unsigned transaction was provided.' unless partial_tx.tx
|
56
60
|
|
57
61
|
# read input data.
|
@@ -83,6 +87,17 @@ module Bitcoin
|
|
83
87
|
partial_tx
|
84
88
|
end
|
85
89
|
|
90
|
+
# Finds the UTXO for a given input index
|
91
|
+
# @param [Integer] index input_index Index of the input to retrieve the UTXO of
|
92
|
+
# @return [Bitcoin::TxOut] The UTXO of the input if found.
|
93
|
+
def input_utxo(index)
|
94
|
+
input = inputs[index]
|
95
|
+
prevout_index = tx.in[index].out_point.index
|
96
|
+
return input.non_witness_utxo.out[prevout_index] if input.non_witness_utxo
|
97
|
+
return input.witness_utxo if input.witness_utxo
|
98
|
+
nil
|
99
|
+
end
|
100
|
+
|
86
101
|
# generate payload.
|
87
102
|
# @return [String] a payload with binary format.
|
88
103
|
def to_payload
|
@@ -136,7 +151,8 @@ module Bitcoin
|
|
136
151
|
# * If a witnessScript is provided, the scriptPubKey or the redeemScript must be for that witnessScript
|
137
152
|
# @return [Boolean]
|
138
153
|
def ready_to_sign?
|
139
|
-
inputs.
|
154
|
+
inputs.each.with_index{|psbt_in, index|return false unless psbt_in.ready_to_sign?(input_utxo(index))}
|
155
|
+
true
|
140
156
|
end
|
141
157
|
|
142
158
|
# get signature script of input specified by +index+
|
@@ -87,17 +87,22 @@ module Bitcoin
|
|
87
87
|
end
|
88
88
|
end
|
89
89
|
|
90
|
+
INITIAL_V = '0101010101010101010101010101010101010101010101010101010101010101'.htb
|
91
|
+
INITIAL_K = '0000000000000000000000000000000000000000000000000000000000000000'.htb
|
92
|
+
ZERO_B = '00'.htb
|
93
|
+
ONE_B = '01'.htb
|
94
|
+
|
90
95
|
# generate temporary key k to be used when ECDSA sign.
|
91
96
|
# https://tools.ietf.org/html/rfc6979#section-3.2
|
92
97
|
def generate_rfc6979_nonce(data, privkey, extra_entropy)
|
93
|
-
v =
|
94
|
-
k =
|
98
|
+
v = INITIAL_V # 3.2.b
|
99
|
+
k = INITIAL_K # 3.2.c
|
95
100
|
# 3.2.d
|
96
|
-
k = Bitcoin.hmac_sha256(k, v +
|
101
|
+
k = Bitcoin.hmac_sha256(k, v + ZERO_B + privkey + data + extra_entropy)
|
97
102
|
# 3.2.e
|
98
103
|
v = Bitcoin.hmac_sha256(k, v)
|
99
104
|
# 3.2.f
|
100
|
-
k = Bitcoin.hmac_sha256(k, v +
|
105
|
+
k = Bitcoin.hmac_sha256(k, v + ONE_B + privkey + data + extra_entropy)
|
101
106
|
# 3.2.g
|
102
107
|
v = Bitcoin.hmac_sha256(k, v)
|
103
108
|
# 3.2.h
|
data/lib/bitcoin/tx.rb
CHANGED
@@ -31,14 +31,14 @@ module Bitcoin
|
|
31
31
|
alias_method :in, :inputs
|
32
32
|
alias_method :out, :outputs
|
33
33
|
|
34
|
-
def self.parse_from_payload(payload)
|
34
|
+
def self.parse_from_payload(payload, non_witness: false)
|
35
35
|
buf = payload.is_a?(String) ? StringIO.new(payload) : payload
|
36
36
|
tx = new
|
37
37
|
tx.version = buf.read(4).unpack('V').first
|
38
38
|
|
39
39
|
in_count = Bitcoin.unpack_var_int_from_io(buf)
|
40
40
|
witness = false
|
41
|
-
if in_count.zero?
|
41
|
+
if in_count.zero? && !non_witness
|
42
42
|
tx.marker = 0
|
43
43
|
tx.flag = buf.read(1).unpack('c').first
|
44
44
|
if tx.flag.zero?
|
data/lib/bitcoin/version.rb
CHANGED
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.7
|
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-05-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ecdsa
|