package nostr import ( "encoding/hex" "errors" "strings" gn "github.com/nbd-wtf/go-nostr" "github.com/nbd-wtf/go-nostr/nip19" ) var ( ErrInvalidPubkey = errors.New("invalid pubkey") ErrInvalidNsec = errors.New("invalid nsec") ) // NormalizePubkey accepts npub bech32 or 64-char hex and returns lowercase hex. func NormalizePubkey(in string) (string, error) { in = strings.TrimSpace(in) if in == "" { return "", ErrInvalidPubkey } if strings.HasPrefix(in, "npub1") { prefix, data, err := nip19.Decode(in) if err != nil { return "", ErrInvalidPubkey } if prefix != "npub" { return "", ErrInvalidPubkey } s, ok := data.(string) if !ok { return "", ErrInvalidPubkey } return strings.ToLower(s), nil } if len(in) != 64 { return "", ErrInvalidPubkey } if _, err := hex.DecodeString(in); err != nil { return "", ErrInvalidPubkey } if !gn.IsValidPublicKey(in) { return "", ErrInvalidPubkey } return strings.ToLower(in), nil } // HexToNpub converts hex pubkey to npub bech32. Empty string on error. func HexToNpub(hexpk string) string { npub, err := nip19.EncodePublicKey(hexpk) if err != nil { return "" } return npub } // NsecToHex decodes nsec1... to hex private key. func NsecToHex(nsec string) (string, error) { prefix, data, err := nip19.Decode(strings.TrimSpace(nsec)) if err != nil { return "", ErrInvalidNsec } if prefix != "nsec" { return "", ErrInvalidNsec } s, ok := data.(string) if !ok { return "", ErrInvalidNsec } return strings.ToLower(s), nil }