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
- DEFAULT_AUX =
([0x00] * 32).pack('C*')
- VERSION =
"0.7.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.
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/schnorr.rb', line 69 def check_sig!(, public_key, signature) = hex2bin() public_key = hex2bin(public_key) 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.
98 99 100 101 |
# File 'lib/schnorr.rb', line 98 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 aux_rand is nil, it is treated the same as an all-zero one. See BIP-340 “Default Signing” for a full explanation of this argument and for guidance if randomness is expensive.
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 49 50 51 |
# File 'lib/schnorr.rb', line 22 def sign(, private_key, aux_rand = nil) 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 else aux_rand = DEFAULT_AUX 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.
107 108 109 110 |
# File 'lib/schnorr.rb', line 107 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.
58 59 60 61 62 |
# File 'lib/schnorr.rb', line 58 def valid_sig?(, public_key, signature) check_sig!(, public_key, signature) rescue InvalidSignatureError, ECDSA::Format::DecodeError false end |