tapyrus 0.2.2 → 0.2.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a1abedf80b636e2bfd80db4617ca9f92e703148f07e59c08b14860c13ac57689
4
- data.tar.gz: 21b478051eb01354e410475e15761f24773fe164fcd9abf3307acb231b5c8ae3
3
+ metadata.gz: 15ad1708c6361b20c98632d45f81d2ad445114b45123fbc5acc2c8da2fc01c1b
4
+ data.tar.gz: 74a754e7045b6a2475eeb913b79acee31fe882ac8bda39918c774017e1d0cb4e
5
5
  SHA512:
6
- metadata.gz: 61c8cc2439074666abffc6ff85ffaa40811e8e0992edb19846876dabf9a300f4822af522a6f621271f310a9b1ea3f9429f30e86452d29b0f2216052568a72a6a
7
- data.tar.gz: f3845015c030c7ccf915700eb45ac2f743c3f0c19dbe077c72c4afe19327252d1f3a64ffb29c1f5790997c8f6f2317930ab5ae99a894687a86f6381154c5429d
6
+ metadata.gz: e71234f42f008a4e81ab87652ffe1e386303b0e0a731fce90a84e7e77fb40ef6549f777762970d6dbbb380d8f6d6fa5f1d4af2a7e42038d8a210221317eb6d33
7
+ data.tar.gz: 21c7fbefd23b4fb42d4dc9400917c2d42650db8b7dfaa09bb5d96ed14f2d04a707fa749e8964c69b6c297261875f30f2e0a0a6e2b7c1a702e607e9bce537fd49
data/.travis.yml CHANGED
@@ -1,8 +1,10 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.4.6
4
- - 2.5.5
5
- - 2.6.3
3
+ - 2.4.10
4
+ - 2.5.8
5
+ - 2.6.6
6
+ - 2.7.2
7
+ - 3.0.0
6
8
  addons:
7
9
  apt:
8
10
  packages:
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, 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.
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
- case encoding
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?
@@ -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
- if algo == :ecdsa
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
- sign_schnorr(data)
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
- verify_ecdsa_sig(sig, origin)
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
- return false unless valid_pubkey?
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
@@ -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.cp2pkh? || script_pubkey.cp2sh?
64
+ script_pubkey.colored?
57
65
  end
58
66
 
59
67
  def color_id
60
- @color_id ||= ColorIdentifier.parse_from_payload(script_pubkey.chunks[0].pushed_data)
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/bitcoin/bitcoin/tree/v0.14.2/src/secp256k1)
8
- # tag: v0.14.2
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 verify_sig(data, sig, pub_key)
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
- private
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
- 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
236
+ signature = FFI::MemoryPointer.new(:uchar, sig.bytesize).put_bytes(0, sig)
159
237
 
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
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
- # verify signature using public key
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
@@ -1,3 +1,3 @@
1
1
  module Tapyrus
2
- VERSION = "0.2.2"
2
+ VERSION = "0.2.7"
3
3
  end
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{[WIP]The implementation of Tapyrus Protocol for Ruby.}
14
- spec.description = %q{[WIP]The implementation of Tapyrus Protocol for Ruby.}
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.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: 2020-09-10 00:00:00.000000000 Z
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: "[WIP]The implementation of Tapyrus Protocol for Ruby."
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.3
424
+ rubygems_version: 3.0.6
453
425
  signing_key:
454
426
  specification_version: 4
455
- summary: "[WIP]The implementation of Tapyrus Protocol for Ruby."
427
+ summary: The implementation of Tapyrus Protocol for Ruby.
456
428
  test_files: []