mirror of
https://github.com/nbd-wtf/go-nostr.git
synced 2025-06-28 17:53:32 +02:00
fix nip19 bech32 encoding and decoding.
This commit is contained in:
parent
dd0571229b
commit
2ec7957409
@ -9,14 +9,13 @@ const charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
|
|||||||
|
|
||||||
var gen = []int{0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3}
|
var gen = []int{0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3}
|
||||||
|
|
||||||
// Decode decodes a bech32 encoded string, returning the human-readable
|
// decode decodes a bech32 encoded string, returning the human-readable
|
||||||
// part and the data part excluding the checksum.
|
// part and the data part excluding the checksum.
|
||||||
func decode(bech string) (string, []byte, error) {
|
func decode(bech string) (string, []byte, error) {
|
||||||
// Only ASCII characters between 33 and 126 are allowed.
|
// Only ASCII characters between 33 and 126 are allowed.
|
||||||
for i := 0; i < len(bech); i++ {
|
for i := 0; i < len(bech); i++ {
|
||||||
if bech[i] < 33 || bech[i] > 126 {
|
if bech[i] < 33 || bech[i] > 126 {
|
||||||
return "", nil, fmt.Errorf("invalid character in "+
|
return "", nil, fmt.Errorf("invalid character in string: '%c'", bech[i])
|
||||||
"string: '%c'", bech[i])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24,8 +23,7 @@ func decode(bech string) (string, []byte, error) {
|
|||||||
lower := strings.ToLower(bech)
|
lower := strings.ToLower(bech)
|
||||||
upper := strings.ToUpper(bech)
|
upper := strings.ToUpper(bech)
|
||||||
if bech != lower && bech != upper {
|
if bech != lower && bech != upper {
|
||||||
return "", nil, fmt.Errorf("string not all lowercase or all " +
|
return "", nil, fmt.Errorf("string not all lowercase or all uppercase")
|
||||||
"uppercase")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We'll work with the lowercase string from now on.
|
// We'll work with the lowercase string from now on.
|
||||||
@ -48,8 +46,7 @@ func decode(bech string) (string, []byte, error) {
|
|||||||
// 'charset'.
|
// 'charset'.
|
||||||
decoded, err := toBytes(data)
|
decoded, err := toBytes(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, fmt.Errorf("failed converting data to bytes: "+
|
return "", nil, fmt.Errorf("failed converting data to bytes: %s", err.Error())
|
||||||
"%v", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !bech32VerifyChecksum(hrp, decoded) {
|
if !bech32VerifyChecksum(hrp, decoded) {
|
||||||
@ -58,8 +55,7 @@ func decode(bech string) (string, []byte, error) {
|
|||||||
expected, err := toChars(bech32Checksum(hrp,
|
expected, err := toChars(bech32Checksum(hrp,
|
||||||
decoded[:len(decoded)-6]))
|
decoded[:len(decoded)-6]))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
moreInfo = fmt.Sprintf("Expected %v, got %v.",
|
moreInfo = fmt.Sprintf("Expected %v, got %v.", expected, checksum)
|
||||||
expected, checksum)
|
|
||||||
}
|
}
|
||||||
return "", nil, fmt.Errorf("checksum failed. " + moreInfo)
|
return "", nil, fmt.Errorf("checksum failed. " + moreInfo)
|
||||||
}
|
}
|
||||||
@ -81,8 +77,7 @@ func encode(hrp string, data []byte) (string, error) {
|
|||||||
// represented using the specified charset.
|
// represented using the specified charset.
|
||||||
dataChars, err := toChars(combined)
|
dataChars, err := toChars(combined)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("unable to convert data bytes to chars: "+
|
return "", fmt.Errorf("unable to convert data bytes to chars: %s", err.Error())
|
||||||
"%v", err)
|
|
||||||
}
|
}
|
||||||
return hrp + "1" + dataChars, nil
|
return hrp + "1" + dataChars, nil
|
||||||
}
|
}
|
||||||
@ -115,9 +110,9 @@ func toChars(data []byte) (string, error) {
|
|||||||
return string(result), nil
|
return string(result), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConvertBits converts a byte slice where each byte is encoding fromBits bits,
|
// convertBits converts a byte slice where each byte is encoding fromBits bits,
|
||||||
// to a byte slice where each byte is encoding toBits bits.
|
// to a byte slice where each byte is encoding toBits bits.
|
||||||
func ConvertBits(data []byte, fromBits, toBits uint8, pad bool) ([]byte, error) {
|
func convertBits(data []byte, fromBits, toBits uint8, pad bool) ([]byte, error) {
|
||||||
if fromBits < 1 || fromBits > 8 || toBits < 1 || toBits > 8 {
|
if fromBits < 1 || fromBits > 8 || toBits < 1 || toBits > 8 {
|
||||||
return nil, fmt.Errorf("only bit groups between 1 and 8 allowed")
|
return nil, fmt.Errorf("only bit groups between 1 and 8 allowed")
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ func EncodePrivateKey(privateKeyHex string) (string, error) {
|
|||||||
func EncodePublicKey(publicKeyHex string, masterRelay string) (string, error) {
|
func EncodePublicKey(publicKeyHex string, masterRelay string) (string, error) {
|
||||||
b, err := hex.DecodeString(publicKeyHex)
|
b, err := hex.DecodeString(publicKeyHex)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", fmt.Errorf("failed to decode public key hex: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
tlv := make([]byte, 0, 64)
|
tlv := make([]byte, 0, 64)
|
||||||
@ -35,7 +35,12 @@ func EncodePublicKey(publicKeyHex string, masterRelay string) (string, error) {
|
|||||||
}
|
}
|
||||||
b = append(b, tlv...)
|
b = append(b, tlv...)
|
||||||
|
|
||||||
return encode("nsec", b)
|
bits5, err := convertBits(b, 8, 5, true)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return encode("npub", bits5)
|
||||||
}
|
}
|
||||||
|
|
||||||
func EncodeNote(eventIdHex string) (string, error) {
|
func EncodeNote(eventIdHex string) (string, error) {
|
||||||
@ -53,9 +58,14 @@ func Decode(bech32string string) ([]byte, string, error) {
|
|||||||
return nil, "", err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bits8, err := convertBits(data, 5, 8, false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", fmt.Errorf("failed translating data into 8 bits: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
if len(data) < 32 {
|
if len(data) < 32 {
|
||||||
return nil, "", fmt.Errorf("data is less than 32 bytes (%d)", len(data))
|
return nil, "", fmt.Errorf("data is less than 32 bytes (%d)", len(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
return data[0:32], prefix, nil
|
return bits8[0:32], prefix, nil
|
||||||
}
|
}
|
||||||
|
17
nip19/utils.go
Normal file
17
nip19/utils.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package nip19
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TranslatePublicKey turns a hex or bech32 public key into always hex
|
||||||
|
func TranslatePublicKey(bech32orHexKey string) string {
|
||||||
|
if strings.HasPrefix(bech32orHexKey, "npub1") {
|
||||||
|
data, _, _ := Decode(bech32orHexKey)
|
||||||
|
return hex.EncodeToString(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// just return what we got
|
||||||
|
return bech32orHexKey
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user