This document outlines the design of integrating W3C VC data model compliant AnonCreds credentials into Aries Framework JavaScript and Bifold.
Opportunity: https://marketplace.digital.gov.bc.ca/opportunities/code-with-us/6f08d6d5-7e3d-489a-a98f-d7c607309dc9
The following lists all the planned changes and areas of complexities we see in Aries Framework JavaScript.
Overview: The first step will be to update AFJ to store all credentials in the new W3C format and not break current flows.
Next, we will focus on issuing credentials in the W3C format using the W3C Verifiable Credential Data Integrity Attachment format. The third step is to allow requesting and presenting presentations of verifiable credentials (anoncredsvc-2023
) in W3C format. After creating a release in AFJ containing the previously mentioned changes, during the last part, we will update Bifold's AFJ version and integrate the newly created functionality.
The implementation parts are driven by test vectors defined in this Github repo.
Issuance of W3C credentials with an AnonCreds signature are handled using the new W3C Verifiable Credential Data Integrity Attachment format.
The DataIntegrity attachment implementation will be part of AFJ's core. For simplicity reasons, we may keep the implementation in the anoncreds package for now. Otherwise, we need to create a way to dynamically register the link-secret binding method, which requires dependencies that are not a part of the core, or move the required dependencies to the core.
A credential using the new attachment format can be issued in AFJ like this:
await issuer.credentials.offerCredential({
connectionId: '<connectionId>',
credentialFormats: {
dataIntegrity: {
// specify if the holder can request the credential without binding method
bindingRequired: true,
credential: { ... }, // the W3cCredential which is offered to the holder
linkSecretBinding: {
credentialDefinitionId: string
},
didCommSignedAttachmentBinding: {
// no properties required
}
}
}
})
await holder.credentials.acceptOffer({
credentialRecordId: holderRecord.id,
credentialFormats: {
// The holder can accept the offer with the binding
// methods offered to him. Or no binding method
// at all, if this is permitted.
dataIntegrity: {
linkSecretBinding: {
linkSecretId: 'linkSecretId',
},
didCommSignedAttachment: {
kid: 'did:example:1234',
}
},
},
})
await issuer.credentials.acceptRequest({
// The issuer can accept the offer with
// no additional information needed,
// as the binding method(s) is implicitly specified
// through the request.
credentialRecordId: issuerRecord.id,
credentialFormats: {
dataIntegrity: { },
},
})
await holder.credentials.acceptCredential({
// the holder accepts storing the received credential in his wallet
credentialRecordId: holderRecord.id,
})
Presentation of W3C credentials with an AnonCreds signature is handled using Aries RFC 0510: Presentation-Exchange Attachment format for requesting and presenting proofs
The base integration of PEX has already been completed an is merged into AFJ main on January 10th 2024. Updates are now being made to the implementation in AFJ, as well as the Sphereon PEX library to support the new DataIntegrityProof
and di_vc
proof formats as described here and in the test vectors.
Selective disclosure and predicates will are handled by the AnonCreds RS implementation.
A proof request is handled like this in AFJ:
await holder.proofs.proposeProof({
protocolVersion: 'v2',
connectionId: holderConnectionId,
proofFormats: {
presentationExchange: {
presentationDefinition: { ... },
},
},
})
await verifier.proofs.acceptProposal({
proofRecordId: issuerProofExchangeRecord.id,
})
const credentialsForRequest = await holder.proofs.getCredentialsForRequest({
proofExchangeId: '<proofExchangeId>'
})
// object containing the credentials that satisfy the different input descriptors from the request
credentialsForRequest.presentationExchange
// You can then either let the framework auto-select
const credentialsForRequest = await holder.proofs.selectCredentialsForRequest({
proofExchangeId: '<proofExchangeId>'
})
// Or you can let the user (e.g. in a mobile wallet) select credentials based
// on the credentialsForRequest structure. This is already implemented in the Paradym Wallet UI
// Then finally you accept it:
await holder.proofs.acceptRequest({
proofExchangeId: '<proofExchangeId>'
proofFormats: {
presentationExchange: {
credentials: // credentials selected by user (or keep empty to auto-select)
}
}
})
// Accept a presentation (by sending a presentation acknowledgement message)
// to the connection associated with the proof record if validation succeeded.
await issuer.proofs.acceptPresentation({ proofRecordId: proofExchangeRecord.id })
The bifold work consists of integrating the added features from AFJ and adding support for rendering W3C and DIF PE models.
The implementation in AFJ is based on the defined test vectors in https://github.com/TimoGlastra/anoncreds-w3c-test-vectors