@dwn-protocol/id-sdk
Version:
SDK for accessing the features and capabilities
791 lines (698 loc) • 28 kB
text/typescript
import type { PrivateKeyJwk, PublicKeyJwk, IDCrypto } from '../crypto/index.js';
import { universalTypeOf } from '../common/index.js';
// import { keyToMultibaseId, multibaseIdToKey } from '../crypto/utils.js';
import {
Jose,
Ed25519,
Secp256k1,
EcdsaAlgorithm,
EdDsaAlgorithm,
utils as cryptoUtils,
} from '../crypto/index.js';
import type {
DidMethod,
DidDocument,
PortableDid,
VerificationMethod,
DidResolutionResult,
DidResolutionOptions,
DidKeySetVerificationMethodKey
} from './types.js';
import { getVerificationMethodTypes, parseDid } from './utils.js';
const SupportedCryptoAlgorithms = [
'Ed25519',
'secp256k1'
] as const;
const SupportedPublicKeyFormats = [
'Ed25519VerificationKey2020',
'JsonWebKey2020',
'X25519KeyAgreementKey2020'
];
const VERIFICATION_METHOD_TYPES: Record<string, string> = {
'Ed25519VerificationKey2020' : 'https://w3id.org/security/suites/ed25519-2020/v1',
'JsonWebKey2020' : 'https://w3id.org/security/suites/jws-2020/v1',
'X25519KeyAgreementKey2020' : 'https://w3id.org/security/suites/x25519-2020/v1',
} as const;
export type DidVerificationMethodType = keyof typeof VERIFICATION_METHOD_TYPES;
const MULTICODEC_PUBLIC_KEY_LENGTH: Record<number, number> = {
// secp256k1-pub - Secp256k1 public key (compressed) - 33 bytes
0xe7: 33,
// x25519-pub - Curve25519 public key - 32 bytes
0xec: 32,
// ed25519-pub - Ed25519 public key - 32 bytes
0xed: 32
};
export type DidKeyCreateOptions = {
enableEncryptionKeyDerivation?: boolean;
keyAlgorithm?: typeof SupportedCryptoAlgorithms[number];
keySet?: DidKeyKeySet;
publicKeyFormat?: DidVerificationMethodType;
}
export type DidKeyCreateDocumentOptions = {
defaultContext?: string;
did: string;
enableEncryptionKeyDerivation?: boolean;
enableExperimentalPublicKeyTypes?: boolean;
publicKeyFormat?: DidVerificationMethodType;
}
export type DidKeyDeriveEncryptionKeyResult = {
key: Uint8Array;
multicodecCode: number;
}
export type DidKeyIdentifier = {
fragment: string;
method: string;
multibaseValue: string;
scheme: string;
version: string;
}
export type DidKeyKeySet = {
verificationMethodKeys?: DidKeySetVerificationMethodKey[];
}
export class DidKeyMethod implements DidMethod {
/**
* Name of the DID method
*/
public static methodName = 'key';
public static async create(options?: DidKeyCreateOptions): Promise<PortableDid> {
let {
enableEncryptionKeyDerivation = false,
keyAlgorithm,
keySet,
publicKeyFormat = 'JsonWebKey2020'
} = options ?? { };
// If keySet not given, generate a default key set.
if (keySet === undefined) {
keySet = await DidKeyMethod.generateKeySet({ keyAlgorithm });
}
const portableDid: Partial<PortableDid> = {};
let multibaseId = '';
if (keySet.verificationMethodKeys?.[0]?.publicKeyJwk) {
// Compute the multibase identifier based on the JSON Web Key.
const publicKeyJwk = keySet.verificationMethodKeys[0].publicKeyJwk;
multibaseId = await Jose.jwkToMultibaseId({ key: publicKeyJwk });
}
if (!multibaseId) {
throw new Error('DidKeyMethod: Failed to create DID with given input.');
}
// Concatenate the DID identifier.
portableDid.did = `did:key:${multibaseId}`;
// Expand the DID identifier to a DID document.
portableDid.document = await DidKeyMethod.createDocument({
did: portableDid.did,
publicKeyFormat,
enableEncryptionKeyDerivation
});
// Return the given or generated key set.
portableDid.keySet = keySet;
return portableDid as PortableDid;
}
/**
* Expands a did:key identifier to a DID Document.
*
* Reference: https://w3c-ccg.github.io/did-method-key/#document-creation-algorithm
*
* @param options
* @returns - A DID dodcument.
*/
public static async createDocument(options: DidKeyCreateDocumentOptions): Promise<DidDocument> {
const {
defaultContext = 'https://www.w3.org/ns/did/v1',
did,
enableEncryptionKeyDerivation = false,
enableExperimentalPublicKeyTypes = false,
publicKeyFormat = 'JsonWebKey2020'
} = options;
/**
* 1. Initialize document to an empty object.
*/
const document: Partial<DidDocument> = {};
/**
* 2. Using a colon (:) as the delimiter, split the identifier into its
* components: a scheme, a method, a version, and a multibaseValue.
* If there are only three components set the version to the string
* value 1 and use the last value as the multibaseValue.
*
* Note: The W3C DID specification makes no mention of a version value
* being part of the DID syntax. Additionally, there does not
* appear to be any real-world usage of the version number.
* Consequently, this implementation will ignore the version
* related guidance in the did:key specification.
*/
let multibaseValue: string;
try {
({ id: multibaseValue } = parseDid({ didUrl: did }));
} catch (error: any) {
throw new Error(`invalidDid: Unknown format: ${did}`);
}
/**
* 3. Check the validity of the input identifier.
* The scheme MUST be the value did. The method MUST be the value key.
* The version MUST be convertible to a positive integer value. The
* multibaseValue MUST be a string and begin with the letter z. If any
* of these requirements fail, an invalidDid error MUST be raised.
*/
if (!DidKeyMethod.validateIdentifier({ did })) {
throw new Error(`invalidDid: Invalid identifier format: ${did}`);
}
/**
* 4. Initialize the signatureVerificationMethod to the result of passing
* identifier, multibaseValue, and options to a
* {@link https://w3c-ccg.github.io/did-method-key/#signature-method-creation-algorithm | Signature Method Creation Algorithm}.
*/
const signatureVerificationMethod = await DidKeyMethod.createSignatureMethod({
did,
enableExperimentalPublicKeyTypes,
multibaseValue,
publicKeyFormat
});
/**
* 5. Set document.id to identifier. If document.id is not a valid DID,
* an invalidDid error MUST be raised.
*
* Note: Identifier was already confirmed to be valid in Step 3, so
* skipping the redundant validation.
*/
document.id = did;
/**
* 6. Initialize the verificationMethod property in document to an array
* where the first value is the signatureVerificationMethod.
*/
document.verificationMethod = [signatureVerificationMethod];
/**
* 7. Initialize the authentication, assertionMethod, capabilityInvocation,
* and the capabilityDelegation properties in document to an array where
* the first item is the value of the id property in
* signatureVerificationMethod.
*/
document.authentication = [signatureVerificationMethod.id];
document.assertionMethod = [signatureVerificationMethod.id];
document.capabilityInvocation = [signatureVerificationMethod.id];
document.capabilityDelegation = [signatureVerificationMethod.id];
/**
* 8. If options.enableEncryptionKeyDerivation is set to true:
* Add the encryptionVerificationMethod value to the verificationMethod
* array. Initialize the keyAgreement property in document to an array
* where the first item is the value of the id property in
* encryptionVerificationMethod.
*/
if (enableEncryptionKeyDerivation === true) {
/**
* Although not covered by the did:key method specification, a sensible
* default will be taken to use the 'X25519KeyAgreementKey2020'
* verification method type if the given publicKeyFormat is
* 'Ed25519VerificationKey2020' and 'JsonWebKey2020' otherwise.
*/
const encryptionPublicKeyFormat =
(publicKeyFormat === 'Ed25519VerificationKey2020')
? 'X25519KeyAgreementKey2020'
: 'JsonWebKey2020';
/**
* 8.1 Initialize the encryptionVerificationMethod to the result of
* passing identifier, multibaseValue, and options to an
* {@link https://w3c-ccg.github.io/did-method-key/#encryption-method-creation-algorithm | Encryption Method Creation Algorithm}.
*/
const encryptionVerificationMethod = await this.createEncryptionMethod({
did,
enableExperimentalPublicKeyTypes,
multibaseValue,
publicKeyFormat: encryptionPublicKeyFormat
});
/**
* 8.2 Add the encryptionVerificationMethod value to the
* verificationMethod array.
*/
document.verificationMethod.push(encryptionVerificationMethod);
/**
* 8.3. Initialize the keyAgreement property in document to an array
* where the first item is the value of the id property in
* encryptionVerificationMethod.
*/
document.keyAgreement = [encryptionVerificationMethod.id];
}
/**
* 9. Initialize the @context property in document to the result of passing
* document and options to the Context Creation algorithm.
*/
// Set contextArray to an array that is initialized to
// options.defaultContext.
const contextArray = [defaultContext];
// For every object in every verification relationship listed in document,
// add a string value to the contextArray based on the object type value,
// if it doesn't already exist, according to the following table:
// {@link https://w3c-ccg.github.io/did-method-key/#context-creation-algorithm | Context Type URL}
const verificationMethodTypes = getVerificationMethodTypes({ didDocument: document });
verificationMethodTypes.forEach((typeName: string) => {
const typeUrl = VERIFICATION_METHOD_TYPES[typeName];
contextArray.push(typeUrl);
});
document['@context'] = contextArray;
/**
* 10. Return document.
*/
return document as DidDocument;
}
/**
* Decoding a multibase-encoded multicodec value into a verification method
* that is suitable for verifying that encrypted information will be
* received by the intended recipient.
*/
public static async createEncryptionMethod(options: {
did: string,
enableExperimentalPublicKeyTypes: boolean,
multibaseValue: string,
publicKeyFormat: DidVerificationMethodType
}): Promise<VerificationMethod> {
const { did, enableExperimentalPublicKeyTypes, multibaseValue, publicKeyFormat } = options;
/**
* 1. Initialize verificationMethod to an empty object.
*/
const verificationMethod: Partial<VerificationMethod> = {};
/**
* 2. Set multicodecValue and rawPublicKeyBytes to the result of passing
* multibaseValue and options to a Derive Encryption Key algorithm.
*/
const {
key: rawPublicKeyBytes,
multicodecCode: multicodecValue,
} = await DidKeyMethod.deriveEncryptionKey({ multibaseValue });
/**
* 3. Ensure the proper key length of rawPublicKeyBytes based on the
* multicodecValue table provided below:
*
* Multicodec hexadecimal value: 0xec
*
* If the byte length of rawPublicKeyBytes
* does not match the expected public key length for the associated
* multicodecValue, an invalidPublicKeyLength error MUST be raised.
*/
const actualLength = rawPublicKeyBytes.byteLength;
const expectedLength = MULTICODEC_PUBLIC_KEY_LENGTH[multicodecValue];
if (actualLength !== expectedLength) {
throw new Error(`invalidPublicKeyLength: Expected ${actualLength} bytes. Actual ${expectedLength} bytes.`);
}
/**
* 4. Create the multibaseValue by concatenating the letter 'z' and the
* base58-btc encoding of the concatenation of the multicodecValue and
* the rawPublicKeyBytes.
*/
const kemMultibaseValue = cryptoUtils.keyToMultibaseId({
key : rawPublicKeyBytes,
multicodecCode : multicodecValue
});
/**
* 5. Set the verificationMethod.id value by concatenating identifier,
* a hash character (#), and the multibaseValue. If verificationMethod.id
* is not a valid DID URL, an invalidDidUrl error MUST be raised.
*/
verificationMethod.id = `${did}#${kemMultibaseValue}`;
try {
new URL(verificationMethod.id);
} catch (error: any) {
throw new Error('invalidDidUrl: Verification Method ID is not a valid DID URL.');
}
/**
* 6. Set the publicKeyFormat value to the options.publicKeyFormat value.
* 7. If publicKeyFormat is not known to the implementation, an
* unsupportedPublicKeyType error MUST be raised.
*/
if (!(SupportedPublicKeyFormats.includes(publicKeyFormat))) {
throw new Error(`unsupportedPublicKeyType: Unsupported format: ${publicKeyFormat}`);
}
/**
* 8. If options.enableExperimentalPublicKeyTypes is set to false and
* publicKeyFormat is not Multikey, JsonWebKey2020, or
* X25519KeyAgreementKey2020, an invalidPublicKeyType error MUST be
* raised.
*/
const StandardPublicKeyTypes = ['Multikey', 'JsonWebKey2020', 'X25519KeyAgreementKey2020'];
if (enableExperimentalPublicKeyTypes === false
&& !(StandardPublicKeyTypes.includes(publicKeyFormat))) {
throw new Error(`invalidPublicKeyType: Specified '${publicKeyFormat}' without setting enableExperimentalPublicKeyTypes to true.`);
}
/**
* 9. Set verificationMethod.type to the publicKeyFormat value.
*/
verificationMethod.type = publicKeyFormat;
/**
* 10. Set verificationMethod.controller to the identifier value.
* If verificationMethod.controller is not a valid DID, an invalidDid
* error MUST be raised.
*/
verificationMethod.controller = did;
if (!DidKeyMethod.validateIdentifier({ did })) {
throw new Error(`invalidDid: Invalid identifier format: ${did}`);
}
/**
* 11. If publicKeyFormat is Multikey or X25519KeyAgreementKey2020,
* set the verificationMethod.publicKeyMultibase value to multibaseValue.
*
* Note: This implementation does not currently support the Multikey
* format.
*/
if (publicKeyFormat === 'X25519KeyAgreementKey2020') {
verificationMethod.publicKeyMultibase = kemMultibaseValue;
}
/**
* 12. If publicKeyFormat is JsonWebKey2020, set the
* verificationMethod.publicKeyJwk value to the result of passing
* multicodecValue and rawPublicKeyBytes to a JWK encoding algorithm.
*/
if (publicKeyFormat === 'JsonWebKey2020') {
const jwkParams = await Jose.multicodecToJose({ code: multicodecValue });
const jsonWebKey = await Jose.keyToJwk({
keyMaterial : rawPublicKeyBytes,
keyType : 'public',
...jwkParams
});
// Ensure that "d" is NOT present.
if ('x' in jsonWebKey && !('d' in jsonWebKey)) {
verificationMethod.publicKeyJwk = jsonWebKey;
}
}
/**
* 13. Return verificationMethod.
*/
return verificationMethod as VerificationMethod;
}
/**
* Transform a multibase-encoded multicodec value to public encryption key
* components that are suitable for encrypting messages to a receiver. A
* mathematical proof elaborating on the safety of performing this operation
* is available in:
* {@link https://eprint.iacr.org/2021/509.pdf | On using the same key pair for Ed25519 and an X25519 based KEM}
*/
public static async deriveEncryptionKey(options: {
multibaseValue: string
}): Promise<DidKeyDeriveEncryptionKeyResult> {
const { multibaseValue } = options;
/**
* 1. Set publicEncryptionKey to an empty object.
*/
let publicEncryptionKey: Partial<DidKeyDeriveEncryptionKeyResult> = {};
/**
* 2. Decode multibaseValue using the base58-btc multibase alphabet and
* set multicodecValue to the multicodec header for the decoded value.
* Implementers are cautioned to ensure that the multicodecValue is set
* to the result after performing varint decoding.
*
* 3. Set the rawPublicKeyBytes to the bytes remaining after the multicodec
* header.
*/
const {
key: rawPublicKeyBytes,
multicodecCode: multicodecValue
} = cryptoUtils.multibaseIdToKey({ multibaseKeyId: multibaseValue });
/**
* 4. If the multicodecValue is 0xed, derive a public X25519 encryption key
* by using the rawPublicKeyBytes and the algorithm defined in
* {@link https://datatracker.ietf.org/doc/html/draft-ietf-core-oscore-groupcomm | Group OSCORE - Secure Group Communication for CoAP}
* for Curve25519 in Section 2.4.2: ECDH with Montgomery Coordinates and
* set generatedPublicEncryptionKeyBytes to the result.
*/
if (multicodecValue === 0xed) {
const generatedPublicEncryptionKeyBytes = await Ed25519.convertPublicKeyToX25519({
publicKey: rawPublicKeyBytes
});
/**
* 5. Set multicodecValue in publicEncryptionKey to 0xec.
*
* 6. Set rawPublicKeyBytes in publicEncryptionKey to
* generatedPublicEncryptionKeyBytes.
*/
publicEncryptionKey = {
key : generatedPublicEncryptionKeyBytes,
multicodecCode : 0xec
};
}
/**
* 7. Return publicEncryptionKey.
*/
return publicEncryptionKey as DidKeyDeriveEncryptionKeyResult;
}
/**
* Decodes a multibase-encoded multicodec value into a verification method
* that is suitable for verifying digital signatures.
* @param options - Signature method creation algorithm inputs.
* @returns - A verification method.
*/
public static async createSignatureMethod(options: {
did: string,
enableExperimentalPublicKeyTypes: boolean,
multibaseValue: string,
publicKeyFormat: DidVerificationMethodType
}): Promise<VerificationMethod> {
const { did, enableExperimentalPublicKeyTypes, multibaseValue, publicKeyFormat } = options;
/**
* 1. Initialize verificationMethod to an empty object.
*/
const verificationMethod: Partial<VerificationMethod> = {};
/**
* 2. Set multicodecValue and rawPublicKeyBytes to the result of passing
* multibaseValue and options to a Decode Public Key algorithm.
*/
const {
key: rawPublicKeyBytes,
multicodecCode: multicodecValue,
multicodecName
} = cryptoUtils.multibaseIdToKey({ multibaseKeyId: multibaseValue });
/**
* 3. Ensure the proper key length of rawPublicKeyBytes based on the
* multicodecValue {@link https://w3c-ccg.github.io/did-method-key/#signature-method-creation-algorithm | table provided}.
* If the byte length of rawPublicKeyBytes does not match the expected
* public key length for the associated multicodecValue, an
* invalidPublicKeyLength error MUST be raised.
*/
const actualLength = rawPublicKeyBytes.byteLength;
const expectedLength = MULTICODEC_PUBLIC_KEY_LENGTH[multicodecValue];
if (actualLength !== expectedLength) {
throw new Error(`invalidPublicKeyLength: Expected ${actualLength} bytes. Actual ${expectedLength} bytes.`);
}
/**
* 4. Ensure the rawPublicKeyBytes are a proper encoding of the public
* key type as specified by the multicodecValue. This validation is often
* done by a cryptographic library when importing the public key by,
* for example, ensuring that an Elliptic Curve public key is a specific
* coordinate that exists on the elliptic curve. If an invalid public key
* value is detected, an invalidPublicKey error MUST be raised.
*/
let isValid = false;
switch (multicodecName) {
case 'secp256k1-pub':
isValid = await Secp256k1.validatePublicKey({ key: rawPublicKeyBytes });
break;
case 'ed25519-pub':
isValid = await Ed25519.validatePublicKey({ key: rawPublicKeyBytes });
break;
case 'x25519-pub':
// TODO: validate key once/if X25519.validatePublicKey() is implemented.
// isValid = X25519.validatePublicKey({ key: rawPublicKeyBytes})
isValid = true;
break;
}
if (!isValid) {
throw new Error('invalidPublicKey: Invalid public key detected.');
}
/**
* 5. Set the verificationMethod.id value by concatenating identifier,
* a hash character (#), and the multibaseValue. If verificationMethod.id
* is not a valid DID URL, an invalidDidUrl error MUST be raised.
*/
verificationMethod.id = `${did}#${multibaseValue}`;
try {
new URL(verificationMethod.id);
} catch (error: any) {
throw new Error('invalidDidUrl: Verification Method ID is not a valid DID URL.');
}
/**
* 6. Set the publicKeyFormat value to the options.publicKeyFormat value.
* 7. If publicKeyFormat is not known to the implementation, an
* unsupportedPublicKeyType error MUST be raised.
*/
if (!(SupportedPublicKeyFormats.includes(publicKeyFormat))) {
throw new Error(`unsupportedPublicKeyType: Unsupported format: ${publicKeyFormat}`);
}
/**
* 8. If options.enableExperimentalPublicKeyTypes is set to false and
* publicKeyFormat is not Multikey, JsonWebKey2020, or
* Ed25519VerificationKey2020, an invalidPublicKeyType error MUST be
* raised.
*/
const StandardPublicKeyTypes = ['Multikey', 'JsonWebKey2020', 'Ed25519VerificationKey2020'];
if (enableExperimentalPublicKeyTypes === false
&& !(StandardPublicKeyTypes.includes(publicKeyFormat))) {
throw new Error(`invalidPublicKeyType: Specified '${publicKeyFormat}' without setting enableExperimentalPublicKeyTypes to true.`);
}
/**
* 9. Set verificationMethod.type to the publicKeyFormat value.
*/
verificationMethod.type = publicKeyFormat;
/**
* 10. Set verificationMethod.controller to the identifier value.
* If verificationMethod.controller is not a valid DID, an invalidDid
* error MUST be raised.
*/
verificationMethod.controller = did;
if (!DidKeyMethod.validateIdentifier({ did })) {
throw new Error(`invalidDid: Invalid identifier format: ${did}`);
}
/**
* 11. If publicKeyFormat is Multikey or Ed25519VerificationKey2020,
* set the verificationMethod.publicKeyMultibase value to multibaseValue.
*
* Note: This implementation does not currently support the Multikey
* format.
*/
if (publicKeyFormat === 'Ed25519VerificationKey2020') {
verificationMethod.publicKeyMultibase = multibaseValue;
}
/**
* 12. If publicKeyFormat is JsonWebKey2020, set the
* verificationMethod.publicKeyJwk value to the result of passing
* multicodecValue and rawPublicKeyBytes to a JWK encoding algorithm.
*/
if (publicKeyFormat === 'JsonWebKey2020') {
const jwkParams = await Jose.multicodecToJose({ code: multicodecValue });
const jsonWebKey = await Jose.keyToJwk({
keyMaterial : rawPublicKeyBytes,
keyType : 'public',
...jwkParams
});
// Ensure that "d" is NOT present.
if ('x' in jsonWebKey && !('d' in jsonWebKey)) {
verificationMethod.publicKeyJwk = jsonWebKey;
}
}
/**
* 13. Return verificationMethod.
*/
return verificationMethod as VerificationMethod;
}
public static async generateKeySet(options?: {
keyAlgorithm?: typeof SupportedCryptoAlgorithms[number]
}): Promise<DidKeyKeySet> {
// Generate Ed25519 keys, by default.
const { keyAlgorithm = 'Ed25519' } = options ?? {};
let keyPair: IDCrypto.CryptoKeyPair;
switch (keyAlgorithm) {
case 'Ed25519': {
keyPair = await new EdDsaAlgorithm().generateKey({
algorithm : { name: 'EdDSA', namedCurve: 'Ed25519' },
extractable : true,
keyUsages : ['sign', 'verify']
});
break;
}
case 'secp256k1': {
keyPair = await new EcdsaAlgorithm().generateKey({
algorithm : { name: 'ECDSA', namedCurve: 'secp256k1' },
extractable : true,
keyUsages : ['sign', 'verify']
});
break;
}
default: {
throw new Error(`Unsupported crypto algorithm: '${keyAlgorithm}'`);
}
}
const publicKeyJwk = await Jose.cryptoKeyToJwk({ key: keyPair.publicKey }) as PublicKeyJwk;
const privateKeyJwk = await Jose.cryptoKeyToJwk({ key: keyPair.privateKey }) as PrivateKeyJwk;
const keySet: DidKeyKeySet = {
verificationMethodKeys: [{
publicKeyJwk,
privateKeyJwk,
relationships: ['authentication']
}]
};
return keySet;
}
/**
* Given the W3C DID Document of a `did:key` DID, return the identifier of
* the verification method key that will be used for signing messages and
* credentials, by default.
*
* @param document = DID Document to get the default signing key from.
* @returns Verification method identifier for the default signing key.
*/
public static async getDefaultSigningKey(options: {
didDocument: DidDocument
}): Promise<string | undefined> {
const { didDocument } = options;
if (didDocument.authentication
&& Array.isArray(didDocument.authentication)
&& didDocument.authentication.length > 0
&& typeof didDocument.authentication[0] === 'string') {
const [verificationMethodId] = didDocument.authentication;
const signingKeyId = verificationMethodId;
return signingKeyId;
}
}
public static async resolve(options: {
didUrl: string,
resolutionOptions?: DidResolutionOptions
}): Promise<DidResolutionResult> {
const { didUrl, resolutionOptions: _ } = options;
// TODO: add resolutionOptions as defined in https://www.w3.org/TR/did-core/#did-resolution
const parsedDid = parseDid({ didUrl });
if (!parsedDid) {
return {
'@context' : 'https://w3id.org/did-resolution/v1',
didDocument : undefined,
didDocumentMetadata : {},
didResolutionMetadata : {
contentType : 'application/did+json',
error : 'invalidDid',
errorMessage : `Cannot parse DID: ${didUrl}`
}
};
}
if (parsedDid.method !== 'key') {
return {
'@context' : 'https://w3id.org/did-resolution/v1',
didDocument : undefined,
didDocumentMetadata : {},
didResolutionMetadata : {
contentType : 'application/did+json',
error : 'methodNotSupported',
errorMessage : `Method not supported: ${parsedDid.method}`
}
};
}
const didDocument = await DidKeyMethod.createDocument({ did: parsedDid.did });
return {
'@context' : 'https://w3id.org/did-resolution/v1',
didDocument,
didDocumentMetadata : {},
didResolutionMetadata : {
contentType : 'application/did+json',
did : {
didString : parsedDid.did,
methodSpecificId : parsedDid.id,
method : parsedDid.method
}
}
};
}
public static validateIdentifier(options: {
did: string
}): boolean {
const { did } = options;
const { method, id: multibaseValue } = parseDid({ didUrl: did });
const [scheme] = did.split(':', 1);
/**
* Note: The W3C DID specification makes no mention of a version value
* being part of the DID syntax. Additionally, there does not
* appear to be any real-world usage of the version number.
* Consequently, this implementation will ignore the version
* related guidance in the did:key specification.
*/
const version = '1';
return (
scheme !== 'did' ||
method !== 'key' ||
parseInt(version) > 0 ||
universalTypeOf(multibaseValue) !== 'String' ||
!multibaseValue.startsWith('z')
);
}
}