owned this note
owned this note
Published
Linked with GitHub
# Ledger Agnostic AnonCreds in ACA-Py
Topics to cover:
- Transaction endorsement
- AnonCreds Routes
- AnonCreds Issuer / Holder / Verifier
- AnonCreds Registry
- AnonCreds Service (Glue)
- Storage of AnonCreds records (backwards compatibility)
## Notes
- The current `/schemas` and `/credential-definitions` api endpoint groups will be deprecated in favour of the new AnonCreds API
- The write non secret record method will be removed as this is a legacy flow
- The Indy AnonCreds Registry will leverage the `BaseLedger` class. The assumption is that the `BaseLedger` will always have an indy implementation. Other ledgers should not implement the `BaseLedger` interface, but rather use more specific interfaces such as the did resolver, did registrar, etc. In the future the `BaseLedger` can be deprecated in favor of the more specific interfaces.
## AnonCreds API
### Schemas
#### Create Schema
```
POST /anoncreds/schemas
```
**Request**
```json
{
"schema": {
"attrNames": ["string"],
"name": "string",
"version": "string",
"issuerId": "string"
},
// options method can be different per method, but it can also include default options for all anoncreds methods (none for schema)
"options": {
// it can also be automatically inferred from the agent startup parameters (default endorser)
// TODO: should we add an endorser did that will return the transaction instead of send
"endorser_connection_id": ""
}
}
```
**Response**
```json
{
"job_id": "string",
"schema_state": {
"state": "string",
"schema_id": "string",
"schema": {
"attrNames": ["string"],
"name": "string",
"version": "string",
"issuerId": "string"
}
},
"registration_metadata": {},
// For indy, schema_metadata will contain the seqNo
"schema_metadata": {}
}
```
- `job_id` - job identifier to keep track of the status of the schema creation. MUST be absent or have a null value if the value of the `schema_state.state` response field is either `finished` or `failed`, and MUST NOT have a null value otherwise.
- `schema_state`
- `state` - The state of the schema creation. Possible values are `finished`, `failed`, `action` and `wait`.
- `schema_id` - The id of the schema. If the value of the `schema_state.state` response field is `finished`, this field MUST be present and MUST NOT have a null value.
- `schema` - The schema. If the value of the `schema_state.state` response field is `finished`, this field MUST be present and MUST NOT have a null value.
- `registration_metadata` - This field contains metadata about hte registration process
- `schema_metadata` - This fields contains metadata about the schema.
#### Get Schema
```
GET /anoncreds/schemas/<schema_id>
```
**Response**
```json
{
"schema": {
"issuerId": "string"
"attrNames": ["string"],
"name": "string",
"version": "string"
},
"schema_id": "string",
"resolution_metadata": {},
"schema_metadata": {}
}
```
- `schema` - The schema.
- `schema_id` - The id of the schema.
- `schema_resolution_metadata` - This field contains metadata about the resolution process
- `schema_metadata` - This fields contains metadata about the schema.
#### Get Created Schemas
```
GET /anoncreds/schemas/created
```
**Request**
- `schema_id` - (optional) The id of the schema.
- `schema_issuer_id` - (optional) The issuer id that created the schema.
- `schema_name` - (optional) The name of the schema.
- `schema_version` - (optional) The version of the schema.
> TODO
> - Add a `method` or `registry` property to get all created schemas anchored on a specific anoncreds registry.
> - Should we return more than just the identifiers?
**Response**
```json
{
"schema_ids": ["string"]
}
```
- `schema_ids` - The ids of the created schemas that match the query
### Credential Definitions
#### Create Credential Definition
```
POST /anoncreds/credential-definitions
```
**Request**
```json
{
// FIXME: this is using snake case, while the schema call is using camelCase (schema is model from anoncreds spec, while this is
// input to the credential definition creation.
"credential_definition": {
"tag": "string",
"schemaId": "string",
"issuerId": "string"
// TODO: we could infer this from whether `revocation_registry_size` is defined
"support_revocation": "boolean",
"revocation_registry_size": "integer",
},
// options method can be different per method, but it can also include default options for all anoncreds methods (such as support_revocation)
"options": {
// For indy it can include e.g. an endorser did
// it can also be automatically inferred from the agent startup parameters (default endorser)
// TODO: should we add an endorser did that will return the transaction instead of send it?
"endorser_connection_id": "string",
// "support_revocation" is optional option for _all_ anoncreds methods
"support_revocation" : "boolean",
// revocation_registry_size is optional and will have a default value if support_revocation is `true`
"revocation_registry_size": "integer",
}
}
```
**Response**
```json
{
"job_id": "string",
"credential_definition_state": {
"state": "string",
"credential_definition_id": "string",
"credential_definition": {
"issuerId": "string",
"schemaId": "string",
"type": "CL",
"tag": "string",
"value": {
"primary": {
"n": "779...397",
"r": {
"link_secret": "521...922",
"<key>": "410...200"
},
"rctxt": "774...977",
"s": "750..893",
"z": "632...005"
}
}
}
},
"registration_metadata": {},
"credential_definition_metadata": {}
}
```
- `job_id` - job identifier to keep track of the status of the credential definition creation. MUST be absent or have a null value if the value of the `credential_definition_state.state` response field is either `finished` or `failed`, and MUST NOT have a null value otherwise.
- `credential_definition_state`
- `state` - The state of the credential definition creation. Possible values are `finished`, `failed`, `action` and `wait`.
- `credential_definition_id` - The id of the credential definition. If the value of the `credential_definition.state` response field is `finished`, this field MUST be present and MUST NOT have a null value.
- `credential_definition` - The credential definition. If the value of the `credential_definition.state` response field is `finished`, this field MUST be present and MUST NOT have a null value.
- `registration_metadata` - This field contains metadata about the credential definition registration process
- `credential_definition_metadata` - This fields contains metadata about the credential definition.
#### Get Credential Definition
```
GET /anoncreds/credential-definitions/<credential_definition_id>
```
**Response**
```json
{
"credential_definition_id": "string",
"credential_definition": {
"issuerId": "string",
"schemaId": "string",
"type": "CL",
"tag": "string",
"value": {
"primary": {
"n": "779...397",
"r": {
"link_secret": "521...922",
"<key>": "410...200"
},
"rctxt": "774...977",
"s": "750..893",
"z": "632...005"
}
}
},
"resolution_metadata": {},
"credential_definition_metadata": {}
}
```
- `credential_definition_id` - The id of the credential definition
- `credential_definition` - The credential definition.
- `resolution_metadata` - This field contains metadata about the resolution process
- `credential_definition_metadata` - This fields contains metadata about the schema.
#### Get Created Credential Definitions
```
GET /anoncreds/credential-definitions/created
```
**Request**
- `credential_definition_id` - (optional) The id of the credential definition
- `issuer_id` - (optional) The issuer id that created the credential definition.
- `schema_id` - (optional) The id of the schema
- `schema_issuer_id` - (optional) The issuer id that created the schema.
- `schema_name` - (optional) The name of the schema.
- `schema_version` - (optional) The version of the schema.
> TODO
> - Add a `method` or `registry` property to get all created credential definitions anchored on a specific anoncreds registry.
> - Should we return more than just the identifiers?
**Response**
```json
{
"credential_definition_ids": ["string"]
}
```
- `credential_definition_ids` - The ids of the created credential definitions that match the query
## AnonCredsRegsitry
```python
from abc import ABC, abstractmethod
from typing import Any, Dict, List, Optional, TypedDict, Literal
class AnonCredsSchema(TypedDict):
issuerId: str
attrNames: List[str]
name: str
version: str
class AnonCredsRegistryGetSchema(TypedDict):
schema: AnonCredsSchema
schema_id: str
resolution_metadata: Dict[str, Any]
schema_metadata: Dict[str, Any]
# TODO: work out
class AnonCredsCredentialDefinitionValue(TypedDict):
primary: Any
revocation: Optional[Any]
class AnonCredsCredentialDefinition(TypedDict):
issuerId: str
schemaId: str
type: Literal["CL"]
tag: str
value: AnonCredsCredentialDefinitionValue
class AnonCredsRegistryGetCredentialDefinition(TypedDict):
credential_definition: AnonCredsCredentialDefinition
credential_definition_id: str
resolution_metadata: Dict[str, Any]
credential_definition_metadata: Dict[str, Any]
class AnonCredsRevocationRegistryDefinition(TypedDict):
issuerId: str
type: Literal["CL_ACCUM"]
credDefId: str
tag: str
# TODO: work out
publicKeys: Any
maxCredNum: int
tailsLocation: str
tailsHash: str
class AnonCredsRegistryGetRevocationRegistryDefinition(TypedDict):
revocation_registry: AnonCredsRevocationRegistryDefinition
revocation_registry_id: str
resolution_metadata: Dict[str, Any]
revocation_registry_metadata: Dict[str, Any]
class AnonCredsRevocationList(TypedDict):
issuerId: str
revRegId: str
revocationList: List[int]
currentAccumulator: str
timestamp: int
class AnonCredsRegistryGetRevocationList(TypedDict):
revocation_list: AnonCredsRevocationList
resolution_metadata: Dict[str, Any]
revocation_registry_metadata: Dict[str, Any]
class AnonCredsRegistry(ABC):
@abstractmethod
async def get_schema(self, schema_id: str) -> AnonCredsRegistryGetSchema:
"""Get a schema from the registry."""
# TODO: work out
@abstractmethod
async def register_schema(self):
"""Register a schema on the registry."""
@abstractmethod
async def get_credential_definition(
self, credential_definition_id: str
) -> AnonCredsRegistryGetCredentialDefinition:
"""Get a credential definition from the registry."""
# TODO: work out
@abstractmethod
async def register_credential_definition(self):
"""Register a credential definition on the registry."""
@abstractmethod
async def get_revocation_registry_definition(
self, revocation_registry_id: str
) -> AnonCredsRegistryGetRevocationRegistryDefinition:
"""Get a revocation registry definition from the registry."""
# TODO: work out
@abstractmethod
async def register_revocation_registry_definition(self):
"""Register a revocation registry definition on the registry."""
@abstractmethod
async def get_revocation_list(
self, revocation_registry_id: str, timestamp: str
) -> AnonCredsRegistryGetRevocationList:
"""Get a revocation list from the registry."""
# TODO: work out
@abstractmethod
async def register_revocation_list(self):
"""Register a revocation list on the registry."""
```