Module: Schnorr
- Defined in:
- lib/schnorr.rb,
lib/schnorr/version.rb,
lib/schnorr/signature.rb
Defined Under Namespace
Classes: InvalidSignatureError, Signature
Constant Summary collapse
- GROUP =
ECDSA::Group::Secp256k1
- VERSION =
"0.4.0"
Class Method Summary collapse
-
.check_sig!(message, public_key, signature) ⇒ Boolean
Verifies the given Signature and raises an InvalidSignatureError if it is invalid.
-
.create_challenge(x, p, message) ⇒ Integer
create signature digest.
-
.sign(message, private_key, aux_rand = nil) ⇒ Schnorr::Signature
Generate schnorr signature.
-
.tagged_hash(tag, msg) ⇒ String
Generate tagged hash value.
-
.valid_sig?(message, public_key, signature) ⇒ Boolean
Verifies the given Signature and returns true if it is valid.
Class Method Details
.check_sig!(message, public_key, signature) ⇒ Boolean
Verifies the given Signature and raises an InvalidSignatureError if it is invalid.
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/schnorr.rb', line 59 def check_sig!(, public_key, signature) raise InvalidSignatureError, 'The message must be a 32-byte array.' unless .bytesize == 32 raise InvalidSignatureError, 'The public key must be a 32-byte array.' unless public_key.bytesize == 32 sig = Schnorr::Signature.decode(signature) pubkey = ECDSA::Format::PointOctetString.decode_from_x(public_key, GROUP) field = GROUP.field raise Schnorr::InvalidSignatureError, 'Invalid signature: r is zero.' if sig.r.zero? raise Schnorr::InvalidSignatureError, 'Invalid signature: s is zero.' if sig.s.zero? raise Schnorr::InvalidSignatureError, 'Invalid signature: r is larger than field size.' if sig.r >= field.prime raise Schnorr::InvalidSignatureError, 'Invalid signature: s is larger than group order.' if sig.s >= GROUP.order e = create_challenge(sig.r, pubkey, ) r = GROUP.new_point(sig.s) + pubkey.multiply_by_scalar(GROUP.order - e) if r.infinity? || !r.has_even_y? || r.x != sig.r raise Schnorr::InvalidSignatureError, 'signature verification failed.' end true end |
.create_challenge(x, p, message) ⇒ Integer
create signature digest.
87 88 89 90 |
# File 'lib/schnorr.rb', line 87 def create_challenge(x, p, ) r_x = ECDSA::Format::IntegerOctetString.encode(x, GROUP.byte_length) (ECDSA.normalize_digest(tagged_hash('BIP0340/challenge', r_x + p.encode(true) + ), GROUP.bit_length)) % GROUP.order end |
.sign(message, private_key, aux_rand = nil) ⇒ Schnorr::Signature
Generate schnorr signature. If not specified, random data is not used and the private key is used to calculate the nonce.
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/schnorr.rb', line 17 def sign(, private_key, aux_rand = nil) raise 'The message must be a 32-byte array.' unless .bytesize == 32 d0 = private_key.unpack1('H*').to_i(16) raise 'private_key must be an integer in the range 1..n-1.' unless 0 < d0 && d0 <= (GROUP.order - 1) raise 'aux_rand must be 32 bytes.' if !aux_rand.nil? && aux_rand.bytesize != 32 p = GROUP.new_point(d0) d = p.has_even_y? ? d0 : GROUP.order - d0 t = aux_rand.nil? ? d : d ^ tagged_hash('BIP0340/aux', aux_rand).unpack1('H*').to_i(16) t = ECDSA::Format::IntegerOctetString.encode(t, GROUP.byte_length) k0 = ECDSA::Format::IntegerOctetString.decode(tagged_hash('BIP0340/nonce', t + p.encode(true) + )) % GROUP.order raise 'Creation of signature failed. k is zero' if k0.zero? r = GROUP.new_point(k0) k = r.has_even_y? ? k0 : GROUP.order - k0 e = create_challenge(r.x, p, ) sig = Schnorr::Signature.new(r.x, (k + e * d) % GROUP.order) raise 'The created signature does not pass verification.' unless valid_sig?(, p.encode(true), sig.encode) sig end |
.tagged_hash(tag, msg) ⇒ String
Generate tagged hash value.
96 97 98 99 |
# File 'lib/schnorr.rb', line 96 def tagged_hash(tag, msg) tag_hash = Digest::SHA256.digest(tag) Digest::SHA256.digest(tag_hash + tag_hash + msg) end |
.valid_sig?(message, public_key, signature) ⇒ Boolean
Verifies the given Signature and returns true if it is valid.
48 49 50 51 52 |
# File 'lib/schnorr.rb', line 48 def valid_sig?(, public_key, signature) check_sig!(, public_key, signature) rescue InvalidSignatureError, ECDSA::Format::DecodeError false end |