Skip to content

Commit

Permalink
Add anoncreds issuance and presentation format (#3331)
Browse files Browse the repository at this point in the history
* Add anoncreds issuance and presentation formats

Signed-off-by: jamshale <[email protected]>

* Fix unit tests

Signed-off-by: jamshale <[email protected]>

* Fix error in _formats_attach

Signed-off-by: jamshale <[email protected]>

* Fix AnoncredsDID validation pattern

Signed-off-by: jamshale <[email protected]>

* Fix name

Signed-off-by: jamshale <[email protected]>

* Fix scenario test

Signed-off-by: jamshale <[email protected]>

* Update demo with anoncreds format

Signed-off-by: jamshale <[email protected]>

* Fix the scenario test and add better description

Signed-off-by: jamshale <[email protected]>

* Add service_healthy check for indy agent

Signed-off-by: jamshale <[email protected]>

* Fix/update BDD tests

Signed-off-by: jamshale <[email protected]>

* Add issuer askar to holder anoncreds support

Signed-off-by: jamshale <[email protected]>

* Update BDD tests

Signed-off-by: jamshale <[email protected]>

* Remove commented code

Signed-off-by: jamshale <[email protected]>

* Expand scenario test

Signed-off-by: jamshale <[email protected]>

* Add better comments for format compatibilty imports

Signed-off-by: jamshale <[email protected]>

* Add anocnreds compatibilty bdd test to PR workflow

Signed-off-by: jamshale <[email protected]>

---------

Signed-off-by: jamshale <[email protected]>
  • Loading branch information
jamshale authored Nov 22, 2024
1 parent e27598d commit a00b5f5
Show file tree
Hide file tree
Showing 96 changed files with 3,917 additions and 1,049 deletions.
6 changes: 3 additions & 3 deletions acapy_agent/anoncreds/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@
from ..config.injection_context import InjectionContext
from ..core.error import BaseError
from ..core.profile import Profile
from .models.anoncreds_cred_def import CredDef, CredDefResult, GetCredDefResult
from .models.anoncreds_revocation import (
from .models.credential_definition import CredDef, CredDefResult, GetCredDefResult
from .models.revocation import (
GetRevListResult,
GetRevRegDefResult,
RevList,
RevListResult,
RevRegDef,
RevRegDefResult,
)
from .models.anoncreds_schema import AnonCredsSchema, GetSchemaResult, SchemaResult
from .models.schema import AnonCredsSchema, GetSchemaResult, SchemaResult

T = TypeVar("T")

Expand Down
6 changes: 3 additions & 3 deletions acapy_agent/anoncreds/default/did_indy/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@
from ....config.injection_context import InjectionContext
from ....core.profile import Profile
from ...base import BaseAnonCredsRegistrar, BaseAnonCredsResolver
from ...models.anoncreds_cred_def import CredDef, CredDefResult, GetCredDefResult
from ...models.anoncreds_revocation import (
from ...models.credential_definition import CredDef, CredDefResult, GetCredDefResult
from ...models.revocation import (
GetRevListResult,
GetRevRegDefResult,
RevList,
RevListResult,
RevRegDef,
RevRegDefResult,
)
from ...models.anoncreds_schema import AnonCredsSchema, GetSchemaResult, SchemaResult
from ...models.schema import AnonCredsSchema, GetSchemaResult, SchemaResult

LOGGER = logging.getLogger(__name__)

Expand Down
6 changes: 3 additions & 3 deletions acapy_agent/anoncreds/default/did_web/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@
from ....config.injection_context import InjectionContext
from ....core.profile import Profile
from ...base import BaseAnonCredsRegistrar, BaseAnonCredsResolver
from ...models.anoncreds_cred_def import CredDef, CredDefResult, GetCredDefResult
from ...models.anoncreds_revocation import (
from ...models.credential_definition import CredDef, CredDefResult, GetCredDefResult
from ...models.revocation import (
GetRevListResult,
GetRevRegDefResult,
RevList,
RevListResult,
RevRegDef,
RevRegDefResult,
)
from ...models.anoncreds_schema import AnonCredsSchema, GetSchemaResult, SchemaResult
from ...models.schema import AnonCredsSchema, GetSchemaResult, SchemaResult


class DIDWebRegistry(BaseAnonCredsResolver, BaseAnonCredsRegistrar):
Expand Down
2 changes: 1 addition & 1 deletion acapy_agent/anoncreds/default/legacy_indy/recover.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import indy_vdr
from anoncreds import RevocationRegistry, RevocationRegistryDefinition

from ...models.anoncreds_revocation import RevList
from ...models.revocation import RevList

LOGGER = logging.getLogger(__name__)

Expand Down
6 changes: 3 additions & 3 deletions acapy_agent/anoncreds/default/legacy_indy/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,14 @@
)
from ...events import RevListFinishedEvent
from ...issuer import CATEGORY_CRED_DEF, AnonCredsIssuer, AnonCredsIssuerError
from ...models.anoncreds_cred_def import (
from ...models.credential_definition import (
CredDef,
CredDefResult,
CredDefState,
CredDefValue,
GetCredDefResult,
)
from ...models.anoncreds_revocation import (
from ...models.revocation import (
GetRevListResult,
GetRevRegDefResult,
RevList,
Expand All @@ -74,7 +74,7 @@
RevRegDefState,
RevRegDefValue,
)
from ...models.anoncreds_schema import (
from ...models.schema import (
AnonCredsSchema,
GetSchemaResult,
SchemaResult,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@
import pytest
from anoncreds import RevocationRegistryDefinition

from acapy_agent.tests import mock

from ....models.anoncreds_revocation import RevList, RevRegDef, RevRegDefValue
from .....tests import mock
from ....models.revocation import RevList, RevRegDef, RevRegDefValue
from ..recover import (
RevocRecoveryException,
_check_tails_hash_for_inconsistency,
Expand Down
34 changes: 15 additions & 19 deletions acapy_agent/anoncreds/default/legacy_indy/tests/test_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,25 +16,6 @@
from .....anoncreds.base import AnonCredsSchemaAlreadyExists
from .....anoncreds.default.legacy_indy import registry as test_module
from .....anoncreds.issuer import AnonCredsIssuer
from .....anoncreds.models.anoncreds_cred_def import (
CredDef,
CredDefResult,
CredDefValue,
CredDefValuePrimary,
)
from .....anoncreds.models.anoncreds_revocation import (
RevList,
RevListResult,
RevRegDef,
RevRegDefResult,
RevRegDefState,
RevRegDefValue,
)
from .....anoncreds.models.anoncreds_schema import (
AnonCredsSchema,
GetSchemaResult,
SchemaResult,
)
from .....askar.profile_anon import (
AskarAnoncredsProfileSession,
)
Expand All @@ -55,6 +36,21 @@
)
from .....tests import mock
from .....utils.testing import create_test_profile
from ....models.credential_definition import (
CredDef,
CredDefResult,
CredDefValue,
CredDefValuePrimary,
)
from ....models.revocation import (
RevList,
RevListResult,
RevRegDef,
RevRegDefResult,
RevRegDefState,
RevRegDefValue,
)
from ....models.schema import AnonCredsSchema, GetSchemaResult, SchemaResult

B58 = alphabet if isinstance(alphabet, str) else alphabet.decode("ascii")
INDY_DID = rf"^(did:sov:)?[{B58}]{{21,22}}$"
Expand Down
2 changes: 1 addition & 1 deletion acapy_agent/anoncreds/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from typing import NamedTuple, Optional

from ..core.event_bus import Event
from .models.anoncreds_revocation import RevRegDef
from .models.revocation import RevRegDef

CRED_DEF_FINISHED_EVENT = "anoncreds::credential-definition::finished"
REV_REG_DEF_FINISHED_EVENT = "anoncreds::revocation-registry-definition::finished"
Expand Down
4 changes: 2 additions & 2 deletions acapy_agent/anoncreds/holder.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
from pyld.jsonld import JsonLdProcessor
from uuid_utils import uuid4

from ..anoncreds.models.anoncreds_schema import AnonCredsSchema
from ..askar.profile_anon import AskarAnoncredsProfile
from ..core.error import BaseError
from ..core.profile import Profile
Expand All @@ -33,7 +32,8 @@
from ..vc.vc_ld import VerifiableCredential
from ..wallet.error import WalletNotFoundError
from .error_messages import ANONCREDS_PROFILE_REQUIRED_MSG
from .models.anoncreds_cred_def import CredDef
from .models.credential_definition import CredDef
from .models.schema import AnonCredsSchema
from .registry import AnonCredsRegistry

LOGGER = logging.getLogger(__name__)
Expand Down
4 changes: 2 additions & 2 deletions acapy_agent/anoncreds/issuer.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
from .base import AnonCredsSchemaAlreadyExists, BaseAnonCredsError
from .error_messages import ANONCREDS_PROFILE_REQUIRED_MSG
from .events import CredDefFinishedEvent
from .models.anoncreds_cred_def import CredDef, CredDefResult
from .models.anoncreds_schema import AnonCredsSchema, SchemaResult, SchemaState
from .models.credential_definition import CredDef, CredDefResult
from .models.schema import AnonCredsSchema, SchemaResult, SchemaState
from .registry import AnonCredsRegistry

LOGGER = logging.getLogger(__name__)
Expand Down
167 changes: 167 additions & 0 deletions acapy_agent/anoncreds/models/credential.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
"""Credential artifacts."""

from typing import Mapping, Optional

from marshmallow import EXCLUDE, ValidationError, fields

from ...messaging.models.base import BaseModel, BaseModelSchema
from ...messaging.valid import (
ANONCREDS_CRED_DEF_ID_EXAMPLE,
ANONCREDS_CRED_DEF_ID_VALIDATE,
ANONCREDS_REV_REG_ID_EXAMPLE,
ANONCREDS_REV_REG_ID_VALIDATE,
ANONCREDS_SCHEMA_ID_EXAMPLE,
ANONCREDS_SCHEMA_ID_VALIDATE,
NUM_STR_ANY_EXAMPLE,
NUM_STR_ANY_VALIDATE,
)


class AnoncredsAttrValue(BaseModel):
"""Anoncreds attribute value."""

class Meta:
"""Anoncreds attribute value."""

schema_class = "AnoncredsAttrValueSchema"

def __init__(
self, raw: Optional[str] = None, encoded: Optional[str] = None, **kwargs
):
"""Initialize anoncreds (credential) attribute value."""
super().__init__(**kwargs)
self.raw = raw
self.encoded = encoded


class AnoncredsAttrValueSchema(BaseModelSchema):
"""Anoncreds attribute value schema."""

class Meta:
"""Anoncreds attribute value schema metadata."""

model_class = AnoncredsAttrValue
unknown = EXCLUDE

raw = fields.Str(required=True, metadata={"description": "Attribute raw value"})
encoded = fields.Str(
required=True,
validate=NUM_STR_ANY_VALIDATE,
metadata={
"description": "Attribute encoded value",
"example": NUM_STR_ANY_EXAMPLE,
},
)


class DictWithAnoncredsAttrValueSchema(fields.Dict):
"""Dict with anoncreds attribute value schema."""

def __init__(self, **kwargs):
"""Initialize the custom schema for a dictionary with AnoncredsAttrValue."""
super().__init__(
keys=fields.Str(metadata={"description": "Attribute name"}),
values=fields.Nested(AnoncredsAttrValueSchema()),
**kwargs,
)

def _deserialize(self, value, attr, data, **kwargs):
"""Deserialize dict with anoncreds attribute value."""
if not isinstance(value, dict):
raise ValidationError("Value must be a dict.")

errors = {}
anoncreds_attr_value_schema = AnoncredsAttrValueSchema()

for k, v in value.items():
if isinstance(v, dict):
validation_errors = anoncreds_attr_value_schema.validate(v)
if validation_errors:
errors[k] = validation_errors

if errors:
raise ValidationError(errors)

return value


class AnoncredsCredential(BaseModel):
"""Anoncreds credential."""

class Meta:
"""Anoncreds credential metadata."""

schema_class = "AnoncredsCredentialSchema"

def __init__(
self,
schema_id: Optional[str] = None,
cred_def_id: Optional[str] = None,
rev_reg_id: Optional[str] = None,
values: Mapping[str, AnoncredsAttrValue] = None,
signature: Optional[Mapping] = None,
signature_correctness_proof: Optional[Mapping] = None,
rev_reg: Optional[Mapping] = None,
witness: Optional[Mapping] = None,
):
"""Initialize anoncreds credential."""
self.schema_id = schema_id
self.cred_def_id = cred_def_id
self.rev_reg_id = rev_reg_id
self.values = values
self.signature = signature
self.signature_correctness_proof = signature_correctness_proof
self.rev_reg = rev_reg
self.witness = witness


class AnoncredsCredentialSchema(BaseModelSchema):
"""Anoncreds credential schema."""

class Meta:
"""Anoncreds credential schemametadata."""

model_class = AnoncredsCredential
unknown = EXCLUDE

schema_id = fields.Str(
required=True,
validate=ANONCREDS_SCHEMA_ID_VALIDATE,
metadata={
"description": "Schema identifier",
"example": ANONCREDS_SCHEMA_ID_EXAMPLE,
},
)
cred_def_id = fields.Str(
required=True,
validate=ANONCREDS_CRED_DEF_ID_VALIDATE,
metadata={
"description": "Credential definition identifier",
"example": ANONCREDS_CRED_DEF_ID_EXAMPLE,
},
)
rev_reg_id = fields.Str(
allow_none=True,
validate=ANONCREDS_REV_REG_ID_VALIDATE,
metadata={
"description": "Revocation registry identifier",
"example": ANONCREDS_REV_REG_ID_EXAMPLE,
},
)
values = DictWithAnoncredsAttrValueSchema(
required=True,
metadata={"description": "Credential attributes"},
)
signature = fields.Dict(
required=True, metadata={"description": "Credential signature"}
)
signature_correctness_proof = fields.Dict(
required=True,
metadata={"description": "Credential signature correctness proof"},
)
rev_reg = fields.Dict(
allow_none=True, metadata={"description": "Revocation registry state"}
)
witness = fields.Dict(
allow_none=True, metadata={"description": "Witness for revocation proof"}
)
Loading

0 comments on commit a00b5f5

Please sign in to comment.