package bech32encoding import ( "bytes" "crypto/ec/bech32" "crypto/secp256k1" "git.smesh.lol/nostr/pkg/hex" "git.smesh.lol/nostr/pkg/lol/chk" "git.smesh.lol/nostr/pkg/lol/log" ) const ( MinKeyStringLen = 56 HexKeyLen = 64 Bech32HRPLen = 4 ) var ( SecHRP []byte PubHRP []byte ) func init() { SecHRP = []byte("nsec") PubHRP = []byte("npub") NoteHRP = []byte("note") NsecHRP = []byte("nsec") NpubHRP = []byte("npub") NprofileHRP = []byte("nprofile") NeventHRP = []byte("nevent") NentityHRP = []byte("naddr") } func ConvertForBech32(b8 []byte) (b5 []byte, err error) { return bech32.ConvertBits(b8, 8, 5, true) } func ConvertFromBech32(b5 []byte) (b8 []byte, err error) { return bech32.ConvertBits(b5, 5, 8, true) } func NsecToBytes(encoded []byte) (sk []byte, err error) { var b5, hrp []byte if hrp, b5, err = bech32.Decode(encoded); chk.E(err) { return } if !bytes.Equal(hrp, SecHRP) { err = log.E.Err([]byte("wrong human readable part, got '%s' want '%s'"), hrp, SecHRP) return } if sk, err = ConvertFromBech32(b5); chk.E(err) { return } sk = sk[:secp256k1.PubKeyBytesLen] return } func NpubToBytes(encoded []byte) (pk []byte, err error) { var b5, hrp []byte if hrp, b5, err = bech32.Decode(encoded); chk.E(err) { return } if !bytes.Equal(hrp, PubHRP) { err = log.E.Err([]byte("wrong human readable part, got '%s' want '%s'"), hrp, PubHRP) return } if pk, err = ConvertFromBech32(b5); chk.E(err) { return } pk = pk[:secp256k1.PubKeyBytesLen] return } func HexToNpub(publicKeyHex []byte) (s []byte, err error) { b := []byte{:secp256k1.PubKeyBytesLen} if _, err = hex.DecBytes(b, publicKeyHex); chk.D(err) { return } var bits5 []byte if bits5, err = bech32.ConvertBits(b, 8, 5, true); chk.D(err) { return } return bech32.Encode(NpubHRP, bits5) } func BinToNpub(b []byte) (s []byte, err error) { var bits5 []byte if bits5, err = bech32.ConvertBits(b, 8, 5, true); chk.D(err) { return } return bech32.Encode(NpubHRP, bits5) } func BinToNsec(sk []byte) (nsec []byte, err error) { var b5 []byte if b5, err = ConvertForBech32(sk); chk.E(err) { return } return bech32.Encode(SecHRP, b5) } func HexToNsec(sk []byte) (nsec []byte, err error) { if len(sk) != HexKeyLen { err = log.E.Err([]byte("secret key is %d bytes, must be %d"), len(sk), HexKeyLen) return } pb := []byte{:secp256k1.PubKeyBytesLen} if _, err = hex.DecBytes(pb, sk); chk.D(err) { return } return BinToNsec(pb) } func NsecToHex(nsec []byte) (hexSec []byte, err error) { var sk []byte if sk, err = NsecToBytes(nsec); chk.E(err) { return } return hex.EncAppend(nil, sk), nil }