class Laksa::Crypto::Schnorr
Constants
- G
- N
Public Class Methods
hash(q_point, pubkey_point, message)
click to toggle source
Hash (r | M).
# File lib/laksa/crypto/schnorr.rb, line 124 def self.hash(q_point, pubkey_point, message) sha256 = Digest::SHA256.new sha256 << q_point.to_octet_string(:compressed) sha256 << pubkey_point.to_octet_string(:compressed) sha256 << Util.decode_hex(message) OpenSSL::BN.new(sha256.hexdigest, 16) end
new()
click to toggle source
# File lib/laksa/crypto/schnorr.rb, line 13 def initialize end
sign(message, private_key, public_key)
click to toggle source
sign
@param {String} msg @param {String} key
# File lib/laksa/crypto/schnorr.rb, line 20 def self.sign(message, private_key, public_key) sig = nil while !sig k = Util.encode_hex SecureRandom.random_bytes(32) k_bn = OpenSSL::BN.new(k, 16) sig = self.try_sign(message, private_key, k_bn, public_key) end sig end
try_sign(message, private_key, k_bn, public_key)
click to toggle source
trySign
@param {String} message - the message to sign over @param {String} privateKey - the private key @param {BN} k_bn - output of the HMAC-DRBG
@returns {Signature | null =>}
# File lib/laksa/crypto/schnorr.rb, line 39 def self.try_sign(message, private_key, k_bn, public_key) group = OpenSSL::PKey::EC::Group.new('secp256k1') prikey_bn = OpenSSL::BN.new(private_key, 16) pubkey_bn = OpenSSL::BN.new(public_key, 16) pubkey_point = OpenSSL::PKey::EC::Point.new(group, pubkey_bn) throw 'Bad private key.' if prikey_bn.zero? || prikey_bn >= N # 1a. check that k is not 0 return nil if k_bn.zero? # 1b. check that k is < the order of the group return nil if k_bn >= N # 2. Compute commitment Q = kG, where g is the base point q_point = pubkey_point.mul(0, k_bn) # 3. Compute the challenge r = H(Q || pubKey || msg) # mod reduce the r value by the order of secp256k1, n r_bn = hash(q_point, pubkey_point, message) % N return nil if r_bn.zero? # 4. Compute s = k - r * prv # 4a. Compute r * prv s_bn = r_bn * prikey_bn % N # 4b. Compute s = k - r * prv mod n s_bn = k_bn.mod_sub(s_bn, N) return nil if s_bn.zero? Signature.new(r_bn.to_s(16), s_bn.to_s(16)) end
verify(message, sig, public_key)
click to toggle source
Verify signature.
@param {Buffer} message @param {Buffer} sig @param {Buffer} public_key
@returns {boolean}
-
Check if r,s is in [1, …, order-1]
-
Compute Q = sG + r*kpub
-
If Q = O (the neutral point), return 0;
-
r' = H(Q, kpub, m)
-
return r' == r
# File lib/laksa/crypto/schnorr.rb, line 89 def self.verify(message, sig, public_key) pubkey = PublicKey.new pubkey.deserialize Util.decode_hex(public_key) r = sig.r r_bn = OpenSSL::BN.new(r, 16) s = sig.s s_bn = OpenSSL::BN.new(s, 16) throw 'Invalid signature' if (s_bn.zero? || r_bn.zero?) throw 'Invalid signature' if (s_bn.negative? || r_bn.negative?) throw 'Invalid signature' if (s_bn >= N || r_bn >= N) group = OpenSSL::PKey::EC::Group.new('secp256k1') pubkey_bn = OpenSSL::BN.new(public_key, 16) pubkey_point = OpenSSL::PKey::EC::Point.new(group, pubkey_bn) throw 'Invalid public key' unless pubkey_point.on_curve? q_point = pubkey_point.mul(r_bn, s_bn) throw 'Invalid intermediate point.' if q_point.infinity? h_bn = self.hash(q_point, pubkey_point, message) % N throw 'Invalid hash.' if (h_bn.zero?) h_bn.eql?(r_bn) end