diff --git a/packages/dids/src/methods/did-dht.ts b/packages/dids/src/methods/did-dht.ts index 8add749c0..0534323e9 100644 --- a/packages/dids/src/methods/did-dht.ts +++ b/packages/dids/src/methods/did-dht.ts @@ -32,6 +32,7 @@ import { extractDidFragment } from '../utils.js'; import { DidError, DidErrorCode } from '../did-error.js'; import { DidVerificationRelationship } from '../types/did-core.js'; import { EMPTY_DID_RESOLUTION_RESULT } from '../types/did-resolution.js'; +import { getJoseSignatureAlgorithmFromPublicKey } from '@web5/crypto/utils'; /** * Represents a BEP44 message, which is used for storing and retrieving data in the Mainline DHT @@ -347,6 +348,15 @@ export enum DidDhtRegisteredKeyType { secp256r1 = 2 } +/** + * Private helper that maps did dht registered key types to their corresponding default algorithm identifiers. + */ +const KeyTypeToDefaultAlgorithmMap = { + [DidDhtRegisteredKeyType.Ed25519] : 'Ed25519', + [DidDhtRegisteredKeyType.secp256k1] : 'ES256K', + [DidDhtRegisteredKeyType.secp256r1] : 'ES256', +}; + /** * Maps {@link https://www.w3.org/TR/did-core/#verification-relationships | DID Core Verification Relationship} * values to the corresponding record name in the DNS packet representation of a DHT DID document. @@ -1014,8 +1024,8 @@ export class DidDhtDocument { // Process verification methods. case dnsRecordId.startsWith('k'): { // Get the method ID fragment (id), key type (t), Base64URL-encoded public key (k), and - // optionally, controller (c) from the decoded TXT record data. - const { id, t, k, c } = DidDhtUtils.parseTxtDataToObject(answer.data); + // optionally, controller (c) and alg (a) from the decoded TXT record data. + const { t, k, c, a: parsedAlg } = DidDhtUtils.parseTxtDataToObject(answer.data); // Convert the public key from Base64URL format to a byte array. const publicKeyBytes = Convert.base64Url(k).toUint8Array(); @@ -1026,11 +1036,19 @@ export class DidDhtDocument { // Convert the public key from a byte array to JWK format. let publicKey = await DidDhtUtils.keyConverter(namedCurve).bytesToPublicKey({ publicKeyBytes }); + // DID DHT spec requires `alg` in keys in the DID document + publicKey.alg = parsedAlg || getJoseSignatureAlgorithmFromPublicKey(publicKey); + + // Determine the Key ID (kid): '0' for the identity key or JWK thumbprint for others. + publicKey.kid = dnsRecordId.endsWith('0') ? '0' : await computeJwkThumbprint({ jwk: publicKey }); + // Initialize the `verificationMethod` array if it does not already exist. didDocument.verificationMethod ??= []; // Prepend the DID URI to the ID fragment to form the full verification method ID. - const methodId = `${didUri}#${id}`; + // const methodId = `${didUri}#${id}`; + const methodIdSuffix = dnsRecordId.substring(1); // Strip the leading 'k' + const methodId = `${didUri}#key${methodIdSuffix}`; // Add the verification method to the DID document. didDocument.verificationMethod.push({ @@ -1181,6 +1199,12 @@ export class DidDhtDocument { // Define the data for the DNS TXT record. const txtData = [`t=${keyType}`, `k=${publicKeyBase64Url}`]; + // Only set the algorithm property (`a`) if it differs from the default algorithm for the key type. + const algorithmUsedByKey = getJoseSignatureAlgorithmFromPublicKey(publicKey); + if(algorithmUsedByKey !== KeyTypeToDefaultAlgorithmMap[keyType]) { + txtData.push(`a=${algorithmUsedByKey}`); + } + // Add the controller property, if set to a value other than the Identity Key (DID Subject). if (verificationMethod.controller !== didDocument.id) txtData.push(`c=${verificationMethod.controller}`);