@nuggetslife/vc 0.0.21 → 0.0.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/test_fuzz.mjs ADDED
@@ -0,0 +1,202 @@
1
+ import { strict as assert } from 'assert';
2
+
3
+ // Import NAPI bindings - matching patterns from test.mjs and test_jose.mjs
4
+ import {
5
+ JsonLd,
6
+ BbsBlsSignature2020,
7
+ BbsBlsSignatureProof2020,
8
+ Bls12381G2KeyPair,
9
+ generateJwk,
10
+ generateKeyPair,
11
+ generalEncryptJson,
12
+ decryptJson,
13
+ compactSignJson,
14
+ compactJsonVerify,
15
+ flattenedSignJson,
16
+ jsonVerify,
17
+ JoseNamedCurve,
18
+ JoseKeyEncryption,
19
+ JoseContentEncryption,
20
+ JoseSigningAlgorithm,
21
+ } from './index.js';
22
+
23
+ let passed = 0;
24
+ let failed = 0;
25
+
26
+ async function test(name, fn) {
27
+ try {
28
+ await fn();
29
+ passed++;
30
+ console.log(` PASS: ${name}`);
31
+ } catch (e) {
32
+ failed++;
33
+ console.log(` FAIL: ${name}`);
34
+ console.log(` ${e.message}`);
35
+ }
36
+ }
37
+
38
+ function randomJson(depth = 0) {
39
+ if (depth > 3) return Math.random().toString(36);
40
+ const type = Math.floor(Math.random() * 5);
41
+ switch (type) {
42
+ case 0: return null;
43
+ case 1: return Math.random() * 1000 - 500;
44
+ case 2: return Math.random().toString(36).substring(2);
45
+ case 3: {
46
+ const arr = [];
47
+ for (let i = 0; i < Math.floor(Math.random() * 4); i++) arr.push(randomJson(depth + 1));
48
+ return arr;
49
+ }
50
+ case 4: {
51
+ const obj = {};
52
+ for (let i = 0; i < Math.floor(Math.random() * 4); i++) {
53
+ obj[Math.random().toString(36).substring(2, 7)] = randomJson(depth + 1);
54
+ }
55
+ return obj;
56
+ }
57
+ }
58
+ }
59
+
60
+ console.log('\n=== NAPI Fuzz Tests ===\n');
61
+
62
+ // Category 1: Random JSON to JsonLd operations (should not crash)
63
+ console.log('--- JSON-LD with random inputs ---');
64
+ for (let i = 0; i < 20; i++) {
65
+ await test(`JsonLd.expand random input #${i}`, async () => {
66
+ const jsonld = new JsonLd();
67
+ try {
68
+ await jsonld.expand(randomJson());
69
+ } catch (e) {
70
+ // Errors are fine, crashes are not
71
+ assert.ok(e instanceof Error, 'should throw Error, not crash');
72
+ }
73
+ });
74
+ }
75
+
76
+ for (let i = 0; i < 10; i++) {
77
+ await test(`JsonLd.compact random input #${i}`, async () => {
78
+ const jsonld = new JsonLd();
79
+ try {
80
+ await jsonld.compact(randomJson(), randomJson());
81
+ } catch (e) {
82
+ assert.ok(e instanceof Error);
83
+ }
84
+ });
85
+ }
86
+
87
+ for (let i = 0; i < 10; i++) {
88
+ await test(`JsonLd.frame random input #${i}`, async () => {
89
+ const jsonld = new JsonLd();
90
+ try {
91
+ await jsonld.frame(randomJson(), randomJson());
92
+ } catch (e) {
93
+ assert.ok(e instanceof Error);
94
+ }
95
+ });
96
+ }
97
+
98
+ // Category 2: Invalid key pairs to BBS operations
99
+ console.log('\n--- BBS with invalid inputs ---');
100
+
101
+ await test('BbsBlsSignature2020.createProof with no key (verifier-only)', async () => {
102
+ try {
103
+ const suite = new BbsBlsSignature2020();
104
+ await suite.createProof({ document: {}, contexts: {} });
105
+ } catch (e) {
106
+ assert.ok(e instanceof Error);
107
+ }
108
+ });
109
+
110
+ await test('BbsBlsSignature2020.verifyProof with random proof', async () => {
111
+ try {
112
+ const suite = new BbsBlsSignature2020();
113
+ await suite.verifyProof({ document: randomJson(), contexts: {} });
114
+ } catch (e) {
115
+ assert.ok(e instanceof Error);
116
+ }
117
+ });
118
+
119
+ // Category 3: Empty/null/undefined arguments
120
+ console.log('\n--- Null/undefined arguments ---');
121
+
122
+ await test('JsonLd.expand with null', async () => {
123
+ const jsonld = new JsonLd();
124
+ try { await jsonld.expand(null); } catch (e) { assert.ok(e instanceof Error); }
125
+ });
126
+
127
+ await test('JsonLd.expand with undefined', async () => {
128
+ const jsonld = new JsonLd();
129
+ try { await jsonld.expand(undefined); } catch (e) { assert.ok(e instanceof Error); }
130
+ });
131
+
132
+ await test('JsonLd.compact with null context', async () => {
133
+ const jsonld = new JsonLd();
134
+ try { await jsonld.compact({}, null); } catch (e) { assert.ok(e instanceof Error); }
135
+ });
136
+
137
+ await test('generateJwk with invalid enum value', async () => {
138
+ try { generateJwk(999); } catch (e) { assert.ok(e instanceof Error); }
139
+ });
140
+
141
+ // Category 4: JOSE with random inputs
142
+ console.log('\n--- JOSE with random inputs ---');
143
+
144
+ await test('compactSignJson with random payload', async () => {
145
+ try {
146
+ const key = generateJwk(JoseNamedCurve.P256);
147
+ compactSignJson(JoseSigningAlgorithm.Es256, randomJson(), key);
148
+ } catch (e) {
149
+ assert.ok(e instanceof Error);
150
+ }
151
+ });
152
+
153
+ await test('compactJsonVerify with random JWS string', async () => {
154
+ try {
155
+ const key = generateJwk(JoseNamedCurve.P256);
156
+ compactJsonVerify('not.a.jws', key);
157
+ } catch (e) {
158
+ assert.ok(e instanceof Error);
159
+ }
160
+ });
161
+
162
+ await test('decryptJson with random JWE', async () => {
163
+ try {
164
+ const key = generateJwk(JoseNamedCurve.X25519);
165
+ decryptJson(randomJson(), key);
166
+ } catch (e) {
167
+ assert.ok(e instanceof Error);
168
+ }
169
+ });
170
+
171
+ // Category 5: Concurrent calls
172
+ console.log('\n--- Concurrent operations ---');
173
+
174
+ await test('50 concurrent JsonLd.expand calls', async () => {
175
+ const jsonld = new JsonLd();
176
+ const doc = {"@context": {"name": "http://schema.org/name"}, "name": "test"};
177
+ const promises = Array.from({length: 50}, () => jsonld.expand(doc).catch(() => null));
178
+ const results = await Promise.all(promises);
179
+ // All should succeed or gracefully fail
180
+ assert.ok(results.length === 50);
181
+ });
182
+
183
+ await test('50 concurrent JOSE sign operations', async () => {
184
+ const key = generateJwk(JoseNamedCurve.P256);
185
+ const payload = {sub: "test", iat: Date.now()};
186
+ const results = [];
187
+ for (let i = 0; i < 50; i++) {
188
+ try {
189
+ results.push(compactSignJson(JoseSigningAlgorithm.Es256, payload, key));
190
+ } catch (e) {
191
+ results.push(null);
192
+ }
193
+ }
194
+ assert.ok(results.length === 50);
195
+ // All should have succeeded
196
+ const successes = results.filter(r => r !== null);
197
+ assert.ok(successes.length === 50, `Expected 50 successes, got ${successes.length}`);
198
+ });
199
+
200
+ // Summary
201
+ console.log(`\n=== Results: ${passed} passed, ${failed} failed out of ${passed + failed} ===`);
202
+ if (failed > 0) process.exit(1);
package/test_jose.mjs ADDED
@@ -0,0 +1,497 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert';
3
+ import { randomBytes } from 'node:crypto';
4
+ import {
5
+ JoseNamedCurve,
6
+ JoseContentEncryption,
7
+ JoseKeyEncryption,
8
+ JoseSigningAlgorithm,
9
+ generateJwk,
10
+ generateKeyPair,
11
+ joseEncrypt,
12
+ joseDecrypt,
13
+ generalEncryptJson,
14
+ decryptJson,
15
+ compactSignJson,
16
+ compactJsonVerify,
17
+ flattenedSignJson,
18
+ jsonVerify,
19
+ generalSignJson,
20
+ } from './index.js';
21
+
22
+
23
+ // =====================================================================
24
+ // Key Generation — Task 15
25
+ // =====================================================================
26
+
27
+ test('generateJwk with P-256 returns EC JWK', () => {
28
+ const jwk = generateJwk(JoseNamedCurve.P256);
29
+ assert.ok(jwk, 'generateJwk returned a result');
30
+ assert.equal(jwk.kty, 'EC', 'key type is EC');
31
+ assert.equal(jwk.crv, 'P-256', 'curve is P-256');
32
+ assert.ok(jwk.x, 'has x coordinate');
33
+ assert.ok(jwk.y, 'has y coordinate');
34
+ assert.ok(jwk.d, 'has private key (d)');
35
+ });
36
+
37
+ test('generateJwk with P-384 returns EC JWK', () => {
38
+ const jwk = generateJwk(JoseNamedCurve.P384);
39
+ assert.equal(jwk.kty, 'EC');
40
+ assert.equal(jwk.crv, 'P-384');
41
+ assert.ok(jwk.d, 'has private key');
42
+ });
43
+
44
+ test('generateJwk with P-521 returns EC JWK', () => {
45
+ const jwk = generateJwk(JoseNamedCurve.P521);
46
+ assert.equal(jwk.kty, 'EC');
47
+ assert.equal(jwk.crv, 'P-521');
48
+ assert.ok(jwk.x, 'has x coordinate');
49
+ assert.ok(jwk.y, 'has y coordinate');
50
+ assert.ok(jwk.d, 'has private key');
51
+ });
52
+
53
+ test('compactSignJson + compactJsonVerify with ES512 (P-521)', () => {
54
+ const jwk = generateJwk(JoseNamedCurve.P521);
55
+ const payload = { alg: 'ES512 test', curve: 'P-521' };
56
+
57
+ const jws = compactSignJson(JoseSigningAlgorithm.Es512, payload, jwk);
58
+ const verified = compactJsonVerify(jws, jwk);
59
+ assert.deepStrictEqual(verified, payload);
60
+ });
61
+
62
+ test('generateJwk with Ed25519 returns OKP JWK', () => {
63
+ const jwk = generateJwk(JoseNamedCurve.Ed25519);
64
+ assert.equal(jwk.kty, 'OKP', 'key type is OKP');
65
+ assert.equal(jwk.crv, 'Ed25519', 'curve is Ed25519');
66
+ assert.ok(jwk.x, 'has public key (x)');
67
+ assert.ok(jwk.d, 'has private key (d)');
68
+ });
69
+
70
+ test('generateJwk with X25519 returns OKP JWK', () => {
71
+ const jwk = generateJwk(JoseNamedCurve.X25519);
72
+ assert.equal(jwk.kty, 'OKP');
73
+ assert.equal(jwk.crv, 'X25519');
74
+ assert.ok(jwk.x, 'has public key');
75
+ assert.ok(jwk.d, 'has private key');
76
+ });
77
+
78
+ test('generateKeyPair with P-256 returns full key pair', () => {
79
+ const kp = generateKeyPair(JoseNamedCurve.P256);
80
+ assert.ok(kp, 'generateKeyPair returned a result');
81
+ assert.ok(kp.jwk_key_pair, 'has jwk_key_pair');
82
+ assert.ok(kp.jwk_private_key, 'has jwk_private_key');
83
+ assert.ok(kp.jwk_public_key, 'has jwk_public_key');
84
+ assert.ok(kp.pem_private_key, 'has pem_private_key');
85
+ assert.ok(kp.pem_public_key, 'has pem_public_key');
86
+ assert.ok(kp.der_private_key, 'has der_private_key');
87
+ assert.ok(kp.der_public_key, 'has der_public_key');
88
+ });
89
+
90
+ test('generateKeyPair with Ed25519 returns full key pair', () => {
91
+ const kp = generateKeyPair(JoseNamedCurve.Ed25519);
92
+ assert.ok(kp.jwk_key_pair, 'has jwk_key_pair');
93
+ assert.ok(kp.jwk_public_key, 'has jwk_public_key');
94
+ assert.ok(kp.pem_private_key, 'has pem_private_key');
95
+ });
96
+
97
+ test('generateJwk generates unique keys each time', () => {
98
+ const jwk1 = generateJwk(JoseNamedCurve.P256);
99
+ const jwk2 = generateJwk(JoseNamedCurve.P256);
100
+ assert.notEqual(jwk1.d, jwk2.d, 'private keys should differ');
101
+ assert.notEqual(jwk1.x, jwk2.x, 'public keys should differ');
102
+ });
103
+
104
+ test('generateKeyPair public key has no private component', () => {
105
+ const kp = generateKeyPair(JoseNamedCurve.P256);
106
+ assert.ok(!kp.jwk_public_key.d, 'public JWK should not have d');
107
+ assert.ok(kp.jwk_private_key.d, 'private JWK should have d');
108
+ });
109
+
110
+
111
+ // =====================================================================
112
+ // Symmetric Encrypt/Decrypt — Task 16
113
+ // =====================================================================
114
+
115
+ test('joseEncrypt + joseDecrypt round-trip with A256GCM', () => {
116
+ // A256GCM requires 32-byte key, 12-byte IV
117
+ const key = randomBytes(32).toString('hex');
118
+ const iv = randomBytes(12).toString('hex');
119
+ const plaintext = Buffer.from('Hello, JOSE!').toString('base64');
120
+
121
+ const encrypted = joseEncrypt(JoseContentEncryption.A256gcm, key, iv, plaintext);
122
+ assert.ok(encrypted.ciphertext, 'has ciphertext');
123
+ assert.ok(encrypted.tag, 'GCM has tag');
124
+
125
+ const decrypted = joseDecrypt(
126
+ JoseContentEncryption.A256gcm, key, iv,
127
+ encrypted.ciphertext, null, encrypted.tag,
128
+ );
129
+ assert.equal(decrypted, plaintext, 'decrypted matches original plaintext');
130
+ });
131
+
132
+ test('joseEncrypt + joseDecrypt round-trip with A128GCM', () => {
133
+ const key = randomBytes(16).toString('hex');
134
+ const iv = randomBytes(12).toString('hex');
135
+ const plaintext = Buffer.from('test message 128').toString('base64');
136
+
137
+ const encrypted = joseEncrypt(JoseContentEncryption.A128gcm, key, iv, plaintext);
138
+ assert.ok(encrypted.ciphertext);
139
+ assert.ok(encrypted.tag);
140
+
141
+ const decrypted = joseDecrypt(
142
+ JoseContentEncryption.A128gcm, key, iv,
143
+ encrypted.ciphertext, null, encrypted.tag,
144
+ );
145
+ assert.equal(decrypted, plaintext);
146
+ });
147
+
148
+ test('joseEncrypt + joseDecrypt with AAD', () => {
149
+ const key = randomBytes(32).toString('hex');
150
+ const iv = randomBytes(12).toString('hex');
151
+ const plaintext = Buffer.from('AAD test').toString('base64');
152
+ const aad = 'additional-authenticated-data';
153
+
154
+ const encrypted = joseEncrypt(JoseContentEncryption.A256gcm, key, iv, plaintext, aad);
155
+ assert.ok(encrypted.ciphertext);
156
+
157
+ const decrypted = joseDecrypt(
158
+ JoseContentEncryption.A256gcm, key, iv,
159
+ encrypted.ciphertext, aad, encrypted.tag,
160
+ );
161
+ assert.equal(decrypted, plaintext, 'decrypted with AAD matches');
162
+ });
163
+
164
+ test('joseEncrypt + joseDecrypt with A256CBC-HS512', () => {
165
+ // A256CBC-HS512 requires 64-byte key, 16-byte IV
166
+ const key = randomBytes(64).toString('hex');
167
+ const iv = randomBytes(16).toString('hex');
168
+ const plaintext = Buffer.from('CBC mode test').toString('base64');
169
+
170
+ const encrypted = joseEncrypt(JoseContentEncryption.A256cbcHs512, key, iv, plaintext);
171
+ assert.ok(encrypted.ciphertext, 'has ciphertext');
172
+
173
+ const decrypted = joseDecrypt(
174
+ JoseContentEncryption.A256cbcHs512, key, iv,
175
+ encrypted.ciphertext, null, encrypted.tag,
176
+ );
177
+ assert.equal(decrypted, plaintext);
178
+ });
179
+
180
+ test('joseDecrypt with wrong key fails', () => {
181
+ const key = randomBytes(32).toString('hex');
182
+ const wrongKey = randomBytes(32).toString('hex');
183
+ const iv = randomBytes(12).toString('hex');
184
+ const plaintext = Buffer.from('secret').toString('base64');
185
+
186
+ const encrypted = joseEncrypt(JoseContentEncryption.A256gcm, key, iv, plaintext);
187
+
188
+ assert.throws(
189
+ () => joseDecrypt(JoseContentEncryption.A256gcm, wrongKey, iv, encrypted.ciphertext, null, encrypted.tag),
190
+ /joseDecrypt failed/,
191
+ 'wrong key should fail',
192
+ );
193
+ });
194
+
195
+
196
+ // =====================================================================
197
+ // JWE — Encrypt/Decrypt JSON — Task 17
198
+ // =====================================================================
199
+
200
+ test('generalEncryptJson + decryptJson round-trip with ECDH-ES+A256KW', () => {
201
+ const jwk = generateJwk(JoseNamedCurve.P256);
202
+ // JWK needs a kid for encryption
203
+ jwk.kid = 'test-key-1';
204
+
205
+ const payload = { hello: 'world', number: 42 };
206
+
207
+ const jwe = generalEncryptJson(
208
+ JoseKeyEncryption.EcdhEsA256kw,
209
+ JoseContentEncryption.A256gcm,
210
+ payload,
211
+ [jwk],
212
+ );
213
+
214
+ assert.ok(jwe, 'generalEncryptJson returned a result');
215
+ assert.ok(jwe.protected, 'JWE has protected header');
216
+ assert.ok(jwe.recipients, 'JWE has recipients');
217
+ assert.ok(jwe.iv, 'JWE has IV');
218
+ assert.ok(jwe.ciphertext, 'JWE has ciphertext');
219
+ assert.ok(jwe.tag, 'JWE has tag');
220
+
221
+ const decrypted = decryptJson(jwe, jwk);
222
+ assert.deepStrictEqual(decrypted, payload, 'decrypted payload matches original');
223
+ });
224
+
225
+ test('generalEncryptJson + decryptJson with X25519', () => {
226
+ const jwk = generateJwk(JoseNamedCurve.X25519);
227
+ jwk.kid = 'x25519-key';
228
+
229
+ const payload = { msg: 'encrypted with X25519' };
230
+
231
+ const jwe = generalEncryptJson(
232
+ JoseKeyEncryption.EcdhEsA256kw,
233
+ JoseContentEncryption.A256gcm,
234
+ payload,
235
+ [jwk],
236
+ );
237
+
238
+ const decrypted = decryptJson(jwe, jwk);
239
+ assert.deepStrictEqual(decrypted, payload);
240
+ });
241
+
242
+ test('generalEncryptJson with didcomm flag', () => {
243
+ const jwk = generateJwk(JoseNamedCurve.P256);
244
+ jwk.kid = 'didcomm-key';
245
+
246
+ const payload = { type: 'didcomm-message' };
247
+
248
+ const jwe = generalEncryptJson(
249
+ JoseKeyEncryption.EcdhEsA256kw,
250
+ JoseContentEncryption.A256gcm,
251
+ payload,
252
+ [jwk],
253
+ true, // didcomm flag
254
+ );
255
+
256
+ assert.ok(jwe, 'didcomm JWE created');
257
+ const decrypted = decryptJson(jwe, jwk);
258
+ assert.deepStrictEqual(decrypted, payload);
259
+ });
260
+
261
+ test('generalEncryptJson with multiple recipients', () => {
262
+ const jwk1 = generateJwk(JoseNamedCurve.P256);
263
+ jwk1.kid = 'recipient-1';
264
+ const jwk2 = generateJwk(JoseNamedCurve.P256);
265
+ jwk2.kid = 'recipient-2';
266
+
267
+ const payload = { data: 'for multiple recipients' };
268
+
269
+ const jwe = generalEncryptJson(
270
+ JoseKeyEncryption.EcdhEsA256kw,
271
+ JoseContentEncryption.A256gcm,
272
+ payload,
273
+ [jwk1, jwk2],
274
+ );
275
+
276
+ assert.ok(jwe.recipients, 'has recipients');
277
+ assert.equal(jwe.recipients.length, 2, 'has 2 recipients');
278
+
279
+ // Both recipients can decrypt
280
+ const decrypted1 = decryptJson(jwe, jwk1);
281
+ assert.deepStrictEqual(decrypted1, payload, 'recipient 1 can decrypt');
282
+
283
+ const decrypted2 = decryptJson(jwe, jwk2);
284
+ assert.deepStrictEqual(decrypted2, payload, 'recipient 2 can decrypt');
285
+ });
286
+
287
+
288
+ // =====================================================================
289
+ // JWS Compact — Sign/Verify — Task 18
290
+ // =====================================================================
291
+
292
+ test('compactSignJson + compactJsonVerify round-trip with ES256', () => {
293
+ const jwk = generateJwk(JoseNamedCurve.P256);
294
+ const payload = { sub: '1234567890', name: 'Test User', iat: 1516239022 };
295
+
296
+ const jws = compactSignJson(JoseSigningAlgorithm.Es256, payload, jwk);
297
+
298
+ assert.ok(typeof jws === 'string', 'compact JWS is a string');
299
+ assert.equal(jws.split('.').length, 3, 'JWS has 3 parts (header.payload.signature)');
300
+
301
+ const verified = compactJsonVerify(jws, jwk);
302
+ assert.deepStrictEqual(verified, payload, 'verified payload matches original');
303
+ });
304
+
305
+ test('compactSignJson + compactJsonVerify with EdDSA', () => {
306
+ const jwk = generateJwk(JoseNamedCurve.Ed25519);
307
+ const payload = { claim: 'EdDSA signed' };
308
+
309
+ const jws = compactSignJson(JoseSigningAlgorithm.Eddsa, payload, jwk);
310
+ const verified = compactJsonVerify(jws, jwk);
311
+ assert.deepStrictEqual(verified, payload);
312
+ });
313
+
314
+ test('compactSignJson + compactJsonVerify with ES384', () => {
315
+ const jwk = generateJwk(JoseNamedCurve.P384);
316
+ const payload = { alg: 'ES384 test' };
317
+
318
+ const jws = compactSignJson(JoseSigningAlgorithm.Es384, payload, jwk);
319
+ const verified = compactJsonVerify(jws, jwk);
320
+ assert.deepStrictEqual(verified, payload);
321
+ });
322
+
323
+ test('compactSignJson with didcomm flag', () => {
324
+ const jwk = generateJwk(JoseNamedCurve.Ed25519);
325
+ const payload = { type: 'didcomm-signed' };
326
+
327
+ const jws = compactSignJson(JoseSigningAlgorithm.Eddsa, payload, jwk, true);
328
+ assert.ok(typeof jws === 'string');
329
+
330
+ const verified = compactJsonVerify(jws, jwk);
331
+ assert.deepStrictEqual(verified, payload);
332
+ });
333
+
334
+ test('compactJsonVerify with wrong key fails', () => {
335
+ const jwk1 = generateJwk(JoseNamedCurve.P256);
336
+ const jwk2 = generateJwk(JoseNamedCurve.P256);
337
+ const payload = { msg: 'should fail' };
338
+
339
+ const jws = compactSignJson(JoseSigningAlgorithm.Es256, payload, jwk1);
340
+
341
+ assert.throws(
342
+ () => compactJsonVerify(jws, jwk2),
343
+ /compactJsonVerify failed/,
344
+ 'wrong key should fail verification',
345
+ );
346
+ });
347
+
348
+
349
+ // =====================================================================
350
+ // JWS Flattened — Sign/Verify
351
+ // =====================================================================
352
+
353
+ test('flattenedSignJson + jsonVerify round-trip with ES256', () => {
354
+ const jwk = generateJwk(JoseNamedCurve.P256);
355
+ jwk.kid = 'flattened-key-1';
356
+ const payload = { data: 'flattened sign test' };
357
+
358
+ const jws = flattenedSignJson(JoseSigningAlgorithm.Es256, payload, jwk);
359
+
360
+ assert.ok(jws, 'flattenedSignJson returned a result');
361
+ assert.ok(jws.protected, 'has protected header');
362
+ assert.ok(jws.payload, 'has payload');
363
+ assert.ok(jws.signature, 'has signature');
364
+
365
+ const verified = jsonVerify(jws, jwk);
366
+ assert.deepStrictEqual(verified, payload, 'verified payload matches original');
367
+ });
368
+
369
+ test('flattenedSignJson + jsonVerify with EdDSA', () => {
370
+ const jwk = generateJwk(JoseNamedCurve.Ed25519);
371
+ jwk.kid = 'ed-flattened';
372
+ const payload = { curve: 'Ed25519', format: 'flattened' };
373
+
374
+ const jws = flattenedSignJson(JoseSigningAlgorithm.Eddsa, payload, jwk);
375
+ const verified = jsonVerify(jws, jwk);
376
+ assert.deepStrictEqual(verified, payload);
377
+ });
378
+
379
+
380
+ // =====================================================================
381
+ // JWS General — Sign/Verify (multiple signers)
382
+ // =====================================================================
383
+
384
+ test('generalSignJson + jsonVerify round-trip with single signer', () => {
385
+ const jwk = generateJwk(JoseNamedCurve.P256);
386
+ jwk.kid = 'general-signer-1';
387
+ jwk.alg = 'ES256';
388
+ const payload = { data: 'general sign test' };
389
+
390
+ const jws = generalSignJson(payload, [jwk]);
391
+
392
+ assert.ok(jws, 'generalSignJson returned a result');
393
+ assert.ok(jws.signatures, 'has signatures array');
394
+ assert.equal(jws.signatures.length, 1, 'has 1 signature');
395
+ assert.ok(jws.payload, 'has payload');
396
+
397
+ const verified = jsonVerify(jws, jwk);
398
+ assert.deepStrictEqual(verified, payload, 'verified payload matches original');
399
+ });
400
+
401
+ test('generalSignJson + jsonVerify with multiple signers', () => {
402
+ const jwk1 = generateJwk(JoseNamedCurve.P256);
403
+ jwk1.kid = 'multi-signer-1';
404
+ jwk1.alg = 'ES256';
405
+ const jwk2 = generateJwk(JoseNamedCurve.P384);
406
+ jwk2.kid = 'multi-signer-2';
407
+ jwk2.alg = 'ES384';
408
+
409
+ const payload = { data: 'multi-signer test' };
410
+
411
+ const jws = generalSignJson(payload, [jwk1, jwk2]);
412
+ assert.equal(jws.signatures.length, 2, 'has 2 signatures');
413
+
414
+ // Each signer can independently verify
415
+ const verified1 = jsonVerify(jws, jwk1);
416
+ assert.deepStrictEqual(verified1, payload, 'signer 1 verifies');
417
+
418
+ const verified2 = jsonVerify(jws, jwk2);
419
+ assert.deepStrictEqual(verified2, payload, 'signer 2 verifies');
420
+ });
421
+
422
+ test('generalSignJson with didcomm flag', () => {
423
+ const jwk = generateJwk(JoseNamedCurve.Ed25519);
424
+ jwk.kid = 'didcomm-signer';
425
+ jwk.alg = 'EdDSA';
426
+ const payload = { type: 'didcomm-general' };
427
+
428
+ const jws = generalSignJson(payload, [jwk], true);
429
+ assert.ok(jws.signatures);
430
+
431
+ const verified = jsonVerify(jws, jwk);
432
+ assert.deepStrictEqual(verified, payload);
433
+ });
434
+
435
+
436
+ // =====================================================================
437
+ // Enum values match ffi-jose
438
+ // =====================================================================
439
+
440
+ test('JoseNamedCurve enum values', () => {
441
+ assert.equal(JoseNamedCurve.P256, 0);
442
+ assert.equal(JoseNamedCurve.P384, 1);
443
+ assert.equal(JoseNamedCurve.P521, 2);
444
+ assert.equal(JoseNamedCurve.Secp256k1, 3);
445
+ assert.equal(JoseNamedCurve.Ed25519, 4);
446
+ assert.equal(JoseNamedCurve.Ed448, 5);
447
+ assert.equal(JoseNamedCurve.X25519, 6);
448
+ assert.equal(JoseNamedCurve.X448, 7);
449
+ });
450
+
451
+ test('JoseContentEncryption enum values', () => {
452
+ assert.equal(JoseContentEncryption.A128gcm, 0);
453
+ assert.equal(JoseContentEncryption.A192gcm, 1);
454
+ assert.equal(JoseContentEncryption.A256gcm, 2);
455
+ assert.equal(JoseContentEncryption.A128cbcHs256, 3);
456
+ assert.equal(JoseContentEncryption.A192cbcHs384, 4);
457
+ assert.equal(JoseContentEncryption.A256cbcHs512, 5);
458
+ });
459
+
460
+ test('JoseKeyEncryption enum values', () => {
461
+ assert.equal(JoseKeyEncryption.Dir, 0);
462
+ assert.equal(JoseKeyEncryption.EcdhEs, 1);
463
+ assert.equal(JoseKeyEncryption.EcdhEsA128kw, 2);
464
+ assert.equal(JoseKeyEncryption.EcdhEsA192kw, 3);
465
+ assert.equal(JoseKeyEncryption.EcdhEsA256kw, 4);
466
+ assert.equal(JoseKeyEncryption.Rsa1_5, 5);
467
+ assert.equal(JoseKeyEncryption.RsaOaep, 6);
468
+ assert.equal(JoseKeyEncryption.RsaOaep256, 7);
469
+ assert.equal(JoseKeyEncryption.RsaOaep384, 8);
470
+ assert.equal(JoseKeyEncryption.RsaOaep512, 9);
471
+ assert.equal(JoseKeyEncryption.Pbes2Hs256A128kw, 10);
472
+ assert.equal(JoseKeyEncryption.Pbes2Hs384A192kw, 11);
473
+ assert.equal(JoseKeyEncryption.Pbes2Hs512A256kw, 12);
474
+ assert.equal(JoseKeyEncryption.A128kw, 13);
475
+ assert.equal(JoseKeyEncryption.A192kw, 14);
476
+ assert.equal(JoseKeyEncryption.A256kw, 15);
477
+ assert.equal(JoseKeyEncryption.A128gcmkw, 16);
478
+ assert.equal(JoseKeyEncryption.A192gcmkw, 17);
479
+ assert.equal(JoseKeyEncryption.A256gcmkw, 18);
480
+ });
481
+
482
+ test('JoseSigningAlgorithm enum values', () => {
483
+ assert.equal(JoseSigningAlgorithm.Es256, 0);
484
+ assert.equal(JoseSigningAlgorithm.Es384, 1);
485
+ assert.equal(JoseSigningAlgorithm.Es512, 2);
486
+ assert.equal(JoseSigningAlgorithm.Es256k, 3);
487
+ assert.equal(JoseSigningAlgorithm.Eddsa, 4);
488
+ assert.equal(JoseSigningAlgorithm.Hs256, 5);
489
+ assert.equal(JoseSigningAlgorithm.Hs384, 6);
490
+ assert.equal(JoseSigningAlgorithm.Hs512, 7);
491
+ assert.equal(JoseSigningAlgorithm.Rs256, 8);
492
+ assert.equal(JoseSigningAlgorithm.Rs384, 9);
493
+ assert.equal(JoseSigningAlgorithm.Rs512, 10);
494
+ assert.equal(JoseSigningAlgorithm.Ps256, 11);
495
+ assert.equal(JoseSigningAlgorithm.Ps384, 12);
496
+ assert.equal(JoseSigningAlgorithm.Ps512, 13);
497
+ });
@@ -21,7 +21,7 @@ const jsonld = require('jsonld');
21
21
  const { extendContextLoader } = require('jsonld-signatures');
22
22
 
23
23
  const __dirname = dirname(fileURLToPath(import.meta.url));
24
- const dataDir = resolve(__dirname, '../../../jsonld-signatures-bbs/sample/ts-node/src/data');
24
+ const dataDir = resolve(__dirname, 'test-data');
25
25
  const loadJson = (name) => JSON.parse(readFileSync(resolve(dataDir, name), 'utf8'));
26
26
 
27
27
  const inputDocument = loadJson('inputDocument.json');