Module: Schnorr
- Extended by:
- Util
- Defined in:
- lib/schnorr.rb,
lib/schnorr/util.rb,
lib/schnorr/musig2.rb,
lib/schnorr/version.rb,
lib/schnorr/signature.rb,
lib/schnorr/musig2/context/key_agg.rb,
lib/schnorr/musig2/context/session.rb
Defined Under Namespace
Modules: MuSig2, Util Classes: InvalidSignatureError, Signature
Constant Summary collapse
- GROUP =
ECDSA::Group::Secp256k1
- VERSION =
"0.5.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.
Methods included from Util
hex2bin, hex_string?, string2point
Class Method Details
.check_sig!(message, public_key, signature) ⇒ Boolean
Verifies the given Signature and raises an InvalidSignatureError if it is invalid.
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/schnorr.rb', line 66 def check_sig!(, public_key, signature) = hex2bin() public_key = hex2bin(public_key) raise InvalidSignatureError, 'The message must be a 32-byte array.' unless .bytesize == 32 public_key = [public_key].pack('H*') if hex_string?(public_key) 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.generator.to_jacobian * sig.s + pubkey.to_jacobian * (GROUP.order - e)).to_affine 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.
96 97 98 99 |
# File 'lib/schnorr.rb', line 96 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.
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/schnorr.rb', line 20 def sign(, private_key, aux_rand = nil) raise 'The message must be a 32-byte array.' unless .bytesize == 32 private_key = private_key.unpack1('H*') unless hex_string?(private_key) d0 = private_key.to_i(16) raise 'private_key must be an integer in the range 1..n-1.' unless 0 < d0 && d0 <= (GROUP.order - 1) if aux_rand aux_rand = [aux_rand].pack("H*") if hex_string?(aux_rand) raise 'aux_rand must be 32 bytes.' unless aux_rand.bytesize == 32 end p = (GROUP.generator.to_jacobian * d0).to_affine d = p.has_even_y? ? d0 : GROUP.order - d0 t = aux_rand.nil? ? d : d ^ tagged_hash('BIP0340/aux', aux_rand).bti 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.generator.to_jacobian * k0).to_affine 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.
105 106 107 108 |
# File 'lib/schnorr.rb', line 105 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.
55 56 57 58 59 |
# File 'lib/schnorr.rb', line 55 def valid_sig?(, public_key, signature) check_sig!(, public_key, signature) rescue InvalidSignatureError, ECDSA::Format::DecodeError false end |