Skip to content

Commit

Permalink
VC DI proof request (#2960)
Browse files Browse the repository at this point in the history
* WIP: vc di proof request - authored by ianco(#3043)

Signed-off-by: Sarthak Vijayvergiya <[email protected]>

* fixed lint checks, cleanup

Signed-off-by: Sarthak Vijayvergiya <[email protected]>

* fix: verify_pres, get_sign_key_credential_subject_id

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

* WIP: debugging revocation & fixes

Signed-off-by: Sarthak Vijayvergiya <[email protected]>

* WIP: fix ununsed import

Signed-off-by: Sarthak Vijayvergiya <[email protected]>

* refactor: create_signed_anoncreds_presentation,   faber vcdi proof_request_web_request  object for revocation

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

* Refactor:Add W3cCredential loading for VCDI format handler

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

* fix: tests
Signed-off-by: EmadAnwer <[email protected]>

* WPA: using static data to test the revocation validation

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

* feat: Add revocation support to VCDI
- getting the correct timestamp
- create  rev_states
- remove static code

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

* Remove unused code for credential definition and revocation

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

* WPA: fix lint

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

* Fix cred search for vc_di proof

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

* Additional integration tests for vc_di and revocation

Signed-off-by: Ian Costanzo <[email protected]>

* refactor: remove unused comments and TODO's
 - implement _extract_cred_idx
- add try catch to some expected fail code

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

* refactor: split create_signed_anoncreds_presentation
to
 - create_rev_states
- prepare_data_for_presentation

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

* refactor: `create_signed_anoncreds_presentation`

add
- prepare_data_for_presentation
- _load_w3c_credentials functions

remove holder flag

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

* add: tests

- test_assert_no_callenge_error
- test_assert_verify_presentation
- test__extract_cred_idx
- test__get_predicate_type_and_value
- test__load_w3c_credentials
Signed-off-by: EmadAnwer <[email protected]>

* add: tests, remove todos

- test_create_presentation_w3c
- test_create_presentation_w3c_create_error

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

* add: tests

- test_create_signed_anoncreds_presentation

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

* fix: linter

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

* fix: remove unused imports

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

* add: tests

- test_store_credential_w3c
- test_get_type_manager_options

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

* refactor: remove extra variables and comments

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

---------

Signed-off-by: Sarthak Vijayvergiya <[email protected]>
Signed-off-by: EmadAnwer <[email protected]>
Signed-off-by: Emad <[email protected]>
Signed-off-by: Ian Costanzo <[email protected]>
Co-authored-by: EmadAnwer <[email protected]>
Co-authored-by: Ian Costanzo <[email protected]>
  • Loading branch information
3 people authored Jul 12, 2024
1 parent 76f5a71 commit a1a5afc
Show file tree
Hide file tree
Showing 25 changed files with 1,739 additions and 103 deletions.
5 changes: 4 additions & 1 deletion aries_cloudagent/anoncreds/default/legacy_indy/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,9 @@ def __init__(self):
B58 = alphabet if isinstance(alphabet, str) else alphabet.decode("ascii")
INDY_DID = rf"^(did:sov:)?[{B58}]{{21,22}}$"
INDY_SCHEMA_ID = rf"^[{B58}]{{21,22}}:2:.+:[0-9.]+$"
# the schema id can be just a number
# (this is how the schema_id is referenced in a cred def)
INDY_SCHEMA_TXN_ID = r"^[0-9.]+$"
INDY_CRED_DEF_ID = (
rf"^([{B58}]{{21,22}})" # issuer DID
f":3" # cred def id marker
Expand All @@ -131,7 +134,7 @@ def __init__(self):
rf"CL_ACCUM:(.+$)"
)
self._supported_identifiers_regex = re.compile(
rf"{INDY_DID}|{INDY_SCHEMA_ID}|{INDY_CRED_DEF_ID}|{INDY_REV_REG_DEF_ID}"
rf"{INDY_DID}|{INDY_SCHEMA_ID}|{INDY_SCHEMA_TXN_ID}|{INDY_CRED_DEF_ID}|{INDY_REV_REG_DEF_ID}"
)

@property
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
B58 = alphabet if isinstance(alphabet, str) else alphabet.decode("ascii")
INDY_DID = rf"^(did:sov:)?[{B58}]{{21,22}}$"
INDY_SCHEMA_ID = rf"^[{B58}]{{21,22}}:2:.+:[0-9.]+$"
INDY_SCHEMA_TXN_ID = r"^[0-9.]+$"
INDY_CRED_DEF_ID = (
rf"^([{B58}]{{21,22}})" # issuer DID
f":3" # cred def id marker
Expand All @@ -73,7 +74,7 @@
rf"CL_ACCUM:(.+$)"
)
SUPPORTED_ID_REGEX = re.compile(
rf"{INDY_DID}|{INDY_SCHEMA_ID}|{INDY_CRED_DEF_ID}|{INDY_REV_REG_DEF_ID}"
rf"{INDY_DID}|{INDY_SCHEMA_ID}|{INDY_SCHEMA_TXN_ID}|{INDY_CRED_DEF_ID}|{INDY_REV_REG_DEF_ID}"
)

TEST_INDY_DID = "WgWxqztrNooG92RXvxSTWv"
Expand Down
109 changes: 104 additions & 5 deletions aries_cloudagent/anoncreds/holder.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
import asyncio
import json
import logging
from marshmallow import INCLUDE
import re
from typing import Dict, Optional, Sequence, Tuple, Union
from pyld import jsonld
from pyld.jsonld import JsonLdProcessor

from anoncreds import (
AnoncredsError,
Expand All @@ -14,6 +17,7 @@
Presentation,
PresentCredentials,
W3cCredential,
W3cPresentation,
create_link_secret,
)
from aries_askar import AskarError, AskarErrorCode
Expand All @@ -23,6 +27,10 @@
from ..askar.profile_anon import AskarAnoncredsProfile
from ..core.error import BaseError
from ..core.profile import Profile
from ..storage.vc_holder.base import VCHolder
from ..storage.vc_holder.vc_record import VCRecord
from ..vc.vc_ld import VerifiableCredential
from ..vc.ld_proofs import DocumentLoader
from ..wallet.error import WalletNotFoundError
from .error_messages import ANONCREDS_PROFILE_REQUIRED_MSG
from .models.anoncreds_cred_def import CredDef
Expand Down Expand Up @@ -307,7 +315,7 @@ async def store_credential_w3c(
try:
secret = await self.get_master_secret()
cred_w3c = W3cCredential.load(credential_data)
await asyncio.get_event_loop().run_in_executor(
cred_w3c_recvd = await asyncio.get_event_loop().run_in_executor(
None,
cred_w3c.process,
credential_request_metadata,
Expand All @@ -327,7 +335,7 @@ async def store_credential_w3c(
except AnoncredsError as err:
raise AnonCredsHolderError("Error processing received credential") from err

return await self._finish_store_credential(
credential_id = await self._finish_store_credential(
credential_definition,
cred_recvd,
credential_request_metadata,
Expand All @@ -336,6 +344,45 @@ async def store_credential_w3c(
rev_reg_def,
)

# also store in W3C format
# create VC record for storage
cred_w3c_recvd_dict = cred_w3c_recvd.to_dict()
cred_w3c_recvd_dict["proof"] = cred_w3c_recvd_dict["proof"][0]
cred_w3c_recvd_vc = VerifiableCredential.deserialize(
cred_w3c_recvd_dict, unknown=INCLUDE
)

# Saving expanded type as a cred_tag
document_loader = self.profile.inject(DocumentLoader)
expanded = jsonld.expand(
cred_w3c_recvd_dict, options={"documentLoader": document_loader}
)
types = JsonLdProcessor.get_values(
expanded[0],
"@type",
)

vc_record = VCRecord(
contexts=cred_w3c_recvd_vc.context_urls,
expanded_types=types,
issuer_id=cred_w3c_recvd_vc.issuer_id,
subject_ids=cred_w3c_recvd_vc.credential_subject_ids,
schema_ids=[], # Schemas not supported yet
proof_types=[cred_w3c_recvd_vc.proof.type],
cred_value=cred_w3c_recvd_vc.serialize(),
given_id=cred_w3c_recvd_vc.id,
record_id=credential_id,
cred_tags=None, # Tags should be derived from credential values
)

# save credential in storage
async with self.profile.session() as session:
vc_holder = session.inject(VCHolder)

await vc_holder.store_credential(vc_record)

return credential_id

async def get_credentials(self, start: int, count: int, wql: dict):
"""Get credentials stored in the wallet.
Expand Down Expand Up @@ -384,16 +431,13 @@ async def get_credentials_for_presentation_request_by_referent(
extra_query: wql query dict
"""

if not referents:
referents = (
*presentation_request["requested_attributes"],
*presentation_request["requested_predicates"],
)
extra_query = extra_query or {}

creds = {}

for reft in referents:
names = set()
if reft in presentation_request["requested_attributes"]:
Expand Down Expand Up @@ -646,6 +690,61 @@ def get_rev_state(cred_id: str, detail: dict):

return presentation.to_json()

async def create_presentation_w3c(
self,
presentation_request: dict,
requested_credentials_w3c: list,
credentials_w3c_metadata: list,
schemas: Dict[str, AnonCredsSchema],
credential_definitions: Dict[str, CredDef],
rev_states: dict = None,
) -> dict:
"""Get credentials stored in the wallet.
Args:
presentation_request: Valid indy format presentation request
requested_credentials_w3c: W3C format requested credentials
credentials_w3c_metadata: W3C format credential metadata
schemas: Indy formatted schemas JSON
credential_definitions: Indy formatted credential definitions JSON
rev_states: Indy format revocation states JSON
"""
present_creds = PresentCredentials()
for idx, cred in enumerate(requested_credentials_w3c):
meta = credentials_w3c_metadata[idx]
rev_state = rev_states.get(meta["rev_reg_id"]) if rev_states else None
for attr in meta["proof_attrs"]:
present_creds.add_attributes(
cred,
attr,
reveal=True,
timestamp=meta.get("timestamp"),
rev_state=rev_state,
)

for pred in meta["proof_preds"]:
present_creds.add_predicates(
cred,
pred,
timestamp=meta.get("timestamp"),
rev_state=rev_state,
)

try:
secret = await self.get_master_secret()
presentation = W3cPresentation.create(
presentation_request,
present_creds,
secret,
schemas,
credential_definitions,
)
except AnoncredsError as err:
raise AnonCredsHolderError("Error creating presentation") from err

return presentation.to_dict()

async def create_revocation_state(
self,
cred_rev_id: str,
Expand Down
Loading

0 comments on commit a1a5afc

Please sign in to comment.