Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add anoncreds issuance and presentation format #3331

Merged
merged 16 commits into from
Nov 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading