tapyrus 0.2.2 → 0.2.3

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 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