Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(credential-ld): Added Ed25519Signature2020 & JsonWebSignature2020 experimental support #1030

Merged
merged 13 commits into from
Nov 18, 2022
Merged
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@
]
},
"resolutions": {
"@types/react": "^18.0.12",
"@types/eslint": "^8.4.3"
"@types/react": "^18.0.21",
"@types/eslint": "^8.4.6"
},
"engines": {
"node": ">= 14.0.0"
Expand Down
5 changes: 5 additions & 0 deletions packages/credential-ld/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,16 @@
}
},
"dependencies": {
"@digitalcredentials/ed25519-signature-2020": "3.0.2",
"@digitalcredentials/jsonld": "^5.2.1",
"@digitalcredentials/jsonld-signatures": "^9.3.1",
"@digitalcredentials/vc": "^4.0.0",
"@transmute/credentials-context": "^0.7.0-unstable.60",
"@transmute/ed25519-signature-2018": "^0.7.0-unstable.60",
"@digitalcredentials/vc": "^5.0.0",
"@transmute/credentials-context": "^0.7.0-unstable.67",
"@transmute/ed25519-signature-2018": "^0.7.0-unstable.67",
"@transmute/json-web-signature": "^0.7.0-unstable.67",
"@veramo-community/lds-ecdsa-secp256k1-recovery2020": "uport-project/EcdsaSecp256k1RecoverySignature2020",
"@veramo/core": "^4.1.1",
"@veramo/did-resolver": "^4.1.1",
Expand Down
6 changes: 6 additions & 0 deletions packages/credential-ld/src/contexts/did_v0.11.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
"EcdsaSecp256k1VerificationKey2019": "sec:EcdsaSecp256k1VerificationKey2019",
"Ed25519Signature2018": "sec:Ed25519Signature2018",
"Ed25519VerificationKey2018": "sec:Ed25519VerificationKey2018",
"Ed25519Signature2020": "sec:Ed25519Signature2020",
"Ed25519VerificationKey2020": "sec:Ed25519VerificationKey2020",
"JsonWebSignature2020": "sec:JsonWebSignature2020",
"JsonWebKey2020": "sec:JsonWebKey2020",
"RsaSignature2018": "sec:RsaSignature2018",
"RsaVerificationKey2018": "sec:RsaVerificationKey2018",
"SchnorrSecp256k1Signature2019": "sec:SchnorrSecp256k1Signature2019",
Expand Down Expand Up @@ -49,6 +53,8 @@
"proofValue": "sec:proofValue",
"publicKey": {"@id": "sec:publicKey", "@type": "@id", "@container": "@set"},
"publicKeyBase58": "sec:publicKeyBase58",
"publicKeyMultibase": "sec:publicKeyMultibase",
"publicKeyJwk": "sec:publicKeyJwk",
"publicKeyPem": "sec:publicKeyPem",
"revoked": {"@id": "sec:revoked", "@type": "xsd:dateTime"},
"service": {"@id": "didv:service", "@type": "@id", "@container": "@set"},
Expand Down
77 changes: 77 additions & 0 deletions packages/credential-ld/src/contexts/ed25519-signature-2020-v1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
{
"@context": {
"id": "@id",
"type": "@type",
"@protected": true,
"proof": {
"@id": "https://w3id.org/security#proof",
"@type": "@id",
"@container": "@graph"
},
"Ed25519VerificationKey2020": {
"@id": "https://w3id.org/security#Ed25519VerificationKey2020"
},
"Ed25519Signature2020": {
"@id": "https://w3id.org/security#Ed25519Signature2020",
"@context": {
"@protected": true,
"id": "@id",
"type": "@type",
"challenge": "https://w3id.org/security#challenge",
"created": {
"@id": "http://purl.org/dc/terms/created",
"@type": "http://www.w3.org/2001/XMLSchema#dateTime"
},
"domain": "https://w3id.org/security#domain",
"expires": {
"@id": "https://w3id.org/security#expiration",
"@type": "http://www.w3.org/2001/XMLSchema#dateTime"
},
"nonce": "https://w3id.org/security#nonce",
"proofPurpose": {
"@id": "https://w3id.org/security#proofPurpose",
"@type": "@vocab",
"@context": {
"@version": 1.1,
"@protected": true,
"id": "@id",
"type": "@type",
"assertionMethod": {
"@id": "https://w3id.org/security#assertionMethod",
"@type": "@id",
"@container": "@set"
},
"authentication": {
"@id": "https://w3id.org/security#authenticationMethod",
"@type": "@id",
"@container": "@set"
},
"capabilityInvocation": {
"@id": "https://w3id.org/security#capabilityInvocationMethod",
"@type": "@id",
"@container": "@set"
},
"capabilityDelegation": {
"@id": "https://w3id.org/security#capabilityDelegationMethod",
"@type": "@id",
"@container": "@set"
},
"keyAgreement": {
"@id": "https://w3id.org/security#keyAgreementMethod",
"@type": "@id",
"@container": "@set"
}
}
},
"proofValue": {
"@id": "https://w3id.org/security#proofValue",
"@type": "https://w3id.org/security#multibase"
},
"verificationMethod": {
"@id": "https://w3id.org/security#verificationMethod",
"@type": "@id"
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
{
"@context": {
"@version": 1.1,
"id": "@id",
"type": "@type",
"@protected": true,
"JsonWebKey2020": {
"@id": "https://w3id.org/security#JsonWebKey2020"
},
"JsonWebSignature2020": {
"@id": "https://w3id.org/security#JsonWebSignature2020",
"@context": {
"@version": 1.1,
"id": "@id",
"type": "@type",
"@protected": true,
"challenge": "https://w3id.org/security#challenge",
"created": {
"@id": "http://purl.org/dc/terms/created",
"@type": "http://www.w3.org/2001/XMLSchema#dateTime"
},
"domain": "https://w3id.org/security#domain",
"expires": {
"@id": "https://w3id.org/security#expiration",
"@type": "http://www.w3.org/2001/XMLSchema#dateTime"
},
"jws": "https://w3id.org/security#jws",
"nonce": "https://w3id.org/security#nonce",
"proofPurpose": {
"@id": "https://w3id.org/security#proofPurpose",
"@type": "@vocab",
"@context": {
"@version": 1.1,
"@protected": true,
"id": "@id",
"type": "@type",
"assertionMethod": {
"@id": "https://w3id.org/security#assertionMethod",
"@type": "@id",
"@container": "@set"
},
"authentication": {
"@id": "https://w3id.org/security#authenticationMethod",
"@type": "@id",
"@container": "@set"
},
"capabilityInvocation": {
"@id": "https://w3id.org/security#capabilityInvocationMethod",
"@type": "@id",
"@container": "@set"
},
"capabilityDelegation": {
"@id": "https://w3id.org/security#capabilityDelegationMethod",
"@type": "@id",
"@container": "@set"
},
"keyAgreement": {
"@id": "https://w3id.org/security#keyAgreementMethod",
"@type": "@id",
"@container": "@set"
}
}
},
"verificationMethod": {
"@id": "https://w3id.org/security#verificationMethod",
"@type": "@id"
}
}
}
}
}
2 changes: 2 additions & 0 deletions packages/credential-ld/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ export { LdDefaultContexts } from './ld-default-contexts'
export { VeramoLdSignature } from './ld-suites'
export * from './suites/EcdsaSecp256k1RecoverySignature2020'
export * from './suites/Ed25519Signature2018'
export * from './suites/Ed25519Signature2020'
export * from './suites/JsonWebSignature2020'

/**
* The parameter and return types schemas for the {@link @veramo/credential-ld#CredentialIssuerLD | CredentialIssuerLD}
Expand Down
8 changes: 4 additions & 4 deletions packages/credential-ld/src/ld-credential-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ export class LdCredentialModule {
options: any,
context: IAgentContext<RequiredAgentMethods>,
): Promise<VerifiableCredential> {
const suite = this.ldSuiteLoader.getSignatureSuiteForKeyType(key.type)
const suite = this.ldSuiteLoader.getSignatureSuiteForKeyType(key.type, key.meta?.verificationMethod?.type ?? '')
const documentLoader = this.getDocumentLoader(context, options.fetchRemoteContexts)

// some suites can modify the incoming credential (e.g. add required contexts)
Expand All @@ -110,7 +110,7 @@ export class LdCredentialModule {
return await vc.issue({
...options,
credential,
suite: suite.getSuiteForSigning(key, issuerDid, verificationMethodId, context),
suite: await suite.getSuiteForSigning(key, issuerDid, verificationMethodId, context),
documentLoader,
compactProof: false,
})
Expand All @@ -126,15 +126,15 @@ export class LdCredentialModule {
options: any,
context: IAgentContext<RequiredAgentMethods>,
): Promise<VerifiablePresentation> {
const suite = this.ldSuiteLoader.getSignatureSuiteForKeyType(key.type)
const suite = this.ldSuiteLoader.getSignatureSuiteForKeyType(key.type, key.meta?.verificationMethod?.type ?? '')
const documentLoader = this.getDocumentLoader(context, options.fetchRemoteContexts)

suite.preSigningPresModification(presentation)

return await vc.signPresentation({
...options,
presentation,
suite: suite.getSuiteForSigning(key, holderDid, verificationMethodId, context),
suite: await suite.getSuiteForSigning(key, holderDid, verificationMethodId, context),
challenge,
domain,
documentLoader,
Expand Down
2 changes: 2 additions & 0 deletions packages/credential-ld/src/ld-default-contexts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ export const LdDefaultContexts = new Map([
['https://w3id.org/security/v3-unstable', require('./contexts/w3id.org_security_v3-unstable.json')],
['https://w3id.org/security/suites/ed25519-2018/v1', require('./contexts/w3id.org_security_suites_ed25519-2018_v1.json')],
['https://w3id.org/security/suites/x25519-2019/v1', require('./contexts/w3id.org_security_suites_x25519-2019_v1.json')],
['https://w3id.org/security/suites/ed25519-2020/v1', require('./contexts/ed25519-signature-2020-v1.json')],
['https://w3id.org/security/suites/jws-2020/v1', require('./contexts/json-web-signature-2020-v1.json')],
// ['https://w3id.org/did/v0.11', require('./contexts/did_v0.11.json')],
// ['https://veramo.io/contexts/socialmedia/v1', require('./contexts/socialmedia-v1.json')],
// ['https://veramo.io/contexts/kyc/v1', require('./contexts/kyc-v1.json')],
Expand Down
16 changes: 9 additions & 7 deletions packages/credential-ld/src/ld-suite-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,25 @@ import { TKeyType } from '@veramo/core'
export class LdSuiteLoader {
constructor(options: { veramoLdSignatures: VeramoLdSignature[] }) {
options.veramoLdSignatures.forEach((obj) => {
this.signatureMap[obj.getSupportedVeramoKeyType()] = obj
const keyType = obj.getSupportedVeramoKeyType()
const verificationType = obj.getSupportedVerificationType()
return this.signatureMap[keyType] = { ...this.signatureMap[keyType], [verificationType]: obj }
})
}
private signatureMap: Record<string, VeramoLdSignature> = {}
private signatureMap: Record<string, Record<string, VeramoLdSignature>> = {}

getSignatureSuiteForKeyType(type: TKeyType) {
const suite = this.signatureMap[type]
getSignatureSuiteForKeyType(type: TKeyType, verificationType: string) {
const suite = this.signatureMap[type]?.[verificationType]
if (suite) return suite

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

getAllSignatureSuites() {
return Object.values(this.signatureMap)
getAllSignatureSuites(): VeramoLdSignature[] {
return Object.values(this.signatureMap).map((x) => Object.values(x)).flat()
}

getAllSignatureSuiteTypes() {
return Object.values(this.signatureMap).map((x) => x.getSupportedVerificationType())
return Object.values(this.signatureMap).map((x) => Object.keys(x)).flat()
}
}
2 changes: 2 additions & 0 deletions packages/credential-ld/src/module-types/jsonld/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
declare module '@digitalcredentials/jsonld'
declare module '@digitalcredentials/jsonld-signatures'
declare module '@digitalcredentials/vc'
declare module '@digitalcredentials/ed25519-signature-2020'
declare module '@digitalcredentials/ed25519-verification-key-2020'
declare module '@veramo-community/lds-ecdsa-secp256k1-recovery2020'

declare module "*.json" {
Expand Down
80 changes: 80 additions & 0 deletions packages/credential-ld/src/suites/Ed25519Signature2020.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { RequiredAgentMethods, VeramoLdSignature } from '../ld-suites'
import { CredentialPayload, DIDDocument, IAgentContext, IKey, TKeyType } from '@veramo/core'
import * as u8a from 'uint8arrays'
import { Ed25519Signature2020 } from '@digitalcredentials/ed25519-signature-2020'
import { Ed25519VerificationKey2020 } from '@digitalcredentials/ed25519-verification-key-2020'
import { TextEncoder } from 'util'
/**
* Veramo wrapper for the Ed25519Signature2020 suite by digitalcredentials
*
* @alpha This API is experimental and is very likely to change or disappear in future releases without notice.
*/
export class VeramoEd25519Signature2020 extends VeramoLdSignature {
private readonly MULTIBASE_BASE58BTC_PREFIX = 'z'
private readonly MULTICODEC_PREFIX = [0xed, 0x01]

getSupportedVerificationType(): string {
return 'Ed25519VerificationKey2020'
}

getSupportedVeramoKeyType(): TKeyType {
return 'Ed25519'
}

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

// DID Key ID
let id = verificationMethodId

const signer = {
// returns signatureBytes
sign: async (args: { data: Uint8Array }): Promise<Uint8Array> => {
const messageString = u8a.toString(args.data, 'base64')
const signature = await context.agent.keyManagerSign({
keyRef: key.kid,
data: messageString,
encoding: 'base64',
})
const utf8Encode = new TextEncoder()
return utf8Encode.encode(signature)
},
}

const verificationKey = new Ed25519VerificationKey2020({
id,
controller,
publicKeyMultibase: this.preSigningKeyModification(u8a.fromString(key.publicKeyHex, 'hex')),
signer: ()=> signer,
type: this.getSupportedVerificationType(),
})
// overwrite the signer since we're not passing the private key
verificationKey.signer = () => signer as any
return new Ed25519Signature2020({
key: verificationKey,
signer: signer
})
}

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

preSigningCredModification(credential: CredentialPayload): void {
// nothing to do here
}

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

preSigningKeyModification(key: Uint8Array): string {
const modifiedKey = Uint8Array.from([...this.MULTICODEC_PREFIX, ...key])
return `${this.MULTIBASE_BASE58BTC_PREFIX}${u8a.toString(modifiedKey, 'base58btc')}`
}
}
Loading