Credential status
Credential Status (CS) is an essential component of Verifiable Credentials (VC). Its primary purpose is to provide information about the revocation status of a credential. Anyone can utilize CS to determine whether a VC has been revoked or remains valid. Within the iden3 Verifiable Credentials system, there are four types of CS available:
- SparseMerkleTreeProof
- Iden3ReverseSparseMerkleTreeProof
- Iden3commRevocationStatusV1.0
- Iden3OnchainSparseMerkleTreeProof2023
All these types have the same message format:
{
"id": "...",
"type": "...",
"revocationNonce": 0
}
id - a unique ID for the CS. The content of this field depends on the type.
type - the type of the credential status.
revocationNonce -a unique number for the Verifiable credential.
SparseMerkleTreeProof
Example of CS:
"credentialStatus": {
"id": "<issuer-agent-url>/api/v1/identities/did%3Apolygonid%3Apolygon%3Amumbai%3A2qEjShhoHGFdi88ZPCXcApSesmGzk8aqqf3hymnyiW/claims/revocation/status/1016367164",
"revocationNonce": 1016367164,
"type": "SparseMerkleTreeProof"
},
If the type == SparseMerkleTreeProof, the id field will contain a URL to the issuer node. Users can utilize this URL to process the revocation status.
Workflow:
-
Making an HTTP call to the URL from the
idfield:Example of response:
{ "issuer": { "state": "52e66f413231e4d7c43cc09aaf076b8bc0f3a4f18f95e29dc92ab001e401e708", "claimsTreeRoot": "c5a516e17a16160fdf567c130d73909fefbd5fcec1ad74b9707fbac989d4e812" }, "mtp": { "existence": false, "siblings": [] } }More about this response: https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/core/vocab/SparseMerkleTreeProof.md
In this case, when
mtp.existence == false, it means that the user's revocationNonce doesn't exist in the revocation tree. This is a positive outcome for the user because it allows them to build a non-revocation proof. -
Building non-revocation/revocation proof using the response.
Iden3ReverseSparseMerkleTreeProof
In this scenario, the issuer utilizes the RHS server to store the tree info in a distributed manner. This approach ensures data resilience and accessibility in a distributed fashion.
Moreover, the credentialStatus contains statusIssuer as a backup mechanism in case the RHS server becomes unavailable. By having the statusIssuer, the issuer retains the ability to verify and manage the CS even if the storage through the RHS server encounters any issues.
This dual approach of utilizing a decentralized system while also having a backup option in the form of statusIssuer enhances the reliability and availability of the revocation and verification process for the users' credentials.
For now, only SparseMerkleTreeProof credential status is supported as a backup optio
****Example :******
"credentialStatus": {
"id": "https://rhs-staging.polygonid.me?state=a1abdb9f44c7b649eb4d21b59ef34bd38e054aa3e500987575a14fc92c49f42c",
"revocationNonce": 1016367164,
"statusIssuer": {
"id": "https://1e1a-46-133-26-136.ngrok-free.app/api/v1/identities/did%3Apolygonid%3Apolygon%3Amumbai%3A2qEeAALESZRcocQTh7ri1skPKkMiHftaH1ufEVJWku/claims/revocation/status/0",
"revocationNonce": 1016367164,
"type": "SparseMerkleTreeProof"
},
"type": "Iden3ReverseSparseMerkleTreeProof"
}
Workflow:
- Attempt to retrieve the latest issuer state using the state contract. Utilize the
GetLatestStateByIdmethod from the state contract. - In the event that the state contract returns the error
IDENTITY_DOES_NOT_EXIST, follow these steps:- If the
stateparameter exists and it is agenesisstate, use this state to generate a non-revocation proof via the RHS service. Provide the extracted state as the latest state and the revocation nonce to the RHS service. - If the
stateparameter does not exist - throw an error.- As a legacy option, for statuses where state doesn’t persist in the current implementation, we use additional custom issuer data from BJJSignatureProof or Iden3SparseMerkleTreeProof to extract tree roots and the issuer’s state to construct a non-revocation proof. If this param is not provided - an error is thrown. This is not mandatory in new implementations.
- If the
- If the state contract returns the latest state, utilize the RHS service with the latest state and nonce to generate non-revocation/revocation proof according to the algorithm.
- In the event that the RHS server is unavailable or encounters issues, users can fall back to using the
credentialStatus.statusIssuerobject to process the revocation status. This object must haveSparseMerkleTreeProoftype, so it will be processed accordingly.
Example of implementation: JS, GO
Iden3commRevocationStatusV1.0
Example of Сredential status:
"credentialStatus": {
"id": "<issuer-agent-url>/api/v1/agent",
"revocationNonce": 2234893355,
"type": "Iden3commRevocationStatusV1.0"
},
In this case, the id is set to the issuer's agent endpoint. To establish communication with the issuer's agent, users should utilize the iden3comm protocol.
Workflow
To verify the revocation status of a credential, follow these steps using the appropriate communication protocols:
- Construct the revocation status request iden3comm message. This message will be used to request information about the revocation status.
- Send the constructed revocation status request message in plain text format to the issuer's agent endpoint, which is specified in the
idfield. The communication will take place using the iden3comm protocol. - The issuer will respond with a status iden3comm protocol message that contains the necessary information.
-
Upon receiving the response, extract the
bodyfield from it. Thebodyfield will contain essential details related to the issuer and the revocation status:{ "issuer": { "state": "52e66f413231e4d7c43cc09aaf076b8bc0f3a4f18f95e29dc92ab001e401e708", "claimsTreeRoot": "c5a516e17a16160fdf567c130d73909fefbd5fcec1ad74b9707fbac989d4e812" }, "mtp": { "existence": false, "siblings": [] } } -
Utilize the information obtained from the
bodyfield of the issuer's response to construct the non-revocation/revocation proof as required.
It's important to note that the difference between revocation statuses SparseMerkleTreeProof and Iden3commRevocationStatusV1.0 lies in the format of the response/request. While SparseMerkleTreeProof uses the non-protocol request-response format, Iden3commRevocationStatusV1.0 relays the iden3comm protocol for communication.
Iden3OnchainSparseMerkleTreeProof2023
The Iden3OnchainSparseMerkleTreeProof2023 type is specifically used for revocation trees which are stored on the blockchain.
Here are two examples of the credential status (CS) objects using this type:
Example:
{
"id": "did:polygonid:polygon:mumbai:2qCU58EJgrELbXjWbWGC9kPPnczQdp93nUR6LC45F6/credentialStatus?revocationNonce=1051565438&contractAddress=80001:0x2fCE183c7Fbc4EbB5DB3B0F5a63e0e02AE9a85d2&state=a1abdb9f44c7b649eb4d21b59ef34bd38e054aa3e500987575a14fc92c49f42c",
"type": "Iden3OnchainSparseMerkleTreeProof2023",
"revocationNonce": 1051565438
}
In both examples, the id field is a valid Decentralized Identifier (DID) with one required contractAddress and two optional parameters: revocationNonce and state.
Where:
contractAddressconsists of two parts: thechainID, which specifies the blockchain where the contract exists, and the smart contract address used for generating non-revocation proof.revocationNoncerepresents the credential nonce.staterefers to the most recently published issuer state or genesis.
The format of the id field follows this structure:
[did]:[methodid]:[chain]:[network]:[id]/credentialStatus?(revocationNonce=value)&[contractAddress=[chainID]:[contractAddress]]&(state=issuerState)
Workflow
To verify the revocation status of an onchain using the Iden3OnchainSparseMerkleTreeProof2023 type, follow these steps:
- Parse the
idas a valid DID and extract the on-chain issuer contract address from thisid: a. If thecontractAddressparameter is not empty, use this address to build the non-revocation proof. b. If thecontractAddressis empty return an error. - Extract
chainIDfromcontractAddressparameter. IfchainIDnot exists - extract chain id from DID. - Parse the
idto obtain therevocationNonce: a. You can extract therevocationNoncefrom theidparameterrevocationNonce. b. If theiddoesn't have therevocationNonce, you can get therevocationNoncefrom therevocationNoncefield. c. If the parameter doesn't exist and therevocationNoncefield is empty, consider this VC document invalid. -
Get latest state for
id-
If you encounter the error Identity does not exist, please check whether the
stateparameter fromidcorresponds to the genesis state.If the state parameter does not exist or is not the genesis state, return an error.
-
-
Generate revocation proof call method
getRevocationStatusByIdAndState.id- id extracted from issuer DID.state- latest state or genesis from step 4.nonce- nonce from step 3.const response = await this.onchainContract.getRevocationStatusByIdAndState(id, state, nonce);-
Use this ABI to make getRevocationStatusByIdAndState call
[ { "inputs": [ { "internalType": "uint256", "name": "id", "type": "uint256" }, { "internalType": "uint256", "name": "state", "type": "uint256" }, { "internalType": "uint64", "name": "nonce", "type": "uint64" } ], "name": "getRevocationStatusByIdAndState", "outputs": [ { "components": [ { "components": [ { "internalType": "uint256", "name": "state", "type": "uint256" }, { "internalType": "uint256", "name": "claimsTreeRoot", "type": "uint256" }, { "internalType": "uint256", "name": "revocationTreeRoot", "type": "uint256" }, { "internalType": "uint256", "name": "rootOfRoots", "type": "uint256" } ], "internalType": "struct IOnchainCredentialStatusResolver.IdentityStateRoots", "name": "issuer", "type": "tuple" }, { "components": [ { "internalType": "uint256", "name": "root", "type": "uint256" }, { "internalType": "bool", "name": "existence", "type": "bool" }, { "internalType": "uint256[]", "name": "siblings", "type": "uint256[]" }, { "internalType": "uint256", "name": "index", "type": "uint256" }, { "internalType": "uint256", "name": "value", "type": "uint256" }, { "internalType": "bool", "name": "auxExistence", "type": "bool" }, { "internalType": "uint256", "name": "auxIndex", "type": "uint256" }, { "internalType": "uint256", "name": "auxValue", "type": "uint256" } ], "internalType": "struct IOnchainCredentialStatusResolver.Proof", "name": "mtp", "type": "tuple" } ], "internalType": "struct IOnchainCredentialStatusResolver.CredentialStatus", "name": "", "type": "tuple" } ], "stateMutability": "view", "type": "function" } ]
Also, you can use the signature of getRevocationStatusByIdAndState
0xaad72921instead of ABI. -