schnorr_sig 0.1.0.1 → 0.2.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/lib/schnorr_sig/fast.rb +2 -2
- data/lib/schnorr_sig/pure.rb +221 -0
- data/lib/schnorr_sig.rb +4 -220
- data/test/vectors.rb +1 -2
- data/test/vectors_extra.rb +1 -2
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 37ba87126b971e1e74099bbed572cb7e088902db0cba9fdf38ef5de96ab75f69
|
4
|
+
data.tar.gz: 9001aae50944fcf3daf558db01a44c6b5f4ee7e74f729292026c83fe38c1367d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a85306c995daa8ce6b30b303e530892a4014f367854dccda5a3f119dc2170087e04fd069d6a8516f30bfe5d1b2e5e351ae495f331b65d1ab920ec767d60f154b
|
7
|
+
data.tar.gz: e7abe94145d870f072924e555e7510e886159aef5119375892ac10243abd08ccf72ff078f545b68b3502a9d09f644f38d5512220796e71b138b24f642813bc78
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0.1
|
data/lib/schnorr_sig/fast.rb
CHANGED
@@ -0,0 +1,221 @@
|
|
1
|
+
require 'schnorr_sig/util' # project
|
2
|
+
require 'ecdsa_ext' # gem
|
3
|
+
autoload :SecureRandom, 'securerandom' # stdlib
|
4
|
+
|
5
|
+
# This implementation is based on the BIP340 spec: https://bips.xyz/340
|
6
|
+
# re-open SchnorrSig to add more functions, errors, and constants
|
7
|
+
module SchnorrSig
|
8
|
+
class Error < RuntimeError; end
|
9
|
+
class BoundsError < Error; end
|
10
|
+
class SanityCheck < Error; end
|
11
|
+
class VerifyFail < Error; end
|
12
|
+
class InfinityPoint < Error; end
|
13
|
+
|
14
|
+
GROUP = ECDSA::Group::Secp256k1
|
15
|
+
P = GROUP.field.prime # smaller than 256**32
|
16
|
+
N = GROUP.order # smaller than P
|
17
|
+
B = GROUP.byte_length # 32
|
18
|
+
|
19
|
+
# val (dot) G, returns ECDSA::Point
|
20
|
+
def self.dot_group(val)
|
21
|
+
# ecdsa_ext uses jacobian projection: 10x faster than GROUP.generator * val
|
22
|
+
(GROUP.generator.to_jacobian * val).to_affine
|
23
|
+
end
|
24
|
+
|
25
|
+
# returns even_val or N - even_val
|
26
|
+
def self.select_even_y(point, even_val)
|
27
|
+
point.y.even? ? even_val : N - even_val
|
28
|
+
end
|
29
|
+
|
30
|
+
# int(x) function signature matches BIP340, returns a bignum (presumably)
|
31
|
+
class << self
|
32
|
+
alias_method :int, :bin2big
|
33
|
+
end
|
34
|
+
|
35
|
+
# bytes(val) function signature matches BIP340, returns a binary string
|
36
|
+
def self.bytes(val)
|
37
|
+
case val
|
38
|
+
when Integer
|
39
|
+
# BIP340: The function bytes(x), where x is an integer,
|
40
|
+
# returns the 32-byte encoding of x, most significant byte first.
|
41
|
+
big2bin(val)
|
42
|
+
when ECDSA::Point
|
43
|
+
# BIP340: The function bytes(P), where P is a point, returns bytes(x(P)).
|
44
|
+
val.infinity? ? raise(InfinityPoint, va.inspect) : big2bin(val.x)
|
45
|
+
else
|
46
|
+
raise(SanityCheck, val.inspect)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Input
|
51
|
+
# The secret key, sk: 32 bytes binary
|
52
|
+
# The message, m: binary / UTF-8 / agnostic
|
53
|
+
# Auxiliary random data, a: 32 bytes binary
|
54
|
+
# Output
|
55
|
+
# The signature, sig: 64 bytes binary
|
56
|
+
def self.sign(sk, m, a = Random.bytes(B))
|
57
|
+
bytestring!(sk, B) and string!(m) and bytestring!(a, B)
|
58
|
+
|
59
|
+
# BIP340: Let d' = int(sk)
|
60
|
+
# BIP340: Fail if d' = 0 or d' >= n
|
61
|
+
d0 = int(sk)
|
62
|
+
raise(BoundsError, "d0") if !d0.positive? or d0 >= N
|
63
|
+
|
64
|
+
# BIP340: Let P = d' . G
|
65
|
+
p = dot_group(d0) # this is a point on the elliptic curve
|
66
|
+
bytes_p = bytes(p)
|
67
|
+
|
68
|
+
# BIP340: Let d = d' if has_even_y(P), otherwise let d = n - d'
|
69
|
+
d = select_even_y(p, d0)
|
70
|
+
|
71
|
+
# BIP340: Let t be the bytewise xor of bytes(d) and hash[BIP0340/aux](a)
|
72
|
+
t = d ^ int(tagged_hash('BIP0340/aux', a))
|
73
|
+
|
74
|
+
# BIP340: Let rand = hash[BIP0340/nonce](t || bytes(P) || m)
|
75
|
+
nonce = tagged_hash('BIP0340/nonce', bytes(t) + bytes_p + m)
|
76
|
+
|
77
|
+
# BIP340: Let k' = int(rand) mod n
|
78
|
+
# BIP340: Fail if k' = 0
|
79
|
+
k0 = int(nonce) % N
|
80
|
+
raise(BoundsError, "k0") if !k0.positive?
|
81
|
+
|
82
|
+
# BIP340: Let R = k' . G
|
83
|
+
r = dot_group(k0) # this is a point on the elliptic curve
|
84
|
+
bytes_r = bytes(r)
|
85
|
+
|
86
|
+
# BIP340: Let k = k' if has_even_y(R), otherwise let k = n - k'
|
87
|
+
k = select_even_y(r, k0)
|
88
|
+
|
89
|
+
# BIP340:
|
90
|
+
# Let e = int(hash[BIP0340/challenge](bytes(R) || bytes(P) || m)) mod n
|
91
|
+
e = int(tagged_hash('BIP0340/challenge', bytes_r + bytes_p + m)) % N
|
92
|
+
|
93
|
+
# BIP340: Let sig = bytes(R) || bytes((k + ed) mod n)
|
94
|
+
# BIP340: Fail unless Verify(bytes(P), m, sig)
|
95
|
+
# BIP340: Return the signature sig
|
96
|
+
sig = bytes_r + bytes((k + e * d) % N)
|
97
|
+
raise(VerifyFail) unless verify?(bytes_p, m, sig)
|
98
|
+
sig
|
99
|
+
end
|
100
|
+
|
101
|
+
# see https://bips.xyz/340#design (Tagged hashes)
|
102
|
+
# Input
|
103
|
+
# A tag: UTF-8 > binary > agnostic
|
104
|
+
# The payload, msg: UTF-8 / binary / agnostic
|
105
|
+
# Output
|
106
|
+
# 32 bytes binary
|
107
|
+
def self.tagged_hash(tag, msg)
|
108
|
+
string!(tag) and string!(msg)
|
109
|
+
warn("tag expected to be UTF-8") unless tag.encoding == Encoding::UTF_8
|
110
|
+
|
111
|
+
# BIP340: The function hash[name](x) where x is a byte array
|
112
|
+
# returns the 32-byte hash
|
113
|
+
# SHA256(SHA256(tag) || SHA256(tag) || x)
|
114
|
+
# where tag is the UTF-8 encoding of name.
|
115
|
+
tag_hash = Digest::SHA256.digest(tag)
|
116
|
+
Digest::SHA256.digest(tag_hash + tag_hash + msg)
|
117
|
+
end
|
118
|
+
|
119
|
+
# Input
|
120
|
+
# The public key, pk: 32 bytes binary
|
121
|
+
# The message, m: UTF-8 / binary / agnostic
|
122
|
+
# A signature, sig: 64 bytes binary
|
123
|
+
# Output
|
124
|
+
# Boolean
|
125
|
+
def self.verify?(pk, m, sig)
|
126
|
+
bytestring!(pk, B) and string!(m) and bytestring!(sig, B * 2)
|
127
|
+
|
128
|
+
# BIP340: Let P = lift_x(int(pk))
|
129
|
+
p = lift_x(int(pk))
|
130
|
+
|
131
|
+
# BIP340: Let r = int(sig[0:32]) fail if r >= p
|
132
|
+
r = int(sig[0..B-1])
|
133
|
+
raise(BoundsError, "r >= p") if r >= P
|
134
|
+
|
135
|
+
# BIP340: Let s = int(sig[32:64]); fail if s >= n
|
136
|
+
s = int(sig[B..-1])
|
137
|
+
raise(BoundsError, "s >= n") if s >= N
|
138
|
+
|
139
|
+
# BIP340:
|
140
|
+
# Let e = int(hash[BIP0340/challenge](bytes(r) || bytes(P) || m)) mod n
|
141
|
+
e = bytes(r) + bytes(p) + m
|
142
|
+
e = int(tagged_hash('BIP0340/challenge', e)) % N
|
143
|
+
|
144
|
+
# BIP340: Let R = s . G - e . P
|
145
|
+
# BIP340: Fail if is_infinite(R)
|
146
|
+
# BIP340: Fail if not has_even_y(R)
|
147
|
+
# BIP340: Fail if x(R) != r
|
148
|
+
# BIP340: Return success iff no failure occurred before reaching this point
|
149
|
+
big_r = dot_group(s) + p.multiply_by_scalar(e).negate
|
150
|
+
!big_r.infinity? and big_r.y.even? and big_r.x == r
|
151
|
+
end
|
152
|
+
|
153
|
+
# BIP340: The function lift_x(x), where x is a 256-bit unsigned integer,
|
154
|
+
# returns the point P for which x(P) = x and has_even_y(P),
|
155
|
+
# or fails if x is greater than p-1 or no such point exists.
|
156
|
+
# Input
|
157
|
+
# A large integer, x
|
158
|
+
# Output
|
159
|
+
# ECDSA::Point
|
160
|
+
def self.lift_x(x)
|
161
|
+
integer!(x)
|
162
|
+
|
163
|
+
# BIP340: Fail if x >= p
|
164
|
+
raise(BoundsError, "x") if x >= P or x <= 0
|
165
|
+
|
166
|
+
# BIP340: Let c = x^3 + 7 mod p
|
167
|
+
c = (x.pow(3, P) + 7) % P
|
168
|
+
|
169
|
+
# BIP340: Let y = c ^ ((p + 1) / 4) mod p
|
170
|
+
y = c.pow((P + 1) / 4, P) # use pow to avoid Bignum overflow
|
171
|
+
|
172
|
+
# BIP340: Fail if c != y^2 mod p
|
173
|
+
raise(SanityCheck, "c != y^2 mod p") if c != y.pow(2, P)
|
174
|
+
|
175
|
+
# BIP340: Return the unique point P such that:
|
176
|
+
# x(P) = x and y(P) = y if y mod 2 = 0
|
177
|
+
# y(P) = p - y otherwise
|
178
|
+
GROUP.new_point [x, y.even? ? y : P - y]
|
179
|
+
end
|
180
|
+
|
181
|
+
# Input
|
182
|
+
# The secret key, sk: 32 bytes binary
|
183
|
+
# Output
|
184
|
+
# 32 bytes binary (represents P.x for point P on the curve)
|
185
|
+
def self.pubkey(sk)
|
186
|
+
bytestring!(sk, B)
|
187
|
+
|
188
|
+
# BIP340: Let d' = int(sk)
|
189
|
+
# BIP340: Fail if d' = 0 or d' >= n
|
190
|
+
# BIP340: Return bytes(d' . G)
|
191
|
+
d0 = int(sk)
|
192
|
+
raise(BoundsError, "d0") if !d0.positive? or d0 >= N
|
193
|
+
bytes(dot_group(d0))
|
194
|
+
end
|
195
|
+
|
196
|
+
# generate a new keypair based on random data
|
197
|
+
def self.keypair
|
198
|
+
sk = Random.bytes(B)
|
199
|
+
[sk, pubkey(sk)]
|
200
|
+
end
|
201
|
+
|
202
|
+
# as above, but using SecureRandom
|
203
|
+
def self.secure_keypair
|
204
|
+
sk = SecureRandom.bytes(B)
|
205
|
+
[sk, pubkey(sk)]
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
if __FILE__ == $0
|
210
|
+
msg = 'hello world'
|
211
|
+
sk, pk = SchnorrSig.keypair
|
212
|
+
puts "Message: #{msg}"
|
213
|
+
puts "Secret key: #{SchnorrSig.bin2hex(sk)}"
|
214
|
+
puts "Public key: #{SchnorrSig.bin2hex(pk)}"
|
215
|
+
|
216
|
+
sig = SchnorrSig.sign(sk, msg)
|
217
|
+
puts
|
218
|
+
puts "Verified signature: #{SchnorrSig.bin2hex(sig)}"
|
219
|
+
puts "Encoding: #{sig.encoding}"
|
220
|
+
puts "Length: #{sig.length}"
|
221
|
+
end
|
data/lib/schnorr_sig.rb
CHANGED
@@ -1,221 +1,5 @@
|
|
1
|
-
|
2
|
-
require '
|
3
|
-
|
4
|
-
|
5
|
-
# This implementation is based on the BIP340 spec: https://bips.xyz/340
|
6
|
-
# re-open SchnorrSig to add more functions, errors, and constants
|
7
|
-
module SchnorrSig
|
8
|
-
class Error < RuntimeError; end
|
9
|
-
class BoundsError < Error; end
|
10
|
-
class SanityCheck < Error; end
|
11
|
-
class VerifyFail < Error; end
|
12
|
-
class InfinityPoint < Error; end
|
13
|
-
|
14
|
-
GROUP = ECDSA::Group::Secp256k1
|
15
|
-
P = GROUP.field.prime # smaller than 256**32
|
16
|
-
N = GROUP.order # smaller than P
|
17
|
-
B = GROUP.byte_length # 32
|
18
|
-
|
19
|
-
# val (dot) G, returns ECDSA::Point
|
20
|
-
def self.dot_group(val)
|
21
|
-
# ecdsa_ext uses jacobian projection: 10x faster than GROUP.generator * val
|
22
|
-
(GROUP.generator.to_jacobian * val).to_affine
|
23
|
-
end
|
24
|
-
|
25
|
-
# returns even_val or N - even_val
|
26
|
-
def self.select_even_y(point, even_val)
|
27
|
-
point.y.even? ? even_val : N - even_val
|
28
|
-
end
|
29
|
-
|
30
|
-
# int(x) function signature matches BIP340, returns a bignum (presumably)
|
31
|
-
class << self
|
32
|
-
alias_method :int, :bin2big
|
33
|
-
end
|
34
|
-
|
35
|
-
# bytes(val) function signature matches BIP340, returns a binary string
|
36
|
-
def self.bytes(val)
|
37
|
-
case val
|
38
|
-
when Integer
|
39
|
-
# BIP340: The function bytes(x), where x is an integer,
|
40
|
-
# returns the 32-byte encoding of x, most significant byte first.
|
41
|
-
big2bin(val)
|
42
|
-
when ECDSA::Point
|
43
|
-
# BIP340: The function bytes(P), where P is a point, returns bytes(x(P)).
|
44
|
-
val.infinity? ? raise(InfinityPoint, va.inspect) : big2bin(val.x)
|
45
|
-
else
|
46
|
-
raise(SanityCheck, val.inspect)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
# Input
|
51
|
-
# The secret key, sk: 32 bytes binary
|
52
|
-
# The message, m: binary / UTF-8 / agnostic
|
53
|
-
# Auxiliary random data, a: 32 bytes binary
|
54
|
-
# Output
|
55
|
-
# The signature, sig: 64 bytes binary
|
56
|
-
def self.sign(sk, m, a = Random.bytes(B))
|
57
|
-
bytestring!(sk, B) and string!(m) and bytestring!(a, B)
|
58
|
-
|
59
|
-
# BIP340: Let d' = int(sk)
|
60
|
-
# BIP340: Fail if d' = 0 or d' >= n
|
61
|
-
d0 = int(sk)
|
62
|
-
raise(BoundsError, "d0") if !d0.positive? or d0 >= N
|
63
|
-
|
64
|
-
# BIP340: Let P = d' . G
|
65
|
-
p = dot_group(d0) # this is a point on the elliptic curve
|
66
|
-
bytes_p = bytes(p)
|
67
|
-
|
68
|
-
# BIP340: Let d = d' if has_even_y(P), otherwise let d = n - d'
|
69
|
-
d = select_even_y(p, d0)
|
70
|
-
|
71
|
-
# BIP340: Let t be the bytewise xor of bytes(d) and hash[BIP0340/aux](a)
|
72
|
-
t = d ^ int(tagged_hash('BIP0340/aux', a))
|
73
|
-
|
74
|
-
# BIP340: Let rand = hash[BIP0340/nonce](t || bytes(P) || m)
|
75
|
-
nonce = tagged_hash('BIP0340/nonce', bytes(t) + bytes_p + m)
|
76
|
-
|
77
|
-
# BIP340: Let k' = int(rand) mod n
|
78
|
-
# BIP340: Fail if k' = 0
|
79
|
-
k0 = int(nonce) % N
|
80
|
-
raise(BoundsError, "k0") if !k0.positive?
|
81
|
-
|
82
|
-
# BIP340: Let R = k' . G
|
83
|
-
r = dot_group(k0) # this is a point on the elliptic curve
|
84
|
-
bytes_r = bytes(r)
|
85
|
-
|
86
|
-
# BIP340: Let k = k' if has_even_y(R), otherwise let k = n - k'
|
87
|
-
k = select_even_y(r, k0)
|
88
|
-
|
89
|
-
# BIP340:
|
90
|
-
# Let e = int(hash[BIP0340/challenge](bytes(R) || bytes(P) || m)) mod n
|
91
|
-
e = int(tagged_hash('BIP0340/challenge', bytes_r + bytes_p + m)) % N
|
92
|
-
|
93
|
-
# BIP340: Let sig = bytes(R) || bytes((k + ed) mod n)
|
94
|
-
# BIP340: Fail unless Verify(bytes(P), m, sig)
|
95
|
-
# BIP340: Return the signature sig
|
96
|
-
sig = bytes_r + bytes((k + e * d) % N)
|
97
|
-
raise(VerifyFail) unless verify?(bytes_p, m, sig)
|
98
|
-
sig
|
99
|
-
end
|
100
|
-
|
101
|
-
# see https://bips.xyz/340#design (Tagged hashes)
|
102
|
-
# Input
|
103
|
-
# A tag: UTF-8 > binary > agnostic
|
104
|
-
# The payload, msg: UTF-8 / binary / agnostic
|
105
|
-
# Output
|
106
|
-
# 32 bytes binary
|
107
|
-
def self.tagged_hash(tag, msg)
|
108
|
-
string!(tag) and string!(msg)
|
109
|
-
warn("tag expected to be UTF-8") unless tag.encoding == Encoding::UTF_8
|
110
|
-
|
111
|
-
# BIP340: The function hash[name](x) where x is a byte array
|
112
|
-
# returns the 32-byte hash
|
113
|
-
# SHA256(SHA256(tag) || SHA256(tag) || x)
|
114
|
-
# where tag is the UTF-8 encoding of name.
|
115
|
-
tag_hash = Digest::SHA256.digest(tag)
|
116
|
-
Digest::SHA256.digest(tag_hash + tag_hash + msg)
|
117
|
-
end
|
118
|
-
|
119
|
-
# Input
|
120
|
-
# The public key, pk: 32 bytes binary
|
121
|
-
# The message, m: UTF-8 / binary / agnostic
|
122
|
-
# A signature, sig: 64 bytes binary
|
123
|
-
# Output
|
124
|
-
# Boolean
|
125
|
-
def self.verify?(pk, m, sig)
|
126
|
-
bytestring!(pk, B) and string!(m) and bytestring!(sig, B * 2)
|
127
|
-
|
128
|
-
# BIP340: Let P = lift_x(int(pk))
|
129
|
-
p = lift_x(int(pk))
|
130
|
-
|
131
|
-
# BIP340: Let r = int(sig[0:32]) fail if r >= p
|
132
|
-
r = int(sig[0..B-1])
|
133
|
-
raise(BoundsError, "r >= p") if r >= P
|
134
|
-
|
135
|
-
# BIP340: Let s = int(sig[32:64]); fail if s >= n
|
136
|
-
s = int(sig[B..-1])
|
137
|
-
raise(BoundsError, "s >= n") if s >= N
|
138
|
-
|
139
|
-
# BIP340:
|
140
|
-
# Let e = int(hash[BIP0340/challenge](bytes(r) || bytes(P) || m)) mod n
|
141
|
-
e = bytes(r) + bytes(p) + m
|
142
|
-
e = int(tagged_hash('BIP0340/challenge', e)) % N
|
143
|
-
|
144
|
-
# BIP340: Let R = s . G - e . P
|
145
|
-
# BIP340: Fail if is_infinite(R)
|
146
|
-
# BIP340: Fail if not has_even_y(R)
|
147
|
-
# BIP340: Fail if x(R) != r
|
148
|
-
# BIP340: Return success iff no failure occurred before reaching this point
|
149
|
-
big_r = dot_group(s) + p.multiply_by_scalar(e).negate
|
150
|
-
!big_r.infinity? and big_r.y.even? and big_r.x == r
|
151
|
-
end
|
152
|
-
|
153
|
-
# BIP340: The function lift_x(x), where x is a 256-bit unsigned integer,
|
154
|
-
# returns the point P for which x(P) = x and has_even_y(P),
|
155
|
-
# or fails if x is greater than p-1 or no such point exists.
|
156
|
-
# Input
|
157
|
-
# A large integer, x
|
158
|
-
# Output
|
159
|
-
# ECDSA::Point
|
160
|
-
def self.lift_x(x)
|
161
|
-
integer!(x)
|
162
|
-
|
163
|
-
# BIP340: Fail if x >= p
|
164
|
-
raise(BoundsError, "x") if x >= P or x <= 0
|
165
|
-
|
166
|
-
# BIP340: Let c = x^3 + 7 mod p
|
167
|
-
c = (x.pow(3, P) + 7) % P
|
168
|
-
|
169
|
-
# BIP340: Let y = c ^ ((p + 1) / 4) mod p
|
170
|
-
y = c.pow((P + 1) / 4, P) # use pow to avoid Bignum overflow
|
171
|
-
|
172
|
-
# BIP340: Fail if c != y^2 mod p
|
173
|
-
raise(SanityCheck, "c != y^2 mod p") if c != y.pow(2, P)
|
174
|
-
|
175
|
-
# BIP340: Return the unique point P such that:
|
176
|
-
# x(P) = x and y(P) = y if y mod 2 = 0
|
177
|
-
# y(P) = p - y otherwise
|
178
|
-
GROUP.new_point [x, y.even? ? y : P - y]
|
179
|
-
end
|
180
|
-
|
181
|
-
# Input
|
182
|
-
# The secret key, sk: 32 bytes binary
|
183
|
-
# Output
|
184
|
-
# 32 bytes binary (represents P.x for point P on the curve)
|
185
|
-
def self.pubkey(sk)
|
186
|
-
bytestring!(sk, B)
|
187
|
-
|
188
|
-
# BIP340: Let d' = int(sk)
|
189
|
-
# BIP340: Fail if d' = 0 or d' >= n
|
190
|
-
# BIP340: Return bytes(d' . G)
|
191
|
-
d0 = int(sk)
|
192
|
-
raise(BoundsError, "d0") if !d0.positive? or d0 >= N
|
193
|
-
bytes(dot_group(d0))
|
194
|
-
end
|
195
|
-
|
196
|
-
# generate a new keypair based on random data
|
197
|
-
def self.keypair
|
198
|
-
sk = Random.bytes(B)
|
199
|
-
[sk, pubkey(sk)]
|
200
|
-
end
|
201
|
-
|
202
|
-
# as above, but using SecureRandom
|
203
|
-
def self.secure_keypair
|
204
|
-
sk = SecureRandom.bytes(B)
|
205
|
-
[sk, pubkey(sk)]
|
206
|
-
end
|
207
|
-
end
|
208
|
-
|
209
|
-
if __FILE__ == $0
|
210
|
-
msg = 'hello world'
|
211
|
-
sk, pk = SchnorrSig.keypair
|
212
|
-
puts "Message: #{msg}"
|
213
|
-
puts "Secret key: #{SchnorrSig.bin2hex(sk)}"
|
214
|
-
puts "Public key: #{SchnorrSig.bin2hex(pk)}"
|
215
|
-
|
216
|
-
sig = SchnorrSig.sign(sk, msg)
|
217
|
-
puts
|
218
|
-
puts "Verified signature: #{SchnorrSig.bin2hex(sig)}"
|
219
|
-
puts "Encoding: #{sig.encoding}"
|
220
|
-
puts "Length: #{sig.length}"
|
1
|
+
if ENV['SCHNORR_SIG']&.downcase == 'fast'
|
2
|
+
require 'schnorr_sig/fast'
|
3
|
+
else
|
4
|
+
require 'schnorr_sig/pure'
|
221
5
|
end
|
data/test/vectors.rb
CHANGED
data/test/vectors_extra.rb
CHANGED
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: 0.
|
4
|
+
version: 0.2.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rick Hull
|
@@ -35,6 +35,7 @@ files:
|
|
35
35
|
- VERSION
|
36
36
|
- lib/schnorr_sig.rb
|
37
37
|
- lib/schnorr_sig/fast.rb
|
38
|
+
- lib/schnorr_sig/pure.rb
|
38
39
|
- lib/schnorr_sig/util.rb
|
39
40
|
- schnorr_sig.gemspec
|
40
41
|
- test/vectors.rb
|