// Package p8k provides a signer.I implementation using the secp256k1/schnorr packages. package p8k import ( "crypto/sha256" "fmt" "smesh.lol/pkg/nostr/ec/secp256k1" "smesh.lol/pkg/nostr/ec/schnorr" "smesh.lol/pkg/nostr/signer" ) type Signer struct { sec *secp256k1.SecretKey pub *secp256k1.PublicKey } var _ signer.I = (*Signer)(nil) func New() (*Signer, error) { return &Signer{}, nil } func MustNew() *Signer { return &Signer{} } func (s *Signer) Generate() error { sk, err := secp256k1.GenerateSecretKey() if err != nil { return err } s.sec = sk s.pub = sk.PubKey() return nil } func (s *Signer) InitSec(sec []byte) error { sk := secp256k1.SecKeyFromBytes(sec) if sk == nil { return fmt.Errorf("invalid secret key") } s.sec = sk s.pub = sk.PubKey() return nil } func (s *Signer) InitPub(pub []byte) error { pk, err := schnorr.ParsePubKey(pub) if err != nil { return err } s.pub = pk return nil } func (s *Signer) Sec() []byte { if s.sec == nil { return nil } return s.sec.Serialize() } func (s *Signer) Pub() []byte { if s.pub == nil { return nil } return schnorr.SerializePubKey(s.pub) } func (s *Signer) Sign(msg []byte) ([]byte, error) { if s.sec == nil { return nil, fmt.Errorf("no secret key") } sig, err := schnorr.Sign(s.sec, msg) if err != nil { return nil, err } return sig.Serialize(), nil } func (s *Signer) Verify(msg, sig []byte) (bool, error) { if s.pub == nil { return false, fmt.Errorf("no public key") } parsed, err := schnorr.ParseSignature(sig) if err != nil { return false, err } return parsed.Verify(msg, s.pub), nil } func (s *Signer) Zero() { if s.sec != nil { s.sec.Zero() s.sec = nil } s.pub = nil } func (s *Signer) ECDH(pub []byte) ([]byte, error) { raw, err := s.ECDHRaw(pub) if err != nil { return nil, err } h := sha256.Sum256(raw) return h[:], nil } func (s *Signer) ECDHRaw(pub []byte) ([]byte, error) { if s.sec == nil { return nil, fmt.Errorf("no secret key") } pk, err := schnorr.ParsePubKey(pub) if err != nil { return nil, err } return secp256k1.GenerateSharedSecret(s.sec, pk), nil }