tapyrus 0.2.2 → 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 +5 -3
- data/README.md +1 -1
- data/lib/tapyrus.rb +1 -8
- data/lib/tapyrus/ext/ecdsa.rb +1 -1
- data/lib/tapyrus/key.rb +10 -32
- data/lib/tapyrus/script/color.rb +10 -2
- data/lib/tapyrus/script/script.rb +36 -0
- data/lib/tapyrus/secp256k1/native.rb +93 -20
- data/lib/tapyrus/secp256k1/ruby.rb +59 -24
- data/lib/tapyrus/util.rb +15 -0
- data/lib/tapyrus/version.rb +1 -1
- data/tapyrusrb.gemspec +2 -4
- metadata +5 -33
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 15ad1708c6361b20c98632d45f81d2ad445114b45123fbc5acc2c8da2fc01c1b
|
4
|
+
data.tar.gz: 74a754e7045b6a2475eeb913b79acee31fe882ac8bda39918c774017e1d0cb4e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e71234f42f008a4e81ab87652ffe1e386303b0e0a731fce90a84e7e77fb40ef6549f777762970d6dbbb380d8f6d6fa5f1d4af2a7e42038d8a210221317eb6d33
|
7
|
+
data.tar.gz: 21c7fbefd23b4fb42d4dc9400917c2d42650db8b7dfaa09bb5d96ed14f2d04a707fa749e8964c69b6c297261875f30f2e0a0a6e2b7c1a702e607e9bce537fd49
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -12,7 +12,7 @@ Tapyrusrb supports following feature:
|
|
12
12
|
* Tapyrus script interpreter
|
13
13
|
* De/serialization of Tapyrus protocol network messages
|
14
14
|
* De/serialization of blocks and transactions
|
15
|
-
* Key generation and verification for ECDSA
|
15
|
+
* Key generation and verification for Schnorr and 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
17
|
* [WIP] SPV node
|
18
18
|
* [WIP] 0ff-chain protocol
|
data/lib/tapyrus.rb
CHANGED
@@ -118,14 +118,7 @@ module Tapyrus
|
|
118
118
|
|
119
119
|
# get opcode
|
120
120
|
def opcode
|
121
|
-
|
122
|
-
when Encoding::ASCII_8BIT
|
123
|
-
each_byte.next
|
124
|
-
when Encoding::US_ASCII
|
125
|
-
ord
|
126
|
-
else
|
127
|
-
to_i
|
128
|
-
end
|
121
|
+
force_encoding(Encoding::ASCII_8BIT).ord
|
129
122
|
end
|
130
123
|
|
131
124
|
def opcode?
|
data/lib/tapyrus/ext/ecdsa.rb
CHANGED
@@ -29,7 +29,7 @@ module ::ECDSA::Format::PointOctetString
|
|
29
29
|
when 4
|
30
30
|
decode_uncompressed string, group
|
31
31
|
when 6..7
|
32
|
-
raise DecodeError, 'Unrecognized start byte for point octet string: 0x%x' % string[0].ord unless allow_hybrid
|
32
|
+
raise ECDSA::Format::DecodeError, 'Unrecognized start byte for point octet string: 0x%x' % string[0].ord unless allow_hybrid
|
33
33
|
decode_uncompressed string, group if allow_hybrid
|
34
34
|
else
|
35
35
|
raise ECDSA::Format::DecodeError, 'Unrecognized start byte for point octet string: 0x%x' % string[0].ord
|
data/lib/tapyrus/key.rb
CHANGED
@@ -96,10 +96,13 @@ module Tapyrus
|
|
96
96
|
# @return [String] signature data with binary format
|
97
97
|
def sign(data, low_r = true, extra_entropy = nil, algo: :ecdsa)
|
98
98
|
raise ArgumentError, "Unsupported algorithm has been specified." unless SIG_ALGO.include?(algo)
|
99
|
-
|
99
|
+
case algo
|
100
|
+
when :ecdsa
|
100
101
|
sign_ecdsa(data, low_r, extra_entropy)
|
102
|
+
when :schnorr
|
103
|
+
secp256k1_module.sign_data(data, priv_key, extra_entropy, algo: algo)
|
101
104
|
else
|
102
|
-
|
105
|
+
false
|
103
106
|
end
|
104
107
|
end
|
105
108
|
|
@@ -112,11 +115,8 @@ module Tapyrus
|
|
112
115
|
return false unless valid_pubkey?
|
113
116
|
begin
|
114
117
|
raise ArgumentError, "Unsupported algorithm has been specified." unless SIG_ALGO.include?(algo)
|
115
|
-
if algo == :ecdsa
|
116
|
-
|
117
|
-
else
|
118
|
-
verify_schnorr_sig(sig, origin)
|
119
|
-
end
|
118
|
+
sig = ecdsa_signature_parse_der_lax(sig) if algo == :ecdsa
|
119
|
+
secp256k1_module.verify_sig(origin, sig, pubkey, algo: algo)
|
120
120
|
rescue Exception
|
121
121
|
false
|
122
122
|
end
|
@@ -225,13 +225,7 @@ module Tapyrus
|
|
225
225
|
|
226
226
|
# fully validate whether this is a valid public key (more expensive than IsValid())
|
227
227
|
def fully_valid_pubkey?(allow_hybrid = false)
|
228
|
-
|
229
|
-
begin
|
230
|
-
point = ECDSA::Format::PointOctetString.decode(pubkey.htb, ECDSA::Group::Secp256k1, allow_hybrid: allow_hybrid)
|
231
|
-
ECDSA::Group::Secp256k1.valid_public_key?(point)
|
232
|
-
rescue ECDSA::Format::DecodeError
|
233
|
-
false
|
234
|
-
end
|
228
|
+
valid_pubkey? && secp256k1_module.parse_ec_pubkey?(pubkey, allow_hybrid)
|
235
229
|
end
|
236
230
|
|
237
231
|
private
|
@@ -292,34 +286,18 @@ module Tapyrus
|
|
292
286
|
|
293
287
|
# generate ecdsa signature
|
294
288
|
def sign_ecdsa(data, low_r, extra_entropy)
|
295
|
-
sig = secp256k1_module.sign_data(data, priv_key, extra_entropy)
|
289
|
+
sig = secp256k1_module.sign_data(data, priv_key, extra_entropy, algo: :ecdsa)
|
296
290
|
if low_r && !sig_has_low_r?(sig)
|
297
291
|
counter = 1
|
298
292
|
until sig_has_low_r?(sig)
|
299
293
|
extra_entropy = [counter].pack('I*').bth.ljust(64, '0').htb
|
300
|
-
sig = secp256k1_module.sign_data(data, priv_key, extra_entropy)
|
294
|
+
sig = secp256k1_module.sign_data(data, priv_key, extra_entropy, algo: :ecdsa)
|
301
295
|
counter += 1
|
302
296
|
end
|
303
297
|
end
|
304
298
|
sig
|
305
299
|
end
|
306
300
|
|
307
|
-
# generate schnorr signature
|
308
|
-
def sign_schnorr(msg)
|
309
|
-
Schnorr.sign(msg, priv_key.to_i(16)).encode
|
310
|
-
end
|
311
|
-
|
312
|
-
# verify ecdsa signature
|
313
|
-
def verify_ecdsa_sig(sig, message)
|
314
|
-
sig = ecdsa_signature_parse_der_lax(sig)
|
315
|
-
secp256k1_module.verify_sig(message, sig, pubkey)
|
316
|
-
end
|
317
|
-
|
318
|
-
# verify schnorr signature
|
319
|
-
def verify_schnorr_sig(sig, message)
|
320
|
-
Schnorr.valid_sig?(message, sig, pubkey.htb)
|
321
|
-
end
|
322
|
-
|
323
301
|
end
|
324
302
|
|
325
303
|
end
|
data/lib/tapyrus/script/color.rb
CHANGED
@@ -43,6 +43,14 @@ module Tapyrus
|
|
43
43
|
true
|
44
44
|
end
|
45
45
|
|
46
|
+
def hash
|
47
|
+
to_payload.hash
|
48
|
+
end
|
49
|
+
|
50
|
+
def eql?(other)
|
51
|
+
to_payload.eql?(other.to_payload)
|
52
|
+
end
|
53
|
+
|
46
54
|
private
|
47
55
|
|
48
56
|
def initialize(type, payload)
|
@@ -53,11 +61,11 @@ module Tapyrus
|
|
53
61
|
|
54
62
|
module ColoredOutput
|
55
63
|
def colored?
|
56
|
-
script_pubkey.
|
64
|
+
script_pubkey.colored?
|
57
65
|
end
|
58
66
|
|
59
67
|
def color_id
|
60
|
-
@color_id ||=
|
68
|
+
@color_id ||= script_pubkey.color_id
|
61
69
|
end
|
62
70
|
|
63
71
|
def reissuable?
|
@@ -75,6 +75,18 @@ module Tapyrus
|
|
75
75
|
end
|
76
76
|
end
|
77
77
|
|
78
|
+
# Remove color identifier from cp2pkh or cp2sh
|
79
|
+
# @param [ColorIdentifier] color identifier
|
80
|
+
# @return [Script] P2PKH or P2SH script
|
81
|
+
# @raise [RuntimeError] if script is neither cp2pkh nor cp2sh
|
82
|
+
def remove_color
|
83
|
+
raise RuntimeError, 'Only cp2pkh and cp2sh can remove color' unless cp2pkh? or cp2sh?
|
84
|
+
|
85
|
+
Tapyrus::Script.new.tap do |s|
|
86
|
+
s.chunks = self.chunks[2..-1]
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
78
90
|
def get_multisig_pubkeys
|
79
91
|
num = Tapyrus::Opcodes.opcode_to_small_int(chunks[-2].bth.to_i(16))
|
80
92
|
(1..num).map{ |i| chunks[i].pushed_data }
|
@@ -118,6 +130,12 @@ module Tapyrus
|
|
118
130
|
Tapyrus::Script.to_p2pkh(hex)
|
119
131
|
when Tapyrus.chain_params.p2sh_version
|
120
132
|
Tapyrus::Script.to_p2sh(hex)
|
133
|
+
when Tapyrus.chain_params.cp2pkh_version
|
134
|
+
color = Tapyrus::Color::ColorIdentifier.parse_from_payload(hex[0..65].htb)
|
135
|
+
Tapyrus::Script.to_cp2pkh(color, hex[66..-1])
|
136
|
+
when Tapyrus.chain_params.cp2sh_version
|
137
|
+
color = Tapyrus::Color::ColorIdentifier.parse_from_payload(hex[0..65].htb)
|
138
|
+
Tapyrus::Script.to_cp2sh(color, hex[66..-1])
|
121
139
|
else
|
122
140
|
throw e
|
123
141
|
end
|
@@ -214,6 +232,8 @@ module Tapyrus
|
|
214
232
|
(chunks.size == 1 || chunks[1].opcode <= OP_16)
|
215
233
|
end
|
216
234
|
|
235
|
+
# Return whether this script is a CP2PKH format script or not.
|
236
|
+
# @return [Boolean] true if this script is cp2pkh, otherwise false.
|
217
237
|
def cp2pkh?
|
218
238
|
return false unless chunks.size == 7
|
219
239
|
return false unless chunks[0].bytesize == 34
|
@@ -223,6 +243,8 @@ module Tapyrus
|
|
223
243
|
(chunks[2..3]+ chunks[5..6]).map(&:ord) && chunks[4].bytesize == 21
|
224
244
|
end
|
225
245
|
|
246
|
+
# Return whether this script is a CP2SH format script or not.
|
247
|
+
# @return [Boolean] true if this script is cp2pkh, otherwise false.
|
226
248
|
def cp2sh?
|
227
249
|
return false unless chunks.size == 5
|
228
250
|
return false unless chunks[0].bytesize == 34
|
@@ -230,6 +252,20 @@ module Tapyrus
|
|
230
252
|
return false unless chunks[1].ord == OP_COLOR
|
231
253
|
OP_HASH160 == chunks[2].ord && OP_EQUAL == chunks[4].ord && chunks[3].bytesize == 21
|
232
254
|
end
|
255
|
+
|
256
|
+
# Return whether this script represents colored coin.
|
257
|
+
# @return [Boolean] true if this script is colored, otherwise false.
|
258
|
+
def colored?
|
259
|
+
cp2pkh? || cp2sh?
|
260
|
+
end
|
261
|
+
|
262
|
+
# Return color identifier for this script.
|
263
|
+
# @return [ColorIdentifer] color identifier for this script if this script is colored. return nil if this script is not colored.
|
264
|
+
def color_id
|
265
|
+
return nil unless colored?
|
266
|
+
|
267
|
+
Tapyrus::Color::ColorIdentifier.parse_from_payload(chunks[0].pushed_data)
|
268
|
+
end
|
233
269
|
|
234
270
|
def op_return_data
|
235
271
|
return nil unless op_return?
|
@@ -4,8 +4,8 @@
|
|
4
4
|
module Tapyrus
|
5
5
|
module Secp256k1
|
6
6
|
|
7
|
-
# binding for secp256k1 (https://github.com/
|
8
|
-
# tag: v0.
|
7
|
+
# binding for secp256k1 (https://github.com/chaintope/tapyrus-core/tree/v0.4.0/src/secp256k1)
|
8
|
+
# tag: v0.4.0
|
9
9
|
# this is not included by default, to enable set shared object path to ENV['SECP256K1_LIB_PATH']
|
10
10
|
# for linux, ENV['SECP256K1_LIB_PATH'] = '/usr/local/lib/libsecp256k1.so'
|
11
11
|
# for mac,
|
@@ -50,6 +50,8 @@ module Tapyrus
|
|
50
50
|
attach_function(:secp256k1_ecdsa_signature_parse_der, [:pointer, :pointer, :pointer, :size_t], :int)
|
51
51
|
attach_function(:secp256k1_ecdsa_signature_normalize, [:pointer, :pointer, :pointer], :int)
|
52
52
|
attach_function(:secp256k1_ecdsa_verify, [:pointer, :pointer, :pointer, :pointer], :int)
|
53
|
+
attach_function(:secp256k1_schnorr_sign, [:pointer, :pointer, :pointer, :pointer, :pointer, :pointer], :int)
|
54
|
+
attach_function(:secp256k1_schnorr_verify, [:pointer, :pointer, :pointer, :pointer], :int)
|
53
55
|
end
|
54
56
|
|
55
57
|
def with_context(flags: (SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN))
|
@@ -100,7 +102,68 @@ module Tapyrus
|
|
100
102
|
# @param [String] privkey a private key using sign
|
101
103
|
# @param [String] extra_entropy a extra entropy for rfc6979
|
102
104
|
# @return [String] signature data with binary format
|
103
|
-
def sign_data(data, privkey, extra_entropy)
|
105
|
+
def sign_data(data, privkey, extra_entropy, algo: :ecdsa)
|
106
|
+
case algo
|
107
|
+
when :ecdsa
|
108
|
+
sign_ecdsa(data, privkey, extra_entropy)
|
109
|
+
when :schnorr
|
110
|
+
sign_schnorr(data, privkey)
|
111
|
+
else
|
112
|
+
nil
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# verify signature.
|
117
|
+
# @param[String] data a data.
|
118
|
+
# @param [String] sig signature data with binary format
|
119
|
+
# @param [String] pub_key a public key using verify.
|
120
|
+
def verify_sig(data, sig, pub_key, algo: :ecdsa)
|
121
|
+
case algo
|
122
|
+
when :ecdsa
|
123
|
+
verify_ecdsa(data, sig, pub_key)
|
124
|
+
when :schnorr
|
125
|
+
verify_schnorr(data, sig, pub_key)
|
126
|
+
else
|
127
|
+
false
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# # validate whether this is a valid public key (more expensive than IsValid())
|
132
|
+
# @param [String] pub_key public key with hex format.
|
133
|
+
# @param [Boolean] allow_hybrid whether support hybrid public key.
|
134
|
+
# @return [Boolean] If valid public key return true, otherwise false.
|
135
|
+
def parse_ec_pubkey?(pub_key, allow_hybrid = false)
|
136
|
+
pub_key = pub_key.htb
|
137
|
+
return false if !allow_hybrid && ![0x02, 0x03, 0x04].include?(pub_key[0].ord)
|
138
|
+
with_context do |context|
|
139
|
+
pubkey = FFI::MemoryPointer.new(:uchar, pub_key.bytesize).put_bytes(0, pub_key)
|
140
|
+
internal_pubkey = FFI::MemoryPointer.new(:uchar, 64)
|
141
|
+
result = secp256k1_ec_pubkey_parse(context, internal_pubkey, pubkey, pub_key.bytesize)
|
142
|
+
result == 1
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
private
|
147
|
+
|
148
|
+
def generate_pubkey_in_context(context, privkey, compressed: true)
|
149
|
+
internal_pubkey = FFI::MemoryPointer.new(:uchar, 64)
|
150
|
+
result = secp256k1_ec_pubkey_create(context, internal_pubkey, privkey.htb)
|
151
|
+
raise 'error creating pubkey' unless result
|
152
|
+
|
153
|
+
pubkey = FFI::MemoryPointer.new(:uchar, 65)
|
154
|
+
pubkey_len = FFI::MemoryPointer.new(:uint64)
|
155
|
+
result = if compressed
|
156
|
+
pubkey_len.put_uint64(0, 33)
|
157
|
+
secp256k1_ec_pubkey_serialize(context, pubkey, pubkey_len, internal_pubkey, SECP256K1_EC_COMPRESSED)
|
158
|
+
else
|
159
|
+
pubkey_len.put_uint64(0, 65)
|
160
|
+
secp256k1_ec_pubkey_serialize(context, pubkey, pubkey_len, internal_pubkey, SECP256K1_EC_UNCOMPRESSED)
|
161
|
+
end
|
162
|
+
raise 'error serialize pubkey' unless result || pubkey_len.read_uint64 > 0
|
163
|
+
pubkey.read_string(pubkey_len.read_uint64).bth
|
164
|
+
end
|
165
|
+
|
166
|
+
def sign_ecdsa(data, privkey, extra_entropy)
|
104
167
|
with_context do |context|
|
105
168
|
secret = FFI::MemoryPointer.new(:uchar, privkey.htb.bytesize).put_bytes(0, privkey.htb)
|
106
169
|
raise 'priv_key invalid' unless secp256k1_ec_seckey_verify(context, secret)
|
@@ -126,7 +189,19 @@ module Tapyrus
|
|
126
189
|
end
|
127
190
|
end
|
128
191
|
|
129
|
-
def
|
192
|
+
def sign_schnorr(data, privkey)
|
193
|
+
with_context do |context|
|
194
|
+
secret = FFI::MemoryPointer.new(:uchar, privkey.htb.bytesize).put_bytes(0, privkey.htb)
|
195
|
+
raise 'priv_key invalid' unless secp256k1_ec_seckey_verify(context, secret)
|
196
|
+
|
197
|
+
signature = FFI::MemoryPointer.new(:uchar, 64)
|
198
|
+
msg32 = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, data)
|
199
|
+
raise 'Failed to generate schnorr signature.' unless secp256k1_schnorr_sign(context, signature, msg32, secret, nil, nil) == 1
|
200
|
+
signature.read_string(64)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
def verify_ecdsa(data, sig, pub_key)
|
130
205
|
with_context do |context|
|
131
206
|
return false if data.bytesize == 0
|
132
207
|
|
@@ -150,25 +225,23 @@ module Tapyrus
|
|
150
225
|
end
|
151
226
|
end
|
152
227
|
|
153
|
-
|
228
|
+
def verify_schnorr(data, sig, pub_key)
|
229
|
+
with_context do |context|
|
230
|
+
return false if data.bytesize == 0
|
231
|
+
pubkey = FFI::MemoryPointer.new(:uchar, pub_key.htb.bytesize).put_bytes(0, pub_key.htb)
|
232
|
+
internal_pubkey = FFI::MemoryPointer.new(:uchar, 64)
|
233
|
+
result = secp256k1_ec_pubkey_parse(context, internal_pubkey, pubkey, pubkey.size)
|
234
|
+
return false unless result
|
154
235
|
|
155
|
-
|
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
|
236
|
+
signature = FFI::MemoryPointer.new(:uchar, sig.bytesize).put_bytes(0, sig)
|
159
237
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
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
|
238
|
+
msg32 = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, data)
|
239
|
+
result = secp256k1_schnorr_verify(context, signature, msg32, internal_pubkey)
|
240
|
+
|
241
|
+
result == 1
|
242
|
+
end
|
171
243
|
end
|
244
|
+
|
172
245
|
end
|
173
246
|
end
|
174
247
|
end
|
@@ -31,7 +31,64 @@ module Tapyrus
|
|
31
31
|
# @param [String] data a data to be signed with binary format
|
32
32
|
# @param [String] privkey a private key using sign
|
33
33
|
# @return [String] signature data with binary format
|
34
|
-
def sign_data(data, privkey, extra_entropy)
|
34
|
+
def sign_data(data, privkey, extra_entropy, algo: :ecdsa)
|
35
|
+
case algo
|
36
|
+
when :ecdsa
|
37
|
+
sign_ecdsa(data, privkey, extra_entropy)
|
38
|
+
when :schnorr
|
39
|
+
Schnorr.sign(data, privkey.to_i(16)).encode
|
40
|
+
else
|
41
|
+
nil
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# verify signature using public key
|
46
|
+
# @param [String] digest a SHA-256 message digest with binary format
|
47
|
+
# @param [String] sig a signature for +data+ with binary format
|
48
|
+
# @param [String] pubkey a public key corresponding to the private key used for sign
|
49
|
+
# @return [Boolean] verify result
|
50
|
+
def verify_sig(digest, sig, pubkey, algo: :ecdsa)
|
51
|
+
case algo
|
52
|
+
when :ecdsa
|
53
|
+
verify_ecdsa(digest, sig, pubkey)
|
54
|
+
when :schnorr
|
55
|
+
Schnorr.valid_sig?(digest, sig, pubkey.htb)
|
56
|
+
else
|
57
|
+
false
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
alias :valid_sig? :verify_sig
|
62
|
+
|
63
|
+
module_function :valid_sig?
|
64
|
+
|
65
|
+
# validate whether this is a valid public key (more expensive than IsValid())
|
66
|
+
# @param [String] pubkey public key with hex format.
|
67
|
+
# @param [Boolean] allow_hybrid whether support hybrid public key.
|
68
|
+
# @return [Boolean] If valid public key return true, otherwise false.
|
69
|
+
def parse_ec_pubkey?(pubkey, allow_hybrid = false)
|
70
|
+
begin
|
71
|
+
point = ECDSA::Format::PointOctetString.decode(pubkey.htb, ECDSA::Group::Secp256k1, allow_hybrid: allow_hybrid)
|
72
|
+
ECDSA::Group::Secp256k1.valid_public_key?(point)
|
73
|
+
rescue ECDSA::Format::DecodeError
|
74
|
+
false
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# if +pubkey+ is hybrid public key format, it convert uncompressed format.
|
79
|
+
# https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2012-June/001578.html
|
80
|
+
def repack_pubkey(pubkey)
|
81
|
+
p = pubkey.htb
|
82
|
+
case p[0]
|
83
|
+
when "\x06", "\x07"
|
84
|
+
p[0] = "\x04"
|
85
|
+
p
|
86
|
+
else
|
87
|
+
pubkey.htb
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def sign_ecdsa(data, privkey, extra_entropy)
|
35
92
|
privkey = privkey.htb
|
36
93
|
private_key = ECDSA::Format::IntegerOctetString.decode(privkey)
|
37
94
|
extra_entropy ||= ''
|
@@ -59,12 +116,7 @@ module Tapyrus
|
|
59
116
|
signature
|
60
117
|
end
|
61
118
|
|
62
|
-
|
63
|
-
# @param [String] digest a SHA-256 message digest with binary format
|
64
|
-
# @param [String] sig a signature for +data+ with binary format
|
65
|
-
# @param [String] pubkey a public key corresponding to the private key used for sign
|
66
|
-
# @return [Boolean] verify result
|
67
|
-
def verify_sig(digest, sig, pubkey)
|
119
|
+
def verify_ecdsa(digest, sig, pubkey)
|
68
120
|
begin
|
69
121
|
k = ECDSA::Format::PointOctetString.decode(repack_pubkey(pubkey), GROUP)
|
70
122
|
signature = ECDSA::Format::SignatureDerString.decode(sig)
|
@@ -74,23 +126,6 @@ module Tapyrus
|
|
74
126
|
end
|
75
127
|
end
|
76
128
|
|
77
|
-
alias :valid_sig? :verify_sig
|
78
|
-
|
79
|
-
module_function :valid_sig?
|
80
|
-
|
81
|
-
# if +pubkey+ is hybrid public key format, it convert uncompressed format.
|
82
|
-
# https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2012-June/001578.html
|
83
|
-
def repack_pubkey(pubkey)
|
84
|
-
p = pubkey.htb
|
85
|
-
case p[0]
|
86
|
-
when "\x06", "\x07"
|
87
|
-
p[0] = "\x04"
|
88
|
-
p
|
89
|
-
else
|
90
|
-
pubkey.htb
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
129
|
end
|
95
130
|
|
96
131
|
end
|
data/lib/tapyrus/util.rb
CHANGED
@@ -113,6 +113,9 @@ module Tapyrus
|
|
113
113
|
if hex.size == 50 && calc_checksum(hex[0...-8]) == hex[-8..-1]
|
114
114
|
raise 'Invalid version bytes.' unless [Tapyrus.chain_params.address_version, Tapyrus.chain_params.p2sh_version].include?(hex[0..1])
|
115
115
|
[hex[2...-8], hex[0..1]]
|
116
|
+
elsif hex.size == 116 && calc_checksum(hex[0...-8]) == hex[-8..-1]
|
117
|
+
raise 'Invalid version bytes.' unless [Tapyrus.chain_params.cp2pkh_version, Tapyrus.chain_params.cp2sh_version].include?(hex[0..1])
|
118
|
+
[hex[2...-8], hex[0..1]]
|
116
119
|
else
|
117
120
|
raise 'Invalid address.'
|
118
121
|
end
|
@@ -128,6 +131,18 @@ module Tapyrus
|
|
128
131
|
OpenSSL::HMAC.digest(DIGEST_NAME_SHA256, key, data)
|
129
132
|
end
|
130
133
|
|
134
|
+
# check whether +addr+ is valid address.
|
135
|
+
# @param [String] addr an address
|
136
|
+
# @return [Boolean] if valid address return true, otherwise false.
|
137
|
+
def valid_address?(addr)
|
138
|
+
begin
|
139
|
+
Tapyrus::Script.parse_from_addr(addr)
|
140
|
+
true
|
141
|
+
rescue Exception => e
|
142
|
+
false
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
131
146
|
end
|
132
147
|
|
133
148
|
module HexConverter
|
data/lib/tapyrus/version.rb
CHANGED
data/tapyrusrb.gemspec
CHANGED
@@ -10,8 +10,8 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.authors = ["azuchi"]
|
11
11
|
spec.email = ["azuchi@chaintope.com"]
|
12
12
|
|
13
|
-
spec.summary = %q{
|
14
|
-
spec.description = %q{
|
13
|
+
spec.summary = %q{The implementation of Tapyrus Protocol for Ruby.}
|
14
|
+
spec.description = %q{The implementation of Tapyrus Protocol for Ruby.}
|
15
15
|
spec.homepage = 'https://github.com/chaintope/tapyrusrb'
|
16
16
|
spec.license = "MIT"
|
17
17
|
|
@@ -30,8 +30,6 @@ Gem::Specification.new do |spec|
|
|
30
30
|
spec.add_runtime_dependency 'eventmachine_httpserver'
|
31
31
|
spec.add_runtime_dependency 'iniparse'
|
32
32
|
spec.add_runtime_dependency 'siphash'
|
33
|
-
spec.add_runtime_dependency 'protobuf', '3.8.5'
|
34
|
-
spec.add_runtime_dependency 'scrypt'
|
35
33
|
spec.add_runtime_dependency 'activesupport', '>= 5.2.3'
|
36
34
|
spec.add_runtime_dependency 'json_pure', '>= 2.3.1'
|
37
35
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tapyrus
|
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:
|
11
|
+
date: 2021-03-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ecdsa
|
@@ -150,34 +150,6 @@ dependencies:
|
|
150
150
|
- - ">="
|
151
151
|
- !ruby/object:Gem::Version
|
152
152
|
version: '0'
|
153
|
-
- !ruby/object:Gem::Dependency
|
154
|
-
name: protobuf
|
155
|
-
requirement: !ruby/object:Gem::Requirement
|
156
|
-
requirements:
|
157
|
-
- - '='
|
158
|
-
- !ruby/object:Gem::Version
|
159
|
-
version: 3.8.5
|
160
|
-
type: :runtime
|
161
|
-
prerelease: false
|
162
|
-
version_requirements: !ruby/object:Gem::Requirement
|
163
|
-
requirements:
|
164
|
-
- - '='
|
165
|
-
- !ruby/object:Gem::Version
|
166
|
-
version: 3.8.5
|
167
|
-
- !ruby/object:Gem::Dependency
|
168
|
-
name: scrypt
|
169
|
-
requirement: !ruby/object:Gem::Requirement
|
170
|
-
requirements:
|
171
|
-
- - ">="
|
172
|
-
- !ruby/object:Gem::Version
|
173
|
-
version: '0'
|
174
|
-
type: :runtime
|
175
|
-
prerelease: false
|
176
|
-
version_requirements: !ruby/object:Gem::Requirement
|
177
|
-
requirements:
|
178
|
-
- - ">="
|
179
|
-
- !ruby/object:Gem::Version
|
180
|
-
version: '0'
|
181
153
|
- !ruby/object:Gem::Dependency
|
182
154
|
name: activesupport
|
183
155
|
requirement: !ruby/object:Gem::Requirement
|
@@ -290,7 +262,7 @@ dependencies:
|
|
290
262
|
- - "~>"
|
291
263
|
- !ruby/object:Gem::Version
|
292
264
|
version: '3.0'
|
293
|
-
description:
|
265
|
+
description: The implementation of Tapyrus Protocol for Ruby.
|
294
266
|
email:
|
295
267
|
- azuchi@chaintope.com
|
296
268
|
executables:
|
@@ -449,8 +421,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
449
421
|
- !ruby/object:Gem::Version
|
450
422
|
version: '0'
|
451
423
|
requirements: []
|
452
|
-
rubygems_version: 3.0.
|
424
|
+
rubygems_version: 3.0.6
|
453
425
|
signing_key:
|
454
426
|
specification_version: 4
|
455
|
-
summary:
|
427
|
+
summary: The implementation of Tapyrus Protocol for Ruby.
|
456
428
|
test_files: []
|