owned this note
owned this note
Published
Linked with GitHub
# Eliminating the AnonCreds `@context` File in a VC
## Why?
We want to encourage the use of AnonCreds in the W3C VC community, including through the use of multiple signatures (AnonCreds and others) on VCs. The introduction of AnonCreds `@context` creates friction in accomplishing that goal. Specifcally, guidance in the JSON-LD specification defines that it is a security risk for a component (such as a verifier) processing a JSON-LD object to dynamically load `@context` files. Thus, if a VC has both a NIST and AnonCreds signature, a verifies that receives a VC embedded in a non-AnonCreds VP would refuse to process the VC since it contains an `@context` that it has not pre-loaded. If we can eliminate the AnonCreds `@context` we can eliminate that friction.
Note that a VP AnonCreds `@context` *could* remain because an AnonCreds VP **should not** be presented with multiple proofs. It makes no sense to present an AnonCreds VP with embedded VCs that expose all of the data. One would either present an AnonCreds VP and get the privacy-preserving benefits, or present a non-AnonCreds VP and lose those benefits. In this, suggestions are offered on how to eliminate the AnonCreds `@context` from the VP as well.
## \<tl;dr>
Proposed minimum changes to eliminate the VC AnonCreds `@context` array entry:
- Define the VC proof as a Data Integrity Proof with the `cryptosuite` of `anoncredsvc-2023`.
- Question: Does that require converting to the W3C VC Data Model (VCDM) 2.0?
- No -- there is a "standard" DataIntegrityProof context to add to a W3C VCDM 1.1
- If we do switch to W3C VCDM 2.0, the `IssuanceDate` also needs to be changed to `validFrom`
- Question: Any other changes needed?
- Suggest that we provide an easy (but hardcoded) flag to simplify the switch between VCDM 1.1 and 2.0
- Remove the AnonCreds `@context` from a VC issued with an AnonCreds proof.
- Eliminate the `CredentialSchema` and `CredentialStatus` items from the VC.
- Move the needed data from those two sections into the `proofvalue` of the AnonCreds2023 Data Integrity Proof, possibly such that some of the data is human-readable.
For also eliminating the AnonCreds `@context` array entry in the VP:
- Apply all the same changes to all of the derived VCs in the VP.
- Define the VC proofs in the VP as a Data Integrity Proof with the `cryptosuite` of `anoncredspresvc-2023`.
- Define the VP proof as a Data Integrity Proof with the `cryptosuite` of `anoncredspresvp-2023`.
- Replace the current structure in the VP `credentialSubject` item for a predicate with a string.
- Ugly, but possible. [See idea below](#Eliminating-the-Use-of-context-in-VPs)
The rest of this document covers the proposed changes and [examples of the revised VC and VP](#Revised-VC-and-VP).
## What Needs To Be Eliminated?
For a W3C VC, we need to make some updates to the elements of the [W3C Format AnonCreds VC] to enable eliminating the [AnonCreds W3C Context] from the VC:
[W3C Format AnonCreds VC]: https://github.com/hyperledger/anoncreds-spec/blob/main/data/W3CCredentialWithRevocation.json
[AnonCreds W3C Context]: https://github.com/hyperledger/anoncreds-spec/blob/main/data/anoncreds-w3c-context.json
- AnonCredsCredential in the CredentialSchema -- which holds the "definition" and "schema" IDs
- AnonCredsCredentialStatusList2023 -- for handling revocation
- AnonCredsProof2023 -- within the `proof` part of the VC.
## Use `proof.type` DataIntegrityProof and `cryptosuite`
We should use the `proof.type` `DataIntegrityProof`, make the `cryptosuite` value appropriate for an AnonCreds VC, and move any AnonCreds items in the body of the verifiable credential/presentation to the encoded `proofvalue` field in the DataIntegrityProof item. The value of the `cryptosuite` is defined in JSON-LD as just a string, and the interpretation of the `proofvalue` is whatever we want to use, dependent on the `cryptosuite`.
As a result, we can update the revocable VC as follows:
- Eliminate the `AnonCredsCredential` from the VC `type` field.
- Eliminate the `CredentialSchema` item from the VC, moving the CredDef and Schema IDs to the encoded `proofvalue` field.
- Eliminate or altering the `CredentialStatus` item from the VC and VP.
- More details on that below.
The cost of this is human readability, and in particular, not being able to see at least the CredDefId of the VC.
## Dealing with the CredentialStatus
It seems like a good idea to put the revocation information for AnonCreds into the place it belongs in the W3C VC Data Model. Further, the AnonCreds Revocation format could be used a similar (possibly identical) way as the linkable approach used by StatusList2021 but that isn't automatic, and so not an immediately useful approach. Instead, I suggest that we handle revocation in the following way.
### AnonCreds v1.0 Revocation Only
If the issuer only supports AnonCreds v1.0 Revocation without change, we should leave off the `CredentialStatus` item entirely, moving the data from that section into the `proofvalue` item. The unfortunate side-effect is that it looks like the credential is not revokable, when it is. Again, we could use a human-readable element of the `proofvalue` to indicate that.
When used with a non-AnonCreds `proof` the presentation of the credential would not be revokable.
### AnonCreds v1.0 Revocation and StatusList2021
An issuer could support **independent** AnonCreds v1.0 Revocation and a StatusList2021 revocation registry, managing the two in parallel -- definitely not ideal. In that case, the issuer would add the `CredentialStatus` separately -- outside of the AnonCreds RS issue handling. A side-effect is that it looks like the AnonCreds handling is not revokable, when it is. Again, we could use a human-readable element of the `proofvalue` to indicate that.
When used with a non-AnonCreds `proof` the presentation of the credential would be revokable via the independent StatusList2022 registry.
### AnonCreds v1.0 Revocation and StatusList2022
An issuer could support an AnonCreds v1.0 Revocation and a **dependent** StatusList2021 revocation registry. The community would provide a component that implements the StatusList2021 interface (for revocation, only) using data from the AnonCreds revocation registry. When accessed, the component would access the (possibly cached) Revocation Registry state from its AnonCreds location, return the required bit array defined for StatusList2021. In that case, the `CredentialStatus` entry would be provided with the URL for a deployed component with the index of the issued credential. It would appear exactly the same as the previous example, but would be based on the same Revocation Registry data used in two different ways.
Note that in a presentation, the revocation status would be shared in different ways depending on the VC proof value being used:
- For an AnonCreds VP, the holder would construct the non-revocation proof, and would **NOT** share the index of the presented credential. The `CredentialStatus` section could be present with only the ID of the Revocation Registry included. The verifier would verify the non-revocation proof.
- For a non-AnonCreds VP, the holder would share the index of the presented credential in the CredentialStatus item, and the verifier would retrieve the registry (the bit array) and check the bit of the presented credential to see if it has been revoked or not.
This approach *could* be done as an option in the AnonCreds RS implementation, but for now I suggest we leave it off.
## Eliminating the Use of @context in VPs
We could eliminate the AnonCreds context entirely with a revision to how we handle the `predicate` item in the `credentialSubject`. Currently it is defined as follows:
```jsonc=
"age": [
{
"type": "AnonCredsPredicate",
"predicate": ">=",
"value": 18
}
]
```
The need for the array (for when there are multiple predicates on a single field) makes another representation tricky. Ideally it would just:
```jsonc
"age": ">= 18"
```
Extending that for arrays is tricky. Perhaps:
```jsonc
"age": ">= 18; <= 30"
```
## Revised VC and VP
Here are the example VC and VP from the AnonCreds repository, revised as recommended here.
VC:
```jsonc=
{
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://w3id.org/security/data-integrity/v2",
{
"@vocab": "https://www.w3.org/ns/credentials/issuer-dependent#"
}
],
"type": [
"VerifiableCredential"
],
"issuer": "did:sov:3avoBCqDMFHFaKUHug9s8W",
"issuanceDate": "2023-11-15T10:00:00.036203Z",
"credentialSubject": {
"firstName": "Alice",
"lastName": "Jones",
"age": "18"
},
"proof": [
{
"type": "DataIntegritySuite",
"cryptosuite": "anoncredsvc-2023",
"proofvalue": "AAAgf9w5.....8Z_x3FqdwRHoWruiF0FlM"
},
{
"type": "DataIntegritySuite",
"cryptosuite": "Ed25519Signature2020",
"created": "2021-11-13T18:19:39Z",
"verificationMethod": "did:sov:3avoBCqDMFHFaKUHug9s8W#key-1",
"proofPurpose": "assertionMethod",
"proofValue": "z58DAdFfa9SkqZMVPxAQpic7ndSayn1PzZs6ZjWp1CktyGesjuTSwRdoWhAfGFCF5bppETSTojQCrfFPP2oumHKtz"
}
]
}
```
VP:
```jsonc
{
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://w3id.org/security/data-integrity/v2",
{
"@vocab": "https://www.w3.org/ns/credentials/issuer-dependent#"
}
],
"type": [
"VerifiablePresentation"
],
"verifiableCredential": [
{
"@context": [
"https://www.w3.org/2018/credentials/v1"
"https://w3id.org/security/data-integrity/v2",
{
"@vocab": "https://www.w3.org/ns/credentials/issuer-dependent#"
}
],
"type": [
"VerifiableCredential"
],
"credentialSubject": {
"firstName": "Alice",
"age": [
{
"type": "AnonCredsPredicate",
"predicate": ">=",
"value": 18
}
]
},
"issuanceDate": "2023-11-15T10:00:00.036203Z",
"issuer": "did:sov:3avoBCqDMFHFaKUHug9s8W",
"proof": {
"type": "DataIntegrityProof",
"cryptosuite": "anoncredspresvc-2023",
"proofValue": "eyJzdWJfcHJvb2Yi...zMTc1NzU0NDAzNDQ0ODUifX1dfX19"
}
}
],
"proof": {
"type": "DataIntegrityProof",
"cryptosuite": "anoncredspresvp-2023",
"challenge": "413296376279822794586260",
"proofValue": "eyJhZ2dyZWdhdGVkIjp7ImNfaGFzaCI6IjEwMT...IsMzAsMTM1LDE4MywxMDcsMTYwXV19fQ=="
}
}
```