tapyrus 0.2.2 → 0.2.3

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: 3838e6da04049e2e82adfa960eb79f538ac4c6778fb3010b9a1423a7c8f2977d
4
+ data.tar.gz: 7c14929d2b2d7dcc388107e2ebbfdbd3891ecfc76a79a12282c518ee5cd160f0
5
5
  SHA512:
6
- metadata.gz: 61c8cc2439074666abffc6ff85ffaa40811e8e0992edb19846876dabf9a300f4822af522a6f621271f310a9b1ea3f9429f30e86452d29b0f2216052568a72a6a
7
- data.tar.gz: f3845015c030c7ccf915700eb45ac2f743c3f0c19dbe077c72c4afe19327252d1f3a64ffb29c1f5790997c8f6f2317930ab5ae99a894687a86f6381154c5429d
6
+ metadata.gz: 828f2fb6bf0a3bf120dab92afb04e4e7e8fce663108328ef6a6be122ff002a197807e0135310b225b65c493492afd0ccf7316b1e499eaa1ac92c0a38e9771199
7
+ data.tar.gz: 2ddd51984e99b5e8d1742d2d2c21b48ab50fd3efbcb64e08eb7908bfa678f788b6caff53029005af5a2ccbfc423d8e4aeab38607654ec73a1c9d199e6a446e84
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
@@ -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
@@ -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
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
@@ -1,3 +1,3 @@
1
1
  module Tapyrus
2
- VERSION = "0.2.2"
2
+ VERSION = "0.2.3"
3
3
  end
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.3
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: 2020-09-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ecdsa