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

signature suite logic exploration #138

Open
wants to merge 8 commits into
base: feature/pluggable-signature-suites
Choose a base branch
from
Open
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
25 changes: 16 additions & 9 deletions aries_cloudagent/config/default_context.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Classes for configuring the default injection context."""

from vc.ld_proofs.suites.bbs_bls_signature_proof_2020 import BbsBlsSignatureProof2020
from ..vc.ld_proofs.suites.bbs_bls_signature_2020 import BbsBlsSignature2020
from ..vc.ld_proofs.suites.ed25519_signature_2018 import Ed25519Signature2018
from ..vc.ld_proofs.suites.registry import LDProofSuiteRegistry
Expand All @@ -19,8 +20,10 @@
from ..resolver.did_resolver import DIDResolver
from ..tails.base import BaseTailsServer
from ..transport.wire_format import BaseWireFormat
from ..utils.dependencies import (is_indy_sdk_module_installed,
is_ursa_bbs_signatures_module_installed)
from ..utils.dependencies import (
is_indy_sdk_module_installed,
is_ursa_bbs_signatures_module_installed,
)
from ..utils.stats import Collector
from .base_context import ContextBuilder
from .injection_context import InjectionContext
Expand Down Expand Up @@ -52,11 +55,16 @@ async def build_context(self) -> InjectionContext:

# Signature suite registry
# Register default signatures
suite = LDProofSuiteRegistry()
suite.register(Ed25519Signature2018, [KeyType.ED25519], False)
if is_ursa_bbs_signatures_module_installed():
suite.register(BbsBlsSignature2020, [KeyType.BLS12381G1G2], True)
context.injector.bind_instance(LDProofSuiteRegistry,suite)
suite: LDProofSuiteRegistry = LDProofSuiteRegistry()
suite.register_suite(Ed25519Signature2018, False)
suite.register_signature(Ed25519Signature2018.signature_type, KeyType.ED25519)
# We only want to add bbs suites to supported if the module is installed
if is_ursa_bbs_signatures_module_installed(): # if BbsBlsSignature2020.BBS_SUPPORTED:
suite.register_suite(BbsBlsSignature2020, False)
suite.register_signature(BbsBlsSignature2020.signature_type, KeyType.BLS12381G2)
suite.register_suite(BbsBlsSignatureProof2020, True)
suite.register_signature(BbsBlsSignatureProof2020.signature_type, KeyType.BLS12381G2)
context.injector.bind_instance(LDProofSuiteRegistry, suite)

# Global event bus
context.injector.bind_instance(EventBus, EventBus())
Expand All @@ -80,8 +88,7 @@ async def bind_providers(self, context: InjectionContext):
# so it can be shared by all wallet instances. If we set it in the indy sdk
# profile provider it could mean other wallets won't have access to the provider
if is_indy_sdk_module_installed():
from ..ledger.indy import (IndySdkLedgerPool,
IndySdkLedgerPoolProvider)
from ..ledger.indy import IndySdkLedgerPool, IndySdkLedgerPoolProvider

context.injector.bind_provider(
IndySdkLedgerPool,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""V2.0 issue-credential linked data proof credential format handler."""

from vc.ld_proofs.suites.registry import LDProofSuiteRegistry
from ......vc.ld_proofs.error import LinkedDataProofException
from ......vc.ld_proofs.check import get_properties_without_context
import logging
Expand Down Expand Up @@ -27,15 +28,12 @@
BbsBlsSignature2020,
CredentialIssuancePurpose,
DocumentLoader,
Ed25519Signature2018,
LinkedDataProof,
ProofPurpose,
WalletKeyPair,
)
from ......vc.ld_proofs.constants import SECURITY_CONTEXT_BBS_URL
from ......wallet.base import BaseWallet, DIDInfo
from ......wallet.error import WalletNotFoundError
from ......wallet.key_type import KeyType

from ...message_types import (
ATTACHMENT_FORMAT,
Expand Down Expand Up @@ -63,24 +61,6 @@
CredentialIssuancePurpose.term,
AuthenticationProofPurpose.term,
}
SUPPORTED_ISSUANCE_SUITES = {Ed25519Signature2018}
SIGNATURE_SUITE_KEY_TYPE_MAPPING = {Ed25519Signature2018: KeyType.ED25519}


# We only want to add bbs suites to supported if the module is installed
if BbsBlsSignature2020.BBS_SUPPORTED:
SUPPORTED_ISSUANCE_SUITES.add(BbsBlsSignature2020)
SIGNATURE_SUITE_KEY_TYPE_MAPPING[BbsBlsSignature2020] = KeyType.BLS12381G2


PROOF_TYPE_SIGNATURE_SUITE_MAPPING = {
suite.signature_type: suite
for suite, key_type in SIGNATURE_SUITE_KEY_TYPE_MAPPING.items()
}

KEY_TYPE_SIGNATURE_SUITE_MAPPING = {
key_type: suite for suite, key_type in SIGNATURE_SUITE_KEY_TYPE_MAPPING.items()
}


class LDProofCredFormatHandler(V20CredFormatHandler):
Expand Down Expand Up @@ -176,13 +156,13 @@ def get_format_data(self, message_type: str, data: dict) -> CredFormatAttachment
)

async def _assert_can_issue_with_id_and_proof_type(
self, issuer_id: str, proof_type: str
self, issuer_id: str, proof_signature_type: str
):
"""Assert that it is possible to issue using the specified id and proof type.

Args:
issuer_id (str): The issuer id
proof_type (str): the signature suite proof type
proof_signature_type (str): the signature suite proof type

Raises:
V20CredFormatError:
Expand All @@ -194,10 +174,11 @@ async def _assert_can_issue_with_id_and_proof_type(
"""
try:
# Check if it is a proof type we can issue with
if proof_type not in PROOF_TYPE_SIGNATURE_SUITE_MAPPING.keys():
suite_registry = self.profile.inject(LDProofSuiteRegistry)
if proof_signature_type not in suite_registry.signature_types:
raise V20CredFormatError(
f"Unable to sign credential with unsupported proof type {proof_type}."
f" Supported proof types: {PROOF_TYPE_SIGNATURE_SUITE_MAPPING.keys()}"
f"Unable to sign credential with unsupported proof type {proof_signature_type}."
f" Supported proof types: {suite_registry.signature_types}"
)

if not issuer_id.startswith("did:"):
Expand All @@ -211,14 +192,7 @@ async def _assert_can_issue_with_id_and_proof_type(

# Raise error if we cannot issue a credential with this proof type
# using this DID from
did_proof_type = KEY_TYPE_SIGNATURE_SUITE_MAPPING[
did.key_type
].signature_type
if proof_type != did_proof_type:
raise V20CredFormatError(
f"Unable to issue credential with issuer id {issuer_id} and proof "
f"type {proof_type}. DID only supports proof type {did_proof_type}"
)
# TODO: is a key type support check needed?

except WalletNotFoundError:
raise V20CredFormatError(
Expand Down Expand Up @@ -267,56 +241,19 @@ async def _get_suite_for_detail(self, detail: LDProofVCDetail) -> LinkedDataProo
)

did_info = await self._did_info_for_did(issuer_id)
verification_method = self._get_verification_method(issuer_id)

suite = await self._get_suite(
proof_type=proof_type,
verification_method=verification_method,
proof=proof.serialize(),
suite_registry = self.profile.inject(LDProofSuiteRegistry)
wallet = self.profile.inject(BaseWallet)
# TODO: get key_type
suite = suite_registry.get_suite(
wallet=wallet,
issuer_id=issuer_id,
did_info=did_info,
signature_type=proof_type,
proof=proof.serialize(),
)

return suite

async def _get_suite(
self,
*,
proof_type: str,
verification_method: str = None,
proof: dict = None,
did_info: DIDInfo = None,
):
"""Get signature suite for issuance of verification."""
session = await self.profile.session()
wallet = session.inject(BaseWallet)

# Get signature class based on proof type
SignatureClass = PROOF_TYPE_SIGNATURE_SUITE_MAPPING[proof_type]

# Generically create signature class
return SignatureClass(
verification_method=verification_method,
proof=proof,
key_pair=WalletKeyPair(
wallet=wallet,
key_type=SIGNATURE_SUITE_KEY_TYPE_MAPPING[SignatureClass],
public_key_base58=did_info.verkey if did_info else None,
),
)

def _get_verification_method(self, did: str):
"""Get the verification method for a did."""

if did.startswith("did:key:"):
return DIDKey.from_did(did).key_id
elif did.startswith("did:sov:"):
# key-1 is what the resolver uses for key id
return did + "#key-1"
else:
raise V20CredFormatError(
f"Unable to get retrieve verification method for did {did}"
)

def _get_proof_purpose(
self, *, proof_purpose: str = None, challenge: str = None, domain: str = None
) -> ProofPurpose:
Expand Down Expand Up @@ -570,7 +507,13 @@ async def store_credential(
credential = VerifiableCredential.deserialize(cred_dict, unknown=INCLUDE)

# Get signature suite, proof purpose and document loader
suite = await self._get_suite(proof_type=credential.proof.type)
suite_registry = self.profile.inject(LDProofSuiteRegistry)
wallet = self.profile.inject(BaseWallet)
# TODO: get key_type
suite = suite_registry.get_suite(
wallet=wallet,
signature_type=credential.proof.type,
)

purpose = self._get_proof_purpose(
proof_purpose=credential.proof.proof_purpose,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ async def test_get_suite_for_detail(self):
detail.credential.issuer_id, detail.options.proof_type
)
mock_did_info.assert_called_once_with(detail.credential.issuer_id)

'''
async def test_get_suite(self):
proof = async_mock.MagicMock()
did_info = async_mock.MagicMock()
Expand Down Expand Up @@ -318,7 +318,7 @@ async def test_get_suite(self):
assert suite.proof == proof
assert suite.key_pair.key_type == KeyType.ED25519
assert suite.key_pair.public_key_base58 == did_info.verkey

'''
async def test_get_verification_method(self):
assert (
self.handler._get_verification_method(TEST_DID_KEY)
Expand Down
89 changes: 12 additions & 77 deletions aries_cloudagent/protocols/present_proof/dif/pres_exch_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,15 @@
from unflatten import unflatten
from uuid import uuid4

from vc.ld_proofs.suites.registry import LDProofSuiteRegistry

from ....core.error import BaseError
from ....core.profile import Profile
from ....did.did_key import DIDKey
from ....storage.vc_holder.vc_record import VCRecord
from ....vc.ld_proofs import (
Ed25519Signature2018,
BbsBlsSignature2020,
BbsBlsSignatureProof2020,
WalletKeyPair,
DocumentLoader,
)
from ....vc.ld_proofs.constants import (
Expand Down Expand Up @@ -72,25 +72,6 @@ class DIFPresExchError(BaseError):
class DIFPresExchHandler:
"""Base Presentation Exchange Handler."""

ISSUE_SIGNATURE_SUITE_KEY_TYPE_MAPPING = {
Ed25519Signature2018: KeyType.ED25519,
}

if BbsBlsSignature2020.BBS_SUPPORTED:
ISSUE_SIGNATURE_SUITE_KEY_TYPE_MAPPING[BbsBlsSignature2020] = KeyType.BLS12381G2

DERIVE_SIGNATURE_SUITE_KEY_TYPE_MAPPING = {
BbsBlsSignatureProof2020: KeyType.BLS12381G2,
}
PROOF_TYPE_SIGNATURE_SUITE_MAPPING = {
suite.signature_type: suite
for suite, key_type in ISSUE_SIGNATURE_SUITE_KEY_TYPE_MAPPING.items()
}
DERIVED_PROOF_TYPE_SIGNATURE_SUITE_MAPPING = {
suite.signature_type: suite
for suite, key_type in DERIVE_SIGNATURE_SUITE_KEY_TYPE_MAPPING.items()
}

def __init__(
self,
profile: Profile,
Expand All @@ -109,60 +90,6 @@ def __init__(
self.is_holder = False
self.reveal_doc_frame = reveal_doc

async def _get_issue_suite(
self,
*,
wallet: BaseWallet,
issuer_id: str,
):
"""Get signature suite for signing presentation."""
did_info = await self._did_info_for_did(issuer_id)
verification_method = self._get_verification_method(issuer_id)

# Get signature class based on proof type
SignatureClass = self.PROOF_TYPE_SIGNATURE_SUITE_MAPPING[self.proof_type]

# Generically create signature class
return SignatureClass(
verification_method=verification_method,
key_pair=WalletKeyPair(
wallet=wallet,
key_type=self.ISSUE_SIGNATURE_SUITE_KEY_TYPE_MAPPING[SignatureClass],
public_key_base58=did_info.verkey if did_info else None,
),
)

async def _get_derive_suite(
self,
*,
wallet: BaseWallet,
):
"""Get signature suite for deriving credentials."""
# Get signature class based on proof type
SignatureClass = self.DERIVED_PROOF_TYPE_SIGNATURE_SUITE_MAPPING[
"BbsBlsSignatureProof2020"
]

# Generically create signature class
return SignatureClass(
key_pair=WalletKeyPair(
wallet=wallet,
key_type=self.DERIVE_SIGNATURE_SUITE_KEY_TYPE_MAPPING[SignatureClass],
),
)

def _get_verification_method(self, did: str):
"""Get the verification method for a did."""
if did.startswith("did:key:"):
return DIDKey.from_did(did).key_id
elif did.startswith("did:sov:"):
# key-1 is what uniresolver uses for key id
return did + "#key-1"
else:
raise DIFPresExchError(
f"Unable to get retrieve verification method for did {did}"
)

async def _did_info_for_did(self, did: str) -> DIDInfo:
"""Get the did info for specified did.

Expand Down Expand Up @@ -410,10 +337,13 @@ async def filter_constraints(
new_credential_dict = self.reveal_doc(
credential_dict=credential_dict, constraints=constraints
)
suites_registry = self.profile.inject(LDProofSuiteRegistry)
async with self.profile.session() as session:
wallet = session.inject(BaseWallet)
derive_suite = await self._get_derive_suite(
# TODO: get key type and pass it into get suite method
derive_suite = suites_registry.get_suite(
wallet=wallet,
signature_type="BbsBlsSignatureProof2020",
)
signed_new_credential_dict = await derive_credential(
credential=credential_dict,
Expand Down Expand Up @@ -1303,11 +1233,16 @@ async def create_vp(
vp["presentation_submission"] = submission_property.serialize()
if self.proof_type is BbsBlsSignature2020.signature_type:
vp["@context"].append(SECURITY_CONTEXT_BBS_URL)
suites_registry = self.profile.inject(LDProofSuiteRegistry)
async with self.profile.session() as session:
wallet = session.inject(BaseWallet)
issue_suite = await self._get_issue_suite(
did_info = await self._did_info_for_did(issuer_id)
# TODO: get key_type
issue_suite = suites_registry.get_suite(
wallet=wallet,
issuer_id=issuer_id,
did_info=did_info,
signature_type=self.proof_type,
)
signed_vp = await sign_presentation(
presentation=vp,
Expand Down
Loading