schnorr_sig 1.0.0.1 → 1.0.1.1

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