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 +4 -4
- data/Rakefile +8 -1
- data/VERSION +1 -1
- data/lib/schnorr_sig/fast.rb +7 -14
- data/lib/schnorr_sig/pure.rb +7 -12
- data/lib/schnorr_sig/utils.rb +15 -7
- data/schnorr_sig.gemspec +1 -0
- data/sig/fast.rbs +15 -0
- data/sig/pure.rbs +24 -0
- data/sig/utils.rbs +18 -0
- data/test/utils.rb +3 -3
- data/test/vectors.rb +1 -2
- data/test/vectors_extra.rb +12 -8
- metadata +4 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 583aef17bbda178fd790a7cfddb29bdd1d38ee1d44092d3cb6afc2517a564a09
|
4
|
+
data.tar.gz: 299a66f0e042c200b81f902e23ab2adb712a6260532fb28a6e23555cfc414db6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
1
|
+
1.0.1.1
|
data/lib/schnorr_sig/fast.rb
CHANGED
@@ -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
|
-
|
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
|
data/lib/schnorr_sig/pure.rb
CHANGED
@@ -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(
|
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
|
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
|
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(
|
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
|
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
|
217
|
+
rescue SanityCheck
|
223
218
|
false
|
224
219
|
end
|
225
220
|
end
|
data/lib/schnorr_sig/utils.rb
CHANGED
@@ -1,21 +1,29 @@
|
|
1
1
|
module SchnorrSig
|
2
2
|
class Error < RuntimeError; end
|
3
|
-
class
|
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
|
9
|
+
# raise SpecError or return val
|
10
10
|
def check!(val, cls)
|
11
|
-
val.is_a?(cls) ? val : raise(
|
11
|
+
val.is_a?(cls) ? val : raise(SpecError, "#{cls}: #{val.inspect}")
|
12
12
|
end
|
13
13
|
|
14
|
-
# raise
|
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
|
-
|
17
|
-
|
18
|
-
|
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
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
|
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
|
20
|
+
}.must_raise SpecError
|
21
21
|
expect {
|
22
22
|
Utils.binary!("\x00\x01", 2)
|
23
|
-
}.must_raise
|
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::
|
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
|
data/test/vectors_extra.rb
CHANGED
@@ -31,18 +31,22 @@ table.each { |row|
|
|
31
31
|
# calculate a signature
|
32
32
|
begin
|
33
33
|
calc_sig = SchnorrSig.sign(sk, m)
|
34
|
-
|
35
|
-
|
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
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
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.
|
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
|