Module: NwcRuby::Crypto::Schnorr

Defined in:
lib/nwc_ruby/crypto/schnorr.rb

Overview

BIP-340 Schnorr signatures for Nostr events.

Nostr event IDs are 32-byte SHA-256 hashes. The event signature is a 64-byte BIP-340 Schnorr signature over that hash, verifiable against the event’s 32-byte x-only public key.

Class Method Summary collapse

Class Method Details

.sign(digest_bytes, privkey_hex) ⇒ Object

Sign a 32-byte digest with a private key. Returns 64-byte signature as a lowercase hex string (128 chars).

Raises:

  • (ArgumentError)


17
18
19
20
21
22
23
24
# File 'lib/nwc_ruby/crypto/schnorr.rb', line 17

def sign(digest_bytes, privkey_hex)
  raise ArgumentError, 'digest must be 32 bytes' unless digest_bytes.bytesize == 32

  ctx = ::Secp256k1::Context.create
  kp  = ctx.key_pair_from_private_key(Keys.hex_to_bytes(privkey_hex))
  sig = ctx.sign_schnorr(kp, digest_bytes)
  Keys.bytes_to_hex(sig.serialized)
end

.verify(digest_bytes, sig_hex, xonly_pubkey_hex) ⇒ Object

Verify a 64-byte Schnorr signature. Returns true / false.



27
28
29
30
31
32
33
34
35
# File 'lib/nwc_ruby/crypto/schnorr.rb', line 27

def verify(digest_bytes, sig_hex, xonly_pubkey_hex)
  return false unless sig_hex.is_a?(String) && sig_hex.length == 128

  xonly_pub = ::Secp256k1::XOnlyPublicKey.from_data(Keys.hex_to_bytes(xonly_pubkey_hex))
  sig_obj   = ::Secp256k1::SchnorrSignature.from_data(Keys.hex_to_bytes(sig_hex))
  sig_obj.verify(digest_bytes, xonly_pub)
rescue ::Secp256k1::Error, ::Secp256k1::DeserializationError, ArgumentError
  false
end