keys.go raw
1 package bech32encoding
2
3 import (
4 "bytes"
5 "strings"
6
7 "next.orly.dev/pkg/nostr/crypto/ec"
8 "next.orly.dev/pkg/nostr/crypto/ec/bech32"
9 "next.orly.dev/pkg/nostr/crypto/ec/schnorr"
10 "next.orly.dev/pkg/nostr/crypto/ec/secp256k1"
11 "next.orly.dev/pkg/nostr/encoders/hex"
12 "next.orly.dev/pkg/nostr/utils"
13 "next.orly.dev/pkg/nostr/utils/constraints"
14 "next.orly.dev/pkg/lol/chk"
15 "next.orly.dev/pkg/lol/log"
16 )
17
18 const (
19 // MinKeyStringLen is 56 because Bech32 needs 52 characters plus 4 for the HRP,
20 // any string shorter than this cannot be a nostr key.
21 MinKeyStringLen = 56
22 // HexKeyLen is the length of a nostr key in hexadecimal.
23 HexKeyLen = 64
24 // Bech32HRPLen is the length of the standard nostr keys, nsec and npub.
25 Bech32HRPLen = 4
26 )
27
28 var (
29 // SecHRP is the standard Human Readable Prefix (HRP) for a nostr secret key in bech32 encoding - nsec
30 SecHRP = []byte("nsec")
31 // PubHRP is the standard Human Readable Prefix (HRP) for a nostr public key in bech32 encoding - nsec
32 PubHRP = []byte("npub")
33 )
34
35 // ConvertForBech32 performs the bit expansion required for encoding into Bech32.
36 func ConvertForBech32(b8 []byte) (b5 []byte, err error) {
37 return bech32.ConvertBits(
38 b8, 8, 5,
39 true,
40 )
41 }
42
43 // ConvertFromBech32 collapses together the bit expanded 5 bit numbers encoded in bech32.
44 func ConvertFromBech32(b5 []byte) (b8 []byte, err error) {
45 return bech32.ConvertBits(
46 b5, 5, 8,
47 true,
48 )
49 }
50
51 // SecretKeyToNsec encodes an secp256k1 secret key as a Bech32 string (nsec).
52 func SecretKeyToNsec(sk *secp256k1.SecretKey) (encoded []byte, err error) {
53 var b5 []byte
54 if b5, err = ConvertForBech32(sk.Serialize()); chk.E(err) {
55 return
56 }
57 return bech32.Encode(SecHRP, b5)
58 }
59
60 // PublicKeyToNpub encodes a public key as a bech32 string (npub).
61 func PublicKeyToNpub(pk *secp256k1.PublicKey) (encoded []byte, err error) {
62 var bits5 []byte
63 pubKeyBytes := schnorr.SerializePubKey(pk)
64 if bits5, err = ConvertForBech32(pubKeyBytes); chk.E(err) {
65 return
66 }
67 return bech32.Encode(PubHRP, bits5)
68 }
69
70 // NsecToSecretKey decodes a nostr secret key (nsec) and returns the secp256k1
71 // secret key.
72 func NsecToSecretKey[V constraints.Bytes](encoded V) (
73 sk *secp256k1.SecretKey, err error,
74 ) {
75 var b8 []byte
76 if b8, err = NsecToBytes(encoded); chk.E(err) {
77 return
78 }
79 sk = secp256k1.SecKeyFromBytes(b8)
80 return
81 }
82
83 // NsecToBytes converts a nostr bech32 encoded secret key to raw bytes.
84 func NsecToBytes[V constraints.Bytes](encoded V) (sk []byte, err error) {
85 var b5, hrp []byte
86 if hrp, b5, err = bech32.Decode([]byte(encoded)); chk.E(err) {
87 return
88 }
89 if !utils.FastEqual(hrp, SecHRP) {
90 err = log.E.Err(
91 "wrong human readable part, got '%s' want '%s'",
92 hrp, SecHRP,
93 )
94 return
95 }
96 if sk, err = ConvertFromBech32(b5); chk.E(err) {
97 return
98 }
99 sk = sk[:secp256k1.SecKeyBytesLen]
100 return
101 }
102
103 // NpubToBytes converts a bech32 encoded public key to raw bytes.
104 func NpubToBytes[V constraints.Bytes](encoded V) (pk []byte, err error) {
105 var b5, hrp []byte
106 if hrp, b5, err = bech32.Decode([]byte(encoded)); chk.E(err) {
107 return
108 }
109 if !utils.FastEqual(hrp, PubHRP) {
110 err = log.E.Err(
111 "wrong human readable part, got '%s' want '%s'",
112 hrp, SecHRP,
113 )
114 return
115 }
116 if pk, err = ConvertFromBech32(b5); chk.E(err) {
117 return
118 }
119 pk = pk[:schnorr.PubKeyBytesLen]
120 return
121 }
122
123 // NpubToPublicKey decodes an nostr public key (npub) and returns an secp256k1
124 // public key.
125 func NpubToPublicKey[V constraints.Bytes](encoded V) (
126 pk *secp256k1.PublicKey, err error,
127 ) {
128 var b5, b8, hrp []byte
129 if hrp, b5, err = bech32.Decode([]byte(encoded)); chk.E(err) {
130 err = log.E.Err("ERROR: '%s'", err)
131 return
132 }
133 if !utils.FastEqual(hrp, PubHRP) {
134 err = log.E.Err(
135 "wrong human readable part, got '%s' want '%s'",
136 hrp, PubHRP,
137 )
138 return
139 }
140 if b8, err = ConvertFromBech32(b5); chk.E(err) {
141 return
142 }
143 return schnorr.ParsePubKey(b8[:schnorr.PubKeyBytesLen])
144 }
145
146 // HexToPublicKey decodes a string that should be a 64 character long hex
147 // encoded public key into a btcec.PublicKey that can be used to verify a
148 // signature or encode to Bech32.
149 func HexToPublicKey[V constraints.Bytes](pk V) (p *btcec.PublicKey, err error) {
150 if len(pk) != HexKeyLen {
151 err = log.E.Err(
152 "secret key is %d bytes, must be %d", len(pk),
153 HexKeyLen,
154 )
155 return
156 }
157 var pb []byte
158 if pb, err = hex.Dec(string(pk)); chk.D(err) {
159 return
160 }
161 if p, err = schnorr.ParsePubKey(pb); chk.D(err) {
162 return
163 }
164 return
165 }
166
167 func NpubOrHexToPublicKey[V constraints.Bytes](encoded V) (
168 pk *btcec.PublicKey, err error,
169 ) {
170 if !strings.HasPrefix(
171 "npub", string(encoded),
172 ) && len(encoded) == HexKeyLen {
173 return HexToPublicKey(encoded)
174 }
175 return NpubToPublicKey(encoded)
176 }
177
178 func NpubOrHexToPublicKeyBinary[V constraints.Bytes](enc V) (
179 pkb []byte, err error,
180 ) {
181 if bytes.HasPrefix([]byte(enc), []byte("npub")) {
182 return NpubToBytes(enc)
183 }
184 return hex.Dec(string(enc))
185 }
186
187 // HexToSecretKey decodes a string that should be a 64 character long hex
188 // encoded public key into a btcec.PublicKey that can be used to verify a
189 // signature or encode to Bech32.
190 func HexToSecretKey[V constraints.Bytes](sk V) (s *btcec.SecretKey, err error) {
191 if len(sk) != HexKeyLen {
192 err = log.E.Err(
193 "secret key is %d bytes, must be %d", len(sk),
194 HexKeyLen,
195 )
196 return
197 }
198 pb := make([]byte, schnorr.PubKeyBytesLen)
199 if _, err = hex.DecBytes(pb, []byte(sk)); chk.D(err) {
200 return
201 }
202 if s = secp256k1.SecKeyFromBytes(pb); chk.D(err) {
203 return
204 }
205 return
206 }
207
208 // HexToNpub converts a raw 64 character hex encoded public key (as used in
209 // standard nostr json events) to a bech32 encoded npub.
210 func HexToNpub[V constraints.Bytes](publicKeyHex V) (s []byte, err error) {
211 b := make([]byte, schnorr.PubKeyBytesLen)
212 if _, err = hex.DecBytes(b, []byte(publicKeyHex)); chk.D(err) {
213 err = log.E.Err("failed to decode public key hex: %w", err)
214 return
215 }
216 var bits5 []byte
217 if bits5, err = bech32.ConvertBits(b, 8, 5, true); chk.D(err) {
218 return nil, err
219 }
220 return bech32.Encode(NpubHRP, bits5)
221 }
222
223 // BinToNpub converts a raw 32 byte public key to nostr bech32 encoded npub.
224 func BinToNpub(b []byte) (s []byte, err error) {
225 var bits5 []byte
226 if bits5, err = bech32.ConvertBits(b, 8, 5, true); chk.D(err) {
227 return nil, err
228 }
229 return bech32.Encode(NpubHRP, bits5)
230 }
231
232 // HexToNsec converts a hex encoded secret key to a bech32 encoded nsec.
233 func HexToNsec[V constraints.Bytes](sk V) (nsec []byte, err error) {
234 var s *btcec.SecretKey
235 if s, err = HexToSecretKey(sk); chk.E(err) {
236 return
237 }
238 if nsec, err = SecretKeyToNsec(s); chk.E(err) {
239 return
240 }
241 return
242 }
243
244 // BinToNsec converts a binary secret key to a bech32 encoded nsec.
245 func BinToNsec(sk []byte) (nsec []byte, err error) {
246 var s *btcec.SecretKey
247 s, _ = btcec.SecKeyFromBytes(sk)
248 if nsec, err = SecretKeyToNsec(s); chk.E(err) {
249 return
250 }
251 return
252 }
253
254 // SecretKeyToHex converts a secret key to the hex encoding.
255 func SecretKeyToHex(sk *btcec.SecretKey) (hexSec []byte) {
256 return hex.EncAppend(nil, sk.Serialize())
257 }
258
259 // NsecToHex converts a bech32 encoded nostr secret key to a raw hexadecimal
260 // string.
261 func NsecToHex[V constraints.Bytes](nsec V) (hexSec []byte, err error) {
262 var sk *secp256k1.SecretKey
263 if sk, err = NsecToSecretKey(nsec); chk.E(err) {
264 return
265 }
266 hexSec = SecretKeyToHex(sk)
267 return
268 }
269