Skip to content

Commit

Permalink
plugin:adding did plugin support in indy-plenum
Browse files Browse the repository at this point in the history
Signed-off-by: Atharva Amritkar <[email protected]>
  • Loading branch information
wiredhikari committed Feb 27, 2024
1 parent 78d3ad3 commit 456dcef
Show file tree
Hide file tree
Showing 27 changed files with 1,849 additions and 0 deletions.
63 changes: 63 additions & 0 deletions plenum/server/plugin/did_plugin/Functionalities/OU_DID.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import json
import base64
from nacl.signing import VerifyKey
from nacl.exceptions import BadSignatureError

"""
1. The function wil recieve REQUEST_BODY somehow
2. The REQUEST_BODY will have `DIDDocment`which will have all the info....
3. I will get `publicKeyMultibase` for verification purposes.
4. Now get the `VerificationKey` and `Signature` from REQUEST_BODY.
5. Then tried to verify it....
"""

request = {
"identifier": "EbP4aYNeTHL6q385GuVpRV",
"operation": {
"dest": "Vzfdscz6YG6n1EuNJV4ob1",
"type": "20226",
"data": {
"DIDDocument": {
"id": "did:exampleiin:org1",
"verificationMethod": [
{
"id": "did:exampleiin:org1#key1",
"type": "Ed25519VerificationKey2020",
"controller": "did:exampleiin:org1",
"publicKeyMultibase": "zH3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV"
}
],
"authentication": ["did:exampleiin:org1"]
},
"signature": {
"verificationMethod": "did:exampleiin:org1#key1",
"sigbase64": "sdfsdfsdf"
}
},
"verkey": "~HFPBKb7S7ocrTzxakNbcao"
},
"protocolVersion": 2,
"reqId": 1704282737760629997
}

# Get DID document
did_doc = json.loads(request["operation"]["data"]["DIDDocument"])

# Get public key from DID document
key_id = "did:exampleiin:org1#key1"
public_key = did_doc["verificationMethod"][0]["publicKeyMultibase"]

# Load public key
verify_key = VerifyKey(base64.standard_b64decode(public_key))

# Get signature
signature = base64.standard_b64decode(request["operation"]["data"]["signature"]["sigbase64"])

# Get signed data
signed_data = json.dumps(did_doc)

try:
verify_key.verify(signed_data.encode(), signature)
print("Signature is valid!")
except BadSignatureError:
print("Invalid signature!")
20 changes: 20 additions & 0 deletions plenum/server/plugin/did_plugin/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from plenum.common.messages.fields import FixedLengthField
from plenum.server.plugin.did_plugin.transactions import DemoTransactions
from plenum.server.plugin.did_plugin.constants import DID_PLUGIN_LEDGER_ID


dummy_field_length = 10
LEDGER_IDS = {DID_PLUGIN_LEDGER_ID, }
CLIENT_REQUEST_FIELDS = {'fix_length_dummy':
FixedLengthField(dummy_field_length,
optional=True, nullable=True)}

AcceptableWriteTypes = {DemoTransactions.CREATE_DID.value,
DemoTransactions.CREATE_NETWORK_DID.value,
DemoTransactions.UPDATE_DID.value,
DemoTransactions.UPDATE_NETWORK_DID.value,
DemoTransactions.DEACTIVATE_DID.value,
DemoTransactions.OUDID.value
}

AcceptableQueryTypes = {DemoTransactions.FETCH_DID.value, }
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from plenum.common.constants import DOMAIN_LEDGER_ID
from plenum.server.batch_handlers.batch_request_handler import BatchRequestHandler
from plenum.server.database_manager import DatabaseManager
from plenum.server.plugin.did_plugin import DID_PLUGIN_LEDGER_ID


class DIDBatchHandler(BatchRequestHandler):

def __init__(self, database_manager: DatabaseManager):
super().__init__(database_manager, DID_PLUGIN_LEDGER_ID)

def post_batch_applied(self, three_pc_batch, prev_handler_result=None):
pass

def post_batch_rejected(self, ledger_id, prev_handler_result=None):
pass
191 changes: 191 additions & 0 deletions plenum/server/plugin/did_plugin/common.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
import json
import libnacl
import libnacl.encode
from plenum.common.exceptions import InvalidSignature

def libnacl_validate(vk_base64, signature_base64, originalhash):
vk = libnacl.encode.base64_decode(vk_base64)
signature = libnacl.encode.base64_decode(signature_base64)
verifiedhash = libnacl.crypto_sign_open(signature, vk)
if signature == originalhash:
raise InvalidSignature("The hash of the DIDDocument did not match.")
#
def libnacl_validate2(vk_base64, signature_base64):
print("vk_base64", vk_base64)
print("signature_base64", signature_base64)
# vk = libnacl.encode.base64_decode(vk_base64)
# signature = libnacl.encode.base64_decode(signature_base64)
# verifiedhash = libnacl.crypto_sign_open(signature, vk)
return signature_base64

def did_id_from_url(did_url: str) -> str:
return did_url.split("#")[0]


class DID:
did = None
id = None
verification_methods = None
authentication_methods = None

def __init__(self, did_json) -> None:
self.did = json.loads(did_json)
self.id = self.did["id"]

# populate verification methods:
self.verification_methods = {}
for method in self.did["verificationMethod"]:
self.verification_methods[method["id"]] = method

# populate authentication methods:
self.authentication_methods = {}
for method in self.did["authentication"]:
if isinstance(method, dict):
# fully specified method
self.authentication_methods[method["id"]] = method
elif isinstance(method, str):
# id points to a verification method
# TODO: if it points to a different did -> resolve that did and fetch method
if method in self.verification_methods:
self.authentication_methods[method] = self.verification_methods[method]
# [{'controller': 'did:exampleiin:org1', 'id': 'did:exampleiin:org1#key1', 'publicKeyMultibase': '4PS3EDQ3dW1tci1Bp6543CfuuebjFrg36kLAUcskGfaA', 'type': 'libnacl'}]}
def fetch_authentication_method(self, authentication_method_id: str) -> dict:
# if authentication_method_id in self.authentication_methods:
# return self.authentication_methods[authentication_method_id]
return authentication_method_id[0]

def fetch_authentication(self, authentication_method_id: str) -> dict:
if authentication_method_id in self.authentication_methods:
return self.authentication_methods[authentication_method_id]
return None



class NetworkDID:
did = None
id = None
verification_methods = None
authentication_methods = None
network_participants: list = None

def __init__(self, did_json) -> None:
self.did = json.loads(did_json)
self.id = self.did["id"]
self.network_participants = self.did["networkMembers"]

assert(len(self.network_participants) > 0)

# populate verification methods:
self.verification_methods = {}
for method in self.did["verificationMethod"]:
self.verification_methods[method["id"]] = method

# populate authentication methods:
self.authentication_methods = {}
for method in self.did["authentication"]:
if isinstance(method, dict):
# fully specified method
self.authentication_methods[method["id"]] = method
elif isinstance(method, str):
# id points to a verification method
# TODO: if it points to a different did -> resolve that did and fetch method
if method in self.verification_methods:
self.authentication_methods[method] = self.verification_methods[method]

# ensure atleast one authentication method of type GroupMultiSig
group_multisig_auth_support = False
for method_id, method in self.authentication_methods.items():
if method["type"] == "BlockchainNetworkMultiSig":
group_multisig_auth_support = True
if not group_multisig_auth_support:
raise Exception("Network DID does not have BlockchainNetworkMultiSig authentication method")

# Get any one authentication method of type GroupMultiSig
def fetch_authentication_method(self) -> dict:
for method_id, method in self.authentication_methods.items():
if method["type"] == "BlockchainNetworkMultiSig":
return method

def fetch_signature(self) -> dict:




class OUDID:
did = None
id = None
verification_methods = None
authentication_methods = None

def __init__(self, did_json) -> None:
self.did = json.loads(did_json)
self.id = self.did["id"]

# populate verification methods:
self.verification_methods = {}
for method in self.did["verificationMethod"]:
self.verification_methods[method["id"]] = method

# "authentication": ["did:<method-name>:<method-specific-id>"]
# populate authentication methods:
self.authentication_methods = {}
for method in self.did["authentication"]:
if isinstance(method, dict):
# fully specified method
self.authentication_methods[method["id"]] = method
elif isinstance(method, str):
# id points to a verification method
# TODO: if it points to a different did -> resolve that did and fetch method
if method in self.verification_methods:
self.authentication_methods[method] = self.verification_methods[method]

def fetch_authentication_method(self) -> dict:
if authentication_method_id in self.authentication_methods:
return self.authentication_methods[authentication_method_id]
return None


class SDDID:
did = None
id = None
verification_methods = None
authentication_methods = None
network_participants: list = None

def __init__(self, did_json) -> None:
self.did = json.loads(did_json)
self.id = self.did["id"]
self.network_participants = self.did["networkMembers"]

assert(len(self.network_participants) > 0)

# populate verification methods:
self.verification_methods = {}
for method in self.did["verificationMethod"]:
self.verification_methods[method["id"]] = method

# populate authentication methods:
self.authentication_methods = {}
for method in self.did["authentication"]:
if isinstance(method, dict):
# fully specified method
self.authentication_methods[method["id"]] = method
elif isinstance(method, str):
# id points to a verification method
# TODO: if it points to a different did -> resolve that did and fetch method
if method in self.verification_methods:
self.authentication_methods[method] = self.verification_methods[method]

# ensure atleast one authentication method of type BlockchainNetworkMultiSig
group_multisig_auth_support = False
for method_id, method in self.authentication_methods.items():
if method["type"] == "BlockchainNetworkMultiSig":
group_multisig_auth_support = True
if not group_multisig_auth_support:
raise Exception("Network DID does not have BlockchainNetworkMultiSig authentication method")

# Get any one authentication method of type BlockchainNetworkMultiSig
def fetch_authentication_method(self) -> dict:
for method_id, method in self.authentication_methods.items():
if method["type"] == "BlockchainNetworkMultiSig":
return method
8 changes: 8 additions & 0 deletions plenum/server/plugin/did_plugin/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from plenum.common.constants import KeyValueStorageType


def get_config(config):
config.didPluginTransactionsFile = 'did_plugin_transactions'
config.didPluginStateStorage = KeyValueStorageType.Leveldb
config.didPluginStateDbName = 'did_plugin_state'
return config
82 changes: 82 additions & 0 deletions plenum/server/plugin/did_plugin/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import importlib

import pytest
from copy import deepcopy

from plenum import setup_plugins, PLUGIN_LEDGER_IDS, PLUGIN_CLIENT_REQUEST_FIELDS
from plenum.common.pkg_util import update_module_vars
from plenum.server.plugin.did_plugin import AUCTION_LEDGER_ID
from plenum.server.plugin.did_plugin.main import integrate_plugin_in_node


def do_plugin_initialisation_for_tests():
# The next imports and reloading are needed only in tests, since in
# production none of these modules would be loaded before plugins are
# setup (not initialised)
import plenum.server
import plenum.common

importlib.reload(plenum.server.replica)
importlib.reload(plenum.server.consensus.view_change_trigger_service)
importlib.reload(plenum.server.consensus.view_change_service)
importlib.reload(plenum.server.consensus.view_change_storages)
importlib.reload(plenum.server.consensus.ordering_service)
importlib.reload(plenum.server.consensus.ordering_service_msg_validator)
importlib.reload(plenum.server.node)
importlib.reload(plenum.server.catchup.utils)
importlib.reload(plenum.server.catchup.catchup_rep_service)
importlib.reload(plenum.server.catchup.cons_proof_service)
importlib.reload(plenum.server.catchup.ledger_leecher_service)
importlib.reload(plenum.server.catchup.node_leecher_service)
importlib.reload(plenum.server.catchup.seeder_service)
importlib.reload(plenum.server.message_handlers)
importlib.reload(plenum.server.observer.observable)
importlib.reload(plenum.common.ledger_manager)


@pytest.fixture(scope="module")
def tconf(tconf, request):
global PLUGIN_LEDGER_IDS, PLUGIN_CLIENT_REQUEST_FIELDS

orig_plugin_root = deepcopy(tconf.PLUGIN_ROOT)
orig_enabled_plugins = deepcopy(tconf.ENABLED_PLUGINS)
orig_plugin_ledger_ids = deepcopy(PLUGIN_LEDGER_IDS)
orig_plugin_client_req_fields = deepcopy(PLUGIN_CLIENT_REQUEST_FIELDS)

update_module_vars('plenum.config',
**{
'PLUGIN_ROOT': 'plenum.test.plugin',
'ENABLED_PLUGINS': ['demo_plugin', ],
})
PLUGIN_LEDGER_IDS = {AUCTION_LEDGER_ID}
PLUGIN_CLIENT_REQUEST_FIELDS = {}
setup_plugins()
do_plugin_initialisation_for_tests()

def reset():
global PLUGIN_LEDGER_IDS, PLUGIN_CLIENT_REQUEST_FIELDS
update_module_vars('plenum.config',
**{
'PLUGIN_ROOT': orig_plugin_root,
'ENABLED_PLUGINS': orig_enabled_plugins,
})
PLUGIN_LEDGER_IDS = orig_plugin_ledger_ids
PLUGIN_CLIENT_REQUEST_FIELDS = orig_plugin_client_req_fields
setup_plugins()

request.addfinalizer(reset)
return tconf


@pytest.fixture(scope="module")
def do_post_node_creation():
# Integrate plugin into each node.
def _post_node_creation(node):
integrate_plugin_in_node(node)

return _post_node_creation


@pytest.fixture(scope="module")
def txn_pool_node_set_post_creation(tconf, do_post_node_creation, txnPoolNodeSet):
return txnPoolNodeSet
Loading

0 comments on commit 456dcef

Please sign in to comment.