Module: BSV::Primitives::SignedMessage
- Defined in:
- lib/bsv/primitives/signed_message.rb
Overview
BRC-77 signed messages.
Provides authenticated messaging using BRC-42 derived signing keys. The sender proves their identity to a specific recipient (or anyone) without encrypting the message content.
Constant Summary collapse
- VERSION =
Protocol version bytes: “BB3x01”
"\x42\x42\x33\x01".b.freeze
Class Method Summary collapse
-
.sign(message, signer, verifier = nil) ⇒ String
Sign a message using the BRC-77 protocol.
-
.verify(message, sig, recipient = nil) ⇒ Boolean
Verify a BRC-77 signed message.
Class Method Details
.sign(message, signer, verifier = nil) ⇒ String
Sign a message using the BRC-77 protocol.
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
# File 'lib/bsv/primitives/signed_message.rb', line 34 def sign(, signer, verifier = nil) anyone = verifier.nil? verifier = PrivateKey.new(OpenSSL::BN.new(1)).public_key if anyone key_id = SecureRandom.random_bytes(32) invoice = "2-message signing-#{[key_id].pack('m0')}" signing_key = signer.derive_child(verifier, invoice) hash = Digest.sha256(.b) signature = signing_key.sign(hash) VERSION + signer.public_key.compressed + (anyone ? "\x00".b : verifier.compressed) + key_id + signature.to_der end |
.verify(message, sig, recipient = nil) ⇒ Boolean
Verify a BRC-77 signed message.
59 60 61 62 63 64 65 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 91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/bsv/primitives/signed_message.rb', line 59 def verify(, sig, recipient = nil) sig = sig.b raise ArgumentError, "signed message too short: #{sig.bytesize} bytes" if sig.bytesize < 38 version = sig.byteslice(0, 4) raise ArgumentError, "message version mismatch: expected #{VERSION.unpack1('H*')}, received #{version.unpack1('H*')}" if version != VERSION sender_pub = PublicKey.from_bytes(sig.byteslice(4, 33)) verifier_first = sig.getbyte(37) if verifier_first.zero? # Anyone-can-verify mode recipient = PrivateKey.new(OpenSSL::BN.new(1)) key_id_offset = 38 else # Specific recipient verifier_pub_bytes = sig.byteslice(37, 33) verifier_pub_hex = verifier_pub_bytes.unpack1('H*') if recipient.nil? raise ArgumentError, "this signature can only be verified with knowledge of a specific private key. The associated public key is: #{verifier_pub_hex}" end recipient_pub_hex = recipient.public_key.compressed.unpack1('H*') if verifier_pub_hex != recipient_pub_hex raise ArgumentError, "the recipient public key is #{recipient_pub_hex} but the signature requires the recipient to have public key #{verifier_pub_hex}" end key_id_offset = 70 end key_id = sig.byteslice(key_id_offset, 32) der_bytes = sig.byteslice(key_id_offset + 32, sig.bytesize - key_id_offset - 32) invoice = "2-message signing-#{[key_id].pack('m0')}" signing_pub = sender_pub.derive_child(recipient, invoice) signature = Signature.from_der(der_bytes) hash = Digest.sha256(.b) ECDSA.verify(hash, signature, signing_pub.point) end |