From 99400689dec9ea00131cf914d1999357b716612c Mon Sep 17 00:00:00 2001 From: Andraz <69682837+andyv09@users.noreply.github.com> Date: Mon, 3 Oct 2022 16:39:19 +0200 Subject: [PATCH] fix(credential-eip712): add support for all did methods that use secp256k (#1011) fixes #991 --- packages/core/plugin.schema.json | 6 +-- packages/credential-eip712/package.json | 4 +- .../src/agent/CredentialEIP712.ts | 9 ++-- packages/did-comm/plugin.schema.json | 2 +- packages/utils/package.json | 4 +- packages/utils/src/did-utils.ts | 53 ++++++++++++++++--- packages/utils/src/encodings.ts | 13 +++++ yarn.lock | 14 +++++ 8 files changed, 88 insertions(+), 17 deletions(-) diff --git a/packages/core/plugin.schema.json b/packages/core/plugin.schema.json index fba54a99e..3dc54373c 100644 --- a/packages/core/plugin.schema.json +++ b/packages/core/plugin.schema.json @@ -3224,7 +3224,7 @@ "save": { "type": "boolean", "description": "Optional. If set to `true`, the message will be saved using\n {@link @veramo/core#IDataStore.dataStoreSaveMessage | dataStoreSaveMessage } \n

", - "deprecated": "Please call {@link @veramo/core#IDataStore.dataStoreSaveMessage | dataStoreSaveMessage()} after\nhandling the message and determining that it must be saved." + "deprecated": "Please call {@link @veramo/core#IDataStore.dataStoreSaveMessage | dataStoreSaveMessage()} after\r\nhandling the message and determining that it must be saved." } }, "required": [ @@ -3560,7 +3560,7 @@ "save": { "type": "boolean", "description": "If this parameter is true, the resulting VerifiablePresentation is sent to the\n {@link @veramo/core#IDataStore | storage plugin } to be saved.", - "deprecated": "Please call\n{@link @veramo/core#IDataStore.dataStoreSaveVerifiableCredential | dataStoreSaveVerifiableCredential()} to save\nthe credential after creating it." + "deprecated": "Please call\r\n{@link @veramo/core#IDataStore.dataStoreSaveVerifiableCredential | dataStoreSaveVerifiableCredential()} to save\r\nthe credential after creating it." }, "proofFormat": { "$ref": "#/components/schemas/ProofFormat", @@ -3763,7 +3763,7 @@ "save": { "type": "boolean", "description": "If this parameter is true, the resulting VerifiablePresentation is sent to the\n {@link @veramo/core#IDataStore | storage plugin } to be saved.

", - "deprecated": "Please call\n{@link @veramo/core#IDataStore.dataStoreSaveVerifiablePresentation | dataStoreSaveVerifiablePresentation()} to\nsave the credential after creating it." + "deprecated": "Please call\r\n{@link @veramo/core#IDataStore.dataStoreSaveVerifiablePresentation | dataStoreSaveVerifiablePresentation()} to\r\nsave the credential after creating it." }, "challenge": { "type": "string", diff --git a/packages/credential-eip712/package.json b/packages/credential-eip712/package.json index c6d23efcd..69b93c49c 100644 --- a/packages/credential-eip712/package.json +++ b/packages/credential-eip712/package.json @@ -16,9 +16,9 @@ "dependencies": { "@metamask/eth-sig-util": "^5.0.0", "@veramo/core": "^4.0.0", - "@veramo/utils": "^4.0.0", "debug": "^4.3.3", - "eip-712-types-generation": "^0.1.6" + "eip-712-types-generation": "^0.1.6", + "@veramo/utils": "^4.0.0" }, "devDependencies": { "@types/debug": "4.1.7", diff --git a/packages/credential-eip712/src/agent/CredentialEIP712.ts b/packages/credential-eip712/src/agent/CredentialEIP712.ts index fdfa50ba0..3533a3caa 100644 --- a/packages/credential-eip712/src/agent/CredentialEIP712.ts +++ b/packages/credential-eip712/src/agent/CredentialEIP712.ts @@ -85,7 +85,9 @@ export class CredentialIssuerEIP712 implements IAgentPlugin { if (!extendedKey) throw Error('key_not_found: The signing key is not available in the issuer DID document') - const chainId = getChainIdForDidEthr(extendedKey.meta.verificationMethod) + let chainId = 1 + if (identifier.did.split(':')[1] === 'ethr') + chainId = getChainIdForDidEthr(extendedKey.meta.verificationMethod) const credential: CredentialPayload = { ...args?.credential, @@ -235,8 +237,9 @@ export class CredentialIssuerEIP712 implements IAgentPlugin { const extendedKey = extendedKeys.find((key) => key.kid === keyRef) if (!extendedKey) throw Error('key_not_found: The signing key is not available in the issuer DID document') - - const chainId = getChainIdForDidEthr(extendedKey.meta.verificationMethod) + let chainId = 1 + if (identifier.did.split(':')[1] === 'ethr') + chainId = getChainIdForDidEthr(extendedKey.meta.verificationMethod) presentation['proof'] = { verificationMethod: extendedKey.meta.verificationMethod.id, created: issuanceDate, diff --git a/packages/did-comm/plugin.schema.json b/packages/did-comm/plugin.schema.json index a75f239db..4c9214835 100644 --- a/packages/did-comm/plugin.schema.json +++ b/packages/did-comm/plugin.schema.json @@ -188,7 +188,7 @@ "required": [ "data" ], - "deprecated": "Please use {@link IDIDComm.sendDIDCommMessage } instead. This will be removed in Veramo 4.0.\nInput arguments for {@link IDIDComm.sendMessageDIDCommAlpha1 }" + "deprecated": "Please use {@link IDIDComm.sendDIDCommMessage } instead. This will be removed in Veramo 4.0.\r\nInput arguments for {@link IDIDComm.sendMessageDIDCommAlpha1 }" }, "IMessage": { "type": "object", diff --git a/packages/utils/package.json b/packages/utils/package.json index a838c4a00..5a2ce7710 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -19,12 +19,12 @@ "did-jwt-vc": "^3.1.0", "did-resolver": "^4.0.0", "uint8arrays": "^3.0.0", - "uuid": "^9.0.0" + "elliptic": "^6.5.4" }, "devDependencies": { "@types/debug": "4.1.7", "@types/uuid": "8.3.4", - "typescript": "4.7.3" + "@types/elliptic": "6.4.14" }, "files": [ "build/**/*", diff --git a/packages/utils/src/did-utils.ts b/packages/utils/src/did-utils.ts index 68b160cb0..cd2691a38 100644 --- a/packages/utils/src/did-utils.ts +++ b/packages/utils/src/did-utils.ts @@ -10,7 +10,9 @@ import { } from './types/utility-types' import { isDefined } from './type-utils' import * as u8a from 'uint8arrays' +import elliptic from 'elliptic' import Debug from 'debug' +import { hexToBytes, bytesToHex, base64ToBytes, base58ToBytes } from './encodings' const debug = Debug('veramo:utils') @@ -80,11 +82,12 @@ export function compressIdentifierSecp256k1Keys(identifier: IIdentifier): IKey[] * * @beta This API may change without a BREAKING CHANGE notice. */ -function compareBlockchainAccountId( - localKey: IKey, - verificationMethod: _NormalizedVerificationMethod, -): boolean { - if (verificationMethod.type !== 'EcdsaSecp256k1RecoveryMethod2020' || localKey.type !== 'Secp256k1') { +function compareBlockchainAccountId(localKey: IKey, verificationMethod: VerificationMethod): boolean { + if ( + (verificationMethod.type !== 'EcdsaSecp256k1RecoveryMethod2020' && + verificationMethod.type !== 'EcdsaSecp256k1RecoveryMethod2019') || + localKey.type !== 'Secp256k1' + ) { return false } let vmEthAddr = getEthereumAddress(verificationMethod) @@ -105,17 +108,55 @@ function compareBlockchainAccountId( * * @beta This API may change without a BREAKING CHANGE notice. */ -export function getEthereumAddress(verificationMethod: _NormalizedVerificationMethod): string | undefined { +export function getEthereumAddress(verificationMethod: VerificationMethod): string | undefined { let vmEthAddr = verificationMethod.ethereumAddress?.toLowerCase() if (!vmEthAddr) { if (verificationMethod.blockchainAccountId?.includes('@eip155')) { vmEthAddr = verificationMethod.blockchainAccountId?.split('@eip155')[0].toLowerCase() } else if (verificationMethod.blockchainAccountId?.startsWith('eip155')) { vmEthAddr = verificationMethod.blockchainAccountId.split(':')[2]?.toLowerCase() + } else if ( + verificationMethod.publicKeyHex || + verificationMethod.publicKeyBase58 || + verificationMethod.publicKeyBase64 + ) { + const pbBytes = extractPublicKeyBytes(verificationMethod) + const pbHex = computePublicKey(pbBytes, false) + + vmEthAddr = computeAddress(pbHex).toLowerCase() } } return vmEthAddr } +interface LegacyVerificationMethod extends VerificationMethod { + publicKeyBase64: string +} + +function extractPublicKeyBytes(pk: VerificationMethod): Uint8Array { + if (pk.publicKeyBase58) { + return base58ToBytes(pk.publicKeyBase58) + } else if ((pk).publicKeyBase64) { + return base64ToBytes((pk).publicKeyBase64) + } else if (pk.publicKeyHex) { + return hexToBytes(pk.publicKeyHex) + } else if ( + pk.publicKeyJwk && + pk.publicKeyJwk.crv === 'secp256k1' && + pk.publicKeyJwk.x && + pk.publicKeyJwk.y + ) { + const secp256k1 = new elliptic.ec('secp256k1') + return hexToBytes( + secp256k1 + .keyFromPublic({ + x: bytesToHex(base64ToBytes(pk.publicKeyJwk.x)), + y: bytesToHex(base64ToBytes(pk.publicKeyJwk.y)), + }) + .getPublic('hex'), + ) + } + return new Uint8Array() +} /** * Extracts the chain ID from a {@link did-resolver#VerificationMethod | verification method} supporting legacy diff --git a/packages/utils/src/encodings.ts b/packages/utils/src/encodings.ts index dd3241f70..97c47c8a2 100644 --- a/packages/utils/src/encodings.ts +++ b/packages/utils/src/encodings.ts @@ -117,3 +117,16 @@ export function bytesToHex(byteArray: Uint8Array, prefix: boolean = false): stri const result = u8a.toString(byteArray, 'base16') return prefix ? `0x${result}` : result } + +/** + * Converts a base58 string to the Uint8Array it represents. + * + * @param s - the string to be converted + * + * @throws if the string is not formatted correctly. + * + * @public + */ +export function base58ToBytes(s: string): Uint8Array { + return u8a.fromString(s, 'base58btc') +} diff --git a/yarn.lock b/yarn.lock index a760efcb2..0c313918c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4645,6 +4645,13 @@ dependencies: "@types/node" "*" +"@types/bn.js@*": + version "5.1.1" + resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.1.1.tgz#b51e1b55920a4ca26e9285ff79936bbdec910682" + integrity sha512-qNrYbZqMx0uJAfKnKclPh+dTwK33KfLHYqtyODwd5HnXOjnkhc4qgn3BrK6RWyGZm5+sIFE7Q7Vz6QQtJB7w7g== + dependencies: + "@types/node" "*" + "@types/bn.js@^5.1.0": version "5.1.0" resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.1.0.tgz#32c5d271503a12653c62cf4d2b45e6eab8cebc68" @@ -4704,6 +4711,13 @@ dependencies: "@types/ms" "*" +"@types/elliptic@6.4.14": + version "6.4.14" + resolved "https://registry.yarnpkg.com/@types/elliptic/-/elliptic-6.4.14.tgz#7bbaad60567a588c1f08b10893453e6b9b4de48e" + integrity sha512-z4OBcDAU0GVwDTuwJzQCiL6188QvZMkvoERgcVjq0/mPM8jCfdwZ3x5zQEVoL9WCAru3aG5wl3Z5Ww5wBWn7ZQ== + dependencies: + "@types/bn.js" "*" + "@types/eslint-scope@^3.7.3": version "3.7.3" resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.3.tgz#125b88504b61e3c8bc6f870882003253005c3224"