summaryrefslogtreecommitdiffstats
path: root/keys_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'keys_test.go')
-rw-r--r--keys_test.go333
1 files changed, 333 insertions, 0 deletions
diff --git a/keys_test.go b/keys_test.go
new file mode 100644
index 0000000..6c3dd3d
--- /dev/null
+++ b/keys_test.go
@@ -0,0 +1,333 @@
1package nostr
2
3import (
4 "encoding/hex"
5 "strings"
6 "testing"
7)
8
9func TestGenerateKey(t *testing.T) {
10 key1, err := GenerateKey()
11 if err != nil {
12 t.Fatalf("GenerateKey() error = %v", err)
13 }
14
15 if !key1.CanSign() {
16 t.Error("Generated key should be able to sign")
17 }
18
19 // Private key should be 64 hex characters
20 if len(key1.Private()) != 64 {
21 t.Errorf("Private() length = %d, want 64", len(key1.Private()))
22 }
23
24 // Public key should be 64 hex characters
25 if len(key1.Public()) != 64 {
26 t.Errorf("Public() length = %d, want 64", len(key1.Public()))
27 }
28
29 // Should be valid hex
30 if _, err := hex.DecodeString(key1.Private()); err != nil {
31 t.Errorf("Private() is not valid hex: %v", err)
32 }
33 if _, err := hex.DecodeString(key1.Public()); err != nil {
34 t.Errorf("Public() is not valid hex: %v", err)
35 }
36
37 // Keys should be unique
38 key2, err := GenerateKey()
39 if err != nil {
40 t.Fatalf("GenerateKey() second call error = %v", err)
41 }
42 if key1.Private() == key2.Private() {
43 t.Error("GenerateKey() returned same private key twice")
44 }
45}
46
47func TestKeyNpubNsec(t *testing.T) {
48 key, err := GenerateKey()
49 if err != nil {
50 t.Fatalf("GenerateKey() error = %v", err)
51 }
52
53 npub := key.Npub()
54 nsec := key.Nsec()
55
56 // Check prefixes
57 if !strings.HasPrefix(npub, "npub1") {
58 t.Errorf("Npub() = %s, want prefix 'npub1'", npub)
59 }
60 if !strings.HasPrefix(nsec, "nsec1") {
61 t.Errorf("Nsec() = %s, want prefix 'nsec1'", nsec)
62 }
63
64 // Should be able to parse them back
65 keyFromNsec, err := ParseKey(nsec)
66 if err != nil {
67 t.Fatalf("ParseKey(nsec) error = %v", err)
68 }
69 if keyFromNsec.Private() != key.Private() {
70 t.Error("ParseKey(nsec) did not restore original private key")
71 }
72
73 keyFromNpub, err := ParsePublicKey(npub)
74 if err != nil {
75 t.Fatalf("ParsePublicKey(npub) error = %v", err)
76 }
77 if keyFromNpub.Public() != key.Public() {
78 t.Error("ParsePublicKey(npub) did not restore original public key")
79 }
80}
81
82func TestParseKey(t *testing.T) {
83 // Known test vector
84 hexKey := "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
85
86 key, err := ParseKey(hexKey)
87 if err != nil {
88 t.Fatalf("ParseKey(hex) error = %v", err)
89 }
90
91 if !key.CanSign() {
92 t.Error("ParseKey should return key that can sign")
93 }
94
95 if key.Private() != hexKey {
96 t.Errorf("Private() = %s, want %s", key.Private(), hexKey)
97 }
98
99 // Parse the nsec back
100 nsec := key.Nsec()
101 key2, err := ParseKey(nsec)
102 if err != nil {
103 t.Fatalf("ParseKey(nsec) error = %v", err)
104 }
105 if key2.Private() != hexKey {
106 t.Error("Round-trip through nsec failed")
107 }
108}
109
110func TestParseKeyErrors(t *testing.T) {
111 tests := []struct {
112 name string
113 key string
114 }{
115 {"invalid hex", "not-hex"},
116 {"too short", "0123456789abcdef"},
117 {"too long", "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef00"},
118 {"invalid nsec", "nsec1invalid"},
119 }
120
121 for _, tt := range tests {
122 t.Run(tt.name, func(t *testing.T) {
123 _, err := ParseKey(tt.key)
124 if err == nil {
125 t.Error("ParseKey() expected error, got nil")
126 }
127 })
128 }
129}
130
131func TestParsePublicKey(t *testing.T) {
132 // Generate a key and extract public
133 fullKey, _ := GenerateKey()
134 pubHex := fullKey.Public()
135
136 // Parse public key from hex
137 key, err := ParsePublicKey(pubHex)
138 if err != nil {
139 t.Fatalf("ParsePublicKey(hex) error = %v", err)
140 }
141
142 if key.CanSign() {
143 t.Error("ParsePublicKey should return key that cannot sign")
144 }
145
146 if key.Public() != pubHex {
147 t.Errorf("Public() = %s, want %s", key.Public(), pubHex)
148 }
149
150 if key.Private() != "" {
151 t.Error("Private() should return empty string for public-only key")
152 }
153
154 if key.Nsec() != "" {
155 t.Error("Nsec() should return empty string for public-only key")
156 }
157
158 // Parse from npub
159 npub := fullKey.Npub()
160 key2, err := ParsePublicKey(npub)
161 if err != nil {
162 t.Fatalf("ParsePublicKey(npub) error = %v", err)
163 }
164 if key2.Public() != pubHex {
165 t.Error("ParsePublicKey(npub) did not restore correct public key")
166 }
167}
168
169func TestParsePublicKeyErrors(t *testing.T) {
170 tests := []struct {
171 name string
172 key string
173 }{
174 {"invalid hex", "not-hex"},
175 {"too short", "0123456789abcdef"},
176 {"invalid npub", "npub1invalid"},
177 }
178
179 for _, tt := range tests {
180 t.Run(tt.name, func(t *testing.T) {
181 _, err := ParsePublicKey(tt.key)
182 if err == nil {
183 t.Error("ParsePublicKey() expected error, got nil")
184 }
185 })
186 }
187}
188
189func TestKeySign(t *testing.T) {
190 key, err := GenerateKey()
191 if err != nil {
192 t.Fatalf("GenerateKey() error = %v", err)
193 }
194
195 event := &Event{
196 CreatedAt: 1704067200,
197 Kind: 1,
198 Tags: Tags{},
199 Content: "Test message",
200 }
201
202 if err := key.Sign(event); err != nil {
203 t.Fatalf("Sign() error = %v", err)
204 }
205
206 // Check that all fields are set
207 if event.PubKey == "" {
208 t.Error("Sign() did not set PubKey")
209 }
210 if event.ID == "" {
211 t.Error("Sign() did not set ID")
212 }
213 if event.Sig == "" {
214 t.Error("Sign() did not set Sig")
215 }
216
217 // PubKey should match
218 if event.PubKey != key.Public() {
219 t.Errorf("PubKey = %s, want %s", event.PubKey, key.Public())
220 }
221
222 // Signature should be 128 hex characters (64 bytes)
223 if len(event.Sig) != 128 {
224 t.Errorf("Signature length = %d, want 128", len(event.Sig))
225 }
226}
227
228func TestKeySignPublicOnlyError(t *testing.T) {
229 fullKey, _ := GenerateKey()
230 pubOnlyKey, _ := ParsePublicKey(fullKey.Public())
231
232 event := &Event{
233 CreatedAt: 1704067200,
234 Kind: 1,
235 Tags: Tags{},
236 Content: "Test",
237 }
238
239 err := pubOnlyKey.Sign(event)
240 if err == nil {
241 t.Error("Sign() with public-only key should return error")
242 }
243}
244
245func TestEventVerify(t *testing.T) {
246 key, err := GenerateKey()
247 if err != nil {
248 t.Fatalf("GenerateKey() error = %v", err)
249 }
250
251 event := &Event{
252 CreatedAt: 1704067200,
253 Kind: 1,
254 Tags: Tags{{"test", "value"}},
255 Content: "Test message for verification",
256 }
257
258 if err := key.Sign(event); err != nil {
259 t.Fatalf("Sign() error = %v", err)
260 }
261
262 if !event.Verify() {
263 t.Error("Verify() returned false for valid signature")
264 }
265}
266
267func TestEventVerifyInvalid(t *testing.T) {
268 key, err := GenerateKey()
269 if err != nil {
270 t.Fatalf("GenerateKey() error = %v", err)
271 }
272
273 event := &Event{
274 CreatedAt: 1704067200,
275 Kind: 1,
276 Tags: Tags{},
277 Content: "Test message",
278 }
279
280 if err := key.Sign(event); err != nil {
281 t.Fatalf("Sign() error = %v", err)
282 }
283
284 // Corrupt the content (ID becomes invalid)
285 event.Content = "Modified content"
286 if event.Verify() {
287 t.Error("Verify() returned true for modified content")
288 }
289
290 // Restore content but corrupt signature
291 event.Content = "Test message"
292 event.SetID()
293 event.Sig = "0000000000000000000000000000000000000000000000000000000000000000" +
294 "0000000000000000000000000000000000000000000000000000000000000000"
295 if event.Verify() {
296 t.Error("Verify() returned true for invalid signature")
297 }
298}
299
300func TestSignAndVerifyRoundTrip(t *testing.T) {
301 // Generate key
302 key, err := GenerateKey()
303 if err != nil {
304 t.Fatalf("GenerateKey() error = %v", err)
305 }
306
307 // Create and sign event
308 event := &Event{
309 CreatedAt: 1704067200,
310 Kind: KindTextNote,
311 Tags: Tags{{"t", "test"}},
312 Content: "Integration test message",
313 }
314
315 if err := key.Sign(event); err != nil {
316 t.Fatalf("Sign() error = %v", err)
317 }
318
319 // Verify public key matches
320 if event.PubKey != key.Public() {
321 t.Errorf("Signed event PubKey = %s, want %s", event.PubKey, key.Public())
322 }
323
324 // Verify the signature
325 if !event.Verify() {
326 t.Error("Verify() failed for freshly signed event")
327 }
328
329 // Check ID is correct
330 if !event.CheckID() {
331 t.Error("CheckID() failed for freshly signed event")
332 }
333}