@nuggetslife/vc 0.0.21 → 0.0.24
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/generate_golden_files.mjs +181 -0
- package/index.d.ts +154 -0
- package/index.js +27 -1
- package/package.json +8 -11
- package/src/bbs_2023.rs +71 -0
- package/src/bbs_ietf.rs +255 -0
- package/src/bls_signatures/bbs_bls_holder_bound_signature_2022/mod.rs +7 -38
- package/src/bls_signatures/bbs_bls_holder_bound_signature_proof_2022/mod.rs +3 -13
- package/src/bls_signatures/bbs_bls_signature_2020/mod.rs +4 -34
- package/src/bls_signatures/bbs_bls_signature_2020/types.rs +0 -1
- package/src/bls_signatures/bbs_bls_signature_proof_2020/mod.rs +3 -13
- package/src/bls_signatures/bls_12381_g2_keypair/mod.rs +16 -16
- package/src/bls_signatures/bound_bls_12381_g2_keypair/mod.rs +3 -3
- package/src/jose.rs +415 -0
- package/src/jsonld.rs +4 -26
- package/src/ld_signatures.rs +29 -24
- package/src/lib.rs +4 -0
- package/src/sd_jwt.rs +133 -0
- package/test-data/golden/inputDocument-minimal.json +17 -0
- package/test-data/golden/inputDocument-rich.json +29 -0
- package/test-data/golden/mattrglobal-derived-prc.json +36 -0
- package/test-data/golden/mattrglobal-signed-minimal.json +30 -0
- package/test-data/golden/mattrglobal-signed-prc.json +42 -0
- package/test-data/golden/mattrglobal-signed-rich.json +42 -0
- package/test.mjs +38 -0
- package/test_backward_compat.mjs +287 -0
- package/test_bbs_2023.mjs +195 -0
- package/test_bbs_ietf.mjs +168 -0
- package/test_fuzz.mjs +202 -0
- package/test_jose.mjs +497 -0
- package/test_jsonld_crossverify.mjs +1 -1
- package/test_sd_jwt.mjs +197 -0
package/test_sd_jwt.mjs
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert';
|
|
3
|
+
import {
|
|
4
|
+
JoseNamedCurve,
|
|
5
|
+
generateJwk,
|
|
6
|
+
sdJwtIssue,
|
|
7
|
+
sdJwtPresent,
|
|
8
|
+
sdJwtVerify,
|
|
9
|
+
} from './index.js';
|
|
10
|
+
|
|
11
|
+
function makeKeyPair(curve = JoseNamedCurve.P256) {
|
|
12
|
+
const jwk = generateJwk(curve);
|
|
13
|
+
const { d, ...pubJwk } = jwk;
|
|
14
|
+
return { privateJwk: jwk, publicJwk: pubJwk };
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// =====================================================================
|
|
18
|
+
// SD-JWT Round-Trip Tests
|
|
19
|
+
// =====================================================================
|
|
20
|
+
|
|
21
|
+
test('SD-JWT round-trip with ES256', () => {
|
|
22
|
+
const issuer = makeKeyPair(JoseNamedCurve.P256);
|
|
23
|
+
|
|
24
|
+
const claims = { sub: 'user123', name: 'Alice', email: 'alice@example.com', age: 30 };
|
|
25
|
+
const result = sdJwtIssue(claims, ['name', 'email'], issuer.privateJwk, 'ES256');
|
|
26
|
+
|
|
27
|
+
assert.ok(result.sdJwt, 'sd_jwt is present');
|
|
28
|
+
assert.ok(result.sdJwt.includes('~'), 'sd_jwt contains tilde separators');
|
|
29
|
+
assert.equal(result.disclosures.length, 2, 'two disclosures');
|
|
30
|
+
|
|
31
|
+
// Present all disclosures
|
|
32
|
+
const allEncoded = result.disclosures.map(d => d.encoded);
|
|
33
|
+
const presentation = sdJwtPresent(result.sdJwt, allEncoded);
|
|
34
|
+
|
|
35
|
+
assert.ok(presentation.presentation, 'presentation is present');
|
|
36
|
+
|
|
37
|
+
// Verify
|
|
38
|
+
const verified = sdJwtVerify(presentation.presentation, issuer.publicJwk);
|
|
39
|
+
assert.ok(verified.verified, 'verification succeeded');
|
|
40
|
+
assert.equal(verified.claims.sub, 'user123');
|
|
41
|
+
assert.equal(verified.claims.name, 'Alice');
|
|
42
|
+
assert.equal(verified.claims.email, 'alice@example.com');
|
|
43
|
+
assert.equal(verified.claims.age, 30);
|
|
44
|
+
assert.equal(verified.error, null);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test('SD-JWT round-trip with EdDSA (Ed25519)', () => {
|
|
48
|
+
const issuer = makeKeyPair(JoseNamedCurve.Ed25519);
|
|
49
|
+
|
|
50
|
+
const claims = { sub: 'user456', name: 'Bob' };
|
|
51
|
+
const result = sdJwtIssue(claims, ['name'], issuer.privateJwk, 'EdDSA');
|
|
52
|
+
|
|
53
|
+
assert.equal(result.disclosures.length, 1);
|
|
54
|
+
|
|
55
|
+
const allEncoded = result.disclosures.map(d => d.encoded);
|
|
56
|
+
const presentation = sdJwtPresent(result.sdJwt, allEncoded);
|
|
57
|
+
const verified = sdJwtVerify(presentation.presentation, issuer.publicJwk);
|
|
58
|
+
|
|
59
|
+
assert.ok(verified.verified);
|
|
60
|
+
assert.equal(verified.claims.name, 'Bob');
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// =====================================================================
|
|
64
|
+
// Selective Reveal
|
|
65
|
+
// =====================================================================
|
|
66
|
+
|
|
67
|
+
test('SD-JWT selective reveal: only name disclosed', () => {
|
|
68
|
+
const issuer = makeKeyPair();
|
|
69
|
+
|
|
70
|
+
const claims = { sub: 'user123', name: 'Alice', email: 'alice@example.com', age: 30 };
|
|
71
|
+
const result = sdJwtIssue(claims, ['name', 'email', 'age'], issuer.privateJwk, 'ES256');
|
|
72
|
+
|
|
73
|
+
// Only reveal name
|
|
74
|
+
const nameDisclosure = result.disclosures.find(d => d.claimName === 'name');
|
|
75
|
+
const presentation = sdJwtPresent(result.sdJwt, [nameDisclosure.encoded]);
|
|
76
|
+
const verified = sdJwtVerify(presentation.presentation, issuer.publicJwk);
|
|
77
|
+
|
|
78
|
+
assert.ok(verified.verified);
|
|
79
|
+
assert.equal(verified.claims.sub, 'user123', 'sub is always visible');
|
|
80
|
+
assert.equal(verified.claims.name, 'Alice', 'name is disclosed');
|
|
81
|
+
assert.equal(verified.claims.email, undefined, 'email is NOT disclosed');
|
|
82
|
+
assert.equal(verified.claims.age, undefined, 'age is NOT disclosed');
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// =====================================================================
|
|
86
|
+
// Wrong Key Rejection
|
|
87
|
+
// =====================================================================
|
|
88
|
+
|
|
89
|
+
test('SD-JWT verification fails with wrong issuer key', () => {
|
|
90
|
+
const issuer = makeKeyPair();
|
|
91
|
+
const wrongKey = makeKeyPair();
|
|
92
|
+
|
|
93
|
+
const claims = { sub: 'user', name: 'Test' };
|
|
94
|
+
const result = sdJwtIssue(claims, ['name'], issuer.privateJwk, 'ES256');
|
|
95
|
+
|
|
96
|
+
const allEncoded = result.disclosures.map(d => d.encoded);
|
|
97
|
+
const presentation = sdJwtPresent(result.sdJwt, allEncoded);
|
|
98
|
+
|
|
99
|
+
assert.throws(() => {
|
|
100
|
+
sdJwtVerify(presentation.presentation, wrongKey.publicJwk);
|
|
101
|
+
}, 'should throw with wrong key');
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// =====================================================================
|
|
105
|
+
// Nested Objects
|
|
106
|
+
// =====================================================================
|
|
107
|
+
|
|
108
|
+
test('SD-JWT with nested object disclosure', () => {
|
|
109
|
+
const issuer = makeKeyPair();
|
|
110
|
+
|
|
111
|
+
const claims = {
|
|
112
|
+
sub: 'user123',
|
|
113
|
+
address: {
|
|
114
|
+
street: '123 Main St',
|
|
115
|
+
city: 'Springfield',
|
|
116
|
+
state: 'IL',
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
const result = sdJwtIssue(
|
|
120
|
+
claims,
|
|
121
|
+
['address.street', 'address.city'],
|
|
122
|
+
issuer.privateJwk,
|
|
123
|
+
'ES256',
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
assert.equal(result.disclosures.length, 2);
|
|
127
|
+
|
|
128
|
+
// Reveal only street
|
|
129
|
+
const streetDisclosure = result.disclosures.find(d => d.claimName === 'street');
|
|
130
|
+
const presentation = sdJwtPresent(result.sdJwt, [streetDisclosure.encoded]);
|
|
131
|
+
const verified = sdJwtVerify(presentation.presentation, issuer.publicJwk);
|
|
132
|
+
|
|
133
|
+
assert.ok(verified.verified);
|
|
134
|
+
assert.equal(verified.claims.address.street, '123 Main St');
|
|
135
|
+
assert.equal(verified.claims.address.state, 'IL', 'state always visible');
|
|
136
|
+
assert.equal(verified.claims.address.city, undefined, 'city not disclosed');
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
// =====================================================================
|
|
140
|
+
// Key Binding
|
|
141
|
+
// =====================================================================
|
|
142
|
+
|
|
143
|
+
test('SD-JWT with Key Binding JWT', () => {
|
|
144
|
+
const issuer = makeKeyPair();
|
|
145
|
+
const holder = makeKeyPair();
|
|
146
|
+
|
|
147
|
+
const claims = { sub: 'user123', name: 'Alice' };
|
|
148
|
+
const result = sdJwtIssue(
|
|
149
|
+
claims,
|
|
150
|
+
['name'],
|
|
151
|
+
issuer.privateJwk,
|
|
152
|
+
'ES256',
|
|
153
|
+
holder.publicJwk,
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
const allEncoded = result.disclosures.map(d => d.encoded);
|
|
157
|
+
const presentation = sdJwtPresent(
|
|
158
|
+
result.sdJwt,
|
|
159
|
+
allEncoded,
|
|
160
|
+
holder.privateJwk,
|
|
161
|
+
'ES256',
|
|
162
|
+
'https://verifier.example.com',
|
|
163
|
+
'nonce123',
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
const verified = sdJwtVerify(
|
|
167
|
+
presentation.presentation,
|
|
168
|
+
issuer.publicJwk,
|
|
169
|
+
holder.publicJwk,
|
|
170
|
+
'https://verifier.example.com',
|
|
171
|
+
'nonce123',
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
assert.ok(verified.verified);
|
|
175
|
+
assert.equal(verified.claims.name, 'Alice');
|
|
176
|
+
assert.equal(verified.error, null);
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// =====================================================================
|
|
180
|
+
// Decoys
|
|
181
|
+
// =====================================================================
|
|
182
|
+
|
|
183
|
+
test('SD-JWT with decoy digests', () => {
|
|
184
|
+
const issuer = makeKeyPair();
|
|
185
|
+
|
|
186
|
+
const claims = { sub: 'user123', name: 'Alice' };
|
|
187
|
+
const result = sdJwtIssue(claims, ['name'], issuer.privateJwk, 'ES256', null, 3);
|
|
188
|
+
|
|
189
|
+
assert.equal(result.disclosures.length, 1, 'only 1 real disclosure');
|
|
190
|
+
|
|
191
|
+
const allEncoded = result.disclosures.map(d => d.encoded);
|
|
192
|
+
const presentation = sdJwtPresent(result.sdJwt, allEncoded);
|
|
193
|
+
const verified = sdJwtVerify(presentation.presentation, issuer.publicJwk);
|
|
194
|
+
|
|
195
|
+
assert.ok(verified.verified);
|
|
196
|
+
assert.equal(verified.claims.name, 'Alice');
|
|
197
|
+
});
|