Skip to content

Commit

Permalink
feat: Add suite lookup based on verification method type next to vera…
Browse files Browse the repository at this point in the history
…mo key type
  • Loading branch information
nklomp committed Dec 10, 2021
1 parent ffbe876 commit 5c18dc2
Show file tree
Hide file tree
Showing 3 changed files with 188 additions and 8 deletions.
19 changes: 11 additions & 8 deletions packages/vc-handler-ld-local/src/ld-suite-loader.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,28 @@
import { VeramoLdSignature } from '@veramo/credential-ld'
import { TKeyType } from '@veramo/core'
import { SphereonLdSignature } from './ld-suites'

/**
* Initializes a list of Veramo-wrapped LD Signature suites and exposes those to the Agent Module
*/
export class LdSuiteLoader {
constructor(options: { veramoLdSignatures: VeramoLdSignature[] }) {
options.veramoLdSignatures.forEach((obj) => {
constructor(options: { ldSignatureSuites: SphereonLdSignature[] }) {
options.ldSignatureSuites.forEach((obj) => {
this.signatureMap[obj.getSupportedVeramoKeyType()] = obj
this.signatureMap[obj.getSupportedVerificationType()] = obj
})
}
private signatureMap: Record<string, VeramoLdSignature> = {}
private signatureMap: Record<string, SphereonLdSignature> = {}

getSignatureSuiteForKeyType(type: TKeyType): VeramoLdSignature {
const suite = this.signatureMap[type]
getSignatureSuiteForKeyType(type: TKeyType, verificationType?: string): SphereonLdSignature {
// Always use verification type if supplied. This is the type denoted by the DID verification method type

const suite = verificationType && this.signatureMap[verificationType] ? this.signatureMap[verificationType] : this.signatureMap[type]
if (suite) return suite

throw new Error('No Veramo LD Signature Suite for ' + type)
throw new Error('No Sphereon or Veramo LD Signature Suite for ' + type)
}

getAllSignatureSuites(): VeramoLdSignature[] {
getAllSignatureSuites(): SphereonLdSignature[] {
return Object.values(this.signatureMap)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { RequiredAgentMethods, SphereonLdSignature } from '../ld-suites'
import { CredentialPayload, DIDDocument, IAgentContext, IKey, TKeyType, VerifiableCredential } from '@veramo/core'
import { EcdsaSecp256k1RecoveryMethod2020, EcdsaSecp256k1RecoverySignature2020 } from '@transmute/lds-ecdsa-secp256k1-recovery2020'

import * as u8a from 'uint8arrays'
import { asArray, encodeJoseBlob } from '@veramo/utils'

export class SphereonEcdsaSecp256k1RecoverySignature2020 extends SphereonLdSignature {
getSupportedVerificationType(): string {
return 'EcdsaSecp256k1RecoveryMethod2020'
}

getSupportedVeramoKeyType(): TKeyType {
return 'Secp256k1'
}

getSuiteForSigning(key: IKey, did: string, verifiableMethodId: string, context: IAgentContext<RequiredAgentMethods>): any {
const controller = did
const signer = {
//returns a JWS detached
sign: async (args: { data: Uint8Array }): Promise<string> => {
const header = {
alg: 'ES256K-R',
b64: false,
crit: ['b64'],
}
const headerString = encodeJoseBlob(header)
const messageBuffer = u8a.concat([u8a.fromString(`${headerString}.`, 'utf-8'), args.data])
const messageString = u8a.toString(messageBuffer, 'base64')
const signature = await context.agent.keyManagerSign({
keyRef: key.kid,
algorithm: 'ES256K-R',
data: messageString,
encoding: 'base64',
})
return `${headerString}..${signature}`
},
}

return new EcdsaSecp256k1RecoverySignature2020({
// signer,
key: new EcdsaSecp256k1RecoveryMethod2020({
publicKeyHex: key.publicKeyHex,
signer: () => signer,
type: this.getSupportedVerificationType(),
controller,
id: verifiableMethodId,
}),
})
}

getSuiteForVerification(): any {
return new EcdsaSecp256k1RecoverySignature2020()
}

preVerificationCredModification(credential: VerifiableCredential): void {}

preSigningCredModification(credential: CredentialPayload): void {
credential['@context'] = [
...asArray(credential['@context'] || []),
'https://identity.foundation/EcdsaSecp256k1RecoverySignature2020/lds-ecdsa-secp256k1-recovery2020-0.0.jsonld',
]
}

preDidResolutionModification(didUrl: string, didDoc: DIDDocument): void {
// did:ethr
if (didUrl.toLowerCase().startsWith('did:ethr')) {
// TODO: EcdsaSecp256k1RecoveryMethod2020 does not support blockchainAccountId
// blockchainAccountId to ethereumAddress
didDoc.verificationMethod?.forEach((x) => {
if (x.blockchainAccountId) {
x.ethereumAddress = x.blockchainAccountId.substring(0, x.blockchainAccountId.lastIndexOf('@'))
}
})
}
}

getContext(): string {
return 'https://identity.foundation/EcdsaSecp256k1RecoverySignature2020/lds-ecdsa-secp256k1-recovery2020-0.0.jsonld'
}
}
96 changes: 96 additions & 0 deletions packages/vc-handler-ld-local/src/suites/Ed25519Signature2020.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { asArray, encodeJoseBlob } from '@veramo/utils'
import { CredentialPayload, DIDDocument, IAgentContext, IKey, TKeyType, VerifiableCredential } from '@veramo/core'
import suiteContext2018 from 'ed25519-signature-2018-context'
import suiteContext2020 from 'ed25519-signature-2020-context'
import { Ed25519Signature2020 } from '@digitalcredentials/ed25519-signature-2020'
import { Ed25519VerificationKey2020 } from '@digitalcredentials/ed25519-verification-key-2020'
import * as u8a from 'uint8arrays'
import { RequiredAgentMethods, SphereonLdSignature } from '../ld-suites'
import { hexToMultibase } from '../../../ssi-sdk-core/src'
import { MultibaseFormat } from '@sphereon/ssi-sdk-core/dist/utils/encoding'

export class SphereonEd25519Signature2020 extends SphereonLdSignature {

constructor() {
super()
// Ensure it is loaded
suiteContext2020?.constants
}

getSupportedVerificationType(): string {
return 'Ed25519VerificationKey2020'
}

getSupportedVeramoKeyType(): TKeyType {
return 'Ed25519'
}

getContext(): string {
return 'https://w3id.org/security/suites/ed25519-2020/v1'
}

getSuiteForSigning(key: IKey, issuerDid: string, verificationMethodId: string, context: IAgentContext<RequiredAgentMethods>): any {
const controller = issuerDid

// DID Key ID
let id = verificationMethodId

const signer = {
// returns a JWS detached
sign: async (args: { data: Uint8Array }): Promise<Uint8Array> => {
const header = {
alg: 'EdDSA',
b64: false,
crit: ['b64'],
}
const headerString = encodeJoseBlob(header)
const messageBuffer = u8a.concat([u8a.fromString(`${headerString}.`, 'utf-8'), args.data])
const messageString = u8a.toString(messageBuffer, 'base64')
const signature = await context.agent.keyManagerSign({
keyRef: key.kid,
algorithm: 'EdDSA',
data: messageString,
encoding: 'base64',
})
return u8a.fromString(`${headerString}..${signature}`)
},
}

const options = {
id: id,
controller: controller,
publicKeyMultibase: hexToMultibase(key.publicKeyHex, MultibaseFormat.BASE58).value,
signer: () => signer,
type: this.getSupportedVerificationType(),
}

// For now we always go through this route given the multibase key has an invalid header
const verificationKey = new Ed25519VerificationKey2020(options)
// overwrite the signer since we're not passing the private key and transmute doesn't support that behavior
verificationKey.signer = () => signer as any
// verificationKey.type = this.getSupportedVerificationType()

return new Ed25519Signature2020({
key: verificationKey,
signer: signer,
})
}
preVerificationCredModification(credential: VerifiableCredential): void {
credential['@context'] = [
...asArray(credential['@context'] || []),
this.getContext()
]
}

getSuiteForVerification(): any {
return new Ed25519Signature2020()
}

preSigningCredModification(credential: CredentialPayload): void {

}

preDidResolutionModification(didUrl: string, didDoc: DIDDocument): void {
// nothing to do here
}
}

0 comments on commit 5c18dc2

Please sign in to comment.