schnorr_sig 1.0.0.1 → 1.0.1.1

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: 2814a65e511ccfe596ddd02783ab04e697e1b8817331e1558928cc7fb1bcf502
4
- data.tar.gz: f7305611c29e474f29dc97b813c520b46e3e583d443c920cf20941d0690ba190
3
+ metadata.gz: 583aef17bbda178fd790a7cfddb29bdd1d38ee1d44092d3cb6afc2517a564a09
4
+ data.tar.gz: 299a66f0e042c200b81f902e23ab2adb712a6260532fb28a6e23555cfc414db6
5
5
  SHA512:
6
- metadata.gz: a1a31085a79d32387d426e7e8600b3752feeec45127e1233bee14db7b931e66ff5de40ca1f520088a70f979cd14efced6f24d5d1d23505028c3dc4c9aa019602
7
- data.tar.gz: 76486cad9ad52e2c9eb40c8c7e04a809f52708381368b4b9f2fa20bd1bb5815ba74c6a30d25918b6edc046feba6d3b9d3605f6afa2b06c708dfbb2aba4eeb828
6
+ metadata.gz: bb3a7ade41fcdd713ae0b9da0d8c0cf8c390f7c3da232e19e4be146f66bf45311aa19ab02025ff3b55e5dc11a000094817751aaf4dd2c4a9d7e9f93b455ff866
7
+ data.tar.gz: 0dd87d6af1595d3a51b4d1788bb3b24f3c1a11a0997ceb3fc0543e422b4dde75fa04e2b3f1ca4ec5cdafe3fbd9f23091c23cd9608e9ea338e7a21f5b515a6dcf
data/Rakefile CHANGED
@@ -4,7 +4,6 @@ Rake::TestTask.new :test do |t|
4
4
  t.test_files = [
5
5
  'test/utils.rb',
6
6
  'test/pure.rb',
7
- 'test/vectors.rb',
8
7
  ]
9
8
  t.warning = true
10
9
  end
@@ -17,6 +16,14 @@ Rake::TestTask.new :vectors do |t|
17
16
  t.warning = true
18
17
  end
19
18
 
19
+ Rake::TestTask.new :fast do |t|
20
+ t.test_files = [
21
+ 'test/utils.rb',
22
+ 'test/fast.rb',
23
+ ]
24
+ t.warning = true
25
+ end
26
+
20
27
  task default: :test
21
28
 
22
29
  begin
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.0.1
1
+ 1.0.1.1
@@ -34,11 +34,10 @@ module SchnorrSig
34
34
  # Output
35
35
  # Secp256k1::KeyPair
36
36
  def keypair_obj(sk = nil)
37
- if sk
38
- binary!(sk, KEY)
39
- CONTEXT.key_pair_from_private_key(sk)
40
- else
37
+ if sk.nil?
41
38
  CONTEXT.generate_key_pair
39
+ else
40
+ CONTEXT.key_pair_from_private_key(binary!(sk, KEY))
42
41
  end
43
42
  end
44
43
 
@@ -69,8 +68,7 @@ module SchnorrSig
69
68
  # Output
70
69
  # Secp256k1::SchnorrSignature
71
70
  def signature(str)
72
- binary!(str, SIG)
73
- Secp256k1::SchnorrSignature.from_data(str)
71
+ Secp256k1::SchnorrSignature.from_data(binary!(str, SIG))
74
72
  end
75
73
 
76
74
  # Input
@@ -78,10 +76,8 @@ module SchnorrSig
78
76
  # The message, m: 32 byte hash value
79
77
  # Output
80
78
  # 64 bytes binary
81
- def sign(sk, m)
82
- binary!(sk, KEY) and binary!(m, 32)
83
- CONTEXT.sign_schnorr(keypair_obj(sk), m).serialized
84
- end
79
+ def sign(sk, m) = CONTEXT.sign_schnorr(keypair_obj(sk),
80
+ binary!(m, 32)).serialized
85
81
 
86
82
  # Input
87
83
  # The public key, pk: 32 bytes binary
@@ -112,10 +108,7 @@ module SchnorrSig
112
108
  # msg: UTF-8 / binary / agnostic
113
109
  # Output
114
110
  # 32 bytes binary
115
- def tagged_hash(tag, msg)
116
- check!(tag, String) and check!(msg, String)
117
- CONTEXT.tagged_sha256(tag, msg)
118
- end
111
+ def tagged_hash(tag, msg) = CONTEXT.tagged_sha256(str!(tag), str!(msg))
119
112
  end
120
113
 
121
114
  Fast.include Utils
@@ -5,8 +5,6 @@ autoload :SecureRandom, 'securerandom' # stdlib
5
5
  # This implementation is based on the BIP340 spec: https://bips.xyz/340
6
6
  module SchnorrSig
7
7
  class SanityCheck < Error; end
8
- class VerifyFail < Error; end
9
- class InfinityPoint < Error; end
10
8
 
11
9
  GROUP = ECDSA::Group::Secp256k1
12
10
  P = GROUP.field.prime # smaller than 256**32
@@ -48,7 +46,7 @@ module SchnorrSig
48
46
  when ECDSA::Point
49
47
  # BIP340: The function bytes(P), where P is a point,
50
48
  # returns bytes(x(P)).
51
- val.infinity? ? raise(InfinityPoint, val.inspect) : big2bin(val.x)
49
+ val.infinity? ? raise(SanityCheck, val.inspect) : big2bin(val.x)
52
50
  else
53
51
  raise(SanityCheck, val.inspect)
54
52
  end
@@ -89,15 +87,12 @@ module SchnorrSig
89
87
  # Output
90
88
  # 32 bytes binary
91
89
  def tagged_hash(tag, msg)
92
- check!(tag, String) and check!(msg, String)
93
- warn("tag expected to be UTF-8") unless tag.encoding == Encoding::UTF_8
94
-
95
90
  # BIP340: The function hash[name](x) where x is a byte array
96
91
  # returns the 32-byte hash
97
92
  # SHA256(SHA256(tag) || SHA256(tag) || x)
98
93
  # where tag is the UTF-8 encoding of name.
99
- tag_hash = Digest::SHA256.digest(tag)
100
- Digest::SHA256.digest(tag_hash + tag_hash + msg)
94
+ tag_hash = Digest::SHA256.digest tag
95
+ Digest::SHA256.digest(tag_hash + tag_hash + str!(msg).b)
101
96
  end
102
97
 
103
98
  #
@@ -137,7 +132,7 @@ module SchnorrSig
137
132
  # The signature, sig: 64 bytes binary
138
133
  def sign(sk, m, auxrand: nil)
139
134
  a = auxrand.nil? ? random_bytes(B) : auxrand
140
- binary!(sk, KEY) and check!(m, String) and binary!(a, B)
135
+ binary!(sk, KEY) and str!(m) and binary!(a, B)
141
136
 
142
137
  # BIP340: Let d' = int(sk)
143
138
  # BIP340: Fail if d' = 0 or d' >= n
@@ -177,7 +172,7 @@ module SchnorrSig
177
172
  # BIP340: Fail unless Verify(bytes(P), m, sig)
178
173
  # BIP340: Return the signature sig
179
174
  sig = bytes_r + bytes((k + e * d) % N)
180
- raise(VerifyFail) unless verify?(bytes_p, m, sig)
175
+ raise(SanityCheck, "sig did not verify") unless verify?(bytes_p, m, sig)
181
176
  sig
182
177
  end
183
178
 
@@ -188,7 +183,7 @@ module SchnorrSig
188
183
  # Output
189
184
  # Boolean
190
185
  def verify?(pk, m, sig)
191
- binary!(pk, KEY) and check!(m, String) and binary!(sig, SIG)
186
+ binary!(pk, KEY) and str!(m) and binary!(sig, SIG)
192
187
 
193
188
  # BIP340: Let P = lift_x(int(pk))
194
189
  p = lift_x(int(pk))
@@ -219,7 +214,7 @@ module SchnorrSig
219
214
  def soft_verify?(pk, m, sig)
220
215
  begin
221
216
  verify?(pk, m, sig)
222
- rescue SanityCheck, InfinityPoint
217
+ rescue SanityCheck
223
218
  false
224
219
  end
225
220
  end
@@ -1,21 +1,29 @@
1
1
  module SchnorrSig
2
2
  class Error < RuntimeError; end
3
- class SizeError < Error; end
3
+ class SpecError < Error; end
4
4
 
5
5
  KEY = 32 # bytes
6
6
  SIG = 64 # bytes
7
7
 
8
8
  module Utils
9
- # raise TypeError or return val
9
+ # raise SpecError or return val
10
10
  def check!(val, cls)
11
- val.is_a?(cls) ? val : raise(TypeError, "#{cls}: #{val.inspect}")
11
+ val.is_a?(cls) ? val : raise(SpecError, "#{cls}: #{val.inspect}")
12
12
  end
13
13
 
14
- # raise TypeError, EncodingError, or SizeError, or return str
14
+ # raise SpecError or return str
15
+ def str!(str, length = nil)
16
+ if check!(str, String) and !length.nil? and length != str.length
17
+ raise(SpecError, "Length #{str.length} should be #{length}")
18
+ end
19
+ str
20
+ end
21
+
22
+ # raise SpecError or return str
15
23
  def binary!(str, length)
16
- check!(str, String)
17
- raise(EncodingError, str.encoding) if str.encoding != Encoding::BINARY
18
- raise(SizeError, str.length) if str.length != length
24
+ if str!(str, length).encoding != Encoding::BINARY
25
+ raise(SpecError, "Encoding: #{str.encoding}")
26
+ end
19
27
  str
20
28
  end
21
29
 
data/schnorr_sig.gemspec CHANGED
@@ -13,6 +13,7 @@ Gem::Specification.new do |s|
13
13
  s.files = %w[schnorr_sig.gemspec VERSION README.md Rakefile]
14
14
  s.files += Dir['lib/**/*.rb']
15
15
  s.files += Dir['test/**/*.rb']
16
+ s.files += Dir['sig/**/*.rbs']
16
17
 
17
18
  s.add_dependency "ecdsa_ext", "~> 0"
18
19
  end
data/sig/fast.rbs ADDED
@@ -0,0 +1,15 @@
1
+ module SchnorrSig
2
+ CONTEXT: Secp256k1::Context
3
+
4
+ module Fast
5
+ def keypair_obj: (?String sk) -> Secp256k1::KeyPair
6
+ def extract_keys: (Secp256k1::KeyPair keypair_obj) -> [String, String]
7
+ def pubkey: (String sk) -> String
8
+ def keypair: -> [String, String]
9
+ def signature: (String str) -> Secp256k1::SchnorrSignature
10
+ def sign: (String sk, String m) -> String
11
+ def verify?: (String pk, String m, String sig) -> bool
12
+ def soft_verify?: (String pk, String m, String sig) -> bool
13
+ def tagged_hash: (String tag, String msg) -> String
14
+ end
15
+ end
data/sig/pure.rbs ADDED
@@ -0,0 +1,24 @@
1
+ module SchnorrSig
2
+ class SanityCheck < Error
3
+ end
4
+
5
+ GROUP: ECDSA::Group::Secp256k1
6
+ P: Integer
7
+ N: Integer
8
+ B: Integer
9
+
10
+ module Pure
11
+ def random_bytes: (Integer count) -> String
12
+ def point: (Integer int) -> ECDSA::Point
13
+ def select_even_y: (ECDSA::Point point, Integer even_val) -> Integer
14
+ def int: (String x) -> Integer
15
+ def bytes: (Integer | ECDSA::Point val) -> String
16
+ def lift_x: (Integer x) -> ECDSA::Point
17
+ def tagged_hash: (String tag, String msg) -> String
18
+ def pubkey: (String sk) -> String
19
+ def keypair: -> [String, String]
20
+ def sign: (String sk, String m, ?auxrand: String?) -> String
21
+ def verify?: (String pk, String m, String sig) -> bool
22
+ def soft_verify?: (String pk, String m, String sig) -> bool
23
+ end
24
+ end
data/sig/utils.rbs ADDED
@@ -0,0 +1,18 @@
1
+ module SchnorrSig
2
+ class Error < RuntimeError
3
+ end
4
+ class SpecError < Error
5
+ end
6
+
7
+ KEY: 32
8
+ SIG: 64
9
+
10
+ module Utils
11
+ def check!: (untyped val, Class cls) -> untyped
12
+ def binary!: (String str, Integer length) -> String
13
+ def bin2big: (String str) -> Integer
14
+ def big2bin: (Integer bignum) -> String
15
+ def bin2hex: (String str) -> String
16
+ def hex2bin: (String hex) -> String
17
+ end
18
+ end
data/test/utils.rb CHANGED
@@ -10,17 +10,17 @@ describe Utils do
10
10
  it "enforces the class of any object" do
11
11
  expect(Utils.check!('123', String)).must_equal '123'
12
12
  expect(Utils.check!(123, Integer)).must_equal 123
13
- expect { Utils.check!([], String) }.must_raise TypeError
13
+ expect { Utils.check!([], String) }.must_raise SpecError
14
14
  end
15
15
 
16
16
  it "enforces binary strings: type, encoding, length" do
17
17
  expect(Utils.binary!("\x00\x01".b, 2)).must_equal "\x00\x01".b
18
18
  expect {
19
19
  Utils.binary!("\x00\x01".b, 3)
20
- }.must_raise SchnorrSig::SizeError
20
+ }.must_raise SpecError
21
21
  expect {
22
22
  Utils.binary!("\x00\x01", 2)
23
- }.must_raise EncodingError
23
+ }.must_raise SpecError
24
24
  end
25
25
  end
26
26
 
data/test/vectors.rb CHANGED
@@ -18,7 +18,7 @@ table.each { |row|
18
18
 
19
19
  result = begin
20
20
  SchnorrSig.soft_verify?(pk, m, sig)
21
- rescue SchnorrSig::SizeError
21
+ rescue SchnorrSig::SpecError
22
22
  skip << row
23
23
  next
24
24
  end
@@ -37,4 +37,3 @@ puts "Failure: #{failure.count}"
37
37
  puts "Skipped: #{skip.count}"
38
38
 
39
39
  failure.each { |row| p row }
40
- exit failure.count
@@ -31,18 +31,22 @@ table.each { |row|
31
31
  # calculate a signature
32
32
  begin
33
33
  calc_sig = SchnorrSig.sign(sk, m)
34
- rescue SchnorrSig::Error
35
- calc_sig = "sig error"
34
+ sig_msg = (calc_sig == sig) ? "sig match" : "sig mismatch"
35
+ rescue SchnorrSig::SpecError
36
+ sig_msg = "sig error"
36
37
  end
37
- sig_msg = (calc_sig == sig) ? "sig match" : "sig mismatch"
38
38
  end
39
39
 
40
- begin
41
- result = SchnorrSig.soft_verify?(pk, m, sig)
42
- rescue SchnorrSig::SizeError
43
- next
40
+ if sig_msg != "sig error"
41
+ begin
42
+ result = SchnorrSig.soft_verify?(pk, m, sig)
43
+ verify_msg = (result == expected) ? "verify match" : "verify mismatch"
44
+ rescue SchnorrSig::SpecError
45
+ verify_msg = "verify error"
46
+ end
47
+ else
48
+ verify_msg = "sig error"
44
49
  end
45
- verify_msg = (result == expected) ? "verify match" : "verify mismatch"
46
50
  puts [index, pk_msg, sig_msg, verify_msg, comment].join("\t")
47
51
  }
48
52
  puts
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: schnorr_sig
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.1
4
+ version: 1.0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rick Hull
@@ -38,6 +38,9 @@ files:
38
38
  - lib/schnorr_sig/pure.rb
39
39
  - lib/schnorr_sig/utils.rb
40
40
  - schnorr_sig.gemspec
41
+ - sig/fast.rbs
42
+ - sig/pure.rbs
43
+ - sig/utils.rbs
41
44
  - test/fast.rb
42
45
  - test/pure.rb
43
46
  - test/utils.rb