Try โ€‚โ€‰HackMD

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.

The rest of this document covers the proposed changes and examples of the 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:

  • 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:

"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:

        "age": ">= 18"

Extending that for arrays is tricky. Perhaps:

        "age": ">= 18; <= 30"

Revised VC and VP

Here are the example VC and VP from the AnonCreds repository, revised as recommended here.

VC:

{ "@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:

{
  "@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=="
  }
}