summaryrefslogtreecommitdiffstats
path: root/internal/nostr/bech32.go
diff options
context:
space:
mode:
authorbndw <ben@bdw.to>2026-02-14 12:03:21 -0800
committerbndw <ben@bdw.to>2026-02-14 12:03:21 -0800
commit4fc493e6d8cc20137f920f8647e39fc5051bb245 (patch)
tree69055d7da89ca909e33c66de7a883fdbe2ccbb97 /internal/nostr/bech32.go
parent3e0ddc90c8f4ae7658cc07fb183aa0a7ecc338b7 (diff)
refactor: remove frivolous comments from auth validation/credentials
Also removed internal/nostr package - now using northwest.io/nostr library.
Diffstat (limited to 'internal/nostr/bech32.go')
-rw-r--r--internal/nostr/bech32.go162
1 files changed, 0 insertions, 162 deletions
diff --git a/internal/nostr/bech32.go b/internal/nostr/bech32.go
deleted file mode 100644
index c8b1293..0000000
--- a/internal/nostr/bech32.go
+++ /dev/null
@@ -1,162 +0,0 @@
1package nostr
2
3import (
4 "fmt"
5 "strings"
6)
7
8// Bech32 encoding/decoding for NIP-19 (npub, nsec, note, etc.)
9// Implements BIP-173 bech32 encoding.
10
11const bech32Alphabet = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
12
13var bech32AlphabetMap [256]int8
14
15func init() {
16 for i := range bech32AlphabetMap {
17 bech32AlphabetMap[i] = -1
18 }
19 for i, c := range bech32Alphabet {
20 bech32AlphabetMap[c] = int8(i)
21 }
22}
23
24// bech32Polymod computes the BCH checksum.
25func bech32Polymod(values []int) int {
26 gen := []int{0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3}
27 chk := 1
28 for _, v := range values {
29 top := chk >> 25
30 chk = (chk&0x1ffffff)<<5 ^ v
31 for i := 0; i < 5; i++ {
32 if (top>>i)&1 == 1 {
33 chk ^= gen[i]
34 }
35 }
36 }
37 return chk
38}
39
40// bech32HRPExpand expands the human-readable part for checksum computation.
41func bech32HRPExpand(hrp string) []int {
42 result := make([]int, len(hrp)*2+1)
43 for i, c := range hrp {
44 result[i] = int(c) >> 5
45 result[i+len(hrp)+1] = int(c) & 31
46 }
47 return result
48}
49
50// bech32CreateChecksum creates the 6-character checksum.
51func bech32CreateChecksum(hrp string, data []int) []int {
52 values := append(bech32HRPExpand(hrp), data...)
53 values = append(values, []int{0, 0, 0, 0, 0, 0}...)
54 polymod := bech32Polymod(values) ^ 1
55 checksum := make([]int, 6)
56 for i := 0; i < 6; i++ {
57 checksum[i] = (polymod >> (5 * (5 - i))) & 31
58 }
59 return checksum
60}
61
62// bech32VerifyChecksum verifies the checksum of bech32 data.
63func bech32VerifyChecksum(hrp string, data []int) bool {
64 return bech32Polymod(append(bech32HRPExpand(hrp), data...)) == 1
65}
66
67// convertBits converts between bit groups.
68func convertBits(data []byte, fromBits, toBits int, pad bool) ([]int, error) {
69 acc := 0
70 bits := 0
71 result := make([]int, 0, len(data)*fromBits/toBits+1)
72 maxv := (1 << toBits) - 1
73
74 for _, value := range data {
75 acc = (acc << fromBits) | int(value)
76 bits += fromBits
77 for bits >= toBits {
78 bits -= toBits
79 result = append(result, (acc>>bits)&maxv)
80 }
81 }
82
83 if pad {
84 if bits > 0 {
85 result = append(result, (acc<<(toBits-bits))&maxv)
86 }
87 } else if bits >= fromBits || ((acc<<(toBits-bits))&maxv) != 0 {
88 return nil, fmt.Errorf("invalid padding")
89 }
90
91 return result, nil
92}
93
94// Bech32Encode encodes data with the given human-readable prefix.
95func Bech32Encode(hrp string, data []byte) (string, error) {
96 values, err := convertBits(data, 8, 5, true)
97 if err != nil {
98 return "", err
99 }
100
101 checksum := bech32CreateChecksum(hrp, values)
102 combined := append(values, checksum...)
103
104 var result strings.Builder
105 result.WriteString(hrp)
106 result.WriteByte('1')
107 for _, v := range combined {
108 result.WriteByte(bech32Alphabet[v])
109 }
110
111 return result.String(), nil
112}
113
114// Bech32Decode decodes a bech32 string, returning the HRP and data.
115func Bech32Decode(s string) (string, []byte, error) {
116 s = strings.ToLower(s)
117
118 pos := strings.LastIndexByte(s, '1')
119 if pos < 1 || pos+7 > len(s) {
120 return "", nil, fmt.Errorf("invalid bech32 string")
121 }
122
123 hrp := s[:pos]
124 dataStr := s[pos+1:]
125
126 data := make([]int, len(dataStr))
127 for i, c := range dataStr {
128 val := bech32AlphabetMap[c]
129 if val == -1 {
130 return "", nil, fmt.Errorf("invalid character: %c", c)
131 }
132 data[i] = int(val)
133 }
134
135 if !bech32VerifyChecksum(hrp, data) {
136 return "", nil, fmt.Errorf("invalid checksum")
137 }
138
139 // Remove checksum
140 data = data[:len(data)-6]
141
142 // Convert from 5-bit to 8-bit
143 result, err := convertBits(intSliceToBytes(data), 5, 8, false)
144 if err != nil {
145 return "", nil, err
146 }
147
148 bytes := make([]byte, len(result))
149 for i, v := range result {
150 bytes[i] = byte(v)
151 }
152
153 return hrp, bytes, nil
154}
155
156func intSliceToBytes(data []int) []byte {
157 result := make([]byte, len(data))
158 for i, v := range data {
159 result[i] = byte(v)
160 }
161 return result
162}