§ AnonCreds Specification

Specification Status: v1.0 Draft

Latest Draft:

https://github.com/hyperledger/anoncreds-spec

Editors:

Participate:
GitHub repo
Commit history
Discord

§ Abstract

The AnonCreds (Anonymous Credentials) specification is based on the open source verifiable credential implementation of AnonCreds that has been in use since 2017, initially as part of the Hyperledger Indy open source project and now in the Hyperledger AnonCreds project. The extensive use of AnonCreds around the world has made it a de facto standard for ZKP-based verifiable credentials, and this specification is the formalization of that implementation.

For more details on what AnonCreds are and how they work you can refer to the Anonymous credentials with type-3 revocation by Dmitry Khovratovisch, Michael Lodder and Cam Parra which is the compiled pdf from their official TeX document published under CC4.0 license.

§ Status of This Memo

This is a proposal for version v1.0 of AnonCreds which aims at AnonCreds being ledger agnostic.

This document is a product of the AnonCreds Working Group. It represents the consensus of the AnonCreds community. The proposal for v1.0 has partly been worked out at the RWOT2022 event in the Hague, Netherlands.

Information about the current status of this document, any errata, and how to provide feedback on it may be obtained at https://github.com/hyperledger/anoncreds-spec.

This specifications is subject to the Community Specification License 1.0 available at https://github.com/CommunitySpecification/1.0.

If source code is included in the specification, that code is subject to the Apache 2.0 license unless otherwise marked. In the case of any conflict or confusion within this specification between the Community Specification License and the designated source code license, the terms of the Community Specification License shall apply.

§ Introduction

AnonCreds ZKP verifiable credentials provide capabilities that many see as important for digital identity use cases in particular, and verifiable data in general. These features include:

This version (v1.0) removes any dependence on Hyperledger Indy by removing any requirements related to the storage of the objects used in AnonCreds, whether they be stored remotely on a “verifiable data registry” (including Hyperledger Indy) or in local secure storage.

The following diagram and explanation below give a high-level overview of all AnonCreds Data objects, their relations and the owner respectively receiver of each of the data objects.

AnonCreds Data Model Overview

AnonCreds require a Verifiable Data Registry (VDR). A VDR (box in green) is a public registry (often a ledger) used for storing some of the AnonCreds data objects.

Schemas are public and reusable templates, which define the attributes of issued AnonCreds credentials and can be written (e.g. by an Issuer) to the VDR.

Based on a Schema, arbitrary Issuers (box in yellow) can create a Credential Definition (Credential Definition) which references the Schema. A Credential Definition enables Issuers to issue AnonCreds Credentials to Holders and enables Verifiers (box in red) to verify Credentials issued to and presented by a Holder. A Credential Definition consists of two pieces of information: First, the Private Credential Definition includes the private signing keys of the Issuer for signing and issuing AnonCreds Credentials to holders and is kept private by the Issuer. Second, the Public Credential Definition includes the public keys of the Issuer, has to be stored on a VDR and is used by holders and arbitrary Verifiers in order to verify AnonCreds Credentials issued to and presented by Holders.

Each Holder (box in blue) has a link secret, which enables Credential to Holder binding: Whenever a Credential is issued to a Holder by an Issuer, the Holder generates a blinding factor and uses this to commit to a blinded version of the link secret which is sent to the Issuer. The Issuer verifies the commitment, before producing a blind signature over the blinded link secret along with the other attributes within the AnonCreds Credential. This blind signature is sent to the Holder, who removes the blinding factor to retrieve a credential signature over the Credential attributes including the unblinded link secret. By using the same link secret for every Credential that is issued to the Holder, the Holder can prove the affiliation of multiple Credentials at presentation time.

Holders never present the raw signed credential data they - received from Issuers - to Verifiers for verification purposes. Instead a Verifiable Presentation is created by the Holder and sent to the Verifier. A Verifiable Presentation is a derivation of an AnonCreds Credential which allows a Holder to proof the correctness of the revealed credential data, without revealing the original raw credential signature(s). Additionally, Holders prove knowledge the link secret attribute within the Credential, without revealing this value to the Verifiers. Verifiers process Verifiable Presentations for verification of credential data.

AnonCreds allows the revocation of Credentials issued to Holders by Issuers. In case revocation is required, at least one (Revocation Registry Definition), which references the associated Public Credential Definition, has to be stored to the VDR by the Issuer in addition to the Public Credential Definition. A Revocation Registry Definition can have Revocation Status Lists. When one or more credentials have to be revoked, the Issuer stores a Revocation Status List with the updated status of the credentials in question to the VDR. Holder use these additional pieces of information in order to generate a Non-Revocation Proof. A Non-Revocation Proof proves to a Verifier, that the credential the Holder presented to the Verifier, has not been revoked. Verifiers use the information provided by a Revocation Registry Definition and associated Revocation Status Lists to verify the Holder`s Non-Revocation Proof. A Tails File supports the revocation mechanism. Each Revocation Registry Definition requires exactly one Tails File.

§ Requirements, Notation and Conventions

The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “NOT RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.

§ Terminology

Accumulator
A [cryptographic accumulator] is used in the AnonCreds v1.0 Revocation scheme as a space- and time-efficient method of proving a value membership in a set of values without revealing the individual members of the set. In AnonCreds v1, an accumulator is a core element of the verifiable credential revocation mechanism.
AnonCreds Method
AnonCreds methods specify how AnonCreds objects are written (registered) and read (resolved) on a given verifiable data registry implementation. AnonCreds was originally written to use Hyperledger Indy as its only VDR implementation, but the evolution of AnonCreds to enable storing objects on any VDR implementation means that AnonCreds methods (comparable to DID Methods from the W3C DID Core specification) are necessary. AnonCreds Methods are defined in the AnonCreds Methods Registry repository.
AnonCreds Objects
The published and shared data objects used in AnonCreds v1.0 including the published objects schema, credential definition, revocation registry definition, revocation registry entry and the shared objects credential offer, credential request, and presentation request.
BigNumber
A BigNumber is an data object which safely allows mathematical operations on numbers of any magnitude. BigNumbers are commonly used in cryptography schemes, including those underlying AnonCreds v1.0.
Blinded Secret
A cryptographic technique where a secret value (a number) is blinded before it is shared such that the sender can later prove knowledge of the secret value without sharing it. The AnonCreds v1.0 link secret mechanism is based on the use of a blinded secret.
Blinded Secrets Correctness Proof
A ZKP-based proof that can be verified to show that a blinded secret was produced correctly from an unblinded secret without exposing the secret.
Blinding Factor
A blinding factor is a random BigNumber selected from the set of integers up to the order of the RSA group, n. It is generated by the holder to blind their link secret during credential issuance. Knowledge of the blinding factor can be used to create a Blinded Secrets Correctness Proof.The blinding factor can be removed from the signature the issuer produces to retrieve a valid signature over the unblinded link secret. A blinding factor and associated Blinded Secrets Correctness Proof are similarly generated for each non-disclosed attribute during credential presentation, such that a holder can prove they know these values without revealing them to the verifier.
Call Home
Call home is a term used when evaluating the privacy characteristics of verifiable credential deployments. If a holder presenting data from a verifiable credential must always contact (“call home to”) the issuer, holder actions are open to the actual, or perception of, tracking of the holder by the issuer. Verifiable credential schemes that do not make possible the tracking of holder activities by issuers are preferred.
Claim
A claim is a part of digital identity related to a subject. A claim can be attested by the identity subject itself, or it can be asserted by another entity.
Correlatability
When a verifiable credential scheme that has the attribute of unlinkability, the data from the process of sharing a verifiable presentations with different verifiers cannot be correlated to identify the holder.
Credential
A credential is a set of claims about an identity subject. A verifiable credential is a tamper-proof credential whose authorship is cryptographically verifiable. An anonymous credential, also known as AnonCreds, is a verifiable credential that has privacy-preserving properties to enable data minimization and correlation resistance.
Credential Definition
A credential definition (also known as CRED_DEF or CLAIM_DEF) contains the public data required for credential issuances (used by the issuer) as well as credential validation data (used by holders and verifiers). Any number of credentials can be issued based on a single credential definition. A credential definition is generated by the issuer before credential any issuances and published for anyone (primarily holders and verifiers) to use. In generating the published credential definition, related private data is also generated and held as a secret by the issuer. The secret data includes the private keys necessary to generate signed verifiable credentials that can be presented and verified using the published credential definition. A credential definition can optionally be generated such that its generated credentials can be revoked.
Credential Key Correctness Proof
A proof generated during the creation of the credential definition and included in the credential offer so that the holder can verify that the issuer is in control of the private data associated with the published credential definition.
Credential Offer
A credential offer is a data object sent by an issuer to a holder offering to issue a credential. The credential offer contains the details about the claims the issuer intends to issue to the holder. A holder can reply to the issuer with a credential request. A credential offer also includes a nonce and a Credential Key Correctness Proof.
Credential Request
A credential request is a request from an holder towards a issuer to get a credential issued by the issuer. The credential request references a preceding credential offer and defines the claims the holder wants to get issued, including a Blinded Secret and associated Blinded Secrets Correctness Proof. A credential request also includes a nonce that is used in issuing the credential.
Data Minimization
An attribute of verifiable data sharing schemes that considers privacy of a scheme based on the amount of data shared in a given interaction. Ideally, the minimum amount of data is shared for the purpose of the interaction. Techniques such as selective disclosure, predicates, and unlinkability, all available in AnonCreds v1.0 support the goal of privacy-preserving, minimal data sharing.
DID
A Decentralized Identifier (DID), defined by the W3C DID Core Specification, is a type of identifier that is useful in enabling verifiable, decentralized digital identity. A DID refers to any subject (e.g., a person, organization, thing, data model, abstract entity, etc.) as determined by the controller of the DID. DIDs are not used in AnonCreds itself but there must be a verifiable identifier (usually a DID) with an enforced relationship between schema publishers and issuers and the AnonCreds objects they publish. This is outlined in a note in this specification section.
DID Method
DID methods specify how DID documents are created and resolved (read) on a given verifiable data registry implementation, allowing DIDs to be created and resolved in a wide variety of storage containers. The capabilities required by DID Methods are defined in the [DID Core specification], and the (many) DID Methods are defined in the DID Methods Registry repository.
Holder

In this specification, the holder is a software component (agent) used by an entity (person, organization, etc.) in possession of credentials issued to them. Where “holder” is used in the specification we mean the software component. In some places where required, we clearly refer to an entity using holder software as separate from the holder software component. Holders interact with issuers to obtain credentials, and derive presentations from the credentials they hold.

Issuer

An issuer is one of the three entities that interact with each other within the domain of digital identities. It can assert claims about a subject in the form of a tamper-proof credential whose origins are cryptographically verifiable.

Issuer Identifier

An issuer identifier is a unique identifier for an issuer. It is used to identify the issuer of AnonCreds objects published to a Verifiable Data Registry.

Link secret

A link secret is a unique identifier known only to the holder used in AnonCreds to bind credentials issued to a holder to that holder, and to demonstrate that all of the source verifiable credentials in a presentation are bound to the same link secret that is known to the holder. During issuance and presentation processes the holder's link secret is blinded with a blinding factor such that it is not correlatable, and a Blinded Secrets Correctness Proof is provided by the holder to demonstrate they know the link secret without revealing it.

Link secret is also known by the deprecated term master_secret in some AnonCreds source code.

Nonce

A nonce is an arbitrary unique number that is often required as an input to the generation of a cryptographic proof to ensure it is uniquely generated and once produced, cannot be replayed. Within AnonCreds, nonces are used during the issuance and presentation processes to prevent replay attacks.

Non-Revocation Proof

A non-revocation proof is a proof provided by a holder to demonstrate that a revocable credential they are presenting has not been revoked, without revealing a unique, correlatable identifier for the credential. A verifier verifies a non-revocation proof using information from the revocation registry to which the credential belongs.

Predicates

A zero-knowledge proof predicate is a boolean assertion (operators <=, <, >, >=) in an presentation about the value of an integer claim without disclosing the value of the claim.

Presentation Request

An AnonCreds presentation request is an object constructed by the verifier and sent to the holder defining the verifiable data that the verifier wants from the holder for some purpose.

Prover

A prover is a synonym for holder that is sometimes used in a holder-verifier interaction. In this specification, we use the term “holder” in all cases. However the underlying AnonCreds implementations use “prover” in code.

Revocation

A unilateral action by the issuer of a verifiable credential issued to a holder to revoke that credential for some reason. Once an issued credential has been revoked, the holder can no longer produce a non-revocation proof for the credential. Verifiers usually (but not always) are interested if a data is presented from a revoked credential.

Revocation Registry

A Revocation registry is a set of objects related to one another and a credential definition that holds information about the revocation status of a set of revocable credentials issued from the credential definition. Each revocation registry consists of a revocation registry definition and one or more revocation registry entries. There can be 0 or more revocation registries related to a credential definition, and every issued AnonCreds revocable credential is in a revocation registry.

Revocation Registry Definition

A revocation registry definition is an object with public and private information about a revocation registry. The public part is published such that it an be resolved and used by anyone, while the private part is a secret held by the issuer for use when publishing revocation registry entries that update the revocation status of one or more credentials.

Revocation Registry Entry

A revocation registry entry is an object that is published by the issuer to set/update the revocation status of one or more issued credentials that are in a revocation registry. Each revocation registry entry has an identifier (sometimes called a timestamp), a cryptographic accumulator that summarizes the revocation state of all the credentials in the revocation registry and, depending on the AnonCreds Method being used to publish the object, either the revocation state of all of the credentials in the registry, or the set of credentials whose revocation state has changed (“deltas”) since the last revocation registry entry was published.

Revocation Status List

A Revocation status list is an object that contains the revocation status (“revoked” or “not revoked”) of all credentials in a Revocation Registry at the time of a given revocation registry entry. For [[AnonCreds Methods]] that store revocation registry entries as deltas (changes to the revocation state of credentials from the previous revocation registry entry), the set of deltas from the initial publication of the revocation registry must be collected and used to calculate the full revocation state of all of the credentials.

Schema

A Schema is a object that defines the set of claims (also known as attributes) that will be populated by issuers in issuing a give type of AnonCreds verifiable credentials. Schemas have a name, version, and are published to a verifiable data registry by a schema publisher using an AnonCreds Method. Credential definitions are generated from a specific schema.

Schema Publisher

A Schema publisher is an entity that publishes a Schema to a verifiable data registry. The schema publisher could be the one issuer of a type of credential, but could also be another entity that creates a Schema to be used by many issuers to issue the same type of credential.

Selective Disclosure

Selective disclosure is the ability to minimize data the shared data from an issued credential in a presentation by revealing to a verifier only a subset of claims in the credential. The source credential is still verified by the verifier, but only the revealed values are disclosed.

Signature Correctness Proof

A ZKP-based proof that can be verified to show that a signature over a message is valid, without revealing the message or signature.

Subject

A subject, also known as an identity subject, is the entity about whom the claims in a credential are asserted. In AnonCreds, the credential subject is not formally defined in credential. Rather, the issuance of a credential is always to a specific holder. The semantics of the credential defines the relationship between the holder and the subject, with the holder frequently being the subject.

Tails File

A tails file is a part of the AnonCreds v1.0 scheme that enables a holder to produce a non-revocation proof. A tails file is a static file generated as part of the creation of a revocation registry by the issuer, published, and retrieved by the holder of a credential that is in the related revocation registry. The holder must have the tails file in order to generate a non-revocation proof for a source credential they are providing in a presentation.

Unlinkability

Unlinkability is the attribute of some verifiable credentials schemes (notably AnonCreds) such that no correlatable identifiers are shared in carrying out verifiable credential issuance and presentation processes. Unlinkability requires that when the processes are repeated with the same or different parties (issuers, verifiers) no common unique identifiers are shared. Note that unlinkability may be lost if there are unique identifiers shared in the revealed claim values of presentations.

Verifiable Data Registry

DIDs, DID documents and published AnonCreds objects are stored in a verifiable data registry (VDR) such that an identifier for an object can be resolved (by anyone, in most cases), and the identified object returned. A VDR can be a distributed ledger, a blockchain, a web server, database or any other type of storage system. The process of going from the identifier to discovering and resolving the object is a DID Method (for DIDs) and AnonCreds Method (for AnonCreds objects). Resolved objects must adhere to their specified data model, regardless of the discover/resolution method used and the verifiable data registry in which the objects are stored.

Verifiable Presentation

An AnonCreds verifiable presentation is a collection of claims and predicates derived from one or more credentials with an added proof that the verifier can verifier. AnonCreds enable the holder to prove it holds a claim from a VC without revealing the VC itself. Verifying a presentation shows the issuer of the source credentials, to whom the credentials where issued, that the claims have not been tampered with, and, if applicable, that the source credentials have not been revoked. AnonCreds presentations are designed to maximize the privacy of the holder sharing the presentation.

Verifier

A verifier is an entity that verifies the information from a holder in a presentation.

Zero-knowledge proof

In cryptography, a zero-knowledge proof is a method by which an entity can prove that they know a certain value without disclosing the value itself. Zero-knowledge proofs in AnonCreds enable a number of privacy-preserving capabilities.

  • Use predicates to minimize the data shared by the holder, such as proving based on a date of birth claim that they are older than 18 without sharing their date of birth.
  • Prove that the source credentials shared in a presentation have not been revoked without sharing unique identifiers for the credentials.

§ Cryptographic Notations

This specification contains the cryptographic calculations necessary to produce the data objects exchanged in using Hyperledger AnonCreds, and to verify the various proofs embedded in those objects. The following is information about the notations used in displaying the cryptographic calculations:

a || b : Denotes the concatenation of octet strings a and b.

I \ J : For sets I and J, denotes the difference of the two sets i.e., all the elements of I that do not appear in J, in the same order as they were in I.

X[a..b] : Denotes a slice of the array X containing all elements from and including the value at index a until and including the value at index b. Note when this syntax is applied to an octet string, each element in the array X is assumed to be a single byte.

range(a, b) : For integers a and b, with a <= b, denotes the ascending ordered list of all integers between a and b inclusive (i.e., the integers i such that a <= i <= b).

length(input) : Takes as input either an array or an octet string. If the input is an array, returns the number of elements of the array. If the input is an octet string, returns the number of bytes of the inputted octet string.

H(...) : Any hash function.

Terms specific to pairing-friendly elliptic curves are:

E1, E2 : elliptic curve groups defined over finite fields. This document assumes that E1 has a more compact representation than E2, i.e., because E1 is defined over a smaller field than E2.

G1, G2 : subgroups of E1 and E2 (respectively) having prime order r.

GT : a subgroup, of prime order r, of the multiplicative group of a field extension.

e : G1 x G2 -> GT a non-degenerate bilinear map.

r : The prime order of the G1 and G2 subgroups.

P1, P2 : points on G1 and G2 respectively. For a pairing-friendly curve, this document denotes operations in E1 and E2 in additive notation, i.e., P + Q denotes point addition and x * P denotes scalar multiplication. Operations in GT are written in multiplicative notation, i.e., a * b is field multiplication.

§ AnonCreds Setup Data Flow

The following sequence diagram summarizes the setup operations performed by a Schema Publisher, the Issuer (one required and one optional) in preparing to issue an AnonCred credential based on provided Schema, and the one setup operation performed by each Holder. On successfully completing the operations, the Issuer is able to issue credentials based on the given Schema to the Holder. The subsections below the diagram detail each of these operations.

sequenceDiagram autonumber participant L as Verifiable
Data Registry participant SP as Schema Publisher participant I as Issuer participant H as Holder Note over L, H: Schema Publisher: Publish Schema SP ->> L: Publish Schema (Schema) L ->> I: Schema ID,
Schema Transaction ID Note over L, H: Issuer: Create, Store and Publish CredDef I ->> I: create_and_store_credential_def
(Schema, tag, support_revocation) Note right of I: store public /
private keys and
correctness proof I ->> L: Publish CredDef (CredDef) Note over L, H: Issuer: Create, Store and Publish Revocation Registry (Optional) I ->> I: create_and_store_revoc_reg (intCredDef) Note right of I: get keys Note right of I: store revoc_reg_def,
revoc_reg_accum,
priv_key,
tails_generator I ->> L: Publish RevReg
(revoc_reg_id,
revoc_reg_def_json,
revoc_reg_entry_json) Note over L, H: Holder: Create and Store Link Secret H ->> H: anoncreds_prover_create_link_secret H ->> H: store link secret rect rgb(191, 223, 255) Note left of H: 💡The "Verifier" role is
omitted in this
diagram, since
it is not required
for the setup end
NOTE

Those with a knowledge of DIDs might expect that in the flow above, the first step would be for the issuer to publish a DID. However, in AnonCreds, DIDs are not used in the processing of credentials, and notably, the public keys used in AnonCreds signatures come not from DIDs, but rather from Credential Definition objects. DIDs may be used to identify the entity publishing the objects that are then used in the processing of credentials – the Schema, Credential Definition, Revocation Registry Definition and Revocation Status List objects. There is an enforced relationship between an identifier (such as a DID) for the entity publishing the AnonCred objects, and the objects themselves. For example, in the Hyperledger Indy implementation of AnonCreds, for a credential issuer to publish a Credential Definition on an instance of Indy it must have a DID on that instance, and it must use that DID to sign the transaction to write the Credential Definition.

The DID of the publisher of an AnonCreds object MUST be identifiable from the published object and enforcement of the relationship between the DID and the object must be enforced. For example, in the Hyperledger Indy implementation of AnonCreds, the DID of the object publisher is part of the identifier of the object – given the identifier for the AnonCreds object (e.g. one found in proving a verifiable credential), the DID of the publisher can be found. Further, the Hyperledger Indy ledger enforces, and makes available for verification, the requirement that the writing of the AnonCreds object must be signed by the DID that is writing the object.

If a DID-based messaging protocol, such as DIDComm is used between the AnonCreds participants (the issuer, holder and verifier) the use of DIDs for messaging is independent of their use (or not) in the publishing AnonCreds objects. Such DIDs are used to facilitate secure messaging between the participants to enable the issuing of credentials and the presentation of proofs.

§ Schema Publisher: Publish Schema Object

Each type of AnonCred credential is based on a Schema published to a Verifiable Data Registry (VDR), an instance of Hyperledger Indy in this version of AnonCreds. The Schema is defined and published by the Schema Publisher. Any issuer who can reference the Schema (including the Schema Publisher) MAY issue credentials of that type by creating and publishing a Credential Definition based on the Schema. This part of the specification covers the operation to create and publish a Schema. The flow of operations to publish a Schema is illustrated in the Schema Publisher: Publish Schema section of the AnonCreds Setup Data Flow sequence diagram.

The Schema is a JSON structure that can be manually constructed, containing the list of attributes (claims) that will be included in each AnonCreds credential of this type. The following is an example Schema:

{
  "issuerId": "https://example.org/issuers/74acabe2-0edc-415e-ad3d-c259bac04c15",
  "name": "Example schema",
  "version": "0.0.1",
  "attrNames": ["name", "age", "vmax"]
}

Once constructed, the Schema is published to a Verifiable Data Registry (VDR) using the Schema Publishers selected AnonCreds Objects Method. For example, see this Schema that is published on the Sovrin MainNet instance of Hyperledger Indy. The schemaId for that object is: Y6LRXGU3ZCpm7yzjVRSaGu:2:BasicIdentity:1.0.0.

The identifier for the schema is dependent on where the Schema is published and the AnonCreds method used.

§ Issuer Create and Publish Credential Definition Object

Each Issuer of credentials of a given type (e.g. based on a specific Schema) must create a Credential Definition for that credential type. The flow of operations to create and publish a Credential Definition is illustrated in the Issuer: Create, Store and Publish Credential Definition section of the AnonCreds Setup Data Flow sequence diagram.

In AnonCreds, the Credential Definition and Credential Definition identifier include the following elements.

We’ll initially cover the generation and data for a Credential Definition created without the option of revoking credentials. In the succeeding section, we describe the additions to the generation process and data structures when credential revocation is enabled for a given Credential Definition.

§ Retrieving the Schema Object

Prior to creating a Credential Definition, the Issuer must get an instance of the Schema upon which the Credential Definition will be created. If the Issuer is also the Schema Publisher, they will already have the Schema. If not, the Issuer must request that information from the VDR on which the Schema is published. In some AnonCreds Objects there is a requirement that the Schema and Credential Definition must be on the same VDR.

§ Generating a Credential Definition Without Revocation Support

The Credential Definition is a JSON structure that is generated using cryptographic primitives (described below) given the following inputs.

The operation produces two objects, as follows.

The following describes the process for generating the Credential Definition and Private Credential Definition data.

Here is the rust implementation of the above process.

The Private Credential Definition produced by the generation process has the following format:

{
  "p_key": {
    "p": "123...782",
    "q": "234...456"
  },
  "r_key": null
}
WARNING

A weakness in this specification is that the Issuer does not provide a key correctness proof to demonstrate that the generated private key is sufficiently strong enough to meet the unlinkability guarantees of AnonCreds.

The proof should demonstrate that:

  • p and q are both prime numbers
  • p and q are not equal
  • p and q are the same, sufficiently large, size
    • For example, using two values both 1024 bits long is sufficient, whereas using one value 2040 bits long and the other 8 bits long is not.

The Issuer SHOULD provide a published key correctness proof based on the approach described in Jan Camenisch and Markus Michels. Proving in zero-knowledge that a number is the product of two safe primes (pages 12-13). In a future version of AnonCreds, the additional key correctness proof could be published separately or added to the Credential Definition prior to publication. In the meantime, Issuers in existing ecosystems can share such a proof with their ecosystem co-participants in an ad hoc manner.

The lack of such a published key correctness proof allows a malicious Issuer to deliberately generate a private key that lacks the requirements listed above, enabling the potential of a brute force attack that breaks the unlinkability guarantee of AnonCreds.

The Credential Definition has the following format (based on this example Credential Definition on the Sovrin MainNet):

{
  "issuerId": "did:indy:sovrin:SGrjRL82Y9ZZbzhUDXokvQ",
  "schemaId": "did:indy:sovrin:SGrjRL82Y9ZZbzhUDXokvQ/anoncreds/v0/SCHEMA/MemberPass/1.0",
  "type": "CL",
  "tag": "latest",
  "value": {
    "primary": {
      "n": "779...397",
      "r": {
        "birthdate": "294...298",
        "birthlocation": "533...284",
        "citizenship": "894...102",
        "expiry_date": "650...011",
        "facephoto": "870...274",
        "firstname": "656...226",
        "link_secret": "521...922",
        "name": "410...200",
        "uuid": "226...757"
      },
      "rctxt": "774...977",
      "s": "750..893",
      "z": "632...005"
    }
  }
}

The Credential Definition contains a cryptographic public key that can be used to verify CL-RSA signatures over a block of L messages m1,m2,...,mL. The Credential Definition contains a public key fragment for each message being signed by signatures generated with the respective private key. The length of the block of messages, L, being signed is defined by referencing a specific Schema with a certain number of attributes, A = a1,a2,.. and setting L to A+1. The additional message being signed as part of a credential is for a link_secret (called the link secret everywhere except in the existing open source code and data models) attribute which is included in all credentials. This value is blindly contributed to the credential during issuance and used to bind the issued credential to the entity to which it was issued.

All integers within the above Credential Definition example json are shown with ellipses (e.g. 123...789). They are 2048-bit integers represented as 617 decimal digits. These integers belong to an RSA-2048 group characterised by the n defined in the Credential Definition.

The identifier for the Credential Definition is dependent on where the Credential Definition is published and the AnonCreds method used.

§ Generating a Credential Definition With Revocation Support

The issuer enables the ability to revoke credentials produced from a Credential Definition by passing to the Credential Definition generation process the flag support_revocation as true. When using revocation in a credential, private key material is added to the Private Credential Definition to allow the issuer to revoke credentials, and public key material is added to the Credential Definition to allow a verifier to check revocation status. The following describes the fields added to the Private Credential Definition and the Credential Definition.

The revocation scheme uses a pairing-based dynamic accumulator defined as a variant of the CKS scheme but with a Type 3 elliptic curve pairing instead of a Type 1 pairing. The curve EE is BN254, which is defined over a 254-bit prime pp. The pairing is an Ate pairing e:G1×G2GTe : G_1 \times G_2 \rightarrow G_T where G1=E(Fp)G_1 = E(\mathbb{F}_p), G2=E(Fp2)G_2 = E(\mathbb{F}_{p^2}), and GTG_T is the group of qthq^{\text{th}} roots of unity in Fp12\mathbb{F}_{p^{12}} where q=E(Fp)q=|E(\mathbb{F}_p)|, which is another 254-bit prime.

In the amcl library used for the elliptic curve arithmetic, points are represented using projective co-ordinates, i.e. a point (X/Z,Y/Z)(X/Z,Y/Z) on the curve EE is mapped to a projective point (X:Y:Z)(X: Y: Z). Additionally, the big-integer co-ordinates are strings of 64 hexadecimal characters, meaning there are up to 64 * 4 - 254 = 2 bits of ‘excess’ in each encoding. The library includes the excess number of bits as an integer (i.e. 1 or 2) before the hexadecimal string. The upshot is:

NOTE

In this section, multiplicative notation is used: a point PP on an elliptic curve EE is considered an element gg in the group GG of points on the curve EE, and for an integer kk modulo the group order qq, we write gkg^k to mean the point kPk \cdot P.

§ Private Revocation Keys

A Private Credential Definition with revocation enabled has the following format. In this, the details of the p_key element are omitted, as they are the same as was covered in the section above. The implementation can be found in the anoncreds-clsignatures-rs repository.

{
  "p_key": {
    "p": "123...782",
    "q": "234...456"
  },
  "r_key": {
    "x": "332...566",
    "sk": "992...237"
  }
}

The value qq is the order of the group G1=E(Fp)G_1=E(\mathbb{F}_p) on the curve BN254 (see above: qq is a 254-bit prime). x and sk are used to generate parts of the revocation public key as described below.

NOTE

The issuer additionally holds a secret value gamma used to construct the accumulator. This is inside the RevocationKeyPrivate object in anoncreds-clsignatures-rs, which is separate from the CredentialRevocationPrivateKey object that stores sk and x.

§ Public Revocation Keys

A Credential Definition with revocation enabled has the following format (from this example Credential Definition on the Sovrin MainNet). In this, the details of the primary element are omitted, as they are the same as was covered above.

{
  "issuerId": "did:indy:sovrin:F72i3Y3Q4i466efjYJYCHM",
  "schemaId": "did:indy:sovrin:F72i3Y3Q4i466efjYJYCHM/anoncreds/v0/SCHEMA/state_license/4.2.0",
  "type": "CL",
  "tag": "latest",
  "value": {
    "primary": {...},
    "revocation": {
      "g": "1 154...813 1 11C...D0D 2 095..8A8",
      "g_dash": "1 1F0...3B5 1 229...41D 1 04B...F7D 1 061...8B7 2 095...8A8 1 000...000",
      "h": "1 131...0DD 1 0D5...66E 2 095...8A8",
      "h0": "1 1AF...246 1 127...361 2 095...8A8",
      "h1": "1 242...F14 1 1AC...2FF 2 095...8A8",
      "h2": "1 072...7A1 1 09E...622 2 095...8A8",
      "h_cap": "1 196...C53 1 238...38B 1 196...C7E 1 198...D31 2 095...8A8 1 000...000",
      "htilde": "1 1D5...797 1 034...232 2 095...8A8",
      "pk": "1 0E7...A88 1 007...4B8 2 095...8A8",
      "u": "1 18E...44B 1 018...F71 1 0D8...2C2 1 003...4CF 2 095...8A8 1 000...000",
      "y": "1 068...F6B 1 16C...F7E 1 01F...68A 1 1E3...9F9 2 095...8A8 1 000...000"
    }
  }
}

In the following, only the revocation item is described, as the rest of items (primary, ref, etc.) are described in the previous section of this document.

§ Publishing the Credential Definition on a Verifiable Data Registry

Once constructed, the Credential Definition is published by the Issuer to a Verifiable Data Registry using the issuers preferred AnonCreds Objects.

For example, see this Credential Definition that is published in the Sovrin MainNet instance of Hyperledger Indy. Note that the contents of the Credential Definition that have are published to the Hyperledger Indy ledger, do not exactly match the Credential Definition data model. The specific AnonCreds Objects can describe how to resolve the contents stored on the ledger into the Credential Definition data model.

§ Issuer Create and Publish Revocation Registry Objects

Once the issuer has created a Credential Definition with revocation enabled, the issuer must also create and publish a Revocation Registry Definition and create and publish the first Revocation Status List for the registry.

In this section, we’ll cover the create and publish steps for each of the Revocation Registry Definition and Revocation Status List objects. The creation and publishing of the Revocation Registry Definition includes creating and publishing the TAILS_FILE for the Revocation Registry.

§ Creating the Revocation Registry Object

A secure process must be run to create the revocation registry object, taking the following input parameters.

Three outputs are generated from the process to generate the Revocation Registry: the Revocation Registry object itself, the TAILS_FILE content, and the Private Revocation Registry object.

§ Revocation Registry Definition Object Generation

The Revocation Registry Definition object has the following data model. This example is from this transaction on the Sovrin MainNet and instance of Hyperledger Indy.

{
  "issuerId": "did:web:example.org",
  "revocDefType": "CL_ACCUM",
  "credDefId": "Gs6cQcvrtWoZKsbBhD3dQJ:3:CL:140384:mctc",
  "tag": "MyCustomCredentialDefinition",
  "value": {
    "publicKeys": {
      "accumKey": {
        "z": "1 0BB...386"
      }
    },
    "maxCredNum": 666,
    "tailsLocation": "https://my.revocations.tails/tailsfile.txt",
    "tailsHash": "91zvq2cFmBZmHCcLqFyzv7bfehHH5rMhdAG5wTjqy2PE"
  }
}

The items within the data model are as follows:

TODO

Update this to be the inputs for generating a Revocation Registry vs. the already published object

As noted, most of the items come directly from the input parameters provided by the issuer. The z Revocation Registry accumulator public key is generated using (TODO: fill in details) algorithm. The use of the accumulator public key is discussed in the Credential Issuance section, when the publication of revocations is described. The calculation of the tailsHash is described in the next section on TAILS_FILE generation.

The identifier for the Revocation Registry is dependent on where the Revocation Registry is published and the AnonCreds method used.

§ Tails File and Tails File Generation

The second of the outcomes from creating of a Revocation Registry is a TAILS_FILE. The contents of a TAILS_FILE is an array of calculated points on curve G2, one for each credential in the registry. Thus, if the Revocation Registry has a capacity (maxCredNum) of 1000, the TAILS_FILE holds an array of 1000 G2 curve points. Each credential issued using the Revocation Registry is given its own index (1 to the capacity of the Revocation Registry) into the array, the index of the point for that credential. The contents of the TAILS_FILE is needed by the holder to produce (if possible) a “proof of non-revocation” to show their issued credential has not been revoked.

The process of generating the points that populate the TAILS_FILE are tail[index] = g_dash * (gamma ** index)

NOTE

Detailed process for tails file generation:

  • Create and open the tails file.
  • To generate a tail point for an attribute located at a specific index, follow the steps.
  • Convert index into an array of bytes(u8) using little endian ordering.
  • Create an element belonging to the finite field group from the u8 array.
  • Calculate pow by doing modular exponentiation of revocation private key(gamma) with the finite field element previously calculated.
  • Multiply pow by g_dash, which is the generator of elliptic curve group G2, and this should be the required point on the curve.
  • Convert this tail point to an array of bytes(u8), and put them into the file as a slice buffer.
  • Repeat for all the attributes from index 11 to LL, by calculating ([γ],[γ2],[γ3],...[γL],[γ],[γL+2],[γL+3],...,[γ2L])([\gamma], [\gamma^2], [\gamma^3], ...[\gamma^L], [\gamma], [\gamma^{L+2}], [\gamma^{L+3}], ..., [\gamma^{2L}]). Note that Instead of inserting [γL+1][\gamma^{L+1}] in the sequence, insert the value [γ][\gamma] (the first value in the sequence) in its place, and then continue with [γL+2][\gamma^{L+2}] and on to [γ2L][\gamma^{2L}]. [γL+1][\gamma^{L+1}] is not used by holders generating the Non-Revocation Proof and a dummy value is inserted in its place.
  • Close the file buffer.

Relevant links: Anoncreds-rs repository, Anoncreds-CLSignatures repository

The process for hashing the TAILS_FILE is as follows:

The SHA256 hash of the array of points is returned to be inserted into the tailsHash item of the Revocation Registry object (as described in the previous section). Typically, the array is streamed into a file (hence, the term “Tails File”) and published to a URL indicated by the tailsLocation input parameter provided by the issuer.

The format of a TAILS_FILE is as follows:

Thus the total size of a Tails File is 2+ 12*Size of the Revocation Registry+6 (the L+1 entry).

While not required, the Hyperledger Indy community has created a component, the “Indy Tails Server,” which is basically a web server for tails files. Holders get the tailsLocation during the issuance process, download the TAILS_FILE (ideally) once and cache it for use when generating proofs of non-revocation when creating a presentation that uses its revocable verifiable credential. How the TAILS_FILE is used is covered elsewhere in this specification:

§ Revocation Registry Definition Object Generation

In addition to generating the Revocation Registry object, a Private Revocation Registry object is generated and securely stored by the issuer. The data model and definition of the items in the Private Revocation Registry is as follows:

TODO

To Do: Fill in the details about the Revocation Registry Definition

§ Publishing the Revocation Registry Object

Once constructed, the Revocation Registry is published by the issuer in a Verifiable Data Registry using the issuer’s AnonCreds Objects. For example, see this Revocation Registry that is published on the Sovrin MainNet instance of Hyperledger Indy. The binary TAILS_FILE associated with the Revocation Registry can be downloaded from the tailsLocation in the Revocation Registry object.

§ Creating the Initial Revocation Status List Object

Published Revocation Status List objects contain the state of the Revocation Registry at a given point in time such that holders can generate a proof of non-revocation (or not) about their specific credential and verifiers can verify that proof. An initial Revocation Status List is generated and published immediately on creation of the Revocation Registry so that it can be used immediately by holders. Over time, additional Revocation Status List objects are generated and published as the revocation status of one or more credentials within the Revocation Registry change.

A secure process must be run to create the initial Revocation Status List object, taking the following input parameters.

The process collects from the identified Private Revocation Registry information to calculate the cryptographic accumulator value for the initial Revocation Status List, including:

With the collected information, the initial cryptographic accumulator for the Revocation Registry can be created. The format of the identifier for the Revocation Status List is dependent on the AnonCreds Objects Method used by the issuer.

In simple terms, the cryptographic accumulator at any given point in time is the (modulo) product of the primes for each non-revoked credential in the Revocation Registry.

If all of the credentials are initially revoked (revocationList only contains 1 values), the accumulator value is 0.

The accumulator is calculated using the following steps:

TODO

To Do: Adding the algorithm for calculating the accumulator

THe following is an example of an initial, published Revocation Status List object:

{
  "revRegDefId": "4xE68b6S5VRFrKMMG1U95M:4:4xE68b6S5VRFrKMMG1U95M:3:CL:59232:default:CL_ACCUM:4ae1cc6c-f6bd-486c-8057-88f2ce74e960",
  "revocationList": [0, 1, 1, 0],
  "currentAccumulator": "21 124C594B6B20E41B681E92B2C43FD165EA9E68BC3C9D63A82C8893124983CAE94 21 124C5341937827427B0A3A32113BD5E64FB7AB39BD3E5ABDD7970874501CA4897 6 5438CB6F442E2F807812FD9DC0C39AFF4A86B1E6766DBB5359E86A4D70401B0F 4 39D1CA5C4716FFC4FE0853C4FF7F081DFD8DF8D2C2CA79705211680AC77BF3A1 6 70504A5493F89C97C225B68310811A41AD9CD889301F238E93C95AD085E84191 4 39582252194D756D5D86D0EED02BF1B95CE12AED2FA5CD3C53260747D891993C",
  "timestamp": 1669640864487
}

The items in the data model are:

§ Publishing the Initial Initial Revocation Status List Object

Once constructed, the initial Revocation Status List is published by the issuer in a Verifiable Data Registry using their selected AnonCreds Objects Method.

It is not required for the Verifiable Data Registry to store the revocation list as defined in this model. For example, the Indy ledger uses deltas (Revocation Registry Entries) to store the change in revoked/un-revoked indices instead of storing the entire revocation list. It is also possible to compress the revocationList entry using e.g. GZIP to reduce the size on the ledger.

To prepare to use AnonCreds credentials, the Holder must create a link secret, a unique identifier that allows credentials issued to a Holder to be bound to that Holder and presented without revealing a unique identifier, thus avoiding correlation of credentials by Verifiers. The link secret is kept private by the Holder. The link secret is used during the credential issuance process to bind the credential to the holder and in the generation of a presentation. For the latter, it allows the holder to create a zero knowledge proof that they were issued the credential.This proof demonstrates knowledge the link secret and prove that it is one of the signed credential attributes, without revealing the link secret to the verifier. The details of how the link secret is used to do this is provided in the issuance, presentation generation and verification sections of this specification.

The link secret is a sufficiently random unique identifier. For example, in the Hyperledger Indy implementation, the link secret is produced by a call to the Rust uuid Crate’s new_v4() method to achieve sufficient randomness.

Once generated, the link secret is stored locally by the Holder for use in subsequent issuance and presentation interactions. If lost, the Holder will not be able to generate a proof that the credential was issued to them. The holder generates only a single link secret, using it for all credentials the holder is issued. This allows for verifiers to verify that all of the credentials used in generating a presentation with attributes from multiple credentials were all issued to the same Holder without requiring the Holder to disclose the unique identifier (link secret) that binds these credentials together.

There is nothing to stop a Holder from generating multiple link secrets and contributing them to different credential issuance processes. However, doing so prevents the Holder from producing a presentation combining credentials issued to distinct link secrets that can be proven to have been issued to the same entity. It is up to the Verifier to require and enforce the binding between multiple credentials used in a presentation.

§ AnonCreds Issuance Data Flow

The issuance of an anonymous credential requires several steps and involves the roles issuer, holder as well as the Verifiable Data Registry (see diagram below).

sequenceDiagram autonumber participant L as Verifiable
Data Registry participant I as Issuer participant H as Holder I ->> I: Create Credential Offer I ->> H: Send Credential Offer H ->> H: Verify Credential Offer opt H ->> L: Request Schema L ->> H: Return Schema end H ->> L: Request Credential Definition L ->> H: Return Credential Definition H ->> H: Create Credential Request H ->> I: Send Credential Request I ->> I: Verify Credential Request I ->> I: Issue Credential I ->> H: Send Credential H ->> H: Remove Credential Blinding H ->> H: Verify and Store Credential rect rgb(191, 223, 255) Note left of H: 💡The "Verifier" and "Schema Publisher" roles are
omitted in this diagram, since they do not participate
in the credential issuance data flow. end

The issuer prepares a Credential Offer for the holder (step 1). A Credential Offer includes a commitment about the credential (referencing a Public Credential Definition) the issuer is intending to issue to the holder. The issuer sends the Credential Offer to the holder (step 2), who evaluates the offer (step 3) and fetches data about the offer (the Public Credential Definition) from the Verifiable Data Registry (steps 4-7).

Using the data from the Credential Offer and the Public Credential Definition retrieved from the Verifiable Data Registry, the holder prepares a Credential Request (step 8), a formal request to the issuer to issue a credential based on the given Public Credential Definition to the holder. The Credential Request includes a cryptographic commitment to the holder's link secret. The holder sends the Credential Request to the issuer (step 9).

The issuer verifies and decides whether to accept the Credential Request (step 10) and if so, prepares the credential (step 11). The issuer sends the credential to the holder (step 12). The holder then removes the blinding factor from the credential (step 13), verifies the credential and (usually) securely stores it (step 14).

Details about each step in the issuance process are covered in the following sections.

§ Credential Offer

The AnonCreds issuance process begins with the issuer constructing and sending a Credential Offer to the potential holder. The Credential Offer contains the following JSON elements:

{
    "schema_id": string,
    "cred_def_id": string,
    "nonce": string,
    "key_correctness_proof" : <key_correctness_proof>
}

The JSON content of the key_correctness_proof is:

"key_correctness_proof": {
    "c": "103...961",
    "xz_cap": "563...205",
    "xr_cap": [
        [
            "<attribute 1>",
            "821...452"
        ],
        [
            "master_secret",
            "156...104"
        ],
        [
            "<attribute 1>",
            "196...694"
        ]
    ]
}

The values in the proof are generated as follows:

c=H(zriz~ri~)c = H(z || {r_i} || \tilde{z} ||\tilde{r_i})

where

Both xz_cap and the second element in the tuple of the xr_cap vector are BigNumbers.

The issuer sends the Credential Offer to the holder.

§ Credential Request

A Credential Request is a formal request from a holder to an issuer to get a credential based on the Credential (and the referenced Public Credential Definition) sent by the issuer to the holder.

On receipt of the Credential Offer, the holder retrieves the referenced Public Credential Definition from a Verifiable Data. The holder MAY want to retrieve the Schema referenced in the Credential Offer and verify the consistency between the list of attributes in the Schema and in the Public Credential.

In addition, the holder also requires access to their link.

The nonce of the Credential Offer is used to generate the proof of correctness for blinded credential secrets, where it is hashed with the blinded secrets to create the proof which is sent to the issuer.

§ Verifying the Key Correctness Proof

The holder must first verify the key_correctness_proof in the Credential Offer using data from the referenced Public Credential Definition. The key_correctness_proof data is described in the previous section about the Credential Offer.

The key_correctness_proof verification is as follows:

  1. Check that all attributes in Public Credential Definition and master_secret (an attribute that will be related to the link secret) are included in xr_cap.
  2. Compute cc', where c=H(zriz^ri^)c' = H(z || {r_i} || \hat{z'} ||\hat{r_i'}).
  3. If z^==z~\hat{z'} == \tilde{z} and ri^==ri~\hat{r_i'} == \tilde{r_i}, then c==cc' == c. The proof is accepted.

For z^\hat{z'}, we first find the multiplicative inverse of zz

z1z=1 (Mod n)z^{-1}z = 1\ (Mod\ n)

Then

z^=zcsxz^ (Mod n)\hat{z'} = z^{-c} s^{\hat{x_z}} \ (Mod\ n)

=zcscxz+xz~ (Mod n)= z^{-c} s^{cx_z + \tilde{x_z}}\ (Mod\ n)

=zczcsxz~ (Mod n)= z^{-c} z^{c} s^{\tilde{x_z}}\ (Mod\ n)

z^=z~\hat{z'} = \tilde{z}

The same can be derived for all ri^\hat{r_i'} by finding the multiplicative inverse of rir_i, where {1 < i < L} for LL attributes.

§ Constructing the Credential Request

The holder constructs the following Credential Request JSON structure:

{
    "prover_did": "BZpdQDGp2ifid3u3Up17MG",
    "cred_def_id": "GvLGiRogTJubmj5B36qhYz:3:CL:8:faber.agent.degree_schema",
    "blinded_ms": {
        # Structure detailed below
    },
    "blinded_ms_correctness_proof": {
        # Structure detailed below
    },
    "nonce": "604812518357657692681285"
}

Once constructed, the holder sends the Credential Request to the issuer, who then can reply to the holder by sending an issued credential.

The holder generates a blinding factor and uses this to create a cryptographic commitment to their link secret. This is the blinded_ms (blinded link secret) in the Credential Request. The blinded_ms will be signed by the issuer along with the rest of the credential attributes to create a blinded Signature. The holder removes the blinding factor from the blinded Signature to retrieve the Credential Signature over their unblinded link secret and the credential attributes.

During presentations, the holder can prove knowledge of the link secret within credential or set of credentials being presented, without revealing the link secret itself. This is the capability that enables the binding of the credentials to each other and to the holder without revealing a correlatable identifier.

TODO

Confirm purpose of the blinding factor and add how it is generated.

The blinding factor is a secret generated by the holder for blinding the link secret before sending it to the issuer. The blinding factor, vv is created by selecting a random integer that is less than the order of the RSA group, n.

The process of blinding the link secret uses the issuer's CredentialPrimaryPublicKey, PP, which is included in the Public Credential Definition, and contains z, r, s and n (described here). While r contains the public keys for all of the attributes to be signed, the only one of interest in this process is rlinksecretr_{link_secret}

The link secret, AlA_l is blinded by

Abl=rlinksecretAl Mod nA_{bl} = r_{link secret}^{A_l}\ Mod\ n

AblA_{bl} is multiplied by the blinding factor, vv',

(sv×Abl) Mod n(s^{v'} \times A_{bl})\ Mod\ n

The resulting blinded link secret data structure inserted into the Credential Offer is defined as follows:

"blinded_ms": {
    "u": "331...544",
    "ur": null,  # Populated when the credential definition supports revoation
    "hidden_attributes": [
        "master_secret"
    ],
    "committed_attributes": {}
}

Where:

In addition to creating the blinded link secret, the holder also creates a blinded link secret correctness proof and inserts it into the Credential Request. The data structure for the blinded link secret correctness proof is as follows:

"blinded_ms_correctness_proof": {
    "c": "702...737",
    "v_dash_cap": "202...924",
    "m_caps": {
        "master_secret": "907...913"
    },
    "r_caps": {}
}

The values in the proof are generated as follows:

c=H(uu~n0)c = H(u || \tilde{u} || n_0)

where

§ Issue Credential

After the issuer receives the Credential Request from the holder, the issuer processes the Credential Request and decides whether to issue the credential as requested in the Credential Request to the holder. In this section, we’ll cover issuing a credential that cannot be revoked, and then cover the additional steps/data elements in issuing a credential that can be revoked.

§ Verifying the Credential Request

Before deciding to issue the credential, the issuer must first verify the Credential Request from the holder by using the nonce from credential offer (n0n_0) to verify the blinded link secret correctness proof.

The blinded_ms_correctness_proof is verified by issuer. The blinded_ms_correctness_proof verification is as follows:

  1. Compute cc', where c=H(uu^n0)c' = H(u || \hat{u} || n_0).
  2. If u^==u~\hat{u} == \tilde{u}, then c==cc' == c. The proof is accepted.

For u^\hat{u}, we first find the multiplicative inverse of uu

u1u=1 (Mod n)u^{-1}u = 1\ (Mod\ n)

Then

u^=uc×rlinksecretm^×sv^ (Mod n)\hat{u} = u^{-c} \times r_{linksecret}^{\hat{m} } \times s^{\hat{v'}} \ (Mod\ n)

=uc×rlinksecretAl~+cAl×sv~+cv (Mod n)= u^{-c} \times r_{linksecret}^{\tilde{A_l}+ cA_l } \times s^{ \tilde{v'} + cv'}\ (Mod\ n)

=uc×uc×rlinksecretAl~×sv~ (Mod n)= u^{-c} \times u^{c} \times r_{linksecret}^{\tilde{A_l}} \times s^{\tilde{v'}}\ (Mod\ n)

u^=u~\hat{u} = \tilde{u}

Once the Credential Request is verified and if the issuer decides to proceed with issuing the credential, the credential creation process is performed.

§ Encoding Attribute Data

The Anoncreds signature is not applied on the data attributes themselves, but rather on 32-byte integers encoded from the data attribute values. In the current version of AnonCreds, the process of encoding the attributes (also known as canonicalization) is a task performed by the issuer, who should do the encoding in a manner understood by all potential verifiers such that any verifier can confirm that the revealed raw attributes in the presentation produce the encoded value signed by the issuer. To enable the broadest possible interoperability, the Hyperledger Aries community formalized the following encoding rules for the raw attribute values in an AnonCreds credential, and those rules are adopted into this specification, as follows:

An example implementation in Python of these rules can be found here.

A gist of test value pairs can be found here.

NOTE

To enable broad interoperability, and to improve the security of AnonCreds by eliminating the risk of malicious holders altering the raw data values in hopes that the verifier will not check the encoding as part of the overall presentation verification, future versions of AnonCreds credentials will not include issuer-created encoded values in the AnonCreds credentials, and will instead require the encoding of the raw data values on as needed basis.

Implementations of AnonCreds MAY

  • Verify the encoded values provided by the issuer and reject the credential input if the encoding does not follow the encoding rules in this specification.
  • Ignore the issuer-provided encoded values and calculate the encoded values before generating signatures based on the encoding rules above.
  • Ignore the encoded values placed in credentials and/or presentations and generate the encoded values “on-the-fly” based on the encoding rules above.

§ Constructing a Credential

To construct a non-revocable credential, the issuer must have available:

Additional data is needed for issuing a revocable credential, as described in the section Supporting Revocation in a Credential.

The JSON of a generated AnonCreds credential is as follows:

{
    "schema_id": string,
    "cred_def_id": string,
    "rev_reg_id": null,
    "values": {
        "first_name": {
            "raw": "Alice",
            "encoded": "113...335"
        },
        "last_name": {
            "raw": "Garcia",
            "encoded": "532...452"
        },
        "birthdate_dateint": {
            "raw": "19981119",
            "encoded": "19981119"
        }
    },
    "signature": {
        "p_credential": {
            "m_2": "992...312",
            "a": "548...252",
            "e": "259...199",
            "v": "977...597"
        },
        "r_credential": null
    },
    "signature_correctness_proof": {
        "se": "898...935",
        "c": "935...598"
    },
    "rev_reg": null,
    "witness": null
}

Once constructed, the issuer sends the credential to the holder for verification and storage.

NOTE

Please note the data attribute “birth_dateint” in the example above. The convention of putting a _dateint suffix on a credential attribute name is used to indicate that the field contains a date in the form of an integer, such as “2022.11.21” as the integer “20221121” (the number 20,221,121). By putting the date in that form, AnonCreds predicates can be applied to the data, such as proving “older than 21” based on date of birth without sharing the date of birth. This convention was initially defined here by the Hyperledger Aries community.

§ The Credential Signature

The credential signature elements are constructed as follows:

  1. Compute q=Zusvrlinksecretm (Mod n)q = \frac{Z}{us^{v''}r^{m}_{linksecret}\ (Mod\ n)} where vv'' is a random 2724-bit number with most significant bit as 11 and ee is a random prime such that 2596e2596+21192^{596} \leq e \leq 2^{596}+2^{119}
  2. Compute a=qe1 (Mod pq) (Mod n)a = q^{e^{-1}\ (Mod\ p'q')}\ (Mod\ n) where p,qp', q' are primes generated during issuer setup, and e1e^{-1} is the multiplicative inverse of ee.
  • m_2 is a linkable identifier to the holder encoded in base 10 that is also called the master_secret in old versions. It is constructed as follows:
    • m2=H(iH)m_2 = H(i || \mathcal{H}), where ii is an index assigned to the holder, and H\mathcal{H} is an identifier with which the holder is known to the issuer.
  • a is the signature of the blinded known attributes. It’s generation is given above.
  • e is a random prime generated by the issuer for creating signature.
  • v is a number generated by the holder to unblind the signature of the blinded attributes. It is constructed as follows:
    • v=v+vv = v' + v'', where vv' is the blinding factor which the holder has and vv'' is a random number generated by the issuer.

§ The Credential Signature Correctness Proof

The credential signature correction proof elements are constructed as follows:

Using random r<pqr<p'q', compute

a^=qr(Mod n)\hat{a} = q^r (Mod\ n)

c=H(qaa^n1)c = H(q||a||\hat{a}||n_1)

where n1n_1 is the nonce from credential request and HH is SHA-256 hashing algorithm. Signature correctness proof se=rce1(Mod pq)s_e = r - ce^{-1} (Mod\ p'q').

  • se is the credential signature correctness proof.
  • c is the witness for the credential signature correctness proof.

§ Supporting Revocation in a Credential

When a credential is revocable, in addition to the listed inputs needed for constructing a credential, the issuer also needs the ID and private Revocation Registry data. Using the inputs, the revocation-related fields in the credential JSON are populated. The following describes the elements and how they are produced.

rev_reg_id is the ID of the Revocation Registry Definition published on a Verifiable Data Registry that is to be used by the holder when trying to generate a Non-Revocation Proof for this credential as part of an AnonCreds presentation.

r_credential is the following JSON data structure:

"r_credential": {
    "sigma": "1 14C...8A8",
    "c": "12A...BB6",
    "vr_prime_prime": "0F3...FC4",
    "witness_signature": {
        "sigma_i": "1 1D72...000",
        "u_i": "1 0B3...000",
        "g_i": "1 10D...8A8"
    },
    "g_i": "1 10D7...8A8",
    "i": 1,
    "m2": "FDC...283"
}

The items in the data structure are:

  • c: is a random number belonging in the group G2 (Mod q)(Mod\ q)
  • vr_prime_prime: is also a random number belonging in the group G2 (Mod q)(Mod\ q)
  • sigma: is calculated as

σ=(h0h1m2 . ur . gi . h2vr)1x+c\sigma = (h_0h_1^{m_2}\ .\ u_r\ .\ g_i\ .\ h_2^{v_r''})^{\frac{1}{x+c}}

where h0h_0, h1h_1 are from revocation public key, uru_r is from the blinded credential secrets, gi=gγig_i = g^{\gamma^i} where ii is the issuer’s accumulator index, h2h_2 is from revocation public key, and xx is from the revocation private key.

  • witness_signature:
    • sigma_i: is calculated as g1sk+γig'^{\frac{1}{sk+\gamma^i}}
    • u_i: is uγiu^{\gamma^i}
    • g_i: is a point in curve G1 which calculated by gγig^{\gamma^i}
  • g_i: is a point in curve G1 which calculated by gγig^{\gamma^i}
  • i: ii is the issuer’s accumulator index
  • m2: is the credential context which acts as a linkable identifier to the holder.

rev_reg is the following JSON data structure:

"rev_reg": {
    "accum": "21 118...1FB"
}

The item in the data structure is:

  • accum: is the accumulator value of the issuer which is updated with the new tails point as soon as new revocation credential is generated, and published to the public ledger.

witness is the following JSON data structure:

"witness": {
    "omega": "21 124...AC8"
}

The item in the data structure is:

  • omega: is calculated by jVgL+1j+i\prod\limits_{j \in V} g'_{L+1-j+i} where VV is the current set of non revoked indices and LL is the number of indices contained in the accumulator.

§ Receiving a Credential

On receipt of a credential from an issuer, the holder must verify the credential and, if verified, will likely store the credential in a secure location.

To verify the signature_correctness_proof, the holder does the following:

  • Verify that ee is a prime and lies within it’s range.
  • Compute

qZSiinCsRimi(Mod n)q \leftarrow \frac{Z}{S \prod\limits_{i in C_s} R_i^{m_i}} (Mod\ n)

  • Verify q=ae(Mod n)q = a^e (Mod\ n)
  • Compute a^ac+se.e(Mod n)\hat{a} \leftarrow a^{c + s_e.e}(Mod\ n)
  • Verify c=H(qaa^n1)c' = H(q || a || \hat{a} || n_1)

The verifying and securely storing of the credential by the holder completes the AnonCreds issuance process.

An AnonCreds credential is expected to be retained by the holder that participated in the issuance process. The holder should not transfer the credential to others for their use, and should only use the credential to generate an AnonCreds verifiable presentation, as outlined in the AnonCreds Presentation section of this specification.

§ AnonCreds Presentation Data Flow

sequenceDiagram autonumber participant L as Verifiable
Data Registry participant SP as Schema Publisher participant I as Issuer participant H as Holder participant V as Verifier Note over L, V: AnonCreds Presentation Data Flow V->>V: Create presentation request V->>H: Send presentation request H->>H: Select credentials to satisfy the presentation request H->>L: If necessary: Request revocation entries L->>H: Return revocation entries H->>H: Generate presentation H->>V: Send presentation V->>L: Request credential definitions, revocation entries L->>V: Return credential definitions, revocation entries V->>V: Verify presentation

The flow of operations to request, create, and verify a verifiable presentation is illustrated in the AnonCreds Presentation Data Flow sequence diagram.

The Verifier starts the process in step 1 by creating and sending a presentation request to the Holder.

In step 2, the Verifier sends the presentation request to the Holder.

In steps 3-6, the Holder collects the required information and creates the verifiable presentation to satisfy the presentation request received from the Verifier. If the Holder does not have the necessary credentials to satisfy the request, the Holder may ignore the presentation.

In step 7, the Holder sends the verifiable presentation according to the presentation request to the Verifier.

In step 8-10, the Verifier collects the required information and verifies the verifiable presentation and accepts it if the signature is valid, otherwise rejects the verifiable presentation.

TODO

Question: VDR access for schema, revocation etc. retrieval mandatory?

§ Create Presentation Request

The verifier starts the presentation process in step 1 of the AnonCreds Presentation Data Flow by creating and sending a presentation to the holder.

The presentation request provides information about the attributes and predicates the verifier is asking the the holder to reveal, restrictions on what verifiable credentials can be the sources for the attributes and predicates, and limitations on the freshness of the credential revocation status. Presentation requests are defined at the “business logic” layer, with any cryptographic processing applied. The verification process includes verifications that the presentation satisfies the request. The verifier SHOULD validate that the presentation satisfies the business requirements for which the presentation was provided.

In reading this section, the term attribute is used in two ways, and readers should be aware of the context of each use. A presentation request has **requested attributes that are to be included in the presentation provided from the holder. Those requested attributes in turn reference attribute names and values from source verifiable credentials held by the holder.

The presentation request is created by the verifier in JSON format, as follows:

{
    "name": string,
    "version": string,
    "nonce": string,
    "requested_attributes": {
        "<attr_referent>": <attr_info>,
        ...,
    },
    "requested_predicates": {
        "<predicate_referent>": <predicate_info>,
        ...,
     },
    "non_revoked": Optional<non_revoc_interval>,
    "ver": Optional<str>
}

attr_info has the following format:

{
    "name": <string>,
    "names": <[string, string]>,
    "restrictions": <restrictions>,
    "non_revoked": <non_revoc_interval>,
}

All of the items are optional, but one of name or names MUST be included, and not both.

predicate_info has the following format:

{
    "name": string,
    "p_type": string,
    "p_value": int,
    "restrictions": <restrictions>,
    "non_revoked": <non_revoc_interval>,
}

§ Restrictions

The restrictions item on attributes (optional) and predicates (required) is a JSON structure that forms a logical expression involving properties of the source verifiable credential. The holder must use source verifiable credentials that satisfy the restrictions expression for each attribute/predicate entry. Each element of the logic expression is a property of source credentials and a value to be matched for that property. The following properties can be specified in the JSON. All except the marker property is specified with a value that must match the property. For the marker property, the value is always 1.

A boolean expression is formed by ORing and ANDing the source credential properties. The following JSON is an example. Any of the source credential properties listed above can be used in the expression components:

      "restrictions": [
        {
          "issuer_did": "<did>",
          "schema_id": "id"
        },
        {
          "cred_def_id" : "<id>",
          "attr::color::marker": "1",
          "attr::color::value" : "red"
        }
      ]

The properties in each list item are AND’d together, and the array elements are OR’d together. As such, the example above defines the logical expression:

The attributes must come from a source verifiable credential such that:
   issuer_did = <did> AND
     schema_id = <id>
   OR
   cred_def_id = <id> AND
      the credential must contain an attribute name "color" AND
      the credential must contain an attribute name "color" with the attribute value "red"

§ Request Non-Revocation Proofs

The presentation request JSON item non_revoked allows the verifier to define an acceptable non-revocation interval for a requested attribute(s) / predicate(s), as follows:

{
    "from": Optional<int>,
    "to": Optional<int>,
}

As noted in the presentation request specification above, a non-revoked item be may at the outer level of the presentation request such that it applies to all requested attributes and predicates, and/or at the attribute/predicate level, applying only to specific requested attributes and/or predicates and overriding the outer layer item.

The non-revoked items apply only to requested attributes/predicates in a presentation that derive from revocable credentials. No proof of non-revocation is needed (or possible) from credentials that cannot be revoked. Verifiers should be aware that different issuers of the same credential type (same schemaId) may or may not use revocation for the credentials they issue.

The use of a “non-revoke interval” was designed to have the semantic meaning that the verifier will accept a non-revocation Proof (NRP) from any point in the from to to interval. The intention is that by being as flexible as the business rules allow, the holder and/or verifier may have cached VDR revocation data such that they don’t have to go to the VDR to get additional RevRegEntry data. The verification of the provided non-revocation interval in a presentation request is limited. For additional details, see the Verify Non-Revocation Proof section of this specification.

In practice, the use of the interval is not well understood and tends to cause confusion amongst those building presentation requests. The AnonCreds community recommends using matching from and to values as outlined in the Aries RFC 0441 Present Proof Best Practices. The verifier can then use business rules (outside of AnonCreds) to decide if the revocation is sufficiently up to date.

While one might expect the to value to always be the current time (“Prove the credential is not revoked now”), its inclusion allows the verifier to ask for a non-revocation proof sometime in the past. This addresses use cases such as “Prove that your car insurance policy was not revoked on June 12, 2021 when the accident occurred.”

§ Presentation Request Example

The following is an example of a full presentation request for a presentation for a set of revealed attribute names from a single source credential, a self-attested attribute, and a predicate.

{
   "nonce":"168240505120030101",
   "name":"Proof of Education",
   "version":"1.0",
   "requested_attributes":{
      "0_degree_uuid":{
         "names":[
            "name",
            "date",
            "degree"
         ],
         "restrictions":[
            {
               "schema_name":"degree schema"
            }
         ]
      },
      "0_self_attested_thing_uuid":{
         "name":"self_attested_thing"
      },
      "non_revoked": {
        "from": 1673885735,
        "to": 1673885735,
      }
   },
   "requested_predicates":{
      "0_age_GE_uuid":{
         "name":"birthdate_dateint",
         "p_type":"<=",
         "p_value":20030101,
         "restrictions":[
            {
               "schema_name":"degree schema"
            }
         ]
      }
   }
}

In step 2 of the AnonCreds Presentation Data Flow, the verifier sends the presentation request to the holder.

§ Generate Presentation

In step 3, 4, and 5 of the AnonCreds Presentation Data Flow, the holder collects the required information to create the verifiable presentation according to the presentation request received from the verifier.

Each attribute and predicate in the presentation request must be satisfied by a source credential held by the holder that meets the associated restrictions item in the presentation request. The same source credential MAY be used to satisfy multiple attributes and predicates. Each attribute in the presentation request may specify (using the names item) that multiple claims from the source credential must be shared. If there is no restrictions item in the presentation request, the holder MAY satisfy the presentation request with self-attested attributes.

NOTE

To prevent confusion, the term “attribute” in this section always refers to the required_attributes in a presentation request, and the term “claim” is used for the data elements in a verifiable credential.

The verifier may specify in the presentation request that if some or all of the attributes/predicates are to be satisfied by revocable credentials, the holder must accompany the verifiable credential proofs with non-revocation proofs (NRPs) for the source credentials. The generation of NRPs is described in the generate non-revocation proofs section of the specification.

NOTE

Often in discussions about verifiable presentations, the term “prover” is used to indicate the participant generating the presentation. Throughout the Hyperledger AnonCreds implementation the term prover is used in the names of methods performed by that participant. However, because in AnonCreds the holder and the prover are always the same entity, we’ll use holder to refer to the participant generating the requested presentation to emphasize that the same entity is both issued credentials and generating presentations from those credentials.

§ Collecting the Source Verifiable Credential Data

Before the holder can generate the presentation to satisfy a request, the source verifiable credentials that will be used in the presentation must be collected.

The source verifiable credentials found for use in generating a presentation must meet the following requirements:

The mechanism to find the credentials in the holder’s wallet that satisfy a presentation request is outside the scope of this specification. As such, the remainder of this section covering how this process is done in Hyperledger Aries implementations is non-normative.

Aries implementations have historically used a mechanism called Wallet Query Language (WQL) to find the source credentials in the holder agent’s storage. Agents iterate through the presentation request attributes and predicates, converting the restrictions item from each into a corresponding WQL query, and calling an Aries key management service, such as Aries Askar, to return the credentials in the wallet that satisfy the query.

Completing the process results in a list of 0 or more source verifiable credentials that satisfy each attribute and predicate. If there is not a source verifiable credential for each, a business process must be invoked to decide if or how to proceed. For example, if some of the attributes or predicates cannot be satisfied with a credential already in the holder's storage, a process to get the necessary additional verifiable credentials may be initiated. If more than one verifiable credential satisfy any of the restrictions items, the holder software might select one to use by default, such as the most recently issued, non-revoked of the credentials, and/or might invoke a user interface to allow the entity that controls the holder software to select from the set of possible credentials to use.

In order to proceed to the presentation generation step, there must be one credential selected for each attribute and predicate in the presentation request.

§ Prepare Inputs to Presentation Generator

The next step of the process to create a presentation is to prepare the inputs to a call to AnonCreds to generate the presentation. The following are the inputs to the generation process (implementation). The holder must prepare each of the inputs by getting data either from local storage or, in the case of public data, retrieving it from the appropriate verifiable data registry(ies). AnonCreds implementations may provide functions to help in preparing some of the data.

The credentials data structure contains for each listed credential:

If the credential is not revocable, the latter two inputs are null, and are not used. See the later section on generating a presentation for a revocable credential for details about populating the timestamp and witness data elements.

The indicator of whether a claim is to be revealed or not in AnonCreds 1.0 must be carefully understood by verifiers. While a verifer requests a set of claims from the prover, the prover may choose to not reveal the raw value of some of those claims. If the prover does not reveal all of the requested claims, AnonCreds treats the presentation as cryptographically verified. It is then up to the verifier to decide, after cryptographic verification, if a presentation with unrevealed values is acceptable for the business purpose of the presentation.

§ Generate the Presentation

From the inputs, the presentation data is generated and put into the following data structure:

The following is an example of a multi-credential presentation without revocation.

TODO

Replace this example with one that includes:

  • two request attributes
  • one predicate request
  • one unrevealed attribute
  • one self-attested attribute
EXAMPLE
{
  "presentation_request": {
    "nonce": "182453895158932070575246",
    "name": "Step 3 Send your Health Information",
    "version": "1.0",
    "requested_attributes": {
      "biomarker_attrs_0": {
        "names": [
          "name",
          "concentration",
          "unit",
          "range",
          "collected_on",
          "biomarker_id",
          "researcher_share"
        ],
        "restrictions": [
          {
            "schema_name": "MYCO Biomarker",
            "attr::name::value": "Iron"
          }
        ]
      },
      "consent_attrs": {
        "restrictions": [
          {
            "schema_name": "MYCO Consent Enablement",
            "schema_version": "0.1.0",
            "attr::jti_unique_identifier::value": "205b1ea0-7848-48d4-b52b-339122d84f62"
          }
        ],
        "name": "jti_unique_identifier"
      }
    },
    "requested_predicates": {}
  },
  "presentation": {
    "proof": {
      "proofs": [
        {
          "primary_proof": {
            "eq_proof": {
              "revealed_attrs": {
                "biomarker_id": "33034450023603237719386825060766757598085121996569112944281451290292212516012",
                "collected_on": "92231735610070911075924224447204218356256133056723930517696107260511721601349",
                "concentration": "10",
                "name": "85547618788485118809771015708850341281587970912661276233439574555663751388073",
                "range": "106828626115908025842177441696860557581575579893927923198365300598359723920768",
                "researcher_share": "101264834079306301897660576123112461042861436742738894013248454492965796383403",
                "unit": "38351211041892038382023569421847544683371072212679556578649761181279472893849"
              },
              "a_prime": "80156520245352052628208149565161465200964633377479145197038408116901327106468493831807000641577246417448908134495822028339761705905365398613527463662816881507291787145610182891716009505407072490691097943029471835157968113065071523597746984296197661560454442163361095634052138951650373193896962906203169809352467024247772052836999799731422581068645748537557874869718897034120634529002420631012358510111427944993245065350416694516913472010105229188198167306183788520891926236449848811955646933539477960935319919207451858981065765523367984374104834278565184338252025155136368869580505679884921590811310587077071610172673",
              "e": "115602723672843258810892161808995599340414281260248127600708536325470178701996999306086286379312077726886107268519700961209712187789855371",
              "v": "1250383260306407741656763352595256748825474237767244783206569756476708112785930898966696687140808011529311298553822794830872826226191807175199015541611342880032928005827271961840046208463350458298210749103878893742434685172894883857423865293195542824393317226300133796527531436931435189766065404966370796699897584860421160155369018136946091524266742514828667575397735892093187106092545876795688095293610064164136737808333322708435913545499149948994191514980395955519036106660001526586674248282052492138917987323789012051794441548696998993861159018178474063785171288325900474499496141522583368982451169653258746506425495702762445790848698570457196767532483566475068200091609719957656394696938689265240025099424248587121592521826940348286940172887963179718337593603053496022182071613592070622825622277436966372346642772481567879001423472517233061740522533372490151585309457871632521280719357505751796940152868034526426510835",
              "m": {
                "master_secret": "3455871040557234123393960708120725061759594951341120214330342075748561632734634451036095543889895409812764789858455375956895105746442946098665140470124325622343440794421325163223",
                "client_share": "4233663763294709836704307308997831519311512039775169744174375585917035614714239153287862168426091336550799195245481707264207548331415960277065672755643752404180562900805493953484"
              },
              "m2": "12942698897200869280316481431207639453433287089474860040781378232999349549981799159560238504559317917040820580596635945161264308025301203452846862479261473387068350544024561412435"
            },
            "ge_proofs": []
          }
        },
        {
          "primary_proof": {
            "eq_proof": {
              "revealed_attrs": {
                "jti_unique_identifier": "46414468020333259158238797309781111434265856695713363124410805958145233348633"
              },
              "a_prime": "52825780315318905340996188008133401356826233601375100674436798295026172087388431332751168238882607201020021795967828258295811342078457860422414605408183505911891895360825745994390769724939582542658347473498091021796952186290990181881158576706521445646669342676592451422000320708168877298354804819261007033664223006892049856834172427934815827786052257552492013807885418893279908149441273603109213847535482251568996326545234910687135167595657148526602160452192374611721411569543183642580629352619161783646990187905911781524203367796090408992624211661598980626941053749241077719601278347846928693650092940416717449494816",
              "e": "40342480172543061520030194979861449480343743039487113094246205723322643070249538229638327935935486373873622430409109409257546971244601965",
              "v": "217871997575635857881367472262154388060800564043554848081521162883333745687724235201324121915821236796357195214089699645741515836727882126142579489701412861659136426497703162695983681701205672924385915403141611021784136285588350763399255203187442277784718461565122805239422370067600654500115262174706580098147603414365915243447789285877195068031630371954678432401446457453517813298670236942253026249413255471803997869331683293818651006043399070308083119054618677128448043841313844695654424369871669436628257531643623230026240200330490039607166147891705813033761093730859310423856156850596341547950105490585959768382544221555877471751940512766452511773683786023245283041103270102119125303027835868565240336923422734962345750992898991606841120358203160628015844345063465293475128118937815965000466081345494616126511595974927544434058100817176268040385848789013718618727873445834393897904247054897801708217939187593785671914",
              "m": {
                "iat_consent_timestamp": "7919242808448912829024078929834347184203169048480606699350973804205285806978474375691141504249426249676222104091995582731720654507393708298132400435805626192291975477967402460279",
                "master_secret": "3455871040557234123393960708120725061759594951341120214330342075748561632734634451036095543889895409812764789858455375956895105746442946098665140470124325622343440794421325163223",
                "data_controller": "16070549690575784944224634793654539357398383214512772967411296056738507137421264813779497172425030465490587794790393434847583852932544021088761347641812155158324233253206392974293",
                "notice": "2790610958721083178459621377821800672322230987466716467063649577108407884592339521820875278264969393963213925568888672412150769438560815981777952572004955362915245795447078373509",
                "sensitive": "13552814315985495030467505807226704038231487014593307078913973520081443107274508887651839292151852713782653522711975492131914644109941607616672243509214979259100892541150351227883",
                "services": "14860984314279608355643170908802532226194914773406547259519961082467311361623076451869406343140860447342041426195737612897540117192702117380288330928866665314831926780606136352645",
                "sub_subject_identifier": "11736177517163751882849070942823049196298287414132249166618760803125435466270948777194044507635346721244111946358927525083691171695431736819244809221351813271261283779276670885101",
                "moc_method_of_collection": "10026360820367693771310999595495505533281326977349798360729122862705999157070660881611421445424239119786180921960380892002204780026072600494332540208429642332890963846523547470729",
                "jurisdiction_data_processing": "15829143141425514118932461858094583045441924952665872659029333578019676797278419825311275014912077620757631693167948665554731430154156737419706553672424812320891308795411687679270",
                "iss_internet_processing_uri": "6900796243066434651671715348976599009606292569990892886896520779618011026060325075822786686418461731663661832508437549373109822105600719490952253743950241384782222356411498407620",
                "version_consent_specification": "7796257942256624260327966366702213561879098947042014532961291550019706546662478888172243088973621029223408695289700984802154645011280488167967047321149956253054269901250137513345",
                "policy_url": "12241676508867847022708464707584814145889660003604359058532137895063826021524887759921830911553663255421852525705197991376264187781979066233701110706958983099645275940668404311601"
              },
              "m2": "6509130065158989037891281073557909501783443634141673890142284302459280804904096303151728187237486991775852971807701594247754409108836089746736345158069365449802597798950172729241"
            },
            "ge_proofs": []
          }
        }
      ],
      "aggregated_proof": {
        "c_hash": "81763443376178433216866153835042672285397553441148068557996780431098922863180",
        "c_list": [
          [
            2,
            122,
            246,
            66,
            85,
            35,
            17,
            213,
            1
          ],
          [
            1,
            162,
            117,
            246,
            95,
            154,
            129,
            32
          ]
        ]
      }
    },
    "requested_proof": {
      "revealed_attrs": {
        "consent_attrs": {
          "sub_proof_index": 1,
          "raw": "205b1ea0-7848-48d4-b52b-339122d84f62",
          "encoded": "46414468020333259158238797309781111434265856695713363124410805958145233348633"
        }
      },
      "revealed_attr_groups": {
        "biomarker_attrs_0": {
          "sub_proof_index": 0,
          "values": {
            "researcher_share": {
              "raw": "bf712cb328a92862b57f0dc806dec12a",
              "encoded": "101264834079306301897660576123112461042861436742738894013248454492965796383403"
            },
            "unit": {
              "raw": "μM",
              "encoded": "38351211041892038382023569421847544683371072212679556578649761181279472893849"
            },
            "concentration": {
              "raw": "10",
              "encoded": "10"
            },
            "name": {
              "raw": "Iron",
              "encoded": "85547618788485118809771015708850341281587970912661276233439574555663751388073"
            },
            "range": {
              "raw": "9.00-30.0",
              "encoded": "106828626115908025842177441696860557581575579893927923198365300598359723920768"
            },
            "collected_on": {
              "raw": "2020-07-05",
              "encoded": "92231735610070911075924224447204218356256133056723930517696107260511721601349"
            },
            "biomarker_id": {
              "raw": "c9ace7dc-0485-4f3f-b466-16a27a80acf1",
              "encoded": "33034450023603237719386825060766757598085121996569112944281451290292212516012"
            }
          }
        }
      },
      "self_attested_attrs": {},
      "unrevealed_attrs": {},
      "predicates": {}
    },
    "identifiers": [
      {
        "schema_id": "CsQY9MGeD3CQP4EyuVFo5m:2:MYCO Biomarker:0.0.3",
        "cred_def_id": "CsQY9MGeD3CQP4EyuVFo5m:3:CL:14951:MYCO_Biomarker"
      },
      {
        "schema_id": "FbozHyf7j5q7TDn2s8MXZN:2:MYCO Consent Enablement:0.1.0",
        "cred_def_id": "TUku9MDGa7QALbAJX4oAww:3:CL:531757:MYCO_Consent_Enablement"
      }
    ]
  }
}

Once the presentation data structure is generated, it is sent to the verifier for processing.

The following describes the data structures listed above, including the process of generating the data of the various types of proofs.

The Presentation Request

The presentation_request is a copy of the presentation_request data structure from the verifier, as described earlier in the specification.

Presentation

The presentation contains:

The presentation data structure is as follows. As noted in the JSON comments included, details for each section of the presentation is provided below.

  "presentation": {
    "proof": {
      "proofs": [
        {
          "primary_proof": {
            "eq_proof": {
              # Described in detail below
            },
            "ge_proofs": [
              # Described in detail below
            ]
          }
        }
      ],
      "aggregated_proof": {
        # Described in detail below
      }
    },
    "requested_proof": {
      # Described in detail below
    }
    "identifiers": {
      # Described in details below
    }
  }

The proofs array contains an entry for each source verifiable credential. For each is a primary_proof covering the claims in the source credential called the eq_proof, and a ge_proof for each of the predicate proofs sourced from the verifiable credential.

Generating the Challenge Hash

For this step the holder follows the following steps:

cHH(T,C,n1)c_H \leftarrow H(\mathcal{T}, \mathcal{C}, n_1)

where n1n_1 is the nonce sent by verifier in proof request.

Each primary eq_proof is generated as follows:

"eq_proof": {
  "revealed_attrs": {
    "jti_unique_identifier": "46414468020333259158238797309781111434265856695713363124410805958145233348633"
  },
  "a_prime": "52825780315318905340996188008133401356826233601375100674436798295026172087388431332751168238882607201020021795967828258295811342078457860422414605408183505911891895360825745994390769724939582542658347473498091021796952186290990181881158576706521445646669342676592451422000320708168877298354804819261007033664223006892049856834172427934815827786052257552492013807885418893279908149441273603109213847535482251568996326545234910687135167595657148526602160452192374611721411569543183642580629352619161783646990187905911781524203367796090408992624211661598980626941053749241077719601278347846928693650092940416717449494816",
  "e": "40342480172543061520030194979861449480343743039487113094246205723322643070249538229638327935935486373873622430409109409257546971244601965",
  "v": "217871997575635857881367472262154388060800564043554848081521162883333745687724235201324121915821236796357195214089699645741515836727882126142579489701412861659136426497703162695983681701205672924385915403141611021784136285588350763399255203187442277784718461565122805239422370067600654500115262174706580098147603414365915243447789285877195068031630371954678432401446457453517813298670236942253026249413255471803997869331683293818651006043399070308083119054618677128448043841313844695654424369871669436628257531643623230026240200330490039607166147891705813033761093730859310423856156850596341547950105490585959768382544221555877471751940512766452511773683786023245283041103270102119125303027835868565240336923422734962345750992898991606841120358203160628015844345063465293475128118937815965000466081345494616126511595974927544434058100817176268040385848789013718618727873445834393897904247054897801708217939187593785671914",
  "m": {
    "iat_consent_timestamp": "7919242808448912829024078929834347184203169048480606699350973804205285806978474375691141504249426249676222104091995582731720654507393708298132400435805626192291975477967402460279",
    "master_secret": "3455871040557234123393960708120725061759594951341120214330342075748561632734634451036095543889895409812764789858455375956895105746442946098665140470124325622343440794421325163223",
    "data_controller": "16070549690575784944224634793654539357398383214512772967411296056738507137421264813779497172425030465490587794790393434847583852932544021088761347641812155158324233253206392974293",
    "notice": "2790610958721083178459621377821800672322230987466716467063649577108407884592339521820875278264969393963213925568888672412150769438560815981777952572004955362915245795447078373509",
    "sensitive": "13552814315985495030467505807226704038231487014593307078913973520081443107274508887651839292151852713782653522711975492131914644109941607616672243509214979259100892541150351227883",
    "services": "14860984314279608355643170908802532226194914773406547259519961082467311361623076451869406343140860447342041426195737612897540117192702117380288330928866665314831926780606136352645",
    "sub_subject_identifier": "11736177517163751882849070942823049196298287414132249166618760803125435466270948777194044507635346721244111946358927525083691171695431736819244809221351813271261283779276670885101",
    "moc_method_of_collection": "10026360820367693771310999595495505533281326977349798360729122862705999157070660881611421445424239119786180921960380892002204780026072600494332540208429642332890963846523547470729",
    "jurisdiction_data_processing": "15829143141425514118932461858094583045441924952665872659029333578019676797278419825311275014912077620757631693167948665554731430154156737419706553672424812320891308795411687679270",
    "iss_internet_processing_uri": "6900796243066434651671715348976599009606292569990892886896520779618011026060325075822786686418461731663661832508437549373109822105600719490952253743950241384782222356411498407620",
    "version_consent_specification": "7796257942256624260327966366702213561879098947042014532961291550019706546662478888172243088973621029223408695289700984802154645011280488167967047321149956253054269901250137513345",
    "policy_url": "12241676508867847022708464707584814145889660003604359058532137895063826021524887759921830911553663255421852525705197991376264187781979066233701110706958983099645275940668404311601"
  },
  "m2": "6509130065158989037891281073557909501783443634141673890142284302459280804904096303151728187237486991775852971807701594247754409108836089746736345158069365449802597798950172729241"
},

Each primary ge_proof is generated as follows:

ge_proofs: [
  {
    u,
    r,
    mj,
    alpha,
    t,
    predicate
  }
]

The aggregated_proof proves that the same linked secret was used to issue all of the source verifiable credentials in the presentation.

The aggregated_proof structure is as follows:

"aggregated_proof": {
        "c_hash": "base10string",
        "c_list": [ ["base10string"] ]
}

Here is an example:

"aggregated_proof": {
        "c_hash": "81763443376178433216866153835042672285397553441148068557996780431098922863180",
        "c_list": [
          [
            2,
            122,
            246,
            66,
            85,
            35,
            17,
            213,
            1
          ],
          [
            1,
            162,
            117,
            246,
            95,
            154,
            129,
            32
          ]
        ]
      }

where:

The requested_proof is the mapping from the presentation request attributes and predicates to the data in the presentation that satisfies the request. This is divided into five parts:

A JSON summary, with comments, for the data in each of the parts is listed below:

Revealed Attributes

An entry for each single name request attribute from the presentation request.

      "revealed_attrs": {
        "consent_attrs": {      # The request attribute name from the presentation request
          "sub_proof_index": 1, # The index of the source credential primary proof for the claim
          "raw": "205b1ea0-7848-48d4-b52b-339122d84f62",  # The raw and encoded claim values
          "encoded": "46414468020333259158238797309781111434265856695713363124410805958145233348633"
        }
      }
NOTE

It is important for all verifiers to understand that the revealed attribute proof (eq_proof described earlier) is a proof on the encoded value, not on the raw value. As such, it is up to the verifier to know the “raw to encoded” algorithm used by the issuer, and to verify that the revealed raw value properly encodes to the proven encoded value. It is possible for a malicious holder to put an unrelated raw value into a presentation to fool a verifier that does not checking the encoding process. In most Aries implementations, the encoding is checked by the Aries framework, as a “post-cryptographic verification” step.

A future version of the AnonCreds specification is likely to do an “on the fly” encoding in AnonCreds rather than including both values in the source credentials and presentations. This would prevent the holder from replacing the raw value without detection.

Revealed Attribute Groups

An entry for each group names request attribute from the presentation request.

      "revealed_attrs": {
        "consent_attrs": {      # The request attribute name from the presentation request
          "sub_proof_index": 1, # The index of the source credential primary proof for the claims
          "values": {           # An entry for the each of the names in the request attribute group
            "claim_name": {     # The name of the claim, its raw and encoded value
              "raw": "205b1ea0-7848-48d4-b52b-339122d84f62",
              "encoded": "46414468020333259158238797309781111434265856695713363124410805958145233348633"
            }
          }
        }
      }

Self Attested Attributes

This is a set any other data that holder wants to provide to the verifier that is not signed by any issuer thus it’s attested only by the holder. This is a set of attributes that the holder is attesting to the verifier. The holder is not claiming that the data is true, only that they are attesting to it.

      "self_attested_attrs": {
        "consent_attrs": "I agree to share my data with the verifier"
      }

Unrevealed Attributes

These are a hashmap of unrevealed attributes that the verifier requested in the presentation request, but the holder has decided not to reveal, along with their sub proof index numbers. The verifier can use the sub proof index numbers to retrieve the corresponding primary proof from the proof array in the presentation.

      "unrevealed_attrs": {
        "consent_attrs": {      # The request attribute name from the presentation request
          "sub_proof_index": 1  # The index of the source credential primary proof for the claim
        }
      }

Predicates

An entry for each predicate request from the presentation request.

      "predicates": {
        "consent_attrs": {      # The request predicate name from the presentation request
          "sub_proof_index": 1, # The index of the source credential primary proof for the claim
        }
      }

Identifiers

The identifiers contains a list of the identifiers to be resolved by the verifier to retrieve the cryptographic material necessary to verify each of the proofs in the presentation. The identifiers are listed in an array with one entry per source verifiable credential, ordered by the proofs list earlier in the presentation.

The data structure is:

    "identifiers": [
      {
        "schema_id": "CsQY9MGeD3CQP4EyuVFo5m:2:MYCO Biomarker:0.0.3",
        "cred_def_id": "CsQY9MGeD3CQP4EyuVFo5m:3:CL:14951:MYCO_Biomarker",
      }
    ]

The example above is for a source credential that is not revocable. For a revocable source credential, the rev_reg_id and timestamp (the identifier for the Revocation Registry Entry used in the non-revocation proof) are added. Those are described in the section below on generation of non-revocation proofs

§ Generate Non-Revocation Proofs

A holder preparing an AnonCreds presentation must determine what, if any, non-revocation proofs (NRPs) must be included the presentation based on a combination of what is in the proof request and what verifiable credentials are to be used in the presentation. As noted in the section on revocation in the presentation request, the presentation request may have the non-revoked item at the outer-most level, applying to all source credentials, or at the requested_attribute and/or requested_predicate level, applying only to specific source credentials. Further, the holder must determine if the source verifiable credential for the requested attributes/predicates where a NRP is requested is a revocable credential. Obviously, an NRP cannot be produced for a verifiable credential issued without that does not support revocation. Where a revocation interval is specified in the request, and where the source credential to satisfy the request is revocable, the holder must provide a non-revocation proof.

Once the holder has determined the which source credentials will required an accompanying NRPs in the presentation, the holder must collect and prepare the necessary proof generation inputs.

§ Collecting Data for Generating the Non-Revocation Proof

Recall from the earlier section on preparing inputs to the presentation generation process that for each revocable source credential, the holder must provide the following data elements:

The witness is an integer that is used in the non-revocation zero knowledge proof to demonstrate to the verifier that the holder’s credential has not been revoked. Recall that the accumulator of a Revocation Registry is the product of the tails file entries for all of the unrevoked credentials in the registry. For a specific holder, its witness is the product of the tails file entries for all of the unrevoked credentials in the registry except for the holder’s own credential. Obviously, if the witness equals the accumulator, the holder’s credential has been revoked. But, if not, then a valid non-revocation proof demonstrates that the witness times the entry from the tails file for the holder’s credential equals the accumulator, without revealing either the witness, the credential’s index, or its tails file entry.

An AnonCreds process is used to calculate the witness value, takes the following inputs:

The holder must use the from and to timestamp revocation interval requirements from the presentation request and knowledge of the Revocation Registry Entries to determine which Revocation Registry to retrieve and use in generating the NRP for a given credential. The selected Revocation Registry Entry must either have been active at the time of the from value or have been published by the issuer between the from and to values. How to determine an appropriate Revocation Registry to use is up to the holder, and their use of the capabilities of the relevant Verifiable Data Registry.

NOTE

When Hyperledger Indy is the Verifiable Data Registry for the Revocation Registry Entry, the state is received from Indy ledger as the “deltas” (state changes) from either the initial state of the Registry or from a previous Revocation Registry Entry. While the older Indy version of AnonCreds used the “deltas” representation directly, the newer AnonCreds version requires that the holder software convert the Indy “deltas” format into the rev_status_list representation, with every credential in the registry is given a revoked or not revoked boolean value.

The benefit of the “full state” representation for Revocation Registry is that the :Verifiable Data Registry can be “dumb”, returning the same static file given to it by the Issuer. With the Indy “deltas” approach, the [[Verifiable Data Registry (VDR)]] must be an active service returning an on-the-fly calculated result based on the inputs of the holder’s request.

In collecting the revocation_list data in the rev_status_list, the holder may discover that their credential has been revoked by the issuer. The holder may choose at that point to stop the presentation process. If the holder decides to proceed, they will not be able to create a valid non-revocation proof for the source credential.

The output of the process is the new witness for a credential that will be used as input to the generate presentation process.

§ Non-Revocation Proof Generation Steps

Init proof generation:

ww.jV\VoldgL+1j+ijVold\VgL+1j+iw \leftarrow w. \frac{\prod_{j \in V \backslash V_{old}} g'_{L+1-j+i}}{\prod_{j \in V_{old} \backslash V} g'_{L+1-j+i}}

Here VoldV_{old} is taken from witiwit_i and updated there.

Ehρho~E \leftarrow h_{ρ}\tilde{h^o}

Dgrh~oD \leftarrow g^r\tilde{h}^{o'}

Aσh~ρA \leftarrow \sigma\tilde{h}^\rho

Ggih~r\mathcal{G} \leftarrow g_i\tilde{h}^r

Wwh^r\mathcal{W} \leftarrow w\hat{h}^{r'}

Sσih^r\mathcal{S} \leftarrow \sigma _i\hat{h}^{r''}

Uuih^r\mathcal{U} \leftarrow u_i\hat{h}^{r'''}

and adds these values to C\mathcal{C}

T1ˉhρ~h~o~\bar{T_1} \leftarrow h^{\tilde{\rho}} \tilde{h} ^ {\tilde{o}}

T2ˉEc~hm~h~t~\bar{T_2} \leftarrow E^{\tilde{c}}h^{-\tilde{m}}\tilde{h}^{-\tilde{t}}

T3ˉe(A,h^)c~.e(h~,h^)r~.e(h~,y)ρ~.e(h~,y)m~.e(h~,y)m2~.e(h~,y)s~\bar{T_3} \leftarrow e(A,\hat{h})^{\tilde{c}}.e(\tilde{h}, \hat{h})^{\tilde{r}}.e(\tilde{h}, y)^{-\tilde{\rho}}.e(\tilde{h}, y)^{-\tilde{m}}.e(\tilde{h}, y)^{-\tilde{m_2}}.e(\tilde{h}, y)^{-{\tilde{s}}}

T4ˉe(h~,acc)r~.e(1/g,h^)r~\bar{T_4} \leftarrow e(\tilde{h}, acc)^{\tilde{r}}.e(1/g, \hat{h})^{\tilde{r'''}}

T5ˉgr~h~o~\bar{T_5} \leftarrow g^{\tilde{r}}\tilde{h}^{\tilde{o'}}

T6ˉDr~gm~h~t~\bar{T_6} \leftarrow D^{\tilde{r''}}g^{-\tilde{m'}}\tilde{h}^{-\tilde{t'}}

T7ˉe(pk.G,h^)r~.e(h~,h^)m~.e(h~,S)r~\bar{T_7} \leftarrow e(pk. \mathcal{G}, \hat{h})^{\tilde{r''}}.e(\tilde{h}, \hat{h})^{-\tilde{m'}}.e(\tilde{h}, \mathcal{S})^{\tilde{r}}

T8ˉe(h~,u)r~.e(1/g,h^)r~\bar{T_8} \leftarrow e(\tilde{h}, u)^{\tilde{r}}.e(1/g, \hat{h})^{\tilde{r'''}}

and add these values to T\mathcal{T}.

ρ^ρ~cHρmodq\widehat{\rho} \leftarrow \widetilde{\rho} - c_H\rho\bmod{q}

o^o~cHomodq\widehat{o} \leftarrow \widetilde{o} - c_H\cdot o\bmod{q}

c^c~cHcmodq\widehat{c} \leftarrow \widetilde{c} - c_H\cdot c\bmod{q}

o^o~cHomodq\widehat{o'} \leftarrow \widetilde{o'} - c_H\cdot o'\bmod{q}

m^m~cHmmodq\widehat{m} \leftarrow \widetilde{m} - c_H m\bmod{q}

m^m~cHmmodq\widehat{m'} \leftarrow \widetilde{m'} - c_H m'\bmod{q}

t^t~cHtmodq\widehat{t} \leftarrow \widetilde{t} - c_H t\bmod{q}

t^t~cHtmodq\widehat{t'} \leftarrow \widetilde{t'} - c_H t'\bmod{q}

m2^m2~cHm2modq\widehat{m_2} \leftarrow \widetilde{m_2} - c_H m_2\bmod{q}

s^s~cHsmodq\widehat{s} \leftarrow \widetilde{s} - c_H s\bmod{q}

r^r~cHrmodq\widehat{r} \leftarrow \widetilde{r} - c_H r\bmod{q}

r^r~cHrmodq\widehat{r'} \leftarrow \widetilde{r'} - c_H r'\bmod{q}

r^r~cHrmodq\widehat{r''} \leftarrow \widetilde{r''} - c_H r''\bmod{q}

r^r~cHrmodq.\widehat{r'''} \leftarrow \widetilde{r'''} - c_H r'''\bmod{q}.

and add them to X\mathcal{X}.

Each NRP is added alongside the credential to which the NRP is applied, to the presentation generated by the holder using this data model:

"non_revoc_proof": {
    "x_list": {
        "rho": "...",
        "r": "...",
        "r_prime": "...",
        "r_prime_prime": "...",
        "r_prime_prime_prime": "...",
        "o": "...",
        "o_prime": "...",
        "m": "...",
        "m_prime": "...",
        "t": "...",
        "t_prime": "...",
        "m2": "...",
        "s": "...",
        "c": "..."
    },
    "c_list": {
        "e": "...",
        "d": "...",
        "a": "...",
        "g": "...",
        "w": "...",
        "s": "...",
        "u": "..."
    }
}

The values in the data model are:

As well, in the presentation data model, added to the identifiers item, is the timestamp (Unix epoch format) of the RevRegEntry used to construct the NRP (see example below). The verifier needs the rev_reg_id and timestamp to get the correct accumulator to use in verifying the NRP.

"identifiers": [
    {
        "schema_id": "7BPMqYgYLQni258J8JPS8K:2:degree schema:46.58.87",
        "cred_def_id": "7BPMqYgYLQni258J8JPS8K:3:CL:70:faber.agent.degree_schema",
        "rev_reg_id": "7BPMqYgYLQni258J8JPS8K:4:7BPMqYgYLQni258J8JPS8K:3:CL:70:faber.agent.degree_schema:CL_ACCUM:61d5a381-30be-4120-9307-b150b49c203c",
        "timestamp": 1656269796
    }
]

In step 6 of the AnonCreds Presentation Data Flow, the holder sends the verifiable presentation, including any embedded NRPs, to the verifier.

Link: indy-anoncreds/docs/dev/anoncred.pdf

§ Verify Presentation

In step 8, 9, and 10 of the AnonCreds Presentation Data Flow, the Verifier collects the required information necessary to verify the verifiable presentation, attempts to verify the proofs that make up the presentation and returns either a true if successful, and a false if any of the proofs fail, or if the presentation does not meet the presentation request.

In the previous section on presentation generation, the contents of the presentation is described. In verifying the presentation, each proof is extracted from the presentation and verified. The following sub-sections cover the verification of the proofs related to the source credentials (the eq_proof, any ge_proofs, and the aggregate_proof), and any non-revocation proofs in the presentation.

For each source credential in the presentation, the Verifier must retrieve (possibly from its cache, otherwise from the VDR) the published Schema and Credential Definition based on the schema_id and cred_def_id values from the identifiers data item. For the non-revocation proof, additional issuer published data must be collected, as described below.

While in this section we mostly focus on the verification of the proofs in the presentation, there are other data elements included, such as the revealed attributes, self-attested attributes, and the Presentation Request for which the presentation was generated. Some of these values contribute to the verification process, as noted below. Finally, an important part of the verification process is not carried out in AnonCreds v1.0 and must be performed by the calling verifier. We highlight that as well.

§ Verify Validity Proofs

An AnoncCreds validity proof is the combination of both equality and inequality predicate proofs. The validity proof is bound to the primary credential by the m2^\widehat{m_2} value that is presented in both proofs. The validity proof is verified by the following steps:

T^(Z(jArRjmj)(A)2596)c(A)e^(j(Ar~)Rjmj^)(Sv^)(modn). \widehat{T} \leftarrow \left( \frac{Z} { \left( \prod_{j \in \mathcal{A}_r}{R_j}^{m_j} \right) (A')^{2^{596}} }\right)^{-c} (A')^{\widehat{e}} \left(\prod_{j\in (\mathcal{A}_{\widetilde{r}})}{R_j}^{\widehat{m_j}}\right) (S^{\widehat{v}})\pmod{n}.

Add T^\widehat{T} to T^\widehat{\mathcal{T}} .

Δ{zj;if  zj1;if  <zj;if  zj+1;if  > \Delta' \leftarrow \begin{cases} z_j; & if\ * \equiv\ \leq z_j-1; & if\ * \equiv\ < z_j; & if\ * \equiv\ \geq z_j+1; & if\ * \equiv\ > \end{cases}

a{1if or<1if or>a \leftarrow \begin{cases} -1 & if\ * \equiv \leq or < 1 & if\ * \equiv \geq or > \end{cases}

Ti^TicZui^Sri^(modn)1i4;TΔ^(TΔaZΔ)cZmj^SarΔ^(modn);Q^(TΔc)i=14Tiui^(Sα^)(modn),\widehat{T_i} \leftarrow T_i^{-c}Z^{\widehat{u_i}} S^{\widehat{r_i}}\pmod{n}_{1\leq i \leq 4}; \widehat{T_{\Delta}} \leftarrow \left(T_{\Delta}^{a}Z^{\Delta'}\right)^{-c}Z^{\widehat{m_j}}S^{a\widehat{r_{\Delta}}}\pmod{n}; \widehat{Q}\leftarrow (T_{\Delta}^{-c})\prod_{i=1}^{4}T_i^{\widehat{u_i}}(S^{\widehat{\alpha}})\pmod{n},

and add these values to T^\widehat{\mathcal{T}} in the order T1^,T2^,T3^,T4^,TΔ^,Q^\widehat{T_1},\widehat{T_2} ,\widehat{T_3},\widehat{T_4},\widehat{T_{\Delta}},\widehat{Q}.

§ Verify Non-Revocation Proof

If the presentation includes one or more Non-Revocation Proofs (NRPs) the verifier must also extract from the verifiable presentation the NRPs and process each of them. If any of the NRPs cannot be verified because one or more of the attributes/predicates came from a revoked credential, the overall status of the presentation is rejected as not verifiable. The following outlines the process for verifying an NRP.

The verifier begins by extracting from the section of the presentation for a given revocable credential the non_revoc_proof and identifiers data items. The verifier must retrieve (possibly from its cache, otherwise from the VDR) the published RevRegEntry given the rev_reg_id and timestamp values from the identifiers data item. The verifier extracts the accumulator item from the RevRegEntry retrieved. Note that the verifier does not need to collect the revocation status of all of the credentials in the registry, nor the contents of the tails file for the RevReg. Only the issuer and holder needs that data. During the verification process, the verifier does not learn the index of the holder's credential in the RevReg.

Once the verifier gets the data in the non_revoc_proof data item from the presentation for the NRP being processed, plus the accumulator from appropriate RevRegEntry, the following steps are carried out to verify the NRP.

Calculation for NRP:

T1^EcHhρ^h~o^\widehat{T_1} \leftarrow E^{c_H}\cdot h^{\widehat{\rho}} \cdot \widetilde{h}^{\widehat{o}}

T2^Ec^hm^h~t^\widehat{T_2} \leftarrow E^{\widehat{c}}\cdot h^{-\widehat{m}}\cdot\widetilde{h}^{-\widehat{t}}

T3^(e(h0G,h^)e(A,y))cHe(A,h^)c^e(h~,h^)r^e(h~,y)ρ^e(h~,h^)m^e(h1,h^)m2^e(h2,h^)s^\widehat{T_3} \leftarrow\left(\frac{e(h_0\mathcal{G},\widehat{h})}{e(A,y)} \right)^{c_H} \cdot e(A,\widehat{h})^{\widehat{c}}\cdot e(\widetilde{h},\widehat{h})^{\widehat{r}}\cdot e(\widetilde{h},y)^{-\widehat{\rho}}\cdot e(\widetilde{h},\widehat{h})^{-\widehat{m}}\cdot e(h_1,\widehat{h})^{-\widehat{m_2}}\cdot e(h_2,\widehat{h})^{-\widehat{s}}

T4^(e(G,acc)e(g,W)z)cHe(h~,acc)r^e(1/g,h^)r^\widehat{T_4} \leftarrow\left(\frac{e(\mathcal{G},\mathrm{acc})}{e(g,\mathcal{W})z}\right)^{c_H} \cdot e(\widetilde{h},\mathrm{acc})^{\widehat{r}}\cdot e(1/g,\widehat{h})^{\widehat{r'}}

T5^DcHgr^h~o^\widehat{T_5} \leftarrow D^{c_H}\cdot g^{\widehat{r}}\widetilde{h}^{\widehat{o'}}

T6^Dr^gm^h~t^\widehat{T_6} \leftarrow D^{\widehat{r''}}\cdot g^{-\widehat{m'}} \widetilde{h}^{-\widehat{t'}}

T7^(e(pkG,S)e(g,g))cHe(pkG,h^)r^e(h~,h^)m^e(h~,S)r^\widehat{T_7} \leftarrow \left(\frac{e(pk\cdot\mathcal{G},\mathcal{S})}{e(g,g')}\right)^{c_H}\cdot e(pk\cdot \mathcal{G},\widehat{h})^{\widehat{r''}}\cdot e(\widetilde{h},\widehat{h})^{-\widehat{m'}}\cdot e(\widetilde{h},\mathcal{S})^{\widehat{r}}

T8^(e(G,u)e(g,U))cHe(h~,u)r^e(1/g,h^)r^\widehat{T_8} \leftarrow \left(\frac{e(\mathcal{G},u)}{e(g,\mathcal{U})}\right)^{c_H}\cdot e(\widetilde{h},u)^{\widehat{r}}\cdot e(1/g,\widehat{h})^{\widehat{r'''}}

Then all these values are added to T^\widehat{T}. This is then added with the validity proof which when hashed with C\mathcal{C} and n1n_1(received from holder) re constructs the challenge hash cH^\widehat{c_H}. If cH^=cH\widehat{c_H} = c_H, then the proof is valid.

The NRP is bound to the primary credential by the m2^\widehat{m_2} value that is presented in both proofs.

The verification code MUST surface to the verifier if any part of the presentation, including any NRP(s), fail cryptographic verification. The verification code MAY surface additional detail about what part of the presentation failed, such as which NRP failed verification (if any).

The verifier SHOULD evaluate the presentation to make sure that the holder provided all requested NRPs. Notably, if any expected NRPs are not received in the presentation, the verifier SHOULD check to see if the given credential type is revocable. If not, it is acceptable that no NRP was received. However, if the credential used in the generation of the proof is revocable, and the holder did not provide the NRP, the verification code SHOULD surface to the verifier that the presentation failed cryptographic verification.

§ Other Verification

The AnonCreds verification code checks some additional non-cryptographic elements of the presentation.

§ Encoding Not Verified

Verifiers using AnonCreds 1.0 MUST verify that revealed attributes presented by the Holder encode to the values signed by the Issuer. AIf not done, a malicious Holder could successfully substitute a different revealed attribute than what the issuer encoded and signed.

As noted in the issuance section of this specification the encoding of raw attribute data to the integers that are actually signed by the Issuer is defined and handled by the Issuer, and is not defined in this specification, nor performed by the implementation. As such, the verification of the encoding is likewise delegated to the Verifier, enabling the risk to the verifier outlined above.

§ AnonCreds Revocation Data Flow

AnonCreds includes a mechanism that supports the revocation of verifiable credentials. This mechanism includes:

A fundamental goal of AnonCreds is to not provide a correlatable identifier for either a holder or a credential as part of generation and verification of an AnonCreds presentation. Applying that goal to revocation means that the revocation mechanism must support the holder proving a credential used in generating a presentation is not revoked without providing a correlatable identifier for that credential or the holder itself. As such, the AnonCreds revocation mechanism uses a Zero Knowledge Proof (ZKP) that allows the holder to prove a credential they hold is not revoked without revealing an identifier for their credential or the holder.

§ AnonCreds Issuer Setup With Revocation

The details of issuer setting up revokable credential types are covered in the issuer setup section of this specification. Note the warning and recommendation against the use of ISSUANCE_ON_DEMAND in that part of the specification.

§ AnonCreds Issuance with Revocation

The details of an issuer issuing a revokable credential to a holder are covered in the issuance data flow section of this specification.

§ AnonCreds Credential Activation/Revocation and Publication

When an issuer decides to revoke a previously issued credential (or activate a previously inactive/revoked credential), they do so by publishing another instance of the RevRegEntry object. Recall from the issuer setup section, the specification about RevRegEntry[creating and publishing the first RevRegEntry](data_flow_setup.md#creating-the-initial-revocation-registry-entry-object) for a RevReg. In that process, the accumulator for the initial state of the RevReg is published. When subsequent RevRegEntry transactions are published to the ledger, each includes an updated value of the accumulator. The update of the accumulator is necessary with each revocation or (re)activation of a credential or set of credentials since the last published RevRegEntry. This is because only the factors (all factors are listed in the respective tails file) of credentials which are active (meaning not being revoked) contribute to the accumulator. Therefore in addition to the updated accumulator value, every RevRegEntry contains lists of indices of credential factors which have been either revoked or (re)activated within the RevRegEntry. This list of factor indices is a so called Witness and enables the Holder to successfully generate a proof of non revocation.

An example of the data in the RevRegEntry is shown in the following example of a RevRegEntry, pulled from this transaction on the Sovrin MainNet.

"data": {
    "revocDefType": "CL_ACCUM",
    "revocRegDefId": "4xE68b6S5VRFrKMMG1U95M:4:4xE68b6S5VRFrKMMG1U95M:3:CL:59232:default:CL_ACCUM:4ae1cc6c-f6bd-486c-8057-88f2ce74e960",
    "value": {
        "accum": "21 116...567",
        "prevAccum": "21 128...C3B",
        "issued": [
        ],
        "revoked": [
            172
        ]
    }
},

In the above:

In the example transaction above no credentials are issued (meaning changed from status revoked to issued) and only one, the credential with index 172, is changed to revoked. Both lists can have an arbitrary number of entries, up to the total number of credentials in the RevReg.

The algorithm to calculate the value of a RevRegEntry accumulator at any time is the same: determine the (modulo) product of the primes for each non-revoked credential in the Revocation Registry, as described here.

NOTE

The issuer MUST track of the revocation status of all of the credentials within a RevReg so that it can both calculate the correct accumulator and send to the VDR accurate lists (issued and revoked) of the indices of the credentials whose status has changed since the last RevRegEntry was published. If the list and accumulator published to VDR get out of sync a holder will not be able to generate a valid NRP.

A VDR publishing a RevReg MAY perform its own calculation of the accumulator based on the list updates received in a RevRegEntry transaction to ensure that the calculation of the accumulator after all of the revocation status updates to the credentials within the RevReg have been applied, rejecting the transaction if the calculated accumulator does not match that from the issuer.

If an issuer's local revocation information gets out of sync with what is in the VDR, the issuer MUST rationalize the differences and produce a RevRegEntry transaction that accounts for both the last published RevRegEntry published in the VDR and the desired revocation status of all of the credentials in the RevReg.

The holder is not involved in the process of revoking a credential. There is no technical requirement for an issuer to notify the holder that a credential they were issued has been revoked. That said, it is a courtesy that may improve the user experience of the holder. Aries RFC 0183 Revocation Notification is an example of how that can be done. Even if not notified by the issuer of the revocation of a credential, the holder can detect their credential has been revoked when they retrieve the list of revoked credentials from the VDR and discover the index of their credential in the list.

§ AnonCreds Presentation Request with Revocation

Carrying out an AnonCreds presentation with revocation is a two-step process, beginning with a request from the verifier asking the holder to include a non-revocation proof (NRP) in the presentation, and then the holder creating the NRP and including it in the presentation sent to the verifier.

The verifier requesting a non-revocation proof, and the holder generating the non-revocation proof are covered in the sections of this specification about requesting and generating presentations, respectively.

§ AnonCreds Verification with Revocation

A verifier receives the presentation from the holder and processes the non-revocation-related parts of the presentation and the revocation-related parts of the presentation (if any) in the presentation. The resulting status of the presentation combines the verification outcomes from processing all proofs within the presentation. If verification of one or more of the embedded proofs is unsuccessful, the presentation is rejected as unverifiable.

§ AnonCreds Methods

In the AnonCreds data flows are specifications of data models that contain identifiers to public AnonCreds objects (Schemas, CredDefs, Revocation Registry Definitions and Rev_Reg_Entrys) that are published by issuers to locations (Verifiable Data Registries or VDRs) that must be accessible to holders and verifiers to enable presentation generation and verification. The format of the objects identifiers and the location of the objects are not defined in this specification. Rather, similar to the approach of DID Methods defined in the W3C DID Specification, AnonCreds methods allow for the registration and resolution mechanisms for AnonCreds objects across a range of VDRs. A registry of supported AnonCreds methods can be found in the AnonCreds Methods Registry.

Each AnonCreds method specifies the format of the object identifiers, to what Verifiable Data Registry the objects are published, how issuers register (publish) objects, and how issuers and verifiers can resolve the identifiers to retrieve the published objects. Implementations of agents (issuers, holders, verifiers) with AnonCreds support should be organized so as to allow issuers to use at least one AnonCreds method for registration, and to allow holders and verifiers to use one or more AnonCreds Methods for resolution. AnonCreds issuers will likely choose just a single AnonCreds registration method(s) they will use, and all AnonCreds participants will choose the set of AnonCreds resolvers they will require based on the issuers and types of credentials they want to support. As with DIDs, an external Universal AnonCreds Resolver is possible, as is a Universal AnonCreds Registrar.

§ AnonCreds Identifiers

AnonCreds identifiers MUST be a Uniform Resource Identifier (URI) conformant with RFC3986, although one notable exception is permitted. The exception is that for backwards compatibility, the AnonCreds identifiers used in the early (pre did:indy) open source Hyperledger Indy AnonCreds implementation are permitted. In the AnonCreds Method Registry, this is the Hyperledger Indy Legacy AnonCreds Method.

§ Issuer Identifiers

All AnonCreds objects that are published to a Verifiable Data Registry (Schema, Credential Definition, Revocation Registry Definition, and Revocation Status List) contain an issuerId reference. This identifier references the creator (issuer) of the specific AnonCreds object.

AnonCreds identifiers MUST be a Uniform Resource Identifier (URI) conformant with RFC3986, although one notable exception is permitted. The exception is that for backwards compatibility, the Indy DIDs used in the early (pre did:indy) open source Hyperledger Indy implementation are permitted.

An AnonCreds object issuer identifier MAY be publicly resolvable. AnonCreds methods MUST define the format of the issuer identifier, and MUST verify that the publisher of the AnonCreds object controls the issuer identifier before publishing the object.

§ Revocation Support

Implementers only familiar with the “deltas”-style data format of Hyperledger Indy RevRegEntries may not be aware that other VDRs may store the contents of each RevRegEntry as “full state”, meaning the status of each credential in the registry (revoked or not) is stored, vs. only the differences from the previous RevRegEntry as in Hyperledger Indy. Either approach is fine as long as data is normalized by the AnonCreds method to the RevReg format expected for AnonCreds generate presentation processing. This allows a AnonCreds Methods to trade-off the size of the RevRegEntry in the VDR with the need for VDR-side processing to collect all of the deltas needed by the holder.

An AnonCreds Method may opt to not support revocation at all, and generate an error if the issuer attempts to create a CredDef that includes revocation support.

§ AnonCreds Method Registry

The AnonCreds Method Registry is published here. The registry contains a description, metadata and a link to a specification for each AnonCreds Method submitted by its implementers/maintainers. The registry is a web page generated from this repository.

The AnonCreds Methods registry repository and published registry is managed by the AnonCreds Specification Working Group based on this governance framework.

Each entry in the AnonCreds Method Registry links to a specification for the associated AnonCreds objects method. The method specifications must include information about the AnonCreds identifiers used by the method, along with the mechanisms for AnonCreds objects registration and resolution. In some cases, the AnonCreds method specification is defined within a DID Method specification, while in other cases, the AnonCreds method is a standalone specification.

§ W3C Verifiable Credentials Representation

This section describes how legacy AnonCreds credentials and presentations can be represented in the form of W3C Verifiable Credentials standard.

§ Credential

This section describes how W3C credential concepts are applied to AnonCreds W3C credential representation.

Example AnonCreds W3C Credential

EXAMPLE
{
  "@context": [
    "https://www.w3.org/2018/credentials/v1",
    "https://raw.githubusercontent.com/hyperledger/anoncreds-spec/main/data/anoncreds-w3c-context.json"
  ],
  "type": [
    "VerifiableCredential",
    "AnonCredsCredential"
  ],
  "issuer": "did:sov:3avoBCqDMFHFaKUHug9s8W",
  "issuanceDate": "2023-11-15T10:00:00.036203Z",
  "credentialSchema": {
    "type": "AnonCredsDefinition",
    "definition": "did:sov:3avoBCqDMFHFaKUHug9s8W:3:CL:13:default",
    "schema": "did:sov:3avoBCqDMFHFaKUHug9s8W:2:basic_person:0.1.0"
  },
  "credentialSubject": {
    "firstName": "Alice",
    "lastName": "Jones",
    "age": "18"
  },
  "proof": [
    {
      "type": "AnonCredsProof2023",
      "signature": "AAAgf9w5.....8Z_x3FqdwRHoWruiF0FlM"
    },
    {
      "type": "Ed25519Signature2020",
      "created": "2021-11-13T18:19:39Z",
      "verificationMethod": "did:sov:3avoBCqDMFHFaKUHug9s8W#key-1",
      "proofPurpose": "assertionMethod",
      "proofValue": "z58DAdFfa9SkqZMVPxAQpic7ndSayn1PzZs6ZjWp1CktyGesjuTSwRdoWhAfGFCF5bppETSTojQCrfFPP2oumHKtz"
    }
  ]
}

§ Context

W3C Context section requires including of @context property to verifiable credential.

The value of the @context property must be one or more resolvable URI that result in machine-readable JSON-LD information about the object format.

The context definition used for AnonCreds W3C credentials representation can be discovered here.

In the case of W3C AnonCreds credentials, the @context attribute includes an extra entry https://raw.githubusercontent.com/hyperledger/anoncreds-spec/main/data/anoncreds-w3c-context.json which is required for the resolution of custom structure definitions and looks the following:

{
  ...
  "@context": [
    "https://www.w3.org/2018/credentials/v1",
    "https://raw.githubusercontent.com/hyperledger/anoncreds-spec/main/data/anoncreds-w3c-context.json"
  ],
  ...
}

§ Identifiers

W3C Identifiers section defines an optional capability to assign some kind of identifier to the verifiable credential so that others can express statements about the same thing.

In the case of W3C AnonCreds credentials, the id attribute is not included into CL credential proof signature, but it can be optionally set in credential to support other integrity proof types.

§ Types

W3C Types section requires including of type property to verifiable credential. The value of the type property must be one or more URI resolvable through the defined @context to the information required for determining whether a verifiable credential has a valid structure.

In the case of W3C AnonCreds credentials, the type attribute includes an extra entry AnonCredsCredential pointing to the difference in a base credential structure and looks the following:

{
  ... 
  "type": [
    "VerifiableCredential",         // general verifiable credential definition
    "AnonCredsCredential",          // definition for AnonCreds credentials
  ]
  ...
}

§ Credential Subject

W3C Credential Subject section requires including of credentialSubject property to verifiable credential.

Credential subject value contains claims about one or more subjects.

In the context of W3C AnonCreds credentials, credential subject property is compliant with the following statements:

In the case of W3C AnonCreds credentials, the credentialSubject attribute looks the following:

{
  ...
  "credentialSubject": {
    "firstName": "Alice",
    "lastName": "Jones",
    "age": "18"
  }
  ...
}

§ Data Schemas

W3C Credential Schema section defines an optional capability to include credentialSchema property to enforce a specific structure on a given verifiable credential and encoding used to map the claims of a verifiable credential to an alternative representation format.

In the case of W3C AnonCreds credentials, the credentialSchema attribute defines a custom AnonCredsDefinition schema in order to include the information about AnonCreds related definitions to credential and looks the following:

{
  ...
  "credentialSchema": {
    "type": "AnonCredsDefinition",
    "definition": "did:sov:3avoBCqDMFHFaKUHug9s8W:3:CL:13:default",
    "schema": "did:sov:3avoBCqDMFHFaKUHug9s8W:2:fabername:0.1.0"
  },
  ...
}

Credential Schema Data:

§ Issuer

W3C Issuer section requires including of issuer property to express the issuer of a verifiable credential.

In the case of W3C AnonCreds credentials, the issuer attribute should be represented as a resolvable DID URL and looks the following:

{
  ...
  "issuer": "did:sov:3avoBCqDMFHFaKUHug9s8W",
  ...
}

§ Issuance Date

W3C Issuance Date section requires including of issuanceDate property to express the date and time when a credential becomes valid. The value of the issuanceDate property must be a string value of an XMLSCHEMA11-2 combined date-time.

In the case of W3C AnonCreds credentials, the issuanceDate attribute should contain the time when a credential was issued or transformed from legacy form, and looks the following:

{
  ...
  "issuanceDate": "2010-01-01T19:23:24Z",
  ...
}

§ Proofs (Signatures)

W3C Proofs (Signatures) section requires including of proof property to express confirmation of the credential’s validity.

According to the specification, one or many proof objects can be added to verifiable credentials. In the case of W3C AnonCreds credentials, the proof attribute must contain AnonCreds CL proof and may contain more Non-AnonCreds Data Integrity proofs.

§ AnonCreds CL proof

AnonCreds CL proof constructed from the CL signature of a verifiable credential.

The defined @context includes a definition for the AnonCredsProof2023 type describing the format of the proof entry:

{
  ...
  "proof": [
    {
      "type": "AnonCredsProof2023",
      "signature": "AAAgf9w5lZg....RYp8Z_x3FqdwRHoWruiF0FlM"
    }
  ]
  ...
}

Credential Proof Signature Data:

§ Non-AnonCreds Integrity proof

In order to better conform to the W3C specification AnonCreds based credential allows including of non-AnonCreds Data Integrity Proof which must be generated using one of NIST-approved algorithms (RSA, ECDSA, EdDSA).

§ Status

W3C Status section defines an optional capability to include credentialStatus property to express credential status information, such as whether it is revoked.

In the case of W3C AnonCreds credentials, if a credential is revocable, the type attribute of credentialStatus must be AnonCredsCredentialStatusList2023 (defined in the scope of @context) pointing that AnonCreds Credential Revocation Flow is used for credential issuance. The id attribute of credentialStatus must contain id of revocation registry.

Also, credential revocation data including revocation registry and witness values (rev_reg and witness) must be included into the credential proof signature as demonstrated above in AnonCreds CL proof section.

A description of generation process when the credential is revocable is in the section Supporting Revocation in a Credential.

{
  ...
  "credentialStatus": {
    "type": "AnonCredsCredentialStatusList2023",
    "id": "did:sov:NcYxiDXkpYi6ov5FcYDi1e:4:NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:tag:CL_ACCUM:TAG_1"
  },
  ...
}

§ Expiration

W3C Expiration section defines an optional capability to include credential expiration information.

In the case of W3C AnonCreds credentials, instead of including expirationDate property there is defined another Announced Revocation Data Flow implementing through the using if credentialStatus property.

{
  ...
  "credentialStatus": {
    "type": "AnonCredsCredentialStatusList2023",
    "id": "did:sov:NcYxiDXkpYi6ov5FcYDi1e:4:NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:tag:CL_ACCUM:TAG_1"
  },
  ...
}

§ AnonCreds W3C Revocable Credential

EXAMPLE
{
  "@context": [
    "https://www.w3.org/2018/credentials/v1",
    "https://raw.githubusercontent.com/hyperledger/anoncreds-spec/main/data/anoncreds-w3c-context.json"
  ],
  "type": [
    "VerifiableCredential",
    "AnonCredsCredential"
  ],
  "issuer": "did:sov:3avoBCqDMFHFaKUHug9s8W",
  "issuanceDate": "2023-11-15T10:00:00.036203Z",
  "credentialSchema": {
    "type": "AnonCredsDefinition",
    "definition": "did:sov:3avoBCqDMFHFaKUHug9s8W:3:CL:13:default",
    "schema": "did:sov:3avoBCqDMFHFaKUHug9s8W:2:basic_person:0.1.0"
  },
  "credentialStatus":{
    "type":"AnonCredsCredentialStatusList2023",
    "id":"did:sov:3avoBCqDMFHFaKUHug9s8W:4:3avoBCqDMFHFaKUHug9s8W:3:CL:3avoBCqDMFHFaKUHug9s8W:2:basic_person:1.0:tag:CL_ACCUM:TAG_1"
  },
  "credentialSubject": {
    "firstName": "Alice",
    "lastName": "Jones",
    "age": "18"
  },
  "proof": [
    {
      "type": "AnonCredsProof2023",
      "signature": "AAAgf9w5.....8Z_x3FqdwRHoWruiF0FlM"
    },
    {
      "type": "Ed25519Signature2020",
      "created": "2021-11-13T18:19:39Z",
      "verificationMethod": "did:sov:3avoBCqDMFHFaKUHug9s8W#key-1",
      "proofPurpose": "assertionMethod",
      "proofValue": "z58DAdFfa9SkqZMVPxAQpic7ndSayn1PzZs6ZjWp1CktyGesjuTSwRdoWhAfGFCF5bppETSTojQCrfFPP2oumHKtz"
    }
  ]
}

§ Presentation

This section describes how W3C presentation concepts are applied to AnonCreds W3C presentation representation.

Example AnonCreds W3C Presentation:

EXAMPLE
{
  "@context": [
    "https://www.w3.org/2018/credentials/v1",
    "https://raw.githubusercontent.com/hyperledger/anoncreds-spec/main/data/anoncreds-w3c-context.json"
  ],
  "type": [
    "VerifiablePresentation",
    "AnonCredsPresentation"
  ],
  "verifiableCredential": [
    {
      "@context": [
        "https://www.w3.org/2018/credentials/v1",
        "https://raw.githubusercontent.com/hyperledger/anoncreds-spec/main/data/anoncreds-w3c-context.json"
      ],
      "type": [
        "VerifiableCredential",
        "AnonCredsCredential"
      ],
      "credentialSchema": {
        "type": "AnonCredsDefinition",
        "definition": "did:sov:3avoBCqDMFHFaKUHug9s8W:3:CL:13:default",
        "schema": "did:sov:3avoBCqDMFHFaKUHug9s8W:2:basic_person:0.1.0"
      },
      "credentialSubject": {
        "firstName": "Alice",
        "age": [
          {
            "type": "AnonCredsPredicate",
            "predicate": ">=",
            "value": 18
          }
        ]
      },
      "issuanceDate": "2023-11-15T10:59:48.036203Z",
      "issuer": "did:sov:3avoBCqDMFHFaKUHug9s8W",
      "proof": {
        "type": "AnonCredsPresentationProof2023",
        "proofValue": "eyJzdWJfcHJvb2Yi...zMTc1NzU0NDAzNDQ0ODUifX1dfX19"
      }
    }
  ],
  "proof": {
    "type": "AnonCredsPresentationProof2023",
    "challenge": "413296376279822794586260",
    "proofValue": "eyJhZ2dyZWdhdGVkIjp7ImNfaGFzaCI6IjEwMT...IsMzAsMTM1LDE4MywxMDcsMTYwXV19fQ=="
  }
}

§ Context

W3C Context section requires including of @context property to verifiable presentation.

The value of the @context property must be one or more resolvable URI that result in machine-readable JSON-LD information about the object format.

The context definition used for AnonCreds W3C presentations representation can be discovered here.

In the case of W3C AnonCreds presentations, the @context attribute includes an extra entry https://raw.githubusercontent.com/hyperledger/anoncreds-spec/main/data/anoncreds-w3c-context.json which is required for the resolution of custom structure definitions and looks the following:

{
  ...
  "@context": [
    "https://www.w3.org/2018/credentials/v1",
    "https://raw.githubusercontent.com/hyperledger/anoncreds-spec/main/data/anoncreds-w3c-context.json"
  ],
  ...
}

§ Types

W3C Types section requires including of type property to verifiable presentation. The value of the type property must be one or more URI resolvable through the defined @context to the information required for determining whether a verifiable presentation has a valid structure.

In the case of W3C AnonCreds presentations, the type attribute includes an extra entry AnonCredsPresentation pointing to the difference in a base presentation structure and looks the following:

{
  ... 
  "type": [
    "VerifiablePresentation",         // general verifiable presentation definition
    "AnonCredsPresentation"           // definition for AnonCreds presentation
  ]
  ...
}

§ Verifiable Credential

W3C Verifiable Credential section requires including of verifiableCredential property to a verifiable presentation constructed from one or more verifiable credentials.

The listed credentials must include attributes and predicated requested in the presentation request.

Verifiable credentials mostly looks same as described at the Credential Structure section but with some differences.

§ Credential Subject

In the case of W3C AnonCreds presentations, in contrast to the general verifiable credential structure (when all attributes represented as key value pairs), the credentialSubject attribute values can be represented in two forms:

§ Proof (Signature)

In the case of W3C AnonCreds presentations, the proof attribute for each verifiable credential must be an object of AnonCredsPresentationProof2023 type which looks the following:

  "proof": {
    "type": "AnonCredsPresentationProof2023",
    "proofValue": "AAEBAnr2Ql...0UhJ-bIIdWFKVWxjU3ePxv_7HoY5pUw",
    "timestamp": Option<1234567>,
  }

Verifiable Credential Proof Data

§ Proof

W3C Proofs (Signatures) section requires including of proof property to express confirmation of the presentation’s validity.

As we described in the above section verifiable credentials can contain two proof entries (CL AnonCreds of Non-AnonCreds Data Integrity). Unlike verifiable credentials, presentations can contain only one proof object.

It is verifier and holder responsibility to negotiate which proof must be used (CL AnonCreds of Non-AnonCreds Data Integrity) in the presentation:

{
  ...
  "proof": {
    "type": "AnonCredsPresentationProof2023",
    "challenge": "182453895158932070575246",
    "proofValue": "AAAgtMR4DrkY--ZVgKHmUANE04ET7TzUxZ0vZmVcNt4nCkwBABUACQJ69kJVIxHVAQAIAaJ19l-agSA"
  }
  ...
}

Presentation Proof structure

§ AnonCreds W3C Presentation containing Revocable Credential

EXAMPLE
{
  "@context": [
    "https://www.w3.org/2018/credentials/v1",
    "https://raw.githubusercontent.com/hyperledger/anoncreds-spec/main/data/anoncreds-w3c-context.json"
  ],
  "type": [
    "VerifiablePresentation",
    "AnonCredsPresentation"
  ],
  "verifiableCredential": [
    {
      "@context": [
        "https://www.w3.org/2018/credentials/v1",
        "https://raw.githubusercontent.com/hyperledger/anoncreds-spec/main/data/anoncreds-w3c-context.json"
      ],
      "type": [
        "VerifiableCredential",
        "AnonCredsCredential"
      ],
      "credentialSchema": {
        "type": "AnonCredsDefinition",
        "definition": "did:sov:3avoBCqDMFHFaKUHug9s8W:3:CL:13:default",
        "schema": "did:sov:3avoBCqDMFHFaKUHug9s8W:2:basic_person:0.1.0"
      },
      "credentialStatus":{
        "type":"AnonCredsCredentialStatusList2023",
        "id":"did:sov:3avoBCqDMFHFaKUHug9s8W:4:3avoBCqDMFHFaKUHug9s8W:3:CL:3avoBCqDMFHFaKUHug9s8W:2:basic_person:1.0:tag:CL_ACCUM:TAG_1"
      },
      "credentialSubject": {
        "firstName": "Alice",
        "age": [
          {
            "type": "AnonCredsPredicate",
            "predicate": ">=",
            "value": 18
          }
        ]
      },
      "issuanceDate": "2023-11-15T10:00:00.036203Z",
      "issuer": "did:sov:3avoBCqDMFHFaKUHug9s8W",
      "proof": {
        "type": "AnonCredsPresentationProof2023",
        "proofValue": "eyJzdWJfcHJvb2Yi...zMTc1NzU0NDAzNDQ0ODUifX1dfX19"
      }
    }
  ],
  "proof": {
    "type": "AnonCredsPresentationProof2023",
    "challenge": "413296376279822794586260",
    "proofValue": "eyJhZ2dyZWdhdGVkIjp7ImNfaGFzaCI6IjEwMT...IsMzAsMTM1LDE4MywxMDcsMTYwXV19fQ=="
  }
}

§ Proof data encoding

  1. Almost all properties of AnonCreds credential signature and presentation are big numbers. The traditional JSON serialization os such data is not very compact. Instead, we use MessagePack binary data serialization format which is faster and produces smaller value. You can find more details on how MessagePack works reading the specification.

  2. Encoding the resulting bytes as Base64Url string without padding

§ Context

The AnonCreds context, located at https://raw.githubusercontent.com/hyperledger/anoncreds-spec/main/data/anoncreds-w3c-context.json can be used to implement a local cached copy. For convenience, the AnonCreds context is also provided in this section.

:::

EXAMPLE
{
  "@context": {
    "@version": 1.1,
    "@protected": true,
    "ac": "https://anoncreds.example/2022/ns#",
    "xsd": "http://www.w3.org/2001/XMLSchema#",

    "AnonCredsCredential": "ac:AnonCredsCredential",

    "AnonCredsDefinition": {
      "@id": "ac:AnonCredsDefinition",
      "@context": {
        "@version": 1.1,
        "@protected": true,
        "definition": {
          "@id": "ac:definition",
          "@type": "@id"
        },
        "schema": {
          "@id": "ac:schema",
          "@type": "@id"
        }
      }
    },

    "AnonCredsCredentialStatusList2023": "ac:AnonCredsCredentialStatusList2023",

    "AnonCredsPresentation": "ac:AnonCredsPresentation",

    "AnonCredsPresentationProof2023": {
      "@id": "ac:AnonCredsPresentationProof2023",
      "@context": {
        "@version": 1.1,
        "@protected": true,
        "proofValue": {
          "@id": "ac:proofValue",
          "@type": "xsd:string"
        },
        "challenge": {
          "@id": "ac:challenge",
          "@type": "xsd:string"
        }
      }
    },

    "AnonCredsProof2023": {
      "@id": "ac:AnonCredsProof2023",
      "@context": {
        "@version": 1.1,
        "@protected": true,
        "signature": {
          "@id": "ac:signature",
          "@type": "xsd:string"
        }
      }
    },

    "AnonCredsPredicate": {
      "@id": "ac:AnonCredsPredicate",
      "@context": {
        "@version": 1.1,
        "@protected": true,
        "predicate": {
          "@id": "ac:predicate",
          "@type": "xsd:string"
        },
        "value": {
          "@id": "ac:value",
          "@type": "xsd:decimal"
        }
      }
    }
  }
}

§ AnonCreds Conventions

Over the years of using Hyperledger AnonCreds, several conventions (listed here) have been defined can or must be used in deploying AnonCreds. The conventions are not required in the current AnonCreds implementation, but are necessary to follow for interoperability with other AnonCreds implementations.

§ Encoding Credential Claims

As described in this specification, the claim data that is actually signed in producing an AnonCreds verifiable credential is not the “raw”, human-readable data of the claims, but rather an integer derived from the raw data. The act of encoding the data was defined to be done by the issuer. However, unless the issuer implements exactly the encoding expected by all others in an ecosystem, the signatures produced for a presentation will not verify. Thus, although the issuer is nominally in control of the encoding, practically, all issuers MUST follow the encoding defined in this specification.

In a future version of AnonCreds we expect to move the encoding process away from the issuer and into AnonCreds.

§ Date and Date/Time Predicates

A powerful capability in AnonCreds is the ability to use predicates on dates, such as proving based on a date of birth (a strongly correlatable value) that a person is older than a certain age without revealing the date of birth. However, because of how credential claims are encoded (above), for a date-based predicate to work, the date must be an integer. Thus, a “date of birth” claim in an ISO 8601 Standard Date String will not be able to be used in a predicate. Rather, the convention of the AnonCreds community has been to put the data into the form of the date as an integer of value YYYYMMDD This convention was initially defined here by the Hyperledger Aries community.

For the same reasons, AnonCreds datetime claims that are to be used in predicates SHOULD be issued in Unix Time format.

In a future version of AnonCreds we expect to define the type of each claim in a credential so that the date and datetime values as strings can be automatically encoded as integers and Unix Time values (respectively). This enables supporting both human-friendly displaying of the claims as well as support for predicates.

§ Presentation Request Revocation Intervals

While the AnonCreds Presentation Request format allows the flexible application of from to to ranges for when the Holder must prove their credential was not revoked, those deploying AnonCreds have found that it is rarely practical or necessary to use such flexibility, and the best practices are to set the two values (from, to) to be the same in Presentation. For Verifiers interested in the current revocation status of the credential, both values should be set to the current time, while if the verifier wants to see the revocation status of the credential at some point in the past, both values should be set to point in time.

Details about this convention can be found in the Presentation Request section of this specification.

Since the Holder must prove non-revocation based on a Revocation published by the issuer, the actual interval that the Holder must use is not from to to, but rather from the Revocation active at time from to the Revocation Registry Entry active at time to, where “time” is as determined by the transaction times recorded at the location on which the issuer published the Revocation.

§ IANA Considerations

This document has no IANA actions.

§ Security Considerations

There are a number of security considerations that issuers, holders, and verifiers should be aware of when processing data described by this specification. Ignoring or not understanding the implications of this section can result in security vulnerabilities.

While this section attempts to highlight a broad set of security considerations, it is not a complete list. Implementers are urged to seek the advice of security and cryptography professionals when implementing mission critical systems using the technology outlined in this specification.

§ Zero Knowledge Proofs in AnonCreds

The security of AnonCreds is primarily based on the security of the AnonCreds cryptography, and in particular, the zero knowledge proofs (ZKPs), upon which this specification is based. Each ZKP used in AnonCreds requires the following security properties be met, as introduced in many ZKP articles, such as this one on non-interactive zero knowledge proofs:

The security of the ZKPs is based on the security of RSA cryptography, and specifically that the factoring of n, where n is the product of two safe primes, is a computationally hard problem.

These properties apply in the places where zero knowledge proofs are used in AnonCreds:

§ Eavesdropping

The prevention of eavesdropping during the exchange of AnonCreds objects during issuance and verification is outside the scope of this specification. The security of the data shared between parties shall be protected by implementing best practices in communications amongst mobile wallet and IT infrastructure, like ISO27001 and Information Security Management systems (ISMS). That said, the AnonCreds cryptography prevents an eavesdropper from gaining other than any plaintext information the parties of an interaction might intentionally or accidentally share.

§ Replay

Replay prevention in AnonCreds for both issuances and presentations are prevented through the use of nonces. During the 3-step issuance process the issuer (in the Credential Offer) and then the holder (in the Credential Request) provide and verify the use of nonces before proceeding. Likewise in the presentation request, the verifier provides a nonce that is incorporated by the holder in generating the presentation, and verified by the verifier.

§ Message Tampering

Message tampering during AnonCreds exchanges is ineffective when the secrets are securely protected by the issuers and holders. Arbitrary modification of AnonCreds data without access to the appropriate secret data is detectable through the failure of the verification of the data objects. See the security considerations sections about the protection of data and protection of key material for more on protecting those secrets and the potentials impacts if those secrets are disclosed.

§ Holder Collusion

Holders that collude by sharing their link secret could each be issued credentials to the same link secret. Subsequently, such holders could present any combination of the credentials together, including generating a proof that they were all issued to the same link. Where such collusion is deemed a significant risk, such as with a mobile wallet application, the agent software should protect the link so as to prevent access or extraction. Issuers and Verifiers may choose to implement verifications that the holder is using a mobile wallet that is known to prevent such extraction and subsequent collusion.

§ Protection of data

The protection of data, both at rest and in motion, is outside the scope of this specification. Protection of data should be accomplished by the participants exchanging AnonCreds verifiable data implementing best practices in data protection for mobile wallet and IT infrastructure, like ISO27001 and Information Security Management systems (ISMS). See the section on the protection of key material for more on the potential impact of disclosed secrets.

When verifiable credentials are stored on a device and that device is lost or stolen, it might be possible for an attacker to use the victim’s verifiable credentials. Mitigating the impacts of such a loss include:

The potential risks in not adequately protecting data are covered in the eavesdropping, message insertion and modification and replay subsection of the Security Considerations.

§ Protection of Key Material

The private keys associated with the public keys used by the issuer must be kept secret. Each issuer is responsible for storing and using their private keys and (for the holder) the link secret in a sufficiently secure manner.

Unintended disclosure of issuer secret information could allow others with access to the secrets issue credentials as if from the original issuer.

Unintended disclosure of the holder's link secret could, if accompanied by the disclosure of the holder’s verifiable credentials, allow others to present those credentials as their own. A malicious presenter could not present their own credentials issued to a different link secret alongside the compromised verifiable credentials.

§ Man-In-The-Middle

The prevention and detection of Man-In-The-Middle (MITM) attacks during the exchange of AnonCreds objects during issuance and verification is outside the scope of this specification. Best practices in preventing MITM attacks while establishing the communications channel between the parties through which the data objects are exchanged should be followed by all of the participants.

As covered in the previous section on Message Insertion and Modification issuance and presentations processes are not susceptible to alteration by a MITM. The primary risk of MITM attacks are the potential for collusion between holders interacting with a verifier. For example, a MITM interacts with a verifier to respond to a presentation request by colluding (in real-time) with a set of one or more holders to pass on each presentation request and get a presentation from the most suitable holder for each individual presentation request. This attack can be mitigated by requesting presentations that are satisfied from multiple source credentials, which will be verified to show all are bound to the same link secret.

§ Deletion

The handling of the deletion of AnonCreds objects by the various participants is outside the scope of this specification. Such objects may be deleted by the participants at any time, understanding that once done, the operations enabled by the possession of those objects cannot be performed. For example, an issuer losing the issuance and revocation private keys can no longer issue or revoke credentials. Likewise, a holder can’t provide a presentation of a deleted source credential. Protection from inadvertent deletion of such data shall be protected by implementing best practices in data management by mobile wallet and IT infrastructure, like ISO27001 and Information Security Management systems (ISMS).

§ Denial of Service

Denial of Service attacks against the various participants in AnonCreds exchanges are outside the scope of this specification.

§ Storage or Network Amplification

Storage or network amplification attacks against the various participants in AnonCreds exchanges are outside the scope of this specification.

§ Residual Risks

The residual risks inherent in AnonCreds include:

§ Privacy Considerations

The business expression of the AnonCreds privacy goal is to allow a verifiable credential holder to minimize the amount of information they share with others in presentations and to minimize the opportunities for holder correlation (also called unlinkability) across issuers and verifiers when using verifiable credentials and presentations. While it is understood that the claims that a holder shares in a verifiable presentation may be correlatable, the act of providing an AnonCreds verifiable presentation must not provide correlatable data.

AnonCreds accomplishes its privacy goals using the following techniques, all of which are based on forms of zero-knowledge proofs, as described in this specification.

The further privacy properties are stated according to Section 5 of RFC6973.

§ Surveillance

In the strict scope of this specification, the activities of the parties are not subject to surveillance due to the presentation data minimization and unlinkability characteristics of the credential issuance and presentation actions. However, in any digital trust ecosystem, there are other components that could lead to surveillance depending on how they are implemented. These include:

§ Stored Data Compromise

The compromise of stored data held by the various agents in a digital trust ecosystem must be mitigated by the respective agent software and hardware, and is out of scope of this specification. The stored data of an individual agent shall be protected by implementing best practices in securing mobile wallet applications and IT infrastructure, like ISO27001 and Information Security Management systems (ISMS).

§ Unsolicited Traffic

The issue of unsolicited traffic is out of scope of this specification. It is a concern of the agents into which the AnonCreds library is embedded. The prevention of unsolicited traffic shall be accomplished by implementing best practices in securing mobile wallet applications and IT infrastructure, like ISO27001 and Information Security Management systems (ISMS).

§ Misattribution

The risk of misattribution when using AnonCreds is mitigated by the participants following the specification. However, as noted in the warning found in this section of this specification, a malicious issuer could deliberately generate a weak private key for use in issuing AnonCreds credentials such that a unique identifier for a holder can be determined via a brute force attack. In that case, anyone applying the brute force attack could issue credentials as it they were from the Issuer, possibly with false information. This risk further incentivize Issuers not to deliberately weaken their keys.

If a third party gains access to the secure storage of a Holder (or a copy thereof), they could present information as if they were the Holder. The stored data of an individual agent shall be protected by implementing best practices in securing mobile wallet applications and IT infrastructure, like ISO27001 and Information Security Management systems (ISMS).

§ Correlation

As noted in the introduction to this section, AnonCreds v1 uses two important techniques to prevent correlation in the issuance and presentation of verifiable data:

§ Identification

AnonCreds v1 enables, but does not itself provide, identification. The unlinkability and data minimization capabilities inherent in AnonCreds enable the Holder to provide presentations anonymously. However, the claims within the presentation are from verifiably issued credentials, and as such, may be used for identification.

§ Secondary Use

The disclosed claims and predicates presented by the Holder to the Verifier are necessarily visible to the verifier. The secondary use of that data is outside the scope of the AnonCreds specification, and is a governance issue. A holder that presents data to a verifier using AnonCreds cannot “revoke” that the presentation was made as the verifier already possesses the disclosed data.

§ Disclosure

The disclosed claims and predicates presented by the Holder to the Verifier are necessarily visible to the verifier. The disclosure of that data by the verifier is outside the scope of the AnonCreds specification, and is a governance issue. A holder that presents data to a verifier using AnonCreds cannot “revoke” that the presentation was made as the verifier already possesses the disclosed data.

§ Exclusion

The participants (issuers, holders, verifiers) using AnonCreds may apply whatever policies (including refusal) they want in issuing, holding, requesting, presenting, and verifying AnonCreds verifiable credential and presentations. Such policies are out outside the scope of the AnonCreds specification, and are governance issues.

§ References

§ Normative References

TODO

Add normative references

§ Informative References

TODO

Add informative references

§ Resources on cryptography

§ Sigma protocols

§ Acknowledgements

AnonCreds was initially created as part of the Open Source Hyperledger Indy project.

This specification is the work of the AnonCreds Working Group, which includes dozens of active and dedicated participants. In particular, the following individuals contributed ideas, feedback, and wording that influenced this specification:

§ Authors’ Addresses

TODO

Add authors’ addresses.

Table of Contents