@twin.org/standards-w3c-did 0.0.1-next.9 → 0.0.2-next.1
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/dist/cjs/index.cjs +459 -3
- package/dist/esm/index.mjs +454 -4
- package/dist/types/index.d.ts +13 -1
- package/dist/types/models/{IDidProof.d.ts → IDataIntegrityProof.d.ts} +18 -6
- package/dist/types/models/IDidCredentialSchema.d.ts +13 -0
- package/dist/types/models/IDidDocument.d.ts +6 -0
- package/dist/types/models/IDidDocumentVerificationMethod.d.ts +3 -2
- package/dist/types/models/IDidLabel.d.ts +17 -0
- package/dist/types/models/IDidVerifiableCredential.d.ts +41 -9
- package/dist/types/models/IDidVerifiablePresentation.d.ts +9 -8
- package/dist/types/models/IJsonWebSignature2020Proof.d.ts +33 -0
- package/dist/types/models/IMultikey.d.ts +41 -0
- package/dist/types/models/IProof.d.ts +6 -0
- package/dist/types/models/IProofSignerVerifier.d.ts +31 -0
- package/dist/types/models/didContexts.d.ts +26 -2
- package/dist/types/models/didCryptoSuites.d.ts +19 -0
- package/dist/types/models/didTypes.d.ts +16 -0
- package/dist/types/models/proofTypes.d.ts +17 -0
- package/dist/types/signerVerifiers/dataIntegrityProofSignerVerifier.d.ts +38 -0
- package/dist/types/signerVerifiers/jsonWebSignature2020SignerVerifier.d.ts +36 -0
- package/dist/types/utils/multikeyHelper.d.ts +37 -0
- package/dist/types/utils/proofHelper.d.ts +47 -0
- package/docs/changelog.md +134 -1
- package/docs/reference/classes/DataIntegrityProofSignerVerifier.md +134 -0
- package/docs/reference/classes/JsonWebSignature2020SignerVerifier.md +133 -0
- package/docs/reference/classes/MultikeyHelper.md +119 -0
- package/docs/reference/classes/ProofHelper.md +159 -0
- package/docs/reference/index.md +18 -1
- package/docs/reference/interfaces/{IDidProof.md → IDataIntegrityProof.md} +23 -7
- package/docs/reference/interfaces/IDidCredentialSchema.md +19 -0
- package/docs/reference/interfaces/IDidCredentialStatus.md +3 -1
- package/docs/reference/interfaces/IDidDocument.md +8 -0
- package/docs/reference/interfaces/IDidDocumentVerificationMethod.md +9 -1
- package/docs/reference/interfaces/IDidLabel.md +27 -0
- package/docs/reference/interfaces/IDidVerifiableCredential.md +57 -12
- package/docs/reference/interfaces/IDidVerifiablePresentation.md +7 -11
- package/docs/reference/interfaces/IJsonWebSignature2020Proof.md +52 -0
- package/docs/reference/interfaces/IMultikey.md +68 -0
- package/docs/reference/interfaces/IProofSignerVerifier.md +99 -0
- package/docs/reference/type-aliases/DidContexts.md +1 -1
- package/docs/reference/type-aliases/DidCryptoSuites.md +5 -0
- package/docs/reference/type-aliases/DidTypes.md +1 -1
- package/docs/reference/type-aliases/DidVerificationMethodType.md +1 -1
- package/docs/reference/type-aliases/IProof.md +5 -0
- package/docs/reference/type-aliases/ProofTypes.md +5 -0
- package/docs/reference/variables/DidContexts.md +40 -4
- package/docs/reference/variables/DidCryptoSuites.md +21 -0
- package/docs/reference/variables/DidTypes.md +24 -0
- package/docs/reference/variables/DidVerificationMethodType.md +1 -1
- package/docs/reference/variables/ProofTypes.md +19 -0
- package/locales/en.json +27 -1
- package/package.json +7 -4
package/dist/esm/index.mjs
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import { Guards, Is, GeneralError, ObjectHelper, Converter, JsonHelper, Uint8ArrayHelper } from '@twin.org/core';
|
|
2
|
+
import { Ed25519, Sha256 } from '@twin.org/crypto';
|
|
3
|
+
import { JsonLdProcessor } from '@twin.org/data-json-ld';
|
|
4
|
+
import { Jwk, Jws } from '@twin.org/web';
|
|
5
|
+
|
|
1
6
|
// Copyright 2024 IOTA Stiftung.
|
|
2
7
|
// SPDX-License-Identifier: Apache-2.0.
|
|
3
8
|
/**
|
|
@@ -5,14 +10,57 @@
|
|
|
5
10
|
*/
|
|
6
11
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
7
12
|
const DidContexts = {
|
|
13
|
+
/**
|
|
14
|
+
* The context root for DID.
|
|
15
|
+
*/
|
|
16
|
+
Context: "https://www.w3.org/ns/did/v1",
|
|
8
17
|
/**
|
|
9
18
|
* The context root for DID VC v1.
|
|
10
19
|
*/
|
|
11
|
-
|
|
20
|
+
ContextVCv1: "https://www.w3.org/2018/credentials/v1",
|
|
12
21
|
/**
|
|
13
22
|
* The context root for DID VC v2.
|
|
14
23
|
*/
|
|
15
|
-
|
|
24
|
+
ContextVCv2: "https://www.w3.org/ns/credentials/v2",
|
|
25
|
+
/**
|
|
26
|
+
* The context root for security ed25519 suites.
|
|
27
|
+
*/
|
|
28
|
+
ContextSecurityEd25519: "https://w3id.org/security/suites/ed25519-2020/v1",
|
|
29
|
+
/**
|
|
30
|
+
* The context root for security jws-2020 suites.
|
|
31
|
+
*/
|
|
32
|
+
ContextSecurityJws2020: "https://w3id.org/security/suites/jws-2020/v1",
|
|
33
|
+
/**
|
|
34
|
+
* The context root for VC Data Integrity.
|
|
35
|
+
*/
|
|
36
|
+
ContextDataIntegrity: "https://www.w3.org/ns/credentials/v2",
|
|
37
|
+
/**
|
|
38
|
+
* The context root for VC Data Integrity.
|
|
39
|
+
*/
|
|
40
|
+
ContextControllerIdentifiers: "https://www.w3.org/ns/cid/v1",
|
|
41
|
+
/**
|
|
42
|
+
* The context root for security multikey suites.
|
|
43
|
+
*/
|
|
44
|
+
ContextSecurityMultikey: "https://w3id.org/security/multikey/v1"
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// Copyright 2024 IOTA Stiftung.
|
|
48
|
+
// SPDX-License-Identifier: Apache-2.0.
|
|
49
|
+
/**
|
|
50
|
+
* The types for DID Proof crypto suites.
|
|
51
|
+
*/
|
|
52
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
53
|
+
const DidCryptoSuites = {
|
|
54
|
+
/**
|
|
55
|
+
* The type for EdDSA crypto suite for JSON Canonicalization Scheme [RFC8785].
|
|
56
|
+
* https://www.w3.org/TR/vc-di-eddsa/#eddsa-jcs-2022
|
|
57
|
+
*/
|
|
58
|
+
EdDSAJcs2022: "eddsa-jcs-2022",
|
|
59
|
+
/**
|
|
60
|
+
* The type for EdDSA crypto suite for RDF Dataset Canonicalization.
|
|
61
|
+
* https://www.w3.org/TR/vc-di-eddsa/#eddsa-rdfc-2022
|
|
62
|
+
*/
|
|
63
|
+
EdDSARdfc2022: "eddsa-rdfc-2022"
|
|
16
64
|
};
|
|
17
65
|
|
|
18
66
|
// Copyright 2024 IOTA Stiftung.
|
|
@@ -29,7 +77,23 @@ const DidTypes = {
|
|
|
29
77
|
/**
|
|
30
78
|
* The type for Verifiable Presentation.
|
|
31
79
|
*/
|
|
32
|
-
VerifiablePresentation: "VerifiablePresentation"
|
|
80
|
+
VerifiablePresentation: "VerifiablePresentation",
|
|
81
|
+
/**
|
|
82
|
+
* The type for Ed25519VerificationKey2020.
|
|
83
|
+
*/
|
|
84
|
+
Ed25519VerificationKey2020: "Ed25519VerificationKey2020",
|
|
85
|
+
/**
|
|
86
|
+
* The type for JsonWebKey2020.
|
|
87
|
+
*/
|
|
88
|
+
JsonWebKey2020: "JsonWebKey2020",
|
|
89
|
+
/**
|
|
90
|
+
* The type for LinkedDomains.
|
|
91
|
+
*/
|
|
92
|
+
LinkedDomains: "LinkedDomains",
|
|
93
|
+
/**
|
|
94
|
+
* The type for Multikey.
|
|
95
|
+
*/
|
|
96
|
+
Multikey: "Multikey"
|
|
33
97
|
};
|
|
34
98
|
|
|
35
99
|
/**
|
|
@@ -63,4 +127,390 @@ const DidVerificationMethodType = {
|
|
|
63
127
|
CapabilityDelegation: "capabilityDelegation"
|
|
64
128
|
};
|
|
65
129
|
|
|
66
|
-
|
|
130
|
+
// Copyright 2024 IOTA Stiftung.
|
|
131
|
+
// SPDX-License-Identifier: Apache-2.0.
|
|
132
|
+
/**
|
|
133
|
+
* The types for proofs.
|
|
134
|
+
*/
|
|
135
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
136
|
+
const ProofTypes = {
|
|
137
|
+
/**
|
|
138
|
+
* The type for Data Integrity Proof.
|
|
139
|
+
*/
|
|
140
|
+
DataIntegrityProof: "DataIntegrityProof",
|
|
141
|
+
/**
|
|
142
|
+
* The type for Json Web Signature 2020.
|
|
143
|
+
*/
|
|
144
|
+
JsonWebSignature2020: "JsonWebSignature2020"
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
// Copyright 2024 IOTA Stiftung.
|
|
148
|
+
// SPDX-License-Identifier: Apache-2.0.
|
|
149
|
+
/**
|
|
150
|
+
* Helper methods for creating and verifying proofs.
|
|
151
|
+
* https://www.w3.org/TR/vc-di-eddsa/#eddsa-jcs-2022
|
|
152
|
+
*/
|
|
153
|
+
class DataIntegrityProofSignerVerifier {
|
|
154
|
+
/**
|
|
155
|
+
* Runtime name for the class.
|
|
156
|
+
*/
|
|
157
|
+
CLASS_NAME = "DataIntegrityProofSignerVerifier";
|
|
158
|
+
/**
|
|
159
|
+
* Create a proof for the given data.
|
|
160
|
+
* @param unsecuredDocument The data to create the proof for.
|
|
161
|
+
* @param unsignedProof The proof options.
|
|
162
|
+
* @param signKey The key to sign the proof with.
|
|
163
|
+
* @returns The created proof.
|
|
164
|
+
*/
|
|
165
|
+
async createProof(unsecuredDocument, unsignedProof, signKey) {
|
|
166
|
+
Guards.object(this.CLASS_NAME, "unsecuredDocument", unsecuredDocument);
|
|
167
|
+
Guards.object(this.CLASS_NAME, "unsignedProof", unsignedProof);
|
|
168
|
+
Guards.object(this.CLASS_NAME, "signKey", signKey);
|
|
169
|
+
const rawKeys = await Jwk.toRaw(signKey);
|
|
170
|
+
if (!Is.uint8Array(rawKeys.privateKey)) {
|
|
171
|
+
throw new GeneralError(this.CLASS_NAME, "missingPrivateKey");
|
|
172
|
+
}
|
|
173
|
+
const unsecuredDocumentClone = ObjectHelper.clone(unsecuredDocument);
|
|
174
|
+
const signedProof = ObjectHelper.clone(unsignedProof);
|
|
175
|
+
unsecuredDocumentClone["@context"] = JsonLdProcessor.combineContexts(unsecuredDocumentClone["@context"], DidContexts.ContextDataIntegrity);
|
|
176
|
+
signedProof["@context"] = unsecuredDocumentClone["@context"];
|
|
177
|
+
const combinedHash = await this.createHash(unsecuredDocument, unsignedProof);
|
|
178
|
+
const signature = Ed25519.sign(rawKeys.privateKey, combinedHash);
|
|
179
|
+
signedProof.proofValue = `z${Converter.bytesToBase58(signature)}`;
|
|
180
|
+
return signedProof;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Verify a proof for the given data in format.
|
|
184
|
+
* @param securedDocument The credential to verify.
|
|
185
|
+
* @param signedProof The proof to verify.
|
|
186
|
+
* @param verifyKey The public key to verify the proof with.
|
|
187
|
+
* @returns True if the credential was verified.
|
|
188
|
+
*/
|
|
189
|
+
async verifyProof(securedDocument, signedProof, verifyKey) {
|
|
190
|
+
Guards.object(this.CLASS_NAME, "securedDocument", securedDocument);
|
|
191
|
+
Guards.object(this.CLASS_NAME, "signedProof", signedProof);
|
|
192
|
+
Guards.stringValue(this.CLASS_NAME, "signedProof.proofValue", signedProof.proofValue);
|
|
193
|
+
Guards.object(this.CLASS_NAME, "verifyKey", verifyKey);
|
|
194
|
+
const rawKeys = await Jwk.toRaw(verifyKey);
|
|
195
|
+
if (!Is.uint8Array(rawKeys.publicKey)) {
|
|
196
|
+
throw new GeneralError(this.CLASS_NAME, "missingPublicKey");
|
|
197
|
+
}
|
|
198
|
+
const combinedHash = await this.createHash(securedDocument, signedProof);
|
|
199
|
+
return Ed25519.verify(rawKeys.publicKey, combinedHash, Converter.base58ToBytes(signedProof.proofValue.slice(1)));
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Create a hash for the given data.
|
|
203
|
+
* @param unsecuredDocument The data to create the proof for.
|
|
204
|
+
* @param unsignedProof The unsigned proof.
|
|
205
|
+
* @returns The created hash.
|
|
206
|
+
*/
|
|
207
|
+
async createHash(unsecuredDocument, unsignedProof) {
|
|
208
|
+
Guards.object(this.CLASS_NAME, "unsecuredDocument", unsecuredDocument);
|
|
209
|
+
Guards.object(this.CLASS_NAME, "unsignedProof", unsignedProof);
|
|
210
|
+
Guards.stringValue(this.CLASS_NAME, "unsignedProof.cryptosuite", unsignedProof.cryptosuite);
|
|
211
|
+
Guards.stringValue(this.CLASS_NAME, "unsignedProof.verificationMethod", unsignedProof.verificationMethod);
|
|
212
|
+
const unsecuredDocumentClone = ObjectHelper.clone(unsecuredDocument);
|
|
213
|
+
const proofOptionsClone = ObjectHelper.clone(unsignedProof);
|
|
214
|
+
delete unsecuredDocumentClone.proof;
|
|
215
|
+
delete proofOptionsClone.proofValue;
|
|
216
|
+
if (proofOptionsClone.cryptosuite !== DidCryptoSuites.EdDSAJcs2022) {
|
|
217
|
+
throw new GeneralError(this.CLASS_NAME, "cryptosuiteNotSupported", {
|
|
218
|
+
cryptoSuite: proofOptionsClone.cryptosuite
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
unsecuredDocumentClone["@context"] = JsonLdProcessor.combineContexts(unsecuredDocumentClone["@context"], DidContexts.ContextDataIntegrity);
|
|
222
|
+
proofOptionsClone["@context"] = unsecuredDocumentClone["@context"];
|
|
223
|
+
const transformedDocument = JsonHelper.canonicalize(unsecuredDocumentClone);
|
|
224
|
+
const transformedDocumentHash = Sha256.sum256(Converter.utf8ToBytes(transformedDocument));
|
|
225
|
+
const transformedProofOptions = JsonHelper.canonicalize(proofOptionsClone);
|
|
226
|
+
const proofOptionsHash = Sha256.sum256(Converter.utf8ToBytes(transformedProofOptions));
|
|
227
|
+
return Uint8ArrayHelper.concat([proofOptionsHash, transformedDocumentHash]);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Copyright 2024 IOTA Stiftung.
|
|
232
|
+
// SPDX-License-Identifier: Apache-2.0.
|
|
233
|
+
/**
|
|
234
|
+
* Helper methods for creating and verifying proofs.
|
|
235
|
+
*/
|
|
236
|
+
class JsonWebSignature2020SignerVerifier {
|
|
237
|
+
/**
|
|
238
|
+
* Runtime name for the class.
|
|
239
|
+
*/
|
|
240
|
+
CLASS_NAME = "JsonWebSignature2020SignerVerifier";
|
|
241
|
+
/**
|
|
242
|
+
* Create a proof for the given data.
|
|
243
|
+
* @param unsecuredDocument The data to create the proof for.
|
|
244
|
+
* @param unsignedProof The proof options.
|
|
245
|
+
* @param signKey The key to sign the proof with.
|
|
246
|
+
* @returns The created proof.
|
|
247
|
+
*/
|
|
248
|
+
async createProof(unsecuredDocument, unsignedProof, signKey) {
|
|
249
|
+
Guards.object(this.CLASS_NAME, "unsecuredDocument", unsecuredDocument);
|
|
250
|
+
Guards.object(this.CLASS_NAME, "unsignedProof", unsignedProof);
|
|
251
|
+
Guards.object(this.CLASS_NAME, "signKey", signKey);
|
|
252
|
+
const unsecuredDocumentClone = ObjectHelper.clone(unsecuredDocument);
|
|
253
|
+
unsecuredDocumentClone["@context"] = JsonLdProcessor.combineContexts(unsecuredDocumentClone["@context"], DidContexts.ContextSecurityJws2020);
|
|
254
|
+
const hash = await this.createHash(unsecuredDocument, unsignedProof);
|
|
255
|
+
const cryptoKey = await Jwk.toCryptoKey(signKey);
|
|
256
|
+
const signature = await Jws.create(cryptoKey, hash, signKey.alg);
|
|
257
|
+
const signedProof = ObjectHelper.clone(unsignedProof);
|
|
258
|
+
signedProof["@context"] = unsecuredDocumentClone["@context"];
|
|
259
|
+
signedProof.jws = signature;
|
|
260
|
+
return signedProof;
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Verify a proof for the given data in format.
|
|
264
|
+
* @param securedDocument The credential to verify.
|
|
265
|
+
* @param signedProof The proof to verify.
|
|
266
|
+
* @param verifyKey The public key to verify the proof with.
|
|
267
|
+
* @returns True if the credential was verified.
|
|
268
|
+
*/
|
|
269
|
+
async verifyProof(securedDocument, signedProof, verifyKey) {
|
|
270
|
+
Guards.object(this.CLASS_NAME, "securedDocument", securedDocument);
|
|
271
|
+
Guards.object(this.CLASS_NAME, "signedProof", signedProof);
|
|
272
|
+
Guards.object(this.CLASS_NAME, "verifyKey", verifyKey);
|
|
273
|
+
const jws = signedProof.jws;
|
|
274
|
+
if (!Is.stringValue(jws)) {
|
|
275
|
+
throw new GeneralError(this.CLASS_NAME, "jwsMissing");
|
|
276
|
+
}
|
|
277
|
+
const hash = await this.createHash(securedDocument, signedProof);
|
|
278
|
+
const cryptoKey = await Jwk.toCryptoKey(verifyKey);
|
|
279
|
+
return Jws.verify(jws, cryptoKey, hash);
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Create a hash for the given data.
|
|
283
|
+
* @param unsecuredDocument The data to create the proof for.
|
|
284
|
+
* @param unsignedProof The unsigned proof.
|
|
285
|
+
* @returns The created hash.
|
|
286
|
+
*/
|
|
287
|
+
async createHash(unsecuredDocument, unsignedProof) {
|
|
288
|
+
Guards.object(this.CLASS_NAME, "unsecuredDocument", unsecuredDocument);
|
|
289
|
+
Guards.object(this.CLASS_NAME, "unsignedProof", unsignedProof);
|
|
290
|
+
Guards.stringValue(this.CLASS_NAME, "unsignedProof.verificationMethod", unsignedProof.verificationMethod);
|
|
291
|
+
const unsecuredDocumentClone = ObjectHelper.clone(unsecuredDocument);
|
|
292
|
+
const proofOptionsClone = ObjectHelper.clone(unsignedProof);
|
|
293
|
+
unsecuredDocumentClone["@context"] = JsonLdProcessor.combineContexts(unsecuredDocumentClone["@context"], DidContexts.ContextSecurityJws2020);
|
|
294
|
+
proofOptionsClone["@context"] = unsecuredDocumentClone["@context"];
|
|
295
|
+
delete unsecuredDocumentClone.proof;
|
|
296
|
+
delete proofOptionsClone.jws;
|
|
297
|
+
const canonizedData = await JsonLdProcessor.canonize(unsecuredDocumentClone);
|
|
298
|
+
const canonizedProof = await JsonLdProcessor.canonize(proofOptionsClone);
|
|
299
|
+
const hashedProof = Sha256.sum256(Converter.utf8ToBytes(canonizedProof));
|
|
300
|
+
const hashedData = Sha256.sum256(Converter.utf8ToBytes(canonizedData));
|
|
301
|
+
return Uint8ArrayHelper.concat([hashedProof, hashedData]);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// Copyright 2024 IOTA Stiftung.
|
|
306
|
+
// SPDX-License-Identifier: Apache-2.0.
|
|
307
|
+
/**
|
|
308
|
+
* Helper methods for multikey.
|
|
309
|
+
*/
|
|
310
|
+
class MultikeyHelper {
|
|
311
|
+
/**
|
|
312
|
+
* Runtime name for the class.
|
|
313
|
+
*/
|
|
314
|
+
static CLASS_NAME = "MultikeyHelper";
|
|
315
|
+
/**
|
|
316
|
+
* Convert a multikey to a JWK.
|
|
317
|
+
* @param multikey The multikey to convert.
|
|
318
|
+
* @returns The JWK.
|
|
319
|
+
* @throws GeneralError if the multikey is invalid.
|
|
320
|
+
*/
|
|
321
|
+
static toJwk(multikey) {
|
|
322
|
+
Guards.object(MultikeyHelper.CLASS_NAME, "multikey", multikey);
|
|
323
|
+
const { publicKey, privateKey } = MultikeyHelper.toRaw(multikey);
|
|
324
|
+
return {
|
|
325
|
+
kty: "OKP",
|
|
326
|
+
crv: "Ed25519",
|
|
327
|
+
alg: "EdDSA",
|
|
328
|
+
x: Is.uint8Array(publicKey) ? Converter.bytesToBase64Url(publicKey) : undefined,
|
|
329
|
+
d: Is.uint8Array(privateKey) ? Converter.bytesToBase64Url(privateKey) : undefined
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Convert a JWK to a Multikey.
|
|
334
|
+
* @param controller The controller of the multikey.
|
|
335
|
+
* @param id The id of the multikey.
|
|
336
|
+
* @param jwk The jwk to convert.
|
|
337
|
+
* @returns The multikey.
|
|
338
|
+
* @throws GeneralError if the jwk is invalid.
|
|
339
|
+
*/
|
|
340
|
+
static fromJwk(controller, id, jwk) {
|
|
341
|
+
Guards.stringValue(MultikeyHelper.CLASS_NAME, "controller", controller);
|
|
342
|
+
Guards.stringValue(MultikeyHelper.CLASS_NAME, "id", id);
|
|
343
|
+
Guards.object(MultikeyHelper.CLASS_NAME, "jwk", jwk);
|
|
344
|
+
Guards.stringValue(MultikeyHelper.CLASS_NAME, "jwk.x", jwk.x);
|
|
345
|
+
if (jwk.kty !== "OKP") {
|
|
346
|
+
throw new GeneralError(MultikeyHelper.CLASS_NAME, "unsupportedKty", { kty: jwk.kty });
|
|
347
|
+
}
|
|
348
|
+
if (jwk.crv !== "Ed25519") {
|
|
349
|
+
throw new GeneralError(MultikeyHelper.CLASS_NAME, "unsupportedCrv", { crv: jwk.crv });
|
|
350
|
+
}
|
|
351
|
+
const publicRaw = Converter.base64UrlToBytes(jwk.x);
|
|
352
|
+
const publicKey = new Uint8Array(2 + publicRaw.length);
|
|
353
|
+
publicKey[0] = 0xed;
|
|
354
|
+
publicKey[1] = 0x01;
|
|
355
|
+
publicKey.set(publicRaw, 2);
|
|
356
|
+
const multikey = {
|
|
357
|
+
"@context": DidContexts.ContextControllerIdentifiers,
|
|
358
|
+
type: DidTypes.Multikey,
|
|
359
|
+
controller,
|
|
360
|
+
id,
|
|
361
|
+
publicKeyMultibase: `z${Converter.bytesToBase58(publicKey)}`
|
|
362
|
+
};
|
|
363
|
+
if (Is.stringValue(jwk.d)) {
|
|
364
|
+
const privateRaw = Converter.base64UrlToBytes(jwk.d);
|
|
365
|
+
const secretKey = new Uint8Array(2 + privateRaw.length);
|
|
366
|
+
secretKey[0] = 0x80;
|
|
367
|
+
secretKey[1] = 0x26;
|
|
368
|
+
secretKey.set(privateRaw, 2);
|
|
369
|
+
multikey.secretKeyMultibase = `z${Converter.bytesToBase58(secretKey)}`;
|
|
370
|
+
}
|
|
371
|
+
return multikey;
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Convert a multikey to raw keys.
|
|
375
|
+
* @param multikey The multikey to convert.
|
|
376
|
+
* @returns The JWK.
|
|
377
|
+
* @throws GeneralError if the multikey is invalid.
|
|
378
|
+
*/
|
|
379
|
+
static toRaw(multikey) {
|
|
380
|
+
Guards.object(MultikeyHelper.CLASS_NAME, "multikey", multikey);
|
|
381
|
+
let publicKeyRaw;
|
|
382
|
+
let secretKeyRaw;
|
|
383
|
+
if (Is.stringValue(multikey.publicKeyMultibase)) {
|
|
384
|
+
if (!multikey.publicKeyMultibase.startsWith("z")) {
|
|
385
|
+
throw new GeneralError(MultikeyHelper.CLASS_NAME, "invalidPublicKeyMultibase", {
|
|
386
|
+
publicKeyMultibase: multikey.publicKeyMultibase
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
publicKeyRaw = Converter.base58ToBytes(multikey.publicKeyMultibase.slice(1));
|
|
390
|
+
if (publicKeyRaw[0] !== 0xed || publicKeyRaw[1] !== 0x01) {
|
|
391
|
+
throw new GeneralError(MultikeyHelper.CLASS_NAME, "publicKeyMultibaseMissingHeader", {
|
|
392
|
+
publicKeyMultibase: multikey.publicKeyMultibase
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
if (Is.stringValue(multikey.secretKeyMultibase)) {
|
|
397
|
+
if (!multikey.secretKeyMultibase.startsWith("z")) {
|
|
398
|
+
throw new GeneralError(MultikeyHelper.CLASS_NAME, "invalidSecretKeyMultibase", {
|
|
399
|
+
secretKeyMultibase: multikey.secretKeyMultibase
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
secretKeyRaw = Converter.base58ToBytes(multikey.secretKeyMultibase.slice(1));
|
|
403
|
+
if (secretKeyRaw[0] !== 0x80 || secretKeyRaw[1] !== 0x26) {
|
|
404
|
+
throw new GeneralError(MultikeyHelper.CLASS_NAME, "publicKeyMultibaseMissingHeader", {
|
|
405
|
+
publicKeyMultibase: multikey.publicKeyMultibase
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
return {
|
|
410
|
+
publicKey: publicKeyRaw?.slice(2) ?? new Uint8Array(),
|
|
411
|
+
privateKey: secretKeyRaw?.slice(2, 34) ?? new Uint8Array()
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// Copyright 2024 IOTA Stiftung.
|
|
417
|
+
// SPDX-License-Identifier: Apache-2.0.
|
|
418
|
+
/**
|
|
419
|
+
* Helper methods for creating and verifying proofs.
|
|
420
|
+
*/
|
|
421
|
+
class ProofHelper {
|
|
422
|
+
/**
|
|
423
|
+
* Runtime name for the class.
|
|
424
|
+
*/
|
|
425
|
+
static CLASS_NAME = "ProofHelper";
|
|
426
|
+
/**
|
|
427
|
+
* Create a signer verifier.
|
|
428
|
+
* @param proofType The type of proof to create.
|
|
429
|
+
* @returns The created signer verifier.
|
|
430
|
+
* @throws GeneralError if the proof type is not supported.
|
|
431
|
+
*/
|
|
432
|
+
static createSignerVerifier(proofType) {
|
|
433
|
+
Guards.arrayOneOf(this.CLASS_NAME, "proofType", proofType, Object.values(ProofTypes));
|
|
434
|
+
let signerVerifier;
|
|
435
|
+
if (proofType === ProofTypes.DataIntegrityProof) {
|
|
436
|
+
signerVerifier = new DataIntegrityProofSignerVerifier();
|
|
437
|
+
}
|
|
438
|
+
else if (proofType === ProofTypes.JsonWebSignature2020) {
|
|
439
|
+
signerVerifier = new JsonWebSignature2020SignerVerifier();
|
|
440
|
+
}
|
|
441
|
+
if (Is.empty(signerVerifier)) {
|
|
442
|
+
throw new GeneralError(ProofHelper.CLASS_NAME, "unsupportedProofType", { proofType });
|
|
443
|
+
}
|
|
444
|
+
return signerVerifier;
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Create a proof for the given data.
|
|
448
|
+
* @param proofType The type of proof to create.
|
|
449
|
+
* @param unsecuredDocument The data to create the proof for.
|
|
450
|
+
* @param unsignedProof The proof options.
|
|
451
|
+
* @param signKey The key to sign the proof with.
|
|
452
|
+
* @returns The created proof.
|
|
453
|
+
*/
|
|
454
|
+
static async createProof(proofType, unsecuredDocument, unsignedProof, signKey) {
|
|
455
|
+
Guards.arrayOneOf(this.CLASS_NAME, "proofType", proofType, Object.values(ProofTypes));
|
|
456
|
+
Guards.object(this.CLASS_NAME, "unsecuredDocument", unsecuredDocument);
|
|
457
|
+
Guards.object(this.CLASS_NAME, "unsignedProof", unsignedProof);
|
|
458
|
+
Guards.object(this.CLASS_NAME, "signKey", signKey);
|
|
459
|
+
return ProofHelper.createSignerVerifier(proofType).createProof(unsecuredDocument, unsignedProof, signKey);
|
|
460
|
+
}
|
|
461
|
+
/**
|
|
462
|
+
* Verify a proof for the given data.
|
|
463
|
+
* @param securedDocument The credential to verify.
|
|
464
|
+
* @param signedProof The proof to verify.
|
|
465
|
+
* @param verifyKey The public key to verify the proof with.
|
|
466
|
+
* @returns True if the credential was verified.
|
|
467
|
+
*/
|
|
468
|
+
static async verifyProof(securedDocument, signedProof, verifyKey) {
|
|
469
|
+
Guards.object(this.CLASS_NAME, "securedDocument", securedDocument);
|
|
470
|
+
Guards.object(this.CLASS_NAME, "signedProof", signedProof);
|
|
471
|
+
Guards.stringValue(this.CLASS_NAME, "signedProof.type", signedProof.type);
|
|
472
|
+
Guards.object(this.CLASS_NAME, "verifyKey", verifyKey);
|
|
473
|
+
const signerVerifier = ProofHelper.createSignerVerifier(signedProof.type);
|
|
474
|
+
return signerVerifier.verifyProof(securedDocument, signedProof, verifyKey);
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* Create an unsigned proof.
|
|
478
|
+
* @param proofType The type of proof to create.
|
|
479
|
+
* @param verificationMethodId The verification method id.
|
|
480
|
+
* @param otherParams Other parameters for the proof.
|
|
481
|
+
* @returns The created proof.
|
|
482
|
+
* @throws GeneralError if the proof type is not supported.
|
|
483
|
+
*/
|
|
484
|
+
static createUnsignedProof(proofType, verificationMethodId,
|
|
485
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
486
|
+
otherParams) {
|
|
487
|
+
let proof;
|
|
488
|
+
if (proofType === ProofTypes.DataIntegrityProof) {
|
|
489
|
+
proof = {
|
|
490
|
+
"@context": DidContexts.ContextDataIntegrity,
|
|
491
|
+
type: ProofTypes.DataIntegrityProof,
|
|
492
|
+
cryptosuite: DidCryptoSuites.EdDSAJcs2022,
|
|
493
|
+
created: new Date(Date.now()).toISOString(),
|
|
494
|
+
verificationMethod: verificationMethodId,
|
|
495
|
+
proofPurpose: "assertionMethod",
|
|
496
|
+
...otherParams
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
else if (proofType === ProofTypes.JsonWebSignature2020) {
|
|
500
|
+
proof = {
|
|
501
|
+
"@context": DidContexts.ContextSecurityJws2020,
|
|
502
|
+
type: ProofTypes.JsonWebSignature2020,
|
|
503
|
+
created: new Date(Date.now()).toISOString(),
|
|
504
|
+
verificationMethod: verificationMethodId,
|
|
505
|
+
proofPurpose: "assertionMethod",
|
|
506
|
+
...otherParams
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
if (Is.empty(proof)) {
|
|
510
|
+
throw new GeneralError(ProofHelper.CLASS_NAME, "unsupportedProofType", { proofType });
|
|
511
|
+
}
|
|
512
|
+
return proof;
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
export { DataIntegrityProofSignerVerifier, DidContexts, DidCryptoSuites, DidTypes, DidVerificationMethodType, JsonWebSignature2020SignerVerifier, MultikeyHelper, ProofHelper, ProofTypes };
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,11 +1,23 @@
|
|
|
1
1
|
export * from "./models/didContexts";
|
|
2
|
+
export * from "./models/didCryptoSuites";
|
|
2
3
|
export * from "./models/didTypes";
|
|
3
4
|
export * from "./models/didVerificationMethodType";
|
|
5
|
+
export * from "./models/IDataIntegrityProof";
|
|
6
|
+
export * from "./models/IDidCredentialSchema";
|
|
4
7
|
export * from "./models/IDidCredentialStatus";
|
|
5
8
|
export * from "./models/IDidDocument";
|
|
6
9
|
export * from "./models/IDidDocumentVerificationMethod";
|
|
10
|
+
export * from "./models/IDidLabel";
|
|
7
11
|
export * from "./models/IDidPresentationVerification";
|
|
8
|
-
export * from "./models/IDidProof";
|
|
9
12
|
export * from "./models/IDidService";
|
|
10
13
|
export * from "./models/IDidVerifiableCredential";
|
|
11
14
|
export * from "./models/IDidVerifiablePresentation";
|
|
15
|
+
export * from "./models/IJsonWebSignature2020Proof";
|
|
16
|
+
export * from "./models/IMultikey";
|
|
17
|
+
export * from "./models/IProof";
|
|
18
|
+
export * from "./models/IProofSignerVerifier";
|
|
19
|
+
export * from "./models/proofTypes";
|
|
20
|
+
export * from "./signerVerifiers/dataIntegrityProofSignerVerifier";
|
|
21
|
+
export * from "./signerVerifiers/jsonWebSignature2020SignerVerifier";
|
|
22
|
+
export * from "./utils/multikeyHelper";
|
|
23
|
+
export * from "./utils/proofHelper";
|
|
@@ -1,18 +1,30 @@
|
|
|
1
|
+
import type { IJsonLdContextDefinitionElement } from "@twin.org/data-json-ld";
|
|
2
|
+
import type { DidContexts } from "./didContexts";
|
|
3
|
+
import type { DidCryptoSuites } from "./didCryptoSuites";
|
|
4
|
+
import type { ProofTypes } from "./proofTypes";
|
|
1
5
|
/**
|
|
2
6
|
* Interface describing a did proof.
|
|
3
7
|
* https://www.w3.org/TR/vc-data-integrity/
|
|
4
8
|
*/
|
|
5
|
-
export interface
|
|
9
|
+
export interface IDataIntegrityProof {
|
|
6
10
|
/**
|
|
7
|
-
*
|
|
11
|
+
* JSON-LD Context.
|
|
8
12
|
*/
|
|
9
|
-
|
|
13
|
+
"@context"?: typeof DidContexts.ContextDataIntegrity | [typeof DidContexts.ContextDataIntegrity, ...IJsonLdContextDefinitionElement[]];
|
|
14
|
+
/**
|
|
15
|
+
* JSON-LD Type.
|
|
16
|
+
*/
|
|
17
|
+
type: typeof ProofTypes.DataIntegrityProof;
|
|
10
18
|
/**
|
|
11
|
-
*
|
|
19
|
+
* An identifier for the cryptographic suite that can be used to verify the proof.
|
|
12
20
|
*/
|
|
13
|
-
|
|
21
|
+
cryptosuite: DidCryptoSuites | string;
|
|
22
|
+
/**
|
|
23
|
+
* The id of the proof.
|
|
24
|
+
*/
|
|
25
|
+
id?: string;
|
|
14
26
|
/**
|
|
15
|
-
* The
|
|
27
|
+
* The reason the proof was created.
|
|
16
28
|
*/
|
|
17
29
|
proofPurpose: string;
|
|
18
30
|
/**
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { IJsonLdContextDefinitionElement } from "@twin.org/data-json-ld";
|
|
2
|
+
import type { DidContexts } from "./didContexts";
|
|
1
3
|
import type { IDidDocumentVerificationMethod } from "./IDidDocumentVerificationMethod";
|
|
2
4
|
import type { IDidService } from "./IDidService";
|
|
3
5
|
/**
|
|
@@ -5,6 +7,10 @@ import type { IDidService } from "./IDidService";
|
|
|
5
7
|
* Spec https://www.w3.org/TR/did-core/#did-document-properties.
|
|
6
8
|
*/
|
|
7
9
|
export interface IDidDocument {
|
|
10
|
+
/**
|
|
11
|
+
* The context for the document.
|
|
12
|
+
*/
|
|
13
|
+
"@context": typeof DidContexts.Context | [typeof DidContexts.Context, ...IJsonLdContextDefinitionElement[]];
|
|
8
14
|
/**
|
|
9
15
|
* The id for the document.
|
|
10
16
|
*/
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import type { IJsonLdNodeObject } from "@twin.org/data-json-ld";
|
|
1
2
|
import type { IJwk } from "@twin.org/web";
|
|
2
3
|
/**
|
|
3
4
|
* Interface describing a DID document verification method.
|
|
4
5
|
*/
|
|
5
|
-
export interface IDidDocumentVerificationMethod {
|
|
6
|
+
export interface IDidDocumentVerificationMethod extends IJsonLdNodeObject {
|
|
6
7
|
/**
|
|
7
8
|
* The id of the entry.
|
|
8
9
|
*/
|
|
@@ -24,7 +25,7 @@ export interface IDidDocumentVerificationMethod {
|
|
|
24
25
|
* The public key for the entry as a JWK.
|
|
25
26
|
* Spec https://datatracker.ietf.org/doc/html/rfc7517 .
|
|
26
27
|
*/
|
|
27
|
-
publicKeyJwk?: IJwk;
|
|
28
|
+
publicKeyJwk?: IJwk & IJsonLdNodeObject;
|
|
28
29
|
/**
|
|
29
30
|
* Multi key partial revocation.
|
|
30
31
|
*/
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interface describing a DID Label.
|
|
3
|
+
*/
|
|
4
|
+
export interface IDidLabel {
|
|
5
|
+
/**
|
|
6
|
+
* The value for the label.
|
|
7
|
+
*/
|
|
8
|
+
"@value": string;
|
|
9
|
+
/**
|
|
10
|
+
* The language for the label.
|
|
11
|
+
*/
|
|
12
|
+
"@language": string;
|
|
13
|
+
/**
|
|
14
|
+
* The direction of the label.
|
|
15
|
+
*/
|
|
16
|
+
"@direction"?: string;
|
|
17
|
+
}
|