signatures.go raw

   1  package event
   2  
   3  import (
   4  	"next.orly.dev/pkg/nostr/interfaces/signer"
   5  	"next.orly.dev/pkg/nostr/interfaces/signer/p8k"
   6  	"next.orly.dev/pkg/nostr/utils"
   7  	"next.orly.dev/pkg/lol/chk"
   8  	"next.orly.dev/pkg/lol/errorf"
   9  	"next.orly.dev/pkg/lol/log"
  10  )
  11  
  12  // Sign the event using the signer.I. Uses github.com/bitcoin-core/secp256k1 if
  13  // available for much faster signatures.
  14  //
  15  // Note that this only populates the Pubkey, ID and Sig. The caller must
  16  // set the CreatedAt timestamp as intended.
  17  func (ev *E) Sign(keys signer.I) (err error) {
  18  	// Copy Pub() and Sign() results — signers may return internal buffers
  19  	// that are reused on subsequent calls (e.g. P256K1Signer.sigBuf).
  20  	pub := keys.Pub()
  21  	ev.Pubkey = make([]byte, len(pub))
  22  	copy(ev.Pubkey, pub)
  23  	ev.ID = ev.GetIDBytes()
  24  	var sig []byte
  25  	if sig, err = keys.Sign(ev.ID); chk.E(err) {
  26  		return
  27  	}
  28  	ev.Sig = make([]byte, len(sig))
  29  	copy(ev.Sig, sig)
  30  	return
  31  }
  32  
  33  // Verify an event is signed by the pubkey it contains. Uses
  34  // github.com/bitcoin-core/secp256k1 if available for faster verification.
  35  func (ev *E) Verify() (valid bool, err error) {
  36  	var keys *p8k.Signer
  37  	if keys, err = p8k.New(); chk.E(err) {
  38  		return
  39  	}
  40  	if err = keys.InitPub(ev.Pubkey); chk.E(err) {
  41  		return
  42  	}
  43  	if valid, err = keys.Verify(ev.ID, ev.Sig); chk.T(err) {
  44  		// check that this isn't because of a bogus ID
  45  		id := ev.GetIDBytes()
  46  		if !utils.FastEqual(id, ev.ID) {
  47  			log.E.Ln("event Subscription incorrect")
  48  			ev.ID = id
  49  			err = nil
  50  			if valid, err = keys.Verify(ev.ID, ev.Sig); chk.E(err) {
  51  				return
  52  			}
  53  			err = errorf.W("event Subscription incorrect but signature is valid on correct Subscription")
  54  		}
  55  		return
  56  	}
  57  	return
  58  }
  59