-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathcrypto.test.js
More file actions
178 lines (150 loc) · 5.98 KB
/
Copy pathcrypto.test.js
File metadata and controls
178 lines (150 loc) · 5.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/**
* Tests for Podkey cryptographic functions
*/
import { describe, it } from 'node:test';
import assert from 'node:assert';
import {
generateKeypair,
getPublicKey,
signEvent,
verifySignature,
getEventHash,
isValidPublicKey
} from '../src/crypto.js';
describe('Crypto Functions', () => {
describe('generateKeypair', () => {
it('should generate a valid keypair', async () => {
const keypair = await generateKeypair();
assert(keypair, 'Keypair should be returned');
assert(keypair.privateKey, 'Private key should exist');
assert(keypair.publicKey, 'Public key should exist');
assert.strictEqual(keypair.privateKey.length, 64, 'Private key should be 64 chars');
assert.strictEqual(keypair.publicKey.length, 64, 'Public key should be 64 chars');
assert(/^[0-9a-fA-F]{64}$/.test(keypair.privateKey), 'Private key should be hex');
assert(/^[0-9a-fA-F]{64}$/.test(keypair.publicKey), 'Public key should be hex');
});
it('should generate different keypairs each time', async () => {
const keypair1 = await generateKeypair();
const keypair2 = await generateKeypair();
assert.notStrictEqual(keypair1.privateKey, keypair2.privateKey, 'Private keys should differ');
assert.notStrictEqual(keypair1.publicKey, keypair2.publicKey, 'Public keys should differ');
});
});
describe('getPublicKey', () => {
it('should derive public key from private key', async () => {
const keypair = await generateKeypair();
const derivedPublicKey = getPublicKey(keypair.privateKey);
assert.strictEqual(derivedPublicKey, keypair.publicKey, 'Derived public key should match');
assert.strictEqual(derivedPublicKey.length, 64, 'Public key should be 64 chars');
});
it('should throw error for invalid private key', () => {
assert.throws(() => getPublicKey('invalid'), /Private key must be/);
assert.throws(() => getPublicKey('123'), /Private key must be/);
assert.throws(() => getPublicKey('x'.repeat(64)), /Private key must be valid hexadecimal/);
});
});
describe('signEvent', () => {
it('should sign an event correctly', async () => {
const keypair = await generateKeypair();
const event = {
kind: 1,
created_at: Math.floor(Date.now() / 1000),
tags: [],
content: 'Test event'
};
const signed = await signEvent(event, keypair.privateKey);
assert(signed.id, 'Event should have id');
assert(signed.pubkey, 'Event should have pubkey');
assert(signed.sig, 'Event should have signature');
assert.strictEqual(signed.id.length, 64, 'Event ID should be 64 chars');
assert.strictEqual(signed.pubkey.length, 64, 'Pubkey should be 64 chars');
assert.strictEqual(signed.sig.length, 128, 'Signature should be 128 chars');
assert.strictEqual(signed.pubkey, keypair.publicKey, 'Pubkey should match');
});
it('should include pubkey in event hash', async () => {
const keypair = await generateKeypair();
const event = {
kind: 1,
created_at: Math.floor(Date.now() / 1000),
tags: [],
content: 'Test'
};
const signed = await signEvent(event, keypair.privateKey);
const hashWithPubkey = getEventHash({ ...event, pubkey: keypair.publicKey });
assert.strictEqual(signed.id, hashWithPubkey, 'Event ID should match hash with pubkey');
});
});
describe('verifySignature', () => {
it('should verify a valid signature', async () => {
const keypair = await generateKeypair();
const event = {
kind: 1,
created_at: Math.floor(Date.now() / 1000),
tags: [],
content: 'Test event'
};
const signed = await signEvent(event, keypair.privateKey);
const isValid = await verifySignature(signed);
assert.strictEqual(isValid, true, 'Signature should be valid');
});
it('should reject invalid signature', async () => {
const keypair = await generateKeypair();
const event = {
kind: 1,
created_at: Math.floor(Date.now() / 1000),
tags: [],
content: 'Test event',
id: 'a'.repeat(64),
pubkey: keypair.publicKey,
sig: 'b'.repeat(128) // Invalid signature
};
const isValid = await verifySignature(event);
assert.strictEqual(isValid, false, 'Invalid signature should be rejected');
});
});
describe('getEventHash', () => {
it('should generate consistent hashes', () => {
const event = {
kind: 1,
created_at: 1234567890,
tags: [],
content: 'Test',
pubkey: 'a'.repeat(64)
};
const hash1 = getEventHash(event);
const hash2 = getEventHash(event);
assert.strictEqual(hash1, hash2, 'Hashes should be consistent');
assert.strictEqual(hash1.length, 64, 'Hash should be 64 chars');
});
it('should include pubkey in hash', () => {
const event1 = {
kind: 1,
created_at: 1234567890,
tags: [],
content: 'Test',
pubkey: 'a'.repeat(64)
};
const event2 = {
...event1,
pubkey: 'b'.repeat(64)
};
const hash1 = getEventHash(event1);
const hash2 = getEventHash(event2);
assert.notStrictEqual(hash1, hash2, 'Different pubkeys should produce different hashes');
});
});
describe('isValidPublicKey', () => {
it('should validate correct public keys', () => {
assert.strictEqual(isValidPublicKey('a'.repeat(64)), true);
assert.strictEqual(isValidPublicKey('0123456789abcdef'.repeat(4)), true);
});
it('should reject invalid public keys', () => {
assert.strictEqual(isValidPublicKey(''), false);
assert.strictEqual(isValidPublicKey('a'.repeat(63)), false);
assert.strictEqual(isValidPublicKey('a'.repeat(65)), false);
assert.strictEqual(isValidPublicKey('g'.repeat(64)), false); // Invalid hex
assert.strictEqual(isValidPublicKey(null), false);
assert.strictEqual(isValidPublicKey(undefined), false);
});
});
});