diff --git a/concepts/0167-data-consent-lifecycle/README.md b/concepts/0167-data-consent-lifecycle/README.md index fcf5029cf..26a6fbe16 100644 --- a/concepts/0167-data-consent-lifecycle/README.md +++ b/concepts/0167-data-consent-lifecycle/README.md @@ -26,6 +26,7 @@ * [Proof Request](#proof-request) * [Performing Proof Request](#performing-proof-request) * [Certification Revocation](#certification-revocation) +* [Implementation Reference](#Implementation Reference) * [Reference](#reference) * [Annex A: PDP Schema mapping to Kantara Consent Receipt](#annex-a-pdp-schema-mapping-to-kantara-consent-receipt) * [Prior art](#prior-art) @@ -410,6 +411,28 @@ These are the steps covered with certification revocation: - data authority initiated revocation (if owns schema base) +## Implementation Reference + +A python jupyter notebook is available as reference implementation +to help with implementation. The base for this example is +getting-started jupyter notebook. In order to run the example take +the following steps. + +1. Clone indy-sdk \ + + git clone https://github.com/hyperledger/indy-sdk.git +2. Copy over following files to doc/getting-started \ + - [consent-flow.ipynb](./reference-implementation/consent-flow.ipynb) + - [docker-compose.yml](./reference-implementation/docker-compose.yml) * + + Note * - Reason for changing the docker-compose.yml is to be able to + view consent-flow.ipynb. + +3. Ready to start docker-compose \ + + docker-compose up +4. Open html link and run consent-flow.ipynb + ## Reference *Provide guidance for implementers, procedures to inform testing, diff --git a/concepts/0167-data-consent-lifecycle/reference-implementation/consent-flow.ipynb b/concepts/0167-data-consent-lifecycle/reference-implementation/consent-flow.ipynb new file mode 100644 index 000000000..7276909b3 --- /dev/null +++ b/concepts/0167-data-consent-lifecycle/reference-implementation/consent-flow.ipynb @@ -0,0 +1,1025 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import asyncio\n", + "import time\n", + "from indy import anoncreds, crypto, did, ledger, pool, wallet, blob_storage\n", + "\n", + "import json\n", + "from typing import Optional\n", + "import os\n", + "\n", + "async def onboarding(_from, to):\n", + " print(\"\\\"{}\\\" -> Create and store in Wallet \\\"{} {}\\\" DID\".format(_from['name'], _from['name'], to['name']))\n", + " (from_to_did, from_to_key) = await did.create_and_store_my_did(_from['wallet'], \"{}\")\n", + "\n", + " print(\"\\\"{}\\\" -> Send Nym to Ledger for \\\"{} {}\\\" DID\".format(_from['name'], _from['name'], to['name']))\n", + " await send_nym(_from['pool'], _from['wallet'], _from['did'], from_to_did, from_to_key, None)\n", + "\n", + " print(\"\\\"{}\\\" -> Send connection request to {} with \\\"{} {}\\\" DID and nonce\"\n", + " .format(_from['name'], to['name'], _from['name'], to['name']))\n", + " connection_request = {\n", + " 'did': from_to_did,\n", + " 'nonce': 123456789\n", + " }\n", + "\n", + " if 'wallet' not in to:\n", + " print(\"\\\"{}\\\" -> Create wallet\".format(to['name']))\n", + " try:\n", + " await wallet.create_wallet(to['wallet_config'], to['wallet_credentials'])\n", + " except IndyError as ex:\n", + " if ex.error_code == ErrorCode.PoolLedgerConfigAlreadyExistsError:\n", + " pass\n", + " to['wallet'] = await wallet.open_wallet(to['wallet_config'], to['wallet_credentials'])\n", + "\n", + " print(\"\\\"{}\\\" -> Create and store in Wallet \\\"{} {}\\\" DID\".format(to['name'], to['name'], _from['name']))\n", + " (to_from_did, to_from_key) = await did.create_and_store_my_did(to['wallet'], \"{}\")\n", + "\n", + " print(\"\\\"{}\\\" -> Get key for did from \\\"{}\\\" connection request\".format(to['name'], _from['name']))\n", + " from_to_verkey = await did.key_for_did(_from['pool'], to['wallet'], connection_request['did'])\n", + "\n", + " print(\"\\\"{}\\\" -> Anoncrypt connection response for \\\"{}\\\" with \\\"{} {}\\\" DID, verkey and nonce\"\n", + " .format(to['name'], _from['name'], to['name'], _from['name']))\n", + " to['connection_response'] = json.dumps({\n", + " 'did': to_from_did,\n", + " 'verkey': to_from_key,\n", + " 'nonce': connection_request['nonce']\n", + " })\n", + " to['anoncrypted_connection_response'] = \\\n", + " await crypto.anon_crypt(from_to_verkey, to['connection_response'].encode('utf-8'))\n", + "\n", + " print(\"\\\"{}\\\" -> Send anoncrypted connection response to \\\"{}\\\"\".format(to['name'], _from['name']))\n", + " _from['anoncrypted_connection_response'] = to['anoncrypted_connection_response']\n", + "\n", + " print(\"\\\"{}\\\" -> Anondecrypt connection response from \\\"{}\\\"\".format(_from['name'], to['name']))\n", + " _from['connection_response'] = \\\n", + " json.loads((await crypto.anon_decrypt(_from['wallet'], from_to_key,\n", + " _from['anoncrypted_connection_response'])).decode(\"utf-8\"))\n", + "\n", + " print(\"\\\"{}\\\" -> Authenticates \\\"{}\\\" by comparision of Nonce\".format(_from['name'], to['name']))\n", + " assert connection_request['nonce'] == _from['connection_response']['nonce']\n", + "\n", + " print(\"\\\"{}\\\" -> Send Nym to Ledger for \\\"{} {}\\\" DID\".format(_from['name'], to['name'], _from['name']))\n", + " await send_nym(_from['pool'], _from['wallet'], _from['did'], to_from_did, to_from_key, None)\n", + "\n", + " return from_to_did, from_to_key, to_from_did, to_from_key, _from['connection_response']\n", + "\n", + "\n", + "async def get_verinym(_from, from_to_did, from_to_key, to, to_from_did, to_from_key):\n", + " print(\"\\\"{}\\\" -> Create and store in Wallet \\\"{}\\\" new DID\".format(to['name'], to['name']))\n", + " (to_did, to_key) = await did.create_and_store_my_did(to['wallet'], \"{}\")\n", + "\n", + " print(\"\\\"{}\\\" -> Authcrypt \\\"{} DID info\\\" for \\\"{}\\\"\".format(to['name'], to['name'], _from['name']))\n", + " to['did_info'] = json.dumps({\n", + " 'did': to_did,\n", + " 'verkey': to_key\n", + " })\n", + " to['authcrypted_did_info'] = \\\n", + " await crypto.auth_crypt(to['wallet'], to_from_key, from_to_key, to['did_info'].encode('utf-8'))\n", + "\n", + " print(\"\\\"{}\\\" -> Send authcrypted \\\"{} DID info\\\" to {}\".format(to['name'], to['name'], _from['name']))\n", + "\n", + " print(\"\\\"{}\\\" -> Authdecrypted \\\"{} DID info\\\" from {}\".format(_from['name'], to['name'], to['name']))\n", + " sender_verkey, authdecrypted_did_info_json, authdecrypted_did_info = \\\n", + " await auth_decrypt(_from['wallet'], from_to_key, to['authcrypted_did_info'])\n", + "\n", + " print(\"\\\"{}\\\" -> Authenticate {} by comparision of Verkeys\".format(_from['name'], to['name'], ))\n", + " assert sender_verkey == await did.key_for_did(_from['pool'], _from['wallet'], to_from_did)\n", + "\n", + " print(\"\\\"{}\\\" -> Send Nym to Ledger for \\\"{} DID\\\" with {} Role\"\n", + " .format(_from['name'], to['name'], to['role']))\n", + " await send_nym(_from['pool'], _from['wallet'], _from['did'], authdecrypted_did_info['did'],\n", + " authdecrypted_did_info['verkey'], to['role'])\n", + "\n", + " return to_did\n", + "\n", + "\n", + "async def send_nym(pool_handle, wallet_handle, _did, new_did, new_key, role):\n", + " nym_request = await ledger.build_nym_request(_did, new_did, new_key, None, role)\n", + " await ledger.sign_and_submit_request(pool_handle, wallet_handle, _did, nym_request)\n", + "\n", + "\n", + "async def send_schema(pool_handle, wallet_handle, _did, schema):\n", + " schema_request = await ledger.build_schema_request(_did, schema)\n", + " await ledger.sign_and_submit_request(pool_handle, wallet_handle, _did, schema_request)\n", + "\n", + "\n", + "async def send_cred_def(pool_handle, wallet_handle, _did, cred_def_json):\n", + " cred_def_request = await ledger.build_cred_def_request(_did, cred_def_json)\n", + " await ledger.sign_and_submit_request(pool_handle, wallet_handle, _did, cred_def_request)\n", + "\n", + "\n", + "async def get_schema(pool_handle, _did, schema_id):\n", + " get_schema_request = await ledger.build_get_schema_request(_did, schema_id)\n", + " get_schema_response = await ledger.submit_request(pool_handle, get_schema_request)\n", + " return await ledger.parse_get_schema_response(get_schema_response)\n", + "\n", + "\n", + "async def get_cred_def(pool_handle, _did, cred_def_id):\n", + " get_cred_def_request = await ledger.build_get_cred_def_request(_did, cred_def_id)\n", + " get_cred_def_response = await ledger.submit_request(pool_handle, get_cred_def_request)\n", + " return await ledger.parse_get_cred_def_response(get_cred_def_response)\n", + "\n", + "\n", + "async def get_credential_for_referent(search_handle, referent):\n", + " credentials = json.loads(\n", + " await anoncreds.prover_fetch_credentials_for_proof_req(search_handle, referent, 10))\n", + " return credentials[0]['cred_info']\n", + "\n", + "\n", + "async def prover_get_entities_from_ledger(pool_handle, _did, identifiers, actor):\n", + " schemas = {}\n", + " cred_defs = {}\n", + " rev_states = {}\n", + " for item in identifiers.values():\n", + " print(\"\\\"{}\\\" -> Get Schema from Ledger\".format(actor))\n", + " (received_schema_id, received_schema) = await get_schema(pool_handle, _did, item['schema_id'])\n", + " schemas[received_schema_id] = json.loads(received_schema)\n", + "\n", + " print(\"\\\"{}\\\" -> Get Credential Definition from Ledger\".format(actor))\n", + " (received_cred_def_id, received_cred_def) = await get_cred_def(pool_handle, _did, item['cred_def_id'])\n", + " cred_defs[received_cred_def_id] = json.loads(received_cred_def)\n", + "\n", + " if 'rev_reg_seq_no' in item:\n", + " pass # TODO Create Revocation States\n", + "\n", + " return json.dumps(schemas), json.dumps(cred_defs), json.dumps(rev_states)\n", + "\n", + "\n", + "async def verifier_get_entities_from_ledger(pool_handle, _did, identifiers, actor):\n", + " schemas = {}\n", + " cred_defs = {}\n", + " rev_reg_defs = {}\n", + " rev_regs = {}\n", + " for item in identifiers:\n", + " print(\"\\\"{}\\\" -> Get Schema from Ledger\".format(actor))\n", + " (received_schema_id, received_schema) = await get_schema(pool_handle, _did, item['schema_id'])\n", + " schemas[received_schema_id] = json.loads(received_schema)\n", + "\n", + " print(\"\\\"{}\\\" -> Get Credential Definition from Ledger\".format(actor))\n", + " (received_cred_def_id, received_cred_def) = await get_cred_def(pool_handle, _did, item['cred_def_id'])\n", + " cred_defs[received_cred_def_id] = json.loads(received_cred_def)\n", + "\n", + " if 'rev_reg_seq_no' in item:\n", + " pass # TODO Get Revocation Definitions and Revocation Registries\n", + "\n", + " return json.dumps(schemas), json.dumps(cred_defs), json.dumps(rev_reg_defs), json.dumps(rev_regs)\n", + "\n", + "\n", + "async def auth_decrypt(wallet_handle, key, message):\n", + " from_verkey, decrypted_message_json = await crypto.auth_decrypt(wallet_handle, key, message)\n", + " decrypted_message_json = decrypted_message_json.decode(\"utf-8\")\n", + " decrypted_message = json.loads(decrypted_message_json)\n", + " return from_verkey, decrypted_message_json, decrypted_message" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "pycharm": {} + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Getting started -> started\n", + "=== 1/9: Open Ledger ==\n", + "Open Pool Ledger: pool1\n", + "==============================\n", + "== 2/9: Setup Steward ==\n", + "=== Getting Trust Anchor credentials for Faber, Acme, Thrift and Government ==\n", + "------------------------------\n", + "\"Sovrin Steward\" -> Create wallet\n", + "\"Sovrin Steward\" -> Create and store in Wallet DID from seed\n", + "==============================\n", + "== 3/9: Onboarded Goverment ==\n", + "== Getting Trust Anchor credentials - Government Onboarding ==\n", + "------------------------------\n", + "\"Sovrin Steward\" -> Create and store in Wallet \"Sovrin Steward Government\" DID\n", + "\"Sovrin Steward\" -> Send Nym to Ledger for \"Sovrin Steward Government\" DID\n", + "\"Sovrin Steward\" -> Send connection request to Government with \"Sovrin Steward Government\" DID and nonce\n", + "\"Government\" -> Create wallet\n", + "\"Government\" -> Create and store in Wallet \"Government Sovrin Steward\" DID\n", + "\"Government\" -> Get key for did from \"Sovrin Steward\" connection request\n", + "\"Government\" -> Anoncrypt connection response for \"Sovrin Steward\" with \"Government Sovrin Steward\" DID, verkey and nonce\n", + "\"Government\" -> Send anoncrypted connection response to \"Sovrin Steward\"\n", + "\"Sovrin Steward\" -> Anondecrypt connection response from \"Government\"\n", + "\"Sovrin Steward\" -> Authenticates \"Government\" by comparision of Nonce\n", + "\"Sovrin Steward\" -> Send Nym to Ledger for \"Government Sovrin Steward\" DID\n", + "==============================\n", + "== Getting Trust Anchor credentials - Government getting Verinym ==\n", + "------------------------------\n", + "\"Government\" -> Create and store in Wallet \"Government\" new DID\n", + "\"Government\" -> Authcrypt \"Government DID info\" for \"Sovrin Steward\"\n", + "\"Government\" -> Send authcrypted \"Government DID info\" to Sovrin Steward\n", + "\"Sovrin Steward\" -> Authdecrypted \"Government DID info\" from Government\n", + "\"Sovrin Steward\" -> Authenticate Government by comparision of Verkeys\n", + "\"Sovrin Steward\" -> Send Nym to Ledger for \"Government DID\" with TRUST_ANCHOR Role\n", + "==============================\n", + "== 4/9: Onboarded Faber ==\n", + "== Getting Trust Anchor credentials - Faber Onboarding ==\n", + "------------------------------\n", + "\"Sovrin Steward\" -> Create and store in Wallet \"Sovrin Steward Faber\" DID\n", + "\"Sovrin Steward\" -> Send Nym to Ledger for \"Sovrin Steward Faber\" DID\n", + "\"Sovrin Steward\" -> Send connection request to Faber with \"Sovrin Steward Faber\" DID and nonce\n", + "\"Faber\" -> Create wallet\n", + "\"Faber\" -> Create and store in Wallet \"Faber Sovrin Steward\" DID\n", + "\"Faber\" -> Get key for did from \"Sovrin Steward\" connection request\n", + "\"Faber\" -> Anoncrypt connection response for \"Sovrin Steward\" with \"Faber Sovrin Steward\" DID, verkey and nonce\n", + "\"Faber\" -> Send anoncrypted connection response to \"Sovrin Steward\"\n", + "\"Sovrin Steward\" -> Anondecrypt connection response from \"Faber\"\n", + "\"Sovrin Steward\" -> Authenticates \"Faber\" by comparision of Nonce\n", + "\"Sovrin Steward\" -> Send Nym to Ledger for \"Faber Sovrin Steward\" DID\n", + "==============================\n", + "== Getting Trust Anchor credentials - Faber getting Verinym ==\n", + "------------------------------\n", + "\"Faber\" -> Create and store in Wallet \"Faber\" new DID\n", + "\"Faber\" -> Authcrypt \"Faber DID info\" for \"Sovrin Steward\"\n", + "\"Faber\" -> Send authcrypted \"Faber DID info\" to Sovrin Steward\n", + "\"Sovrin Steward\" -> Authdecrypted \"Faber DID info\" from Faber\n", + "\"Sovrin Steward\" -> Authenticate Faber by comparision of Verkeys\n", + "\"Sovrin Steward\" -> Send Nym to Ledger for \"Faber DID\" with TRUST_ANCHOR Role\n", + "Create blob storage\n", + "==============================\n", + "== 5/9: Onboarded Acme ==\n", + "== Getting Trust Anchor credentials - Acme Onboarding ==\n", + "------------------------------\n", + "\"Sovrin Steward\" -> Create and store in Wallet \"Sovrin Steward Acme\" DID\n", + "\"Sovrin Steward\" -> Send Nym to Ledger for \"Sovrin Steward Acme\" DID\n", + "\"Sovrin Steward\" -> Send connection request to Acme with \"Sovrin Steward Acme\" DID and nonce\n", + "\"Acme\" -> Create wallet\n", + "\"Acme\" -> Create and store in Wallet \"Acme Sovrin Steward\" DID\n", + "\"Acme\" -> Get key for did from \"Sovrin Steward\" connection request\n", + "\"Acme\" -> Anoncrypt connection response for \"Sovrin Steward\" with \"Acme Sovrin Steward\" DID, verkey and nonce\n", + "\"Acme\" -> Send anoncrypted connection response to \"Sovrin Steward\"\n", + "\"Sovrin Steward\" -> Anondecrypt connection response from \"Acme\"\n", + "\"Sovrin Steward\" -> Authenticates \"Acme\" by comparision of Nonce\n", + "\"Sovrin Steward\" -> Send Nym to Ledger for \"Acme Sovrin Steward\" DID\n", + "==============================\n", + "== Getting Trust Anchor credentials - Acme getting Verinym ==\n", + "------------------------------\n", + "\"Acme\" -> Create and store in Wallet \"Acme\" new DID\n", + "\"Acme\" -> Authcrypt \"Acme DID info\" for \"Sovrin Steward\"\n", + "\"Acme\" -> Send authcrypted \"Acme DID info\" to Sovrin Steward\n", + "\"Sovrin Steward\" -> Authdecrypted \"Acme DID info\" from Acme\n", + "\"Sovrin Steward\" -> Authenticate Acme by comparision of Verkeys\n", + "\"Sovrin Steward\" -> Send Nym to Ledger for \"Acme DID\" with TRUST_ANCHOR Role\n", + "==============================\n", + "=== 6/9: Schema setup ==\n", + "=== Credential Schemas Setup ==\n", + "------------------------------\n", + "\"Government\" -> Create \"Job-Certificate\" Schema\n", + "\"Government\" -> Send \"Job-Certificate\" Schema to Ledger\n", + "\"Government\" -> Create \"PDP\" Schema\n", + "\"Government\" -> Send \"PDP\" Schema to Ledger\n", + "==============================\n", + "=== 7/9: Faber Consent Receipt Setup ==\n", + "=== Faber Credential Definition Setup ==\n", + "------------------------------\n", + "\"Faber\" -> Get \"PDP\" Schema from Ledger\n", + "\"Faber\" -> Create and store in Wallet \"Faber PDP\" Credential Definition\n", + "\"Faber\" -> Send \"Faber PDP\" Credential Definition to Ledger\n", + "==============================\n", + "=== 8/9: Acme Proof ==\n", + "=== Acme Credential Definition Setup ==\n", + "------------------------------\n", + "\"Acme\" -> Get from Ledger \"Job-Certificate\" Schema\n", + "\"Acme\" -> Create and store in Wallet \"Acme Job-Certificate\" Credential Definition\n", + "\"Acme\" -> Send \"Acme Job-Certificate\" Credential Definition to Ledger\n", + "==============================\n", + "== 9/9: Alice onboarded ==\n", + "== Prep - Alice Onboarding ==\n", + "------------------------------\n", + "\"Faber\" -> Create and store in Wallet \"Faber Alice\" DID\n", + "\"Faber\" -> Send Nym to Ledger for \"Faber Alice\" DID\n", + "\"Faber\" -> Send connection request to Alice with \"Faber Alice\" DID and nonce\n", + "\"Alice\" -> Create wallet\n", + "\"Alice\" -> Create and store in Wallet \"Alice Faber\" DID\n", + "\"Alice\" -> Get key for did from \"Faber\" connection request\n", + "\"Alice\" -> Anoncrypt connection response for \"Faber\" with \"Alice Faber\" DID, verkey and nonce\n", + "\"Alice\" -> Send anoncrypted connection response to \"Faber\"\n", + "\"Faber\" -> Anondecrypt connection response from \"Alice\"\n", + "\"Faber\" -> Authenticates \"Alice\" by comparision of Nonce\n", + "\"Faber\" -> Send Nym to Ledger for \"Alice Faber\" DID\n", + "Getting started -> done\n", + "*********************************************\n", + "*********************************************\n", + "*** Creating Consent Receipt Certificatem ***\n", + "*********************************************\n", + "*********************************************\n", + "==============================\n", + "=== Getting PDP with Faber ==\n", + "==============================\n", + "== Getting PDP with Faber - Onboarding ==\n", + "------------------------------\n", + "\"Faber\" -> Create and store in Wallet \"Faber Alice\" DID\n", + "\"Faber\" -> Send Nym to Ledger for \"Faber Alice\" DID\n", + "\"Faber\" -> Send connection request to Alice with \"Faber Alice\" DID and nonce\n", + "\"Alice\" -> Create and store in Wallet \"Alice Faber\" DID\n", + "\"Alice\" -> Get key for did from \"Faber\" connection request\n", + "\"Alice\" -> Anoncrypt connection response for \"Faber\" with \"Alice Faber\" DID, verkey and nonce\n", + "\"Alice\" -> Send anoncrypted connection response to \"Faber\"\n", + "\"Faber\" -> Anondecrypt connection response from \"Alice\"\n", + "\"Faber\" -> Authenticates \"Alice\" by comparision of Nonce\n", + "\"Faber\" -> Send Nym to Ledger for \"Alice Faber\" DID\n", + "==============================\n", + "== Getting PDP with Faber - Getting PDP Credential ==\n", + "------------------------------\n", + "\"Faber\" -> Create \"PDP\" Credential Offer for Alice\n", + "\"Faber\" -> Get key for Alice did\n", + "\"Faber\" -> Authcrypt \"PDP\" Credential Offer for Alice\n", + "\"Faber\" -> Send authcrypted \"PDP\" Credential Offer to Alice\n", + "\"Alice\" -> Authdecrypted \"PDP\" Credential Offer from Faber\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "1114098bb96a4349959bf80cc78f30d3", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "VBox(children=(Box(children=(Box(children=(HTML(value='\\n

Privay Policy

\\n Purpose
\\n …" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\"Alice\" -> Create and store \"Alice\" Master Secret in Wallet\n", + "\"Alice\" -> Get \"Faber PDP\" Credential Definition from Ledger\n", + "\"Alice\" -> Create \"PDP\" Credential Request for Faber\n", + "\"Alice\" -> Authcrypt \"PDP\" Credential Request for Faber\n", + "\"Alice\" -> Send authcrypted \"PDP\" Credential Request to Faber\n", + "\"Faber\" -> Authdecrypt \"PDP\" Credential Request from Alice\n", + "\"Faber\" -> Create \"PDP\" Credential for Alice\n", + "\"Faber\" -> Authcrypt \"PDP\" Credential for Alice\n", + "\"Faber\" -> Send authcrypted \"PDP\" Credential to Alice\n", + "\"Alice\" -> Authdecrypted \"PDP\" Credential from Faber\n", + "\"Alice\" -> Store \"PDP\" Credential from Faber\n", + "Consent Receipt Certificate\n", + "{\"schema_id\":\"QFhKsBzE8ZVThtdEc4swwf:2:PDP:1.2\",\"cred_def_id\":\"G2BcB9MJCuGxGAKeYX62u8:3:CL:541:TAG1\",\"rev_reg_id\":null,\"values\":{\"expiration\":{\"raw\":\"2020-07-01\",\"encoded\":\"20200701\"},\"id\":{\"raw\":\"123-45-6789\",\"encoded\":\"3124141231422543541\"},\"first_name\":{\"raw\":\"Alice\",\"encoded\":\"1139481716457488690172217916278103335\"},\"limitation\":{\"raw\":\"360\",\"encoded\":\"360\"},\"last_name\":{\"raw\":\"Garcia\",\"encoded\":\"5321642780241790123587902456789123452\"},\"consent\":{\"raw\":\"1\",\"encoded\":\"1\"},\"validity_ttl\":{\"raw\":\"3\",\"encoded\":\"3\"}},\"signature\":{\"p_credential\":{\"m_2\":\"114149088040006641764699089875860843854045970786461354058704713399501515931137\",\"a\":\"70306835669066111361540999085770737234442113499954857422121593225721814789428722560887232933232250832395263603406977646196095994661926141608237811131759249773538838886254978680057860884913616526510239541242904988870668235772991206055560970482652385437557430912071294012488580826178990773099399654294549282801688205449580137480041174188338486688464133888105516978261619143577807872089559436144743171618561974958956409254393263471567731960849385588001833323797802996462691034939502665964287981536780022417027006778602128707912192656408117285068936055923263217917121753028634889580429128764627904114176055927616768797207\",\"e\":\"259344723055062059907025491480697571938277889515152306249728583105665800713306759149981690559193987143012367913206299323899696942213235956742929850138290324646550051479827899473067\",\"v\":\"6506508806032766069727550137568911163958828128389051338321755397390118681468319703967877230306595628055815015667172150190669333972888809915591886788531906634873683356356479187124137812670369400042500780929137844842200125263320337299095749632541803899246287554732462839482507024900559123804836806610834084988543502556080764455812635482727022569518909458331404680886528387182089215157135128313487662488975184027756483425024273591233472604308924436408267169487145112076020495996313353258953760539768150657964085928364344923076679122705983136377531985301716255731630621671411710144343408099094676800764082732426358100735571433642311475821620302382409061699610072214739717962481386785854580071676135207551598078600893451615993581471931124106903449670853027174862002008441814045819958901504729200752163757993594497140947112014\"},\"r_credential\":null},\"signature_correctness_proof\":{\"se\":\"5871070722555296023225621358182294069229040248932159825571695869751340419181006699291245757569952142953012733521176207717523938800381468614843980486744919086984205185727830626963582181401773749945218829404921457330809815380353965021956164892949164758420919431824038138523674956835862185489456307843508838365952216144623575975556108706045869807110905377283903001260631085790713219907139753514201426939490345560305442003211696712233720737769603252352826163348511565037897907850484259494290837585557666501322411745134540326874942704396425742663372013388849591403642025607631392469861916080318607282668997443603282019243\",\"c\":\"72311222642326098106468309283792752672440425237712995478296279984591162967815\"},\"rev_reg\":null,\"witness\":null}\n", + "*********************************************\n", + "*********************************************\n", + "*** Performing Proof (without PII) ***\n", + "*********************************************\n", + "==============================\n", + "=== Apply for the job with Acme ==\n", + "==============================\n", + "== Apply for the job with Acme - Onboarding ==\n", + "------------------------------\n", + "\"Acme\" -> Create and store in Wallet \"Acme Alice\" DID\n", + "\"Acme\" -> Send Nym to Ledger for \"Acme Alice\" DID\n", + "\"Acme\" -> Send connection request to Alice with \"Acme Alice\" DID and nonce\n", + "\"Alice\" -> Create and store in Wallet \"Alice Acme\" DID\n", + "\"Alice\" -> Get key for did from \"Acme\" connection request\n", + "\"Alice\" -> Anoncrypt connection response for \"Acme\" with \"Alice Acme\" DID, verkey and nonce\n", + "\"Alice\" -> Send anoncrypted connection response to \"Acme\"\n", + "\"Acme\" -> Anondecrypt connection response from \"Alice\"\n", + "\"Acme\" -> Authenticates \"Alice\" by comparision of Nonce\n", + "\"Acme\" -> Send Nym to Ledger for \"Alice Acme\" DID\n", + "==============================\n", + "== Apply for the job with Acme - PDP proving ==\n", + "------------------------------\n", + "\"Acme\" -> Create \"PDP\" Proof Request\n", + "\"Acme\" -> Get key for Alice did\n", + "\"Acme\" -> Authcrypt \"PDP\" Proof Request for Alice\n", + "\"Acme\" -> Send authcrypted \"PDP\" Proof Request to Alice\n", + "\"Alice\" -> Authdecrypt \"PDP\" Proof Request from Acme\n", + "\"Alice\" -> Get credentials for \"PDP\" Proof Request\n", + "\"Alice\" -> Get Schema from Ledger\n", + "\"Alice\" -> Get Credential Definition from Ledger\n", + "\"Alice\" -> Create \"PDP\" Proof\n", + "\"Alice\" -> Authcrypt \"PDP\" Proof for Acme\n", + "\"Alice\" -> Send authcrypted \"PDP\" Proof to Acme\n", + "\"Acme\" -> Authdecrypted \"PDP\" Proof from Alice\n", + "\"Acme\" -> Get Schema from Ledger\n", + "\"Acme\" -> Get Credential Definition from Ledger\n", + "\"Acme\" -> Verify \"PDP\" Proof from Alice\n", + "\"Acme\" -> Verify \"PDP\" Proof from Alice\n", + "PDP Proof Request\n", + "{'version': '0.1', 'name': 'PDP', 'nonce': '1432422343242122312411212', 'requested_predicates': {}, 'requested_attributes': {'attr3_referent': {'name': 'validity_ttl', 'restrictions': [{'cred_def_id': 'G2BcB9MJCuGxGAKeYX62u8:3:CL:541:TAG1'}]}, 'attr2_referent': {'name': 'consent', 'restrictions': [{'cred_def_id': 'G2BcB9MJCuGxGAKeYX62u8:3:CL:541:TAG1'}]}}}\n", + "Attribute consent confirmed\n", + "Attribute validity_ttl confirmed\n", + "Proof confirmed\n", + "*********************************************\n", + "*********************************************\n", + "*** Close ledger ***\n", + "*********************************************\n", + " \"Sovrin Steward\" -> Close and Delete wallet\n", + "\"Government\" -> Close and Delete wallet\n", + "\"Faber\" -> Close and Delete wallet\n", + "\"Acme\" -> Close and Delete wallet\n", + "\"Alice\" -> Close and Delete wallet\n", + "Close and Delete pool\n" + ] + } + ], + "source": [ + "import asyncio\n", + "import time\n", + "from indy import anoncreds, crypto, did, ledger, pool, wallet, blob_storage\n", + "import os\n", + "import json\n", + "from typing import Optional\n", + "from ipywidgets import Box, Layout, VBox, Output, HTML\n", + "import ipywidgets as widgets\n", + "\n", + "async def run():\n", + " print(\"Getting started -> started\")\n", + " print(\"=== 1/9: Open Ledger ==\")\n", + "\n", + "\n", + " # Set protocol version 2 to work with Indy Node 1.4\n", + " await pool.set_protocol_version(2)\n", + " \n", + " pool_ = {\n", + " 'name': 'pool1',\n", + " 'config': json.dumps({\"genesis_txn\": '/home/indy/sandbox/pool_transactions_genesis'})\n", + " }\n", + " print(\"Open Pool Ledger: {}\".format(pool_['name']))\n", + "\n", + " try:\n", + " await pool.create_pool_ledger_config(pool_['name'], pool_['config'])\n", + " except:\n", + " pass\n", + " pool_['handle'] = await pool.open_pool_ledger(pool_['name'], None)\n", + "\n", + " print(\"==============================\")\n", + " print(\"== 2/9: Setup Steward ==\")\n", + " print(\"=== Getting Trust Anchor credentials for Faber, Acme, Thrift and Government ==\")\n", + " print(\"------------------------------\")\n", + "\n", + " print(\"\\\"Sovrin Steward\\\" -> Create wallet\")\n", + " steward = {\n", + " 'name': \"Sovrin Steward\",\n", + " 'wallet_config': json.dumps({'id': 'sovrin_steward_wallet'}),\n", + " 'wallet_credentials': json.dumps({'key': 'steward_wallet_key'}),\n", + " 'pool': pool_['handle'],\n", + " 'seed': '000000000000000000000000Steward1'\n", + " }\n", + "\n", + " try:\n", + " await wallet.create_wallet(steward['wallet_config'], steward['wallet_credentials'])\n", + " except IndyError as ex:\n", + " if ex.error_code == ErrorCode.WalletAlreadyExistsError:\n", + " pass\n", + "\n", + " steward['wallet'] = await wallet.open_wallet(steward['wallet_config'], steward['wallet_credentials'])\n", + "\n", + " print(\"\\\"Sovrin Steward\\\" -> Create and store in Wallet DID from seed\")\n", + " steward['did_info'] = json.dumps({'seed': steward['seed']})\n", + " steward['did'], steward['key'] = await did.create_and_store_my_did(steward['wallet'], steward['did_info'])\n", + "\n", + " print(\"==============================\")\n", + " print(\"== 3/9: Onboarded Goverment ==\")\n", + " print(\"== Getting Trust Anchor credentials - Government Onboarding ==\")\n", + " print(\"------------------------------\")\n", + "\n", + " government = {\n", + " 'name': 'Government',\n", + " 'wallet_config': json.dumps({'id': 'government_wallet'}),\n", + " 'wallet_credentials': json.dumps({'key': 'government_wallet_key'}),\n", + " 'pool': pool_['handle'],\n", + " 'role': 'TRUST_ANCHOR'\n", + " }\n", + " steward['did_for_government'], steward['key_for_government'], government['did_for_steward'], \\\n", + " government['key_for_steward'], _ = await onboarding(steward, government)\n", + "\n", + " print(\"==============================\")\n", + " print(\"== Getting Trust Anchor credentials - Government getting Verinym ==\")\n", + " print(\"------------------------------\")\n", + "\n", + " government['did'] = await get_verinym(steward, steward['did_for_government'], steward['key_for_government'],\n", + " government, government['did_for_steward'], government['key_for_steward'])\n", + " \n", + " print(\"==============================\")\n", + " print(\"== 4/9: Onboarded Faber ==\")\n", + " print(\"== Getting Trust Anchor credentials - Faber Onboarding ==\")\n", + " print(\"------------------------------\")\n", + "\n", + " faber = {\n", + " 'name': 'Faber',\n", + " 'wallet_config': json.dumps({'id': 'faber_wallet'}),\n", + " 'wallet_credentials': json.dumps({'key': 'faber_wallet_key'}),\n", + " 'pool': pool_['handle'],\n", + " 'role': 'TRUST_ANCHOR'\n", + " }\n", + " steward['did_for_faber'], steward['key_for_faber'], faber['did_for_steward'], faber['key_for_steward'], _ = \\\n", + " await onboarding(steward, faber)\n", + "\n", + " print(\"==============================\")\n", + " print(\"== Getting Trust Anchor credentials - Faber getting Verinym ==\")\n", + " print(\"------------------------------\")\n", + "\n", + " faber['did'] = \\\n", + " await get_verinym(steward, steward['did_for_faber'], steward['key_for_faber'],\n", + " faber, faber['did_for_steward'], faber['key_for_steward'])\n", + " \n", + " print(\"Create blob storage\")\n", + " faber['tails_writer_config'] = json.dumps({'base_dir': str(os.path.join(\"/tmp\",\"tails\")), 'uri_pattern': ''})\n", + " faber['tails_writer'] = await blob_storage.open_writer('default', faber['tails_writer_config'])\n", + " \n", + " print(\"==============================\")\n", + " print(\"== 5/9: Onboarded Acme ==\")\n", + " print(\"== Getting Trust Anchor credentials - Acme Onboarding ==\")\n", + " print(\"------------------------------\")\n", + "\n", + " acme = {\n", + " 'name': 'Acme',\n", + " 'wallet_config': json.dumps({'id': 'acme_wallet'}),\n", + " 'wallet_credentials': json.dumps({'key': 'acme_wallet_key'}),\n", + " 'pool': pool_['handle'],\n", + " 'role': 'TRUST_ANCHOR'\n", + " }\n", + " steward['did_for_acme'], steward['key_for_acme'], acme['did_for_steward'], acme['key_for_steward'], _ = \\\n", + " await onboarding(steward, acme)\n", + " \n", + " print(\"==============================\")\n", + " print(\"== Getting Trust Anchor credentials - Acme getting Verinym ==\")\n", + " print(\"------------------------------\")\n", + "\n", + " acme['did'] = await get_verinym(steward, steward['did_for_acme'], steward['key_for_acme'],\n", + " acme, acme['did_for_steward'], acme['key_for_steward'])\n", + " \n", + " print(\"==============================\")\n", + " print(\"=== 6/9: Schema setup ==\")\n", + " print(\"=== Credential Schemas Setup ==\")\n", + " print(\"------------------------------\")\n", + "\n", + " print(\"\\\"Government\\\" -> Create \\\"Job-Certificate\\\" Schema\")\n", + " job_certificate = {\n", + " 'name': 'Job-Certificate',\n", + " 'version': '0.2',\n", + " 'attributes': ['first_name', 'last_name', 'salary', 'employee_status', 'experience']\n", + " }\n", + " (government['job_certificate_schema_id'], government['job_certificate_schema']) = \\\n", + " await anoncreds.issuer_create_schema(government['did'], job_certificate['name'], job_certificate['version'],\n", + " json.dumps(job_certificate['attributes']))\n", + " job_certificate_schema_id = government['job_certificate_schema_id']\n", + "\n", + " print(\"\\\"Government\\\" -> Send \\\"Job-Certificate\\\" Schema to Ledger\")\n", + " await send_schema(government['pool'], government['wallet'], government['did'], government['job_certificate_schema'])\n", + "\n", + " print(\"\\\"Government\\\" -> Create \\\"PDP\\\" Schema\")\n", + " pdp = {\n", + " 'name': 'PDP',\n", + " 'version': '1.2',\n", + " 'attributes': ['first_name', 'last_name', 'id', 'expiration', 'limitation', 'consent', 'validity_ttl']\n", + " }\n", + " (government['pdp_schema_id'], government['pdp_schema']) = \\\n", + " await anoncreds.issuer_create_schema(government['did'], pdp['name'], pdp['version'],\n", + " json.dumps(pdp['attributes']))\n", + " pdp_schema_id = government['pdp_schema_id']\n", + "\n", + " print(\"\\\"Government\\\" -> Send \\\"PDP\\\" Schema to Ledger\")\n", + " await send_schema(government['pool'], government['wallet'], government['did'], government['pdp_schema'])\n", + "\n", + " time.sleep(1) # sleep 1 second before getting schema\n", + " \n", + " print(\"==============================\")\n", + " print(\"=== 7/9: Faber Consent Receipt Setup ==\")\n", + " print(\"=== Faber Credential Definition Setup ==\")\n", + " print(\"------------------------------\")\n", + "\n", + " print(\"\\\"Faber\\\" -> Get \\\"PDP\\\" Schema from Ledger\")\n", + " (faber['pdp_schema_id'], faber['pdp_schema']) = \\\n", + " await get_schema(faber['pool'], faber['did'], pdp_schema_id)\n", + "\n", + " print(\"\\\"Faber\\\" -> Create and store in Wallet \\\"Faber PDP\\\" Credential Definition\")\n", + " pdp_cred_def = {\n", + " 'tag': 'TAG1',\n", + " 'type': 'CL',\n", + " 'config': {\"support_revocation\": False}\n", + " }\n", + " (faber['pdp_cred_def_id'], faber['pdp_cred_def']) = \\\n", + " await anoncreds.issuer_create_and_store_credential_def(faber['wallet'], faber['did'],\n", + " faber['pdp_schema'], pdp_cred_def['tag'],\n", + " pdp_cred_def['type'],\n", + " json.dumps(pdp_cred_def['config']))\n", + "\n", + " print(\"\\\"Faber\\\" -> Send \\\"Faber PDP\\\" Credential Definition to Ledger\")\n", + " await send_cred_def(faber['pool'], faber['wallet'], faber['did'], faber['pdp_cred_def'])\n", + "\n", + " print(\"==============================\")\n", + " print(\"=== 8/9: Acme Proof ==\")\n", + " print(\"=== Acme Credential Definition Setup ==\")\n", + " print(\"------------------------------\")\n", + "\n", + " print(\"\\\"Acme\\\" -> Get from Ledger \\\"Job-Certificate\\\" Schema\")\n", + " (acme['job_certificate_schema_id'], acme['job_certificate_schema']) = \\\n", + " await get_schema(acme['pool'], acme['did'], job_certificate_schema_id)\n", + "\n", + " print(\"\\\"Acme\\\" -> Create and store in Wallet \\\"Acme Job-Certificate\\\" Credential Definition\")\n", + " job_certificate_cred_def = {\n", + " 'tag': 'TAG1',\n", + " 'type': 'CL',\n", + " 'config': {\"support_revocation\": False}\n", + " }\n", + " (acme['job_certificate_cred_def_id'], acme['job_certificate_cred_def']) = \\\n", + " await anoncreds.issuer_create_and_store_credential_def(acme['wallet'], acme['did'],\n", + " acme['job_certificate_schema'],\n", + " job_certificate_cred_def['tag'],\n", + " job_certificate_cred_def['type'],\n", + " json.dumps(job_certificate_cred_def['config']))\n", + "\n", + " print(\"\\\"Acme\\\" -> Send \\\"Acme Job-Certificate\\\" Credential Definition to Ledger\")\n", + " await send_cred_def(acme['pool'], acme['wallet'], acme['did'], acme['job_certificate_cred_def'])\n", + " \n", + " print(\"==============================\")\n", + " print(\"== 9/9: Alice onboarded ==\")\n", + " print(\"== Prep - Alice Onboarding ==\")\n", + " print(\"------------------------------\")\n", + " \n", + " alice = {\n", + " 'name': 'Alice',\n", + " 'wallet_config': json.dumps({'id': 'alice_wallet'}),\n", + " 'wallet_credentials': json.dumps({'key': 'alice_wallet_key'}),\n", + " 'pool': pool_['handle'],\n", + " }\n", + " faber['did_for_alice'], faber['key_for_alice'], alice['did_for_faber'], alice['key_for_faber'], \\\n", + " faber['alice_connection_response'] = await onboarding(faber, alice)\n", + " \n", + " print(\"Getting started -> done\")\n", + " \n", + " print(\"*********************************************\")\n", + " print(\"*********************************************\")\n", + " print(\"*** Creating Consent Receipt Certificatem ***\")\n", + " print(\"*********************************************\")\n", + " print(\"*********************************************\")\n", + "\n", + " print(\"==============================\")\n", + " print(\"=== Getting PDP with Faber ==\")\n", + " print(\"==============================\")\n", + " print(\"== Getting PDP with Faber - Onboarding ==\")\n", + " print(\"------------------------------\")\n", + "\n", + " faber['did_for_alice'], faber['key_for_alice'], alice['did_for_faber'], alice['key_for_faber'], \\\n", + " faber['alice_connection_response'] = await onboarding(faber, alice)\n", + "\n", + " print(\"==============================\")\n", + " print(\"== Getting PDP with Faber - Getting PDP Credential ==\")\n", + " print(\"------------------------------\")\n", + "\n", + " print(\"\\\"Faber\\\" -> Create \\\"PDP\\\" Credential Offer for Alice\")\n", + " faber['pdp_cred_offer'] = \\\n", + " await anoncreds.issuer_create_credential_offer(faber['wallet'], faber['pdp_cred_def_id'])\n", + "\n", + " print(\"\\\"Faber\\\" -> Get key for Alice did\")\n", + " faber['alic_key_for_faber'] = \\\n", + " await did.key_for_did(faber['pool'], faber['wallet'], faber['alice_connection_response']['did'])\n", + "\n", + " print(\"\\\"Faber\\\" -> Authcrypt \\\"PDP\\\" Credential Offer for Alice\")\n", + " faber['authcrypted_pdp_cred_offer'] = \\\n", + " await crypto.auth_crypt(faber['wallet'], faber['key_for_alice'], faber['alic_key_for_faber'],\n", + " faber['pdp_cred_offer'].encode('utf-8'))\n", + "\n", + " print(\"\\\"Faber\\\" -> Send authcrypted \\\"PDP\\\" Credential Offer to Alice\")\n", + " alice['authcrypted_pdp_cred_offer'] = faber['authcrypted_pdp_cred_offer']\n", + " print(\"\\\"Alice\\\" -> Authdecrypted \\\"PDP\\\" Credential Offer from Faber\")\n", + " alice['faber_key_for_alice'], alice['pdp_cred_offer'], authdecrypted_pdp_cred_offer = \\\n", + " await auth_decrypt(alice['wallet'], alice['key_for_faber'], alice['authcrypted_pdp_cred_offer'])\n", + " alice['pdp_schema_id'] = authdecrypted_pdp_cred_offer['schema_id']\n", + " alice['pdp_cred_def_id'] = authdecrypted_pdp_cred_offer['cred_def_id']\n", + "\n", + "\n", + " # privacy agreement\n", + " form_item_layout = Layout(\n", + " display='flex',\n", + " flex_flow='row',\n", + " justify_content='space-between'\n", + " )\n", + " \n", + " form_items = [\n", + " Box([HTML(value= '''\n", + "

Privay Policy

\n", + " Purpose
\n", + " Private Data is collected to improve services. The data is used for purpose a, b and c.
\n", + " Data collected
\n", + " Data is collected while using the service which expires on 2020-07-01. After this period if \n", + " service is not renewed then no more data is collected.
\n", + " Data limitation
\n", + " Data is only kept for a duration of 1 year.
\n", + " Data sharing
\n", + " Data may be shared with your consent with Acme to provided additional service of \n", + " recommendation on study plan in order to secure a job after college.\n", + " ''')], layout=form_item_layout),\n", + " Box([HTML(value='Once you have read the privacy policy indicate if you agree with the conditions of using of your \\\n", + " private data.')], layout=form_item_layout)\n", + " ]\n", + "\n", + " form = Box(form_items, layout=Layout(\n", + " display='flex',\n", + " flex_flow='column',\n", + " border='solid 2px',\n", + " align_items='stretch',\n", + " width='100%'\n", + " ))\n", + "\n", + " out_cert = Output()\n", + " display(VBox([form,out_cert]))\n", + "\n", + " print(\"\\\"Alice\\\" -> Create and store \\\"Alice\\\" Master Secret in Wallet\")\n", + " alice['master_secret_id'] = await anoncreds.prover_create_master_secret(alice['wallet'], None)\n", + "\n", + " print(\"\\\"Alice\\\" -> Get \\\"Faber PDP\\\" Credential Definition from Ledger\")\n", + " (alice['faber_pdp_cred_def_id'], alice['faber_pdp_cred_def']) = \\\n", + " await get_cred_def(alice['pool'], alice['did_for_faber'], alice['pdp_cred_def_id'])\n", + "\n", + " print(\"\\\"Alice\\\" -> Create \\\"PDP\\\" Credential Request for Faber\")\n", + " (alice['pdp_cred_request'], alice['pdp_cred_request_metadata']) = \\\n", + " await anoncreds.prover_create_credential_req(alice['wallet'], alice['did_for_faber'],\n", + " alice['pdp_cred_offer'], alice['faber_pdp_cred_def'],\n", + " alice['master_secret_id'])\n", + "\n", + " print(\"\\\"Alice\\\" -> Authcrypt \\\"PDP\\\" Credential Request for Faber\")\n", + " alice['authcrypted_pdp_cred_request'] = \\\n", + " await crypto.auth_crypt(alice['wallet'], alice['key_for_faber'], alice['faber_key_for_alice'],\n", + " alice['pdp_cred_request'].encode('utf-8'))\n", + "\n", + " #TODO: values come from entry overlay\n", + " \n", + " print(\"\\\"Alice\\\" -> Send authcrypted \\\"PDP\\\" Credential Request to Faber\")\n", + " alice['pdp_cred_values'] = json.dumps({\n", + " \"first_name\": {\"raw\": \"Alice\", \"encoded\": \"1139481716457488690172217916278103335\"},\n", + " \"last_name\": {\"raw\": \"Garcia\", \"encoded\": \"5321642780241790123587902456789123452\"},\n", + " \"id\": {\"raw\": \"123-45-6789\", \"encoded\": \"3124141231422543541\"},\n", + " \"expiration\": {\"raw\": \"2020-07-01\", \"encoded\": \"20200701\"},\n", + " \"limitation\": {\"raw\": \"360\", \"encoded\": \"360\"},\n", + " \"consent\": {\"raw\": \"1\", \"encoded\": \"1\"},\n", + " \"validity_ttl\": {\"raw\": \"3\", \"encoded\": \"3\"}\n", + " })\n", + " \n", + " faber['authcrypted_pdp_cred_request'] = alice['authcrypted_pdp_cred_request']\n", + " faber['alice_pdp_cred_values'] = alice['pdp_cred_values']\n", + "\n", + " print(\"\\\"Faber\\\" -> Authdecrypt \\\"PDP\\\" Credential Request from Alice\")\n", + " faber['alice_key_for_faber'], faber['pdp_cred_request'], _ = \\\n", + " await auth_decrypt(faber['wallet'], faber['key_for_alice'], faber['authcrypted_pdp_cred_request'])\n", + " \n", + " #TODO: verify that default values are not modified/hacked\n", + "\n", + " print(\"\\\"Faber\\\" -> Create \\\"PDP\\\" Credential for Alice\")\n", + "\n", + " # Issuer Opens Tails reader\n", + " faber['blob_storage_reader_cfg_handle'] = await blob_storage.open_reader('default', faber['tails_writer_config'])\n", + " \n", + " # pdp_cred is cred_json\n", + " faber['pdp_cred'], faber['cred_revoc_id'], faber['revoc_reg_delta_json'] = \\\n", + " await anoncreds.issuer_create_credential(faber['wallet'], faber['pdp_cred_offer'],\n", + " faber['pdp_cred_request'],\n", + " faber['alice_pdp_cred_values'], None, None)\n", + "\n", + "\n", + " print(\"\\\"Faber\\\" -> Authcrypt \\\"PDP\\\" Credential for Alice\")\n", + " faber['authcrypted_pdp_cred'] = \\\n", + " await crypto.auth_crypt(faber['wallet'], faber['key_for_alice'], faber['alice_key_for_faber'],\n", + " faber['pdp_cred'].encode('utf-8'))\n", + "\n", + " print(\"\\\"Faber\\\" -> Send authcrypted \\\"PDP\\\" Credential to Alice\")\n", + " alice['authcrypted_pdp_cred'] = faber['authcrypted_pdp_cred']\n", + "\n", + " print(\"\\\"Alice\\\" -> Authdecrypted \\\"PDP\\\" Credential from Faber\")\n", + " _, alice['pdp_cred'], _ = \\\n", + " await auth_decrypt(alice['wallet'], alice['key_for_faber'], alice['authcrypted_pdp_cred'])\n", + "\n", + " #TODO: Alice should verify that same values as she sends it\n", + " print(\"\\\"Alice\\\" -> Store \\\"PDP\\\" Credential from Faber\")\n", + " _, alice['pdp_cred_def'] = await get_cred_def(alice['pool'], alice['did_for_faber'],\n", + " alice['pdp_cred_def_id'])\n", + "\n", + " await anoncreds.prover_store_credential(alice['wallet'], None, alice['pdp_cred_request_metadata'],\n", + " alice['pdp_cred'], alice['pdp_cred_def'], None)\n", + " \n", + " print('Consent Receipt Certificate')\n", + " print(alice['pdp_cred'])\n", + " \n", + " print(\"*********************************************\")\n", + " print(\"*********************************************\")\n", + " print(\"*** Performing Proof (without PII) ***\")\n", + " print(\"*********************************************\")\n", + "\n", + " print(\"==============================\")\n", + " print(\"=== Apply for the job with Acme ==\")\n", + " print(\"==============================\")\n", + " print(\"== Apply for the job with Acme - Onboarding ==\")\n", + " print(\"------------------------------\")\n", + "\n", + " acme['did_for_alice'], acme['key_for_alice'], alice['did_for_acme'], alice['key_for_acme'], \\\n", + " acme['alice_connection_response'] = await onboarding(acme, alice)\n", + "\n", + " print(\"==============================\")\n", + " print(\"== Apply for the job with Acme - PDP proving ==\")\n", + " print(\"------------------------------\")\n", + "\n", + " print(\"\\\"Acme\\\" -> Create \\\"PDP\\\" Proof Request\")\n", + " acme['pdp_proof_request'] = json.dumps({\n", + " 'nonce': '1432422343242122312411212',\n", + " 'name': 'PDP',\n", + " 'version': '0.1',\n", + " 'requested_attributes': {\n", + " 'attr2_referent': {\n", + " 'name': 'consent',\n", + " 'restrictions': [{'cred_def_id': faber['pdp_cred_def_id']}]\n", + " } \n", + ",\n", + " 'attr3_referent': {\n", + " 'name': 'validity_ttl',\n", + " 'restrictions': [{'cred_def_id': faber['pdp_cred_def_id']}]\n", + " } \n", + " },\n", + " 'requested_predicates': {}\n", + " })\n", + " \n", + " print(\"\\\"Acme\\\" -> Get key for Alice did\")\n", + " acme['alice_key_for_acme'] = \\\n", + " await did.key_for_did(acme['pool'], acme['wallet'], acme['alice_connection_response']['did'])\n", + "\n", + " print(\"\\\"Acme\\\" -> Authcrypt \\\"PDP\\\" Proof Request for Alice\")\n", + " acme['authcrypted_pdp_proof_request'] = \\\n", + " await crypto.auth_crypt(acme['wallet'], acme['key_for_alice'], acme['alice_key_for_acme'],\n", + " acme['pdp_proof_request'].encode('utf-8'))\n", + "\n", + " print(\"\\\"Acme\\\" -> Send authcrypted \\\"PDP\\\" Proof Request to Alice\")\n", + " alice['authcrypted_pdp_proof_request'] = acme['authcrypted_pdp_proof_request']\n", + "\n", + " print(\"\\\"Alice\\\" -> Authdecrypt \\\"PDP\\\" Proof Request from Acme\")\n", + " alice['acme_key_for_alice'], alice['pdp_proof_request'], _ = \\\n", + " await auth_decrypt(alice['wallet'], alice['key_for_acme'], alice['authcrypted_pdp_proof_request'])\n", + "\n", + " print(\"\\\"Alice\\\" -> Get credentials for \\\"PDP\\\" Proof Request\")\n", + "\n", + " search_for_pdp_proof_request = \\\n", + " await anoncreds.prover_search_credentials_for_proof_req(alice['wallet'],\n", + " alice['pdp_proof_request'], None)\n", + "\n", + " cred_for_attr2 = await get_credential_for_referent(search_for_pdp_proof_request, 'attr2_referent')\n", + " cred_for_attr3 = await get_credential_for_referent(search_for_pdp_proof_request, 'attr3_referent')\n", + "\n", + " await anoncreds.prover_close_credentials_search_for_proof_req(search_for_pdp_proof_request)\n", + "\n", + " alice['creds_for_pdp_proof'] = {cred_for_attr2['referent']: cred_for_attr2,\n", + " cred_for_attr3['referent']: cred_for_attr3}\n", + "\n", + " alice['schemas'], alice['cred_defs'], alice['revoc_states'] = \\\n", + " await prover_get_entities_from_ledger(alice['pool'], alice['did_for_acme'],\n", + " alice['creds_for_pdp_proof'], alice['name'])\n", + "\n", + " print(\"\\\"Alice\\\" -> Create \\\"PDP\\\" Proof\")\n", + " alice['pdp_requested_creds'] = json.dumps({\n", + " 'self_attested_attributes': {},\n", + " 'requested_attributes': {\n", + " 'attr2_referent': {'cred_id': cred_for_attr2['referent'], 'revealed': True},\n", + " 'attr3_referent': {'cred_id': cred_for_attr3['referent'], 'revealed': True}\n", + " },\n", + " 'requested_predicates': {}\n", + " })\n", + "\n", + " alice['pdp_proof'] = \\\n", + " await anoncreds.prover_create_proof(alice['wallet'], alice['pdp_proof_request'],\n", + " alice['pdp_requested_creds'], alice['master_secret_id'],\n", + " alice['schemas'], alice['cred_defs'], alice['revoc_states'])\n", + "\n", + " print(\"\\\"Alice\\\" -> Authcrypt \\\"PDP\\\" Proof for Acme\")\n", + " alice['authcrypted_pdp_proof'] = \\\n", + " await crypto.auth_crypt(alice['wallet'], alice['key_for_acme'], alice['acme_key_for_alice'],\n", + " alice['pdp_proof'].encode('utf-8'))\n", + "\n", + " print(\"\\\"Alice\\\" -> Send authcrypted \\\"PDP\\\" Proof to Acme\")\n", + " acme['authcrypted_pdp_proof'] = alice['authcrypted_pdp_proof']\n", + " \n", + " print(\"\\\"Acme\\\" -> Authdecrypted \\\"PDP\\\" Proof from Alice\")\n", + " _, acme['pdp_proof'], decrypted_pdp_proof = \\\n", + " await auth_decrypt(acme['wallet'], acme['key_for_alice'], acme['authcrypted_pdp_proof'])\n", + "\n", + " acme['schemas'], acme['cred_defs'], acme['revoc_ref_defs'], acme['revoc_regs'] = \\\n", + " await verifier_get_entities_from_ledger(acme['pool'], acme['did'],\n", + " decrypted_pdp_proof['identifiers'], acme['name'])\n", + "\n", + " print(\"\\\"Acme\\\" -> Verify \\\"PDP\\\" Proof from Alice\")\n", + " try:\n", + " assert '1' == \\\n", + " decrypted_pdp_proof['requested_proof']['revealed_attrs']['attr2_referent']['raw']\n", + " assert2 = ' confirmed'\n", + " except:\n", + " assert2 = ' failed'\n", + " \n", + " print(\"\\\"Acme\\\" -> Verify \\\"PDP\\\" Proof from Alice\")\n", + " try:\n", + " assert '3' == \\\n", + " decrypted_pdp_proof['requested_proof']['revealed_attrs']['attr3_referent']['raw']\n", + " assert3 = ' confirmed'\n", + " except:\n", + " assert3 = ' failed'\n", + " try:\n", + " assert await anoncreds.verifier_verify_proof(acme['pdp_proof_request'], acme['pdp_proof'],\n", + " acme['schemas'], acme['cred_defs'], acme['revoc_ref_defs'],\n", + " acme['revoc_regs'])\n", + " proof1 = 'Proof confirmed'\n", + " except AssertionError as e:\n", + " proof1 = 'Proof failed'\n", + " \n", + " print('PDP Proof Request')\n", + " print(json.loads(acme['pdp_proof_request']))\n", + " print('Attribute '+json.loads(acme['pdp_proof_request'])['requested_attributes']['attr2_referent']['name'] + assert2)\n", + " print('Attribute '+json.loads(acme['pdp_proof_request'])['requested_attributes']['attr3_referent']['name'] + assert3)\n", + " print(proof1)\n", + " \n", + " print(\"*********************************************\")\n", + " print(\"*********************************************\")\n", + " print(\"*** Close ledger ***\")\n", + " print(\"*********************************************\")\n", + "\n", + " print(\" \\\"Sovrin Steward\\\" -> Close and Delete wallet\")\n", + " await wallet.close_wallet(steward['wallet'])\n", + " await wallet.delete_wallet(steward['wallet_config'], steward['wallet_credentials'])\n", + "\n", + " print(\"\\\"Government\\\" -> Close and Delete wallet\")\n", + " await wallet.close_wallet(government['wallet'])\n", + " await wallet.delete_wallet(government['wallet_config'], government['wallet_credentials'])\n", + " \n", + " try:\n", + " print(\"\\\"Faber\\\" -> Close and Delete wallet\")\n", + " await wallet.close_wallet(faber['wallet'])\n", + " await wallet.delete_wallet(faber['wallet_config'], faber['wallet_credentials'])\n", + " except:\n", + " pass\n", + " \n", + " try:\n", + " print(\"\\\"Acme\\\" -> Close and Delete wallet\")\n", + " await wallet.close_wallet(acme['wallet'])\n", + " await wallet.delete_wallet(acme['wallet_config'], acme['wallet_credentials'])\n", + " except:\n", + " pass\n", + " \n", + " try:\n", + " print(\"\\\"Alice\\\" -> Close and Delete wallet\")\n", + " await wallet.close_wallet(alice['wallet'])\n", + " await wallet.delete_wallet(alice['wallet_config'], alice['wallet_credentials'])\n", + " except:\n", + " pass\n", + " \n", + " print(\"Close and Delete pool\")\n", + " await pool.close_pool_ledger(pool_['handle'])\n", + " await pool.delete_pool_ledger_config(pool_['name'])\n", + " \n", + "if __name__ == '__main__':\n", + " loop = asyncio.new_event_loop()\n", + " asyncio.set_event_loop(loop)\n", + " loop.run_until_complete(run())\n", + " time.sleep(1) # FIXME waiting for libindy thread complete\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": {} + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "hide_input": false, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.5.2" + }, + "stem_cell": { + "cell_type": "raw", + "metadata": { + "pycharm": { + "metadata": false + } + }, + "source": "" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/concepts/0167-data-consent-lifecycle/reference-implementation/docker-compose.yml b/concepts/0167-data-consent-lifecycle/reference-implementation/docker-compose.yml new file mode 100644 index 000000000..913bd0ae7 --- /dev/null +++ b/concepts/0167-data-consent-lifecycle/reference-implementation/docker-compose.yml @@ -0,0 +1,52 @@ +version: '2' +services: + indy_pool: + build: + context: ../../ci/ + dockerfile: indy-pool.dockerfile + args: + pool_ip: '10.0.0.2' + image: indy_pool + container_name: indy_pool + working_dir: /home/indy + ports: + - "9701:9701" + - "9702:9702" + - "9703:9703" + - "9704:9704" + - "9705:9705" + - "9706:9706" + - "9707:9707" + - "9708:9708" + networks: + pool_network: + ipv4_address: 10.0.0.2 + volumes: + - sandbox:/var/lib/indy/sandbox/ + jupyter: + build: + context: . + dockerfile: getting-started.dockerfile + command: jupyter notebook --ip=0.0.0.0 + image: getting-started + container_name: getting_started + working_dir: /home/indy + volumes: + - ./:/home/indy + - sandbox:/home/indy/sandbox + ports: + - "8888:8888" + networks: + - pool_network + links: + - indy_pool +networks: + pool_network: + driver: bridge + ipam: + driver: default + config: + - + subnet: 10.0.0.0/24 +volumes: + sandbox: