@digitalbazaar/vc 6.1.0 → 6.3.0
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/README.md +214 -10
- package/lib/index.js +7 -3
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -48,7 +48,7 @@ the following:
|
|
|
48
48
|
|
|
49
49
|
## Install
|
|
50
50
|
|
|
51
|
-
- Browsers and Node.js
|
|
51
|
+
- Browsers and Node.js 18+ are supported.
|
|
52
52
|
|
|
53
53
|
To install from NPM:
|
|
54
54
|
|
|
@@ -116,18 +116,161 @@ const signedVC = await vc.issue({credential, suite, documentLoader});
|
|
|
116
116
|
console.log(JSON.stringify(signedVC, null, 2));
|
|
117
117
|
```
|
|
118
118
|
|
|
119
|
+
### Issuing a Selective Disclosure Verifiable Credential
|
|
120
|
+
|
|
121
|
+
Pre-requisites:
|
|
122
|
+
|
|
123
|
+
* You have a private key (with id and controller) and corresponding suite
|
|
124
|
+
* You have are using a cryptosuite that supports selective disclosure, such
|
|
125
|
+
as `ecdsa-sd-2023` or `bbs-2023`
|
|
126
|
+
* If you're using a custom `@context`, make sure it's resolvable
|
|
127
|
+
* (Recommended) You have a strategy for where to publish your Controller
|
|
128
|
+
Document and Public Key
|
|
129
|
+
|
|
130
|
+
Issuing using `ecdsa-sd-2023`:
|
|
131
|
+
|
|
132
|
+
```js
|
|
133
|
+
import * as EcdsaMultikey from '@digitalbazaar/ecdsa-multikey';
|
|
134
|
+
import * as ecdsaSd2023Cryptosuite from
|
|
135
|
+
'@digitalbazaar/ecdsa-sd-2023-cryptosuite';
|
|
136
|
+
import * as vc from '@digitalbazaar/vc';
|
|
137
|
+
import {DataIntegrityProof} from '@digitalbazaar/data-integrity';
|
|
138
|
+
|
|
139
|
+
const ecdsaKeyPair = await EcdsaMultikey.generate({
|
|
140
|
+
curve: 'P-256',
|
|
141
|
+
id: 'https://example.edu/issuers/keys/2',
|
|
142
|
+
controller: 'https://example.edu/issuers/565049'
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
// sample exported key pair
|
|
146
|
+
/*
|
|
147
|
+
{
|
|
148
|
+
"@context": "https://w3id.org/security/multikey/v1",
|
|
149
|
+
"id": "https://example.edu/issuers/keys/2",
|
|
150
|
+
"type": "Multikey",
|
|
151
|
+
"controller": "https://example.edu/issuers/565049",
|
|
152
|
+
"publicKeyMultibase": "zDnaeWJjGpXnQAbEpRur3kSWFapGZbwGnFCkzyhiq7nDeXXrM",
|
|
153
|
+
"secretKeyMultibase": "z42trzSpncjWFaB9cKE2Gg5hxtbuAQa5mVJgGwjrugHMacdM"
|
|
154
|
+
}
|
|
155
|
+
*/
|
|
156
|
+
|
|
157
|
+
// sample unsigned credential
|
|
158
|
+
const credential = {
|
|
159
|
+
"@context": [
|
|
160
|
+
"https://www.w3.org/2018/credentials/v1",
|
|
161
|
+
"https://www.w3.org/2018/credentials/examples/v1"
|
|
162
|
+
],
|
|
163
|
+
"id": "https://example.com/credentials/1872",
|
|
164
|
+
"type": ["VerifiableCredential", "AlumniCredential"],
|
|
165
|
+
"issuer": "https://example.edu/issuers/565049",
|
|
166
|
+
"issuanceDate": "2010-01-01T19:23:24Z",
|
|
167
|
+
"credentialSubject": {
|
|
168
|
+
"id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
|
|
169
|
+
"alumniOf": "Example University"
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
// setup ecdsa-sd-2023 suite for signing selective disclosure VCs
|
|
174
|
+
const suite = new DataIntegrityProof({
|
|
175
|
+
signer: ecdsaKeyPair.signer(),
|
|
176
|
+
cryptosuite: createSignCryptosuite({
|
|
177
|
+
// require the `issuer` and `issuanceDate` fields to always be disclosed
|
|
178
|
+
// by the holder (presenter)
|
|
179
|
+
mandatoryPointers: [
|
|
180
|
+
'/issuanceDate',
|
|
181
|
+
'/issuer'
|
|
182
|
+
]
|
|
183
|
+
})
|
|
184
|
+
});
|
|
185
|
+
// use a proof ID to enable it to be found and transformed into a disclosure
|
|
186
|
+
// proof by the holder later
|
|
187
|
+
const proofId = `urn:uuid:${uuid()}`;
|
|
188
|
+
suite.proof = {id: proofId};
|
|
189
|
+
|
|
190
|
+
const signedVC = await vc.issue({credential, suite, documentLoader});
|
|
191
|
+
console.log(JSON.stringify(signedVC, null, 2));
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Issuing using `bbs-2023`:
|
|
195
|
+
|
|
196
|
+
```js
|
|
197
|
+
import * as bbs2023Cryptosuite from '@digitalbazaar/bbs-2023-cryptosuite';
|
|
198
|
+
import * as bls12381Multikey from '@digitalbazaar/bls12-381-multikey';
|
|
199
|
+
import * as vc from '@digitalbazaar/vc';
|
|
200
|
+
import {DataIntegrityProof} from '@digitalbazaar/data-integrity';
|
|
201
|
+
|
|
202
|
+
const bbsKeyPair = await bls12381Multikey.generate({
|
|
203
|
+
algorithm: 'BBS-BLS12-381-SHA-256';
|
|
204
|
+
id: 'https://example.edu/issuers/keys/3',
|
|
205
|
+
controller: 'https://example.edu/issuers/565049'
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
// sample exported key pair
|
|
209
|
+
/*
|
|
210
|
+
{
|
|
211
|
+
"@context": "https://w3id.org/security/multikey/v1",
|
|
212
|
+
"id": "https://example.edu/issuers/keys/3",
|
|
213
|
+
"type": "Multikey",
|
|
214
|
+
"controller": "https://example.edu/issuers/565049",
|
|
215
|
+
"publicKeyMultibase": "zUC72jQrt2BfyE57AVgHgThKCsH6HNo85X9SLNpAJaHb42cNDXhsRWL2KkrFtaiztPbbZjfDVQnQQMw2nMqAPUHnaQ3xEr7kUmcnBgv7S2wQSbRbr7mqsP153nU7yMh3ZN4ZryL",
|
|
216
|
+
"secretKeyMultibase": "z488y1niFCWnaV2i86q1raaa7qwBWZ6WTLeS1W1PrsbcsoNg"
|
|
217
|
+
}
|
|
218
|
+
*/
|
|
219
|
+
|
|
220
|
+
// sample unsigned credential
|
|
221
|
+
const credential = {
|
|
222
|
+
"@context": [
|
|
223
|
+
"https://www.w3.org/2018/credentials/v1",
|
|
224
|
+
"https://www.w3.org/2018/credentials/examples/v1"
|
|
225
|
+
],
|
|
226
|
+
// omit `id` to enable unlinkable disclosure
|
|
227
|
+
"type": ["VerifiableCredential", "AlumniCredential"],
|
|
228
|
+
"issuer": "https://example.edu/issuers/565049",
|
|
229
|
+
// use less precise date that is shared by a sufficiently large group
|
|
230
|
+
// of VCs to enable unlinkable disclosure
|
|
231
|
+
"issuanceDate": "2010-01-01T01:00:00Z",
|
|
232
|
+
"credentialSubject": {
|
|
233
|
+
// omit `id` to enable unlinkable disclosure
|
|
234
|
+
"alumniOf": "Example University"
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
// setup bbs-2023 suite for signing unlinkable selective disclosure VCs
|
|
239
|
+
const suite = new DataIntegrityProof({
|
|
240
|
+
signer: bbsKeyPair.signer(),
|
|
241
|
+
cryptosuite: createSignCryptosuite({
|
|
242
|
+
// require the `issuer` and `issuanceDate` fields to always be disclosed
|
|
243
|
+
// by the holder (presenter)
|
|
244
|
+
mandatoryPointers: [
|
|
245
|
+
'/issuanceDate',
|
|
246
|
+
'/issuer'
|
|
247
|
+
]
|
|
248
|
+
})
|
|
249
|
+
});
|
|
250
|
+
// note: do not include a proof ID to enable unlinkable selective disclosure
|
|
251
|
+
|
|
252
|
+
const signedVC = await vc.issue({credential, suite, documentLoader});
|
|
253
|
+
console.log(JSON.stringify(signedVC, null, 2));
|
|
254
|
+
```
|
|
255
|
+
|
|
119
256
|
### Deriving a Selective Disclosure Verifiable Credential
|
|
120
257
|
|
|
258
|
+
Note: This step is performed as a holder of a verifiable credential, not as
|
|
259
|
+
an issuer.
|
|
260
|
+
|
|
121
261
|
Pre-requisites:
|
|
122
262
|
|
|
123
263
|
* You have a verifiable credential that was issued using a cryptosuite that
|
|
124
|
-
|
|
264
|
+
supports selective disclosure, such as `ecdsa-sd-2023` or `bbs-2023`
|
|
125
265
|
* If you're using a custom `@context`, make sure it's resolvable
|
|
126
266
|
|
|
267
|
+
Deriving using `ecdsa-sd-2023`:
|
|
268
|
+
|
|
127
269
|
```js
|
|
128
|
-
import * as
|
|
270
|
+
import * as EcdsaMultikey from '@digitalbazaar/ecdsa-multikey';
|
|
129
271
|
import * as ecdsaSd2023Cryptosuite from
|
|
130
272
|
'@digitalbazaar/ecdsa-sd-2023-cryptosuite';
|
|
273
|
+
import * as vc from '@digitalbazaar/vc';
|
|
131
274
|
import {DataIntegrityProof} from '@digitalbazaar/data-integrity';
|
|
132
275
|
|
|
133
276
|
const {
|
|
@@ -136,8 +279,8 @@ const {
|
|
|
136
279
|
createVerifyCryptosuite
|
|
137
280
|
} = ecdsaSd2023Cryptosuite;
|
|
138
281
|
|
|
139
|
-
//
|
|
140
|
-
const
|
|
282
|
+
// sample VC
|
|
283
|
+
const verifiableCredential = {
|
|
141
284
|
"@context": [
|
|
142
285
|
"https://www.w3.org/2018/credentials/v1",
|
|
143
286
|
"https://www.w3.org/2018/credentials/examples/v1",
|
|
@@ -155,19 +298,19 @@ const credential = {
|
|
|
155
298
|
"alumniOf": "<span lang=\"en\">Example University</span>"
|
|
156
299
|
},
|
|
157
300
|
"proof": {
|
|
158
|
-
"id": "urn:uuid:
|
|
301
|
+
"id": "urn:uuid:318d9dce-bc7b-40b9-a956-c9160bf910db",
|
|
159
302
|
"type": "DataIntegrityProof",
|
|
160
|
-
"created": "
|
|
303
|
+
"created": "2024-01-12T21:53:11Z",
|
|
161
304
|
"verificationMethod": "https://example.edu/issuers/keys/2",
|
|
162
305
|
"cryptosuite": "ecdsa-sd-2023",
|
|
163
306
|
"proofPurpose": "assertionMethod",
|
|
164
|
-
"proofValue": "
|
|
307
|
+
"proofValue": "u2V0AhVhAsl6PQKYE15R0O5Qd267ntwHGNH6JRvZ1y8A-fTCQLUoupP8SCZzzmyc0a1AnabHEVKhpHtYV8j9Kapp-fHFBtFgjgCQCIMn2L1R7D5VPnNn_2foxdj8qvsuUTGFqA34YBkguzCpYILfJ-qNQpn6_dJGpkG24FynqbHpnzoHWVJc2kiLqEKHRglhAUmZtstR9MOLrZjcR8J303MXFvRiE6J3bbaPT1_I9-6578-Wj-eydv2TEGBq_dmsjxsOh4_2Va0etw8CXXMAzaVhA9fr7_Sl9D67AfvLhkJTZ0uJCAXcbL2MaS-DmoC7K-ABxroL1_wj119J8yTMlazxzYBwYkihrdp4ZWJZxraX9tIJtL2lzc3VhbmNlRGF0ZWcvaXNzdWVy"
|
|
165
308
|
}
|
|
166
309
|
};
|
|
167
310
|
|
|
168
311
|
// note no `signer` needed; the selective disclosure credential will be
|
|
169
312
|
// derived from the base proof already provided by the issuer
|
|
170
|
-
const
|
|
313
|
+
const suite = new DataIntegrityProof({
|
|
171
314
|
cryptosuite: createDiscloseCryptosuite({
|
|
172
315
|
// the ID of the base proof to convert to a disclosure proof
|
|
173
316
|
proofId: 'urn:uuid:da088899-3439-41ea-a580-af3f1cf98cd3',
|
|
@@ -181,7 +324,68 @@ const ecdsaSdDeriveSuite = new DataIntegrityProof({
|
|
|
181
324
|
})
|
|
182
325
|
});
|
|
183
326
|
|
|
184
|
-
const derivedVC = await vc.derive({
|
|
327
|
+
const derivedVC = await vc.derive({
|
|
328
|
+
verifiableCredential, suite, documentLoader
|
|
329
|
+
});
|
|
330
|
+
console.log(JSON.stringify(derivedVC, null, 2));
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
Deriving using `bbs-2023`:
|
|
334
|
+
|
|
335
|
+
```js
|
|
336
|
+
import * as bbs2023Cryptosuite from '@digitalbazaar/bbs-2023-cryptosuite';
|
|
337
|
+
import * as bls12381Multikey from '@digitalbazaar/bls12-381-multikey';
|
|
338
|
+
import * as vc from '@digitalbazaar/vc';
|
|
339
|
+
import {DataIntegrityProof} from '@digitalbazaar/data-integrity';
|
|
340
|
+
|
|
341
|
+
const {
|
|
342
|
+
createDiscloseCryptosuite,
|
|
343
|
+
createSignCryptosuite,
|
|
344
|
+
createVerifyCryptosuite
|
|
345
|
+
} = bbs2023Cryptosuite;
|
|
346
|
+
|
|
347
|
+
// sample VC
|
|
348
|
+
const verifiableCredential = {
|
|
349
|
+
"@context": [
|
|
350
|
+
"https://www.w3.org/2018/credentials/v1",
|
|
351
|
+
"https://www.w3.org/2018/credentials/examples/v1",
|
|
352
|
+
"https://w3id.org/security/data-integrity/v2"
|
|
353
|
+
],
|
|
354
|
+
"type": [
|
|
355
|
+
"VerifiableCredential",
|
|
356
|
+
"AlumniCredential"
|
|
357
|
+
],
|
|
358
|
+
"issuer": "https://example.edu/issuers/565049",
|
|
359
|
+
"issuanceDate": "2010-01-01T01:00:00Z",
|
|
360
|
+
"credentialSubject": {
|
|
361
|
+
"alumniOf": "<span lang=\"en\">Example University</span>"
|
|
362
|
+
},
|
|
363
|
+
"proof": {
|
|
364
|
+
"type": "DataIntegrityProof",
|
|
365
|
+
"verificationMethod": "https://example.edu/issuers/keys/3",
|
|
366
|
+
"cryptosuite": "bbs-2023",
|
|
367
|
+
"proofPurpose": "assertionMethod",
|
|
368
|
+
"proofValue": "u2V0ChVhQp1smqO-Qmc-1KpNkShjevTeylTdVlpH_RNXeJ_cNniErWPbEWILvsoH5mYjnun5ibZHq0m7BEIaLv8sfMtLfcmgPj6tbAFwDWvEcbRWg7CFYQGWqCAnvTpL_Aao3aVCg5svdzFuvKqnvneA0UwaN0lagvGpWT7fCDGgcYPyNPKaCX94Xo06aTcSwOXgyGUbtN1xYYIU6t5wv20lVdESfzkYOFXTxIZa1HSBAZYWDyEgQ3A3ajzWX5qeFc3cwmnnrGUfJYwawgGLQAY3vBi3LTM2i3jCOPvxCEJALPIjK4tEmWb6uFjT4PWLlIEeTtYj_0yEv91ggsm9vw1PPlK6q8wQiw2i2joZ-OKkvHz7rDSxPYfmQNrqCbS9pc3N1YW5jZURhdGVnL2lzc3Vlcg"
|
|
369
|
+
}
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
// note no `signer` needed; the selective disclosure credential will be
|
|
373
|
+
// derived from the base proof already provided by the issuer
|
|
374
|
+
const suite = new DataIntegrityProof({
|
|
375
|
+
cryptosuite: createDiscloseCryptosuite({
|
|
376
|
+
// selectively disclose the entire credential subject; different JSON
|
|
377
|
+
// pointers could be provided to selectively disclose different information;
|
|
378
|
+
// the issuer will have mandatory fields that will be automatically
|
|
379
|
+
// disclosed such as the `issuer` and `issuanceDate` fields
|
|
380
|
+
selectivePointers: [
|
|
381
|
+
'/credentialSubject'
|
|
382
|
+
]
|
|
383
|
+
})
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
const derivedVC = await vc.derive({
|
|
387
|
+
verifiableCredential, suite, documentLoader
|
|
388
|
+
});
|
|
185
389
|
console.log(JSON.stringify(derivedVC, null, 2));
|
|
186
390
|
```
|
|
187
391
|
|
package/lib/index.js
CHANGED
|
@@ -167,7 +167,8 @@ export async function derive({
|
|
|
167
167
|
documentLoader = defaultDocumentLoader
|
|
168
168
|
} = {}) {
|
|
169
169
|
if(!verifiableCredential) {
|
|
170
|
-
throw new TypeError(
|
|
170
|
+
throw new TypeError(
|
|
171
|
+
'"verifiableCredential" parameter is required for deriving.');
|
|
171
172
|
}
|
|
172
173
|
if(!suite) {
|
|
173
174
|
throw new TypeError('"suite" parameter is required for deriving.');
|
|
@@ -654,10 +655,13 @@ export function _checkCredential({
|
|
|
654
655
|
}
|
|
655
656
|
|
|
656
657
|
if('credentialStatus' in credential) {
|
|
657
|
-
|
|
658
|
+
const {credentialStatus} = credential;
|
|
659
|
+
if(Array.isArray(credentialStatus) ?
|
|
660
|
+
credentialStatus.some(cs => !cs.id) : !credentialStatus.id) {
|
|
658
661
|
throw new Error('"credentialStatus" must include an id.');
|
|
659
662
|
}
|
|
660
|
-
if(
|
|
663
|
+
if(Array.isArray(credentialStatus) ?
|
|
664
|
+
credentialStatus.some(cs => !cs.type) : !credentialStatus.type) {
|
|
661
665
|
throw new Error('"credentialStatus" must include a type.');
|
|
662
666
|
}
|
|
663
667
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@digitalbazaar/vc",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.3.0",
|
|
4
4
|
"description": "Verifiable Credentials JavaScript library.",
|
|
5
5
|
"homepage": "https://github.com/digitalbazaar/vc",
|
|
6
6
|
"author": {
|
|
@@ -33,6 +33,8 @@
|
|
|
33
33
|
"jsonld-signatures": "^11.2.1"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
|
+
"@digitalbazaar/bbs-2023-cryptosuite": "^1.0.0",
|
|
37
|
+
"@digitalbazaar/bls12-381-multikey": "^1.1.1",
|
|
36
38
|
"@digitalbazaar/credentials-examples-context": "^1.0.0",
|
|
37
39
|
"@digitalbazaar/data-integrity": "^2.0.0",
|
|
38
40
|
"@digitalbazaar/data-integrity-context": "^2.0.0",
|
|
@@ -72,7 +74,7 @@
|
|
|
72
74
|
]
|
|
73
75
|
},
|
|
74
76
|
"engines": {
|
|
75
|
-
"node": ">=
|
|
77
|
+
"node": ">=18"
|
|
76
78
|
},
|
|
77
79
|
"keywords": [
|
|
78
80
|
"JSON",
|