# TNO PET Lab - secure Multi-Party Computation (MPC) - Protocols - Risk Propagation
Secure Risk Propagation initially developed within the MPC4AML project.
### PET Lab
The TNO PET Lab consists of generic software components, procedures, and functionalities developed and maintained on a regular basis to facilitate and aid in the development of PET solutions. The lab is a cross-project initiative allowing us to integrate and reuse previously developed PET functionalities to boost the development of new protocols and solutions.
The package `tno.mpc.protocols.risk_propagation` is part of the [TNO Python Toolbox](https://github.com/TNO-PET).
_Limitations in (end-)use: the content of this software package may solely be used for applications that comply with international export control laws._
_This implementation of cryptographic software has not been audited. Use at your own risk._
## Documentation
Documentation of the `tno.mpc.protocols.risk_propagation` package can be found
[here](https://docs.pet.tno.nl/mpc/protocols/risk_propagation/2.2.3).
## Install
Easily install the `tno.mpc.protocols.risk_propagation` package using `pip`:
```console
$ python -m pip install tno.mpc.protocols.risk_propagation
```
_Note:_ If you are cloning the repository and wish to edit the source code, be
sure to install the package in editable mode:
```console
$ python -m pip install -e 'tno.mpc.protocols.risk_propagation'
```
If you wish to run the tests you can use:
```console
$ python -m pip install 'tno.mpc.protocols.risk_propagation[tests]'
```
_Note:_ A significant performance improvement can be achieved by installing the GMPY2 library.
```console
$ python -m pip install 'tno.mpc.protocols.risk_propagation[gmpy]'
```
## Protocol description
Risk propagation is an algorithm that propagates risk scores through a (transaction) network.
Using distributed partial homomorphic encryption, the secure risk propagation implementation performs this algorithm on a network that is distributed among multiple parties.
As input of the algorithm, every party possesses a list of nodes (i.e. bank accounts) with initial risk scores and has a list of transactions (weighted, directed edges) from and to its bank accounts.
Using encrypted incoming risk scores scores from other parties, every party can securely update its risk scores using the formula for risk propagation.
After a set number of iterations, the eventual risk scores are revealed to the parties that own the accounts, using the distributed private key.
In [ERCIM News 126 (July 2021)](https://ercim-news.ercim.eu/en126/special/privacy-preserving-collaborative-money-laundering-detection), we presented a more elaborate protocol descriptions. Figure 1 demonstrates a high-level overview of the idea behind the protocol. Figure 2 visualizes the decentralized approach.
<figure>
<img src="assets/risk-propagation-overview.svg" width=100% alt="Risk Propagation High Level Overview"/>
<figcaption>
__Figure 1.__ _We consider a three-bank scenario (Orange, Blue, and Purple). In this scenario the first (left) account at bank Orange is classified as high risk (due to e.g., large cash deposits) by bank Orange.
This account wishes to launder its resources. To stay under the radar, the resources are funnelled through multiple accounts, at various banks, before arriving at their eventual destination, e.g., the account at bank Purple (right).
To detect money laundering, we wish to follow (propagate) the risky money and classify the endpoint as high risk too. Full (global) knowledge of the network enables us to propagate the risk.
However, how can we achieve something similar when there is only partial (local) knowledge of the entire network available? This is where MPC comes into play._
</figcaption>
</figure>
<figure>
<img src="assets/approach.svg" width=100% alt="Risk Propagation Decentralized Approach"/>
<figcaption>
__Figure 2.__ _In our approach, the data is analyzed in a decentralized manner. From left-to-right, we visualize encryption,
propagation and decryption. The parties encrypt their data using the additive homomorphic encryption scheme, no
communication takes place. Once the data is encrypted locally, the distributed propagation (computation) over the
encrypted data takes place. During this computation the data remains encrypted, the parties communicate intermediate
(encrypted) results, and there is no central party. During the decryption phase, we need to decrypt the encrypted values
with every party's key. We view the decryption from the green party's perspective. The lock on the risk scores belonging to
the green party is opened part-by-part and the final opening happens by the green party. This ensures that only the green
party gets to see the decrypted, propagated risk scores of his own bank accounts._
</figcaption>
</figure>
## Usage
The protocol is symmetric. For determining a secure set of parameters for the distributed keygen we refer to [protocols.distributed_keygen](https://github.com/TNO-MPC/protocols.distributed_keygen/#usage).
### Input
For the input two numpy arrays are expected. The structure and types are given in the tables below:
Input of the accounts:
| id | risk_score |
|--------|------------|
| string | float 64 |
Input of the transactions:
| id_source | bank_source | id_destination | bank_destination | amount |
|-----------|-------------|----------------|------------------|--------|
| string | string | string | string | int32 |
A string is expected to consist out of at most 100 unicode characters.
For example data see the folder `example_data` in `tno/mpc/protocols/risk_propagation`.
### Example usage
>`example_usage.py`
>```python
>"""
> Example usage for performing secure risk propagation
> Run three separate instances e.g.,
> $ python example_usage.py -p Alice
> $ python example_usage.py -p Bob
> $ python example_usage.py -p Charlie
>"""
>import argparse
>import asyncio
>
>from tno.mpc.communication import Pool
>from tno.mpc.protocols.distributed_keygen import DistributedPaillier
>
>from tno.mpc.protocols.risk_propagation import Player
>from tno.mpc.protocols.risk_propagation.test.test_data.small import input_data
>
>"""
>Default parameters for distributed keygen
>"""
>corruption_threshold = 1 # corruption threshold
>key_length = 512 # bit length of private key
>prime_thresh = 2000 # threshold for primality check
>correct_param_biprime = 40 # correctness parameter for biprimality test
>stat_sec_shamir = (
> 40 # statistical security parameter for secret sharing over the integers
>)
>
>
>def parse_args():
> parser = argparse.ArgumentParser()
> parser.add_argument(
> "-p",
> "--player",
> help="Name of the sending player",
> type=str.lower,
> required=True,
> choices=["alice", "bob", "charlie", "all"],
> )
> args = parser.parse_args()
> return args
>
>
>async def main(player, pool, nodes, transactions, distributed):
> distributed_paillier = await DistributedPaillier.from_security_parameter(
> pool,
> corruption_threshold,
> key_length,
> prime_thresh,
> correct_param_biprime,
> stat_sec_shamir,
> precision=8,
> distributed=distributed,
> )
> player_instance = Player(player, nodes, transactions, pool, distributed_paillier)
>
> await player_instance.run_protocol(iterations=3)
> print(player_instance.risk_scores)
> await asyncio.gather(
> *[shutdown(pool, player) for player in pool.pool_handlers.keys()]
> )
>
>
>async def shutdown(pool, player):
> await pool.send(player, "Shutting down..")
> return await pool.recv(player)
>
>
>async def generate_instance(player, distributed=True):
> parties = {
> "alice": {"address": "127.0.0.1", "port": 8080},
> "bob": {"address": "127.0.0.1", "port": 8081},
> "charlie": {"address": "127.0.0.1", "port": 8082},
> }
>
> port = parties[player]["port"]
> del parties[player]
>
> pool = Pool()
> pool.add_http_server(port=port)
> for name, party in parties.items():
> assert "address" in party
> pool.add_http_client(
> name, party["address"], port=party["port"] if "port" in party else 80
> ) # default port=80
>
> if player == "alice":
> transactions = input_data["numpy_transactions_A"]
> nodes = input_data["numpy_nodes_A"]
> elif player == "bob":
> transactions = input_data["numpy_transactions_B"]
> nodes = input_data["numpy_nodes_B"]
> elif player == "charlie":
> transactions = input_data["numpy_transactions_C"]
> nodes = input_data["numpy_nodes_C"]
>
> await main(player, pool, nodes, transactions, distributed)
>
>
>async def all():
> await asyncio.gather(
> *[
> generate_instance("alice", distributed=False),
> generate_instance("bob", distributed=False),
> generate_instance("charlie", distributed=False),
> ],
> return_exceptions=True,
> )
>
>
>if __name__ == "__main__":
> # Parse arguments and acquire configuration parameters
> args = parse_args()
> player = args.player
> loop = asyncio.get_event_loop()
> if player == "all":
> loop.run_until_complete(all())
> else:
> loop.run_until_complete(generate_instance(player))
>```
- Run three separate instances specifying the players:
```console
$ python example_usage.py -p Alice
$ python example_usage.py -p Bob
$ python example_usage.py -p Charlie
```
or
- Run all three players in one Python instance:
```console
$ python example_usage.py -p all
```
Raw data
{
"_id": null,
"home_page": null,
"name": "tno.mpc.protocols.risk-propagation",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": "TNO PET Lab <petlab@tno.nl>",
"keywords": "TNO, MPC, multi-party computation, protocols, risk propagation",
"author": null,
"author_email": "TNO PET Lab <petlab@tno.nl>",
"download_url": "https://files.pythonhosted.org/packages/88/7b/e8d74ae2e07280f02c83bd691f6be68fff6d93a6ecf60ee54f12e21fc879/tno_mpc_protocols_risk_propagation-2.2.3.tar.gz",
"platform": "any",
"description": "# TNO PET Lab - secure Multi-Party Computation (MPC) - Protocols - Risk Propagation\n\nSecure Risk Propagation initially developed within the MPC4AML project.\n\n### PET Lab\n\nThe TNO PET Lab consists of generic software components, procedures, and functionalities developed and maintained on a regular basis to facilitate and aid in the development of PET solutions. The lab is a cross-project initiative allowing us to integrate and reuse previously developed PET functionalities to boost the development of new protocols and solutions.\n\nThe package `tno.mpc.protocols.risk_propagation` is part of the [TNO Python Toolbox](https://github.com/TNO-PET).\n\n_Limitations in (end-)use: the content of this software package may solely be used for applications that comply with international export control laws._ \n_This implementation of cryptographic software has not been audited. Use at your own risk._\n\n## Documentation\n\nDocumentation of the `tno.mpc.protocols.risk_propagation` package can be found\n[here](https://docs.pet.tno.nl/mpc/protocols/risk_propagation/2.2.3).\n\n## Install\n\nEasily install the `tno.mpc.protocols.risk_propagation` package using `pip`:\n\n```console\n$ python -m pip install tno.mpc.protocols.risk_propagation\n```\n\n_Note:_ If you are cloning the repository and wish to edit the source code, be\nsure to install the package in editable mode:\n\n```console\n$ python -m pip install -e 'tno.mpc.protocols.risk_propagation'\n```\n\nIf you wish to run the tests you can use:\n\n```console\n$ python -m pip install 'tno.mpc.protocols.risk_propagation[tests]'\n```\n_Note:_ A significant performance improvement can be achieved by installing the GMPY2 library.\n\n```console\n$ python -m pip install 'tno.mpc.protocols.risk_propagation[gmpy]'\n```\n\n## Protocol description\n\nRisk propagation is an algorithm that propagates risk scores through a (transaction) network.\nUsing distributed partial homomorphic encryption, the secure risk propagation implementation performs this algorithm on a network that is distributed among multiple parties.\nAs input of the algorithm, every party possesses a list of nodes (i.e. bank accounts) with initial risk scores and has a list of transactions (weighted, directed edges) from and to its bank accounts.\nUsing encrypted incoming risk scores scores from other parties, every party can securely update its risk scores using the formula for risk propagation.\nAfter a set number of iterations, the eventual risk scores are revealed to the parties that own the accounts, using the distributed private key.\n\nIn [ERCIM News 126 (July 2021)](https://ercim-news.ercim.eu/en126/special/privacy-preserving-collaborative-money-laundering-detection), we presented a more elaborate protocol descriptions. Figure 1 demonstrates a high-level overview of the idea behind the protocol. Figure 2 visualizes the decentralized approach.\n<figure>\n <img src=\"assets/risk-propagation-overview.svg\" width=100% alt=\"Risk Propagation High Level Overview\"/>\n <figcaption>\n\n__Figure 1.__ _We consider a three-bank scenario (Orange, Blue, and Purple). In this scenario the first (left) account at bank Orange is classified as high risk (due to e.g., large cash deposits) by bank Orange.\nThis account wishes to launder its resources. To stay under the radar, the resources are funnelled through multiple accounts, at various banks, before arriving at their eventual destination, e.g., the account at bank Purple (right).\nTo detect money laundering, we wish to follow (propagate) the risky money and classify the endpoint as high risk too. Full (global) knowledge of the network enables us to propagate the risk.\nHowever, how can we achieve something similar when there is only partial (local) knowledge of the entire network available? This is where MPC comes into play._\n </figcaption>\n</figure>\n\n<figure>\n <img src=\"assets/approach.svg\" width=100% alt=\"Risk Propagation Decentralized Approach\"/>\n <figcaption>\n\n__Figure 2.__ _In our approach, the data is analyzed in a decentralized manner. From left-to-right, we visualize encryption,\npropagation and decryption. The parties encrypt their data using the additive homomorphic encryption scheme, no\ncommunication takes place. Once the data is encrypted locally, the distributed propagation (computation) over the\nencrypted data takes place. During this computation the data remains encrypted, the parties communicate intermediate\n(encrypted) results, and there is no central party. During the decryption phase, we need to decrypt the encrypted values\nwith every party's key. We view the decryption from the green party's perspective. The lock on the risk scores belonging to\nthe green party is opened part-by-part and the final opening happens by the green party. This ensures that only the green\nparty gets to see the decrypted, propagated risk scores of his own bank accounts._\n </figcaption>\n</figure>\n\n## Usage\n\nThe protocol is symmetric. For determining a secure set of parameters for the distributed keygen we refer to [protocols.distributed_keygen](https://github.com/TNO-MPC/protocols.distributed_keygen/#usage).\n\n### Input\n\nFor the input two numpy arrays are expected. The structure and types are given in the tables below:\n\nInput of the accounts:\n\n| id | risk_score |\n|--------|------------|\n| string | float 64 |\n\n\nInput of the transactions:\n\n| id_source | bank_source | id_destination | bank_destination | amount |\n|-----------|-------------|----------------|------------------|--------|\n| string | string | string | string | int32 |\n\nA string is expected to consist out of at most 100 unicode characters.\n\nFor example data see the folder `example_data` in `tno/mpc/protocols/risk_propagation`.\n\n### Example usage\n\n\n\n>`example_usage.py`\n>```python\n>\"\"\"\n> Example usage for performing secure risk propagation\n> Run three separate instances e.g.,\n> $ python example_usage.py -p Alice\n> $ python example_usage.py -p Bob\n> $ python example_usage.py -p Charlie\n>\"\"\"\n>import argparse\n>import asyncio\n>\n>from tno.mpc.communication import Pool\n>from tno.mpc.protocols.distributed_keygen import DistributedPaillier\n>\n>from tno.mpc.protocols.risk_propagation import Player\n>from tno.mpc.protocols.risk_propagation.test.test_data.small import input_data\n>\n>\"\"\"\n>Default parameters for distributed keygen\n>\"\"\"\n>corruption_threshold = 1 # corruption threshold\n>key_length = 512 # bit length of private key\n>prime_thresh = 2000 # threshold for primality check\n>correct_param_biprime = 40 # correctness parameter for biprimality test\n>stat_sec_shamir = (\n> 40 # statistical security parameter for secret sharing over the integers\n>)\n>\n>\n>def parse_args():\n> parser = argparse.ArgumentParser()\n> parser.add_argument(\n> \"-p\",\n> \"--player\",\n> help=\"Name of the sending player\",\n> type=str.lower,\n> required=True,\n> choices=[\"alice\", \"bob\", \"charlie\", \"all\"],\n> )\n> args = parser.parse_args()\n> return args\n>\n>\n>async def main(player, pool, nodes, transactions, distributed):\n> distributed_paillier = await DistributedPaillier.from_security_parameter(\n> pool,\n> corruption_threshold,\n> key_length,\n> prime_thresh,\n> correct_param_biprime,\n> stat_sec_shamir,\n> precision=8,\n> distributed=distributed,\n> )\n> player_instance = Player(player, nodes, transactions, pool, distributed_paillier)\n>\n> await player_instance.run_protocol(iterations=3)\n> print(player_instance.risk_scores)\n> await asyncio.gather(\n> *[shutdown(pool, player) for player in pool.pool_handlers.keys()]\n> )\n>\n>\n>async def shutdown(pool, player):\n> await pool.send(player, \"Shutting down..\")\n> return await pool.recv(player)\n>\n>\n>async def generate_instance(player, distributed=True):\n> parties = {\n> \"alice\": {\"address\": \"127.0.0.1\", \"port\": 8080},\n> \"bob\": {\"address\": \"127.0.0.1\", \"port\": 8081},\n> \"charlie\": {\"address\": \"127.0.0.1\", \"port\": 8082},\n> }\n>\n> port = parties[player][\"port\"]\n> del parties[player]\n>\n> pool = Pool()\n> pool.add_http_server(port=port)\n> for name, party in parties.items():\n> assert \"address\" in party\n> pool.add_http_client(\n> name, party[\"address\"], port=party[\"port\"] if \"port\" in party else 80\n> ) # default port=80\n>\n> if player == \"alice\":\n> transactions = input_data[\"numpy_transactions_A\"]\n> nodes = input_data[\"numpy_nodes_A\"]\n> elif player == \"bob\":\n> transactions = input_data[\"numpy_transactions_B\"]\n> nodes = input_data[\"numpy_nodes_B\"]\n> elif player == \"charlie\":\n> transactions = input_data[\"numpy_transactions_C\"]\n> nodes = input_data[\"numpy_nodes_C\"]\n>\n> await main(player, pool, nodes, transactions, distributed)\n>\n>\n>async def all():\n> await asyncio.gather(\n> *[\n> generate_instance(\"alice\", distributed=False),\n> generate_instance(\"bob\", distributed=False),\n> generate_instance(\"charlie\", distributed=False),\n> ],\n> return_exceptions=True,\n> )\n>\n>\n>if __name__ == \"__main__\":\n> # Parse arguments and acquire configuration parameters\n> args = parse_args()\n> player = args.player\n> loop = asyncio.get_event_loop()\n> if player == \"all\":\n> loop.run_until_complete(all())\n> else:\n> loop.run_until_complete(generate_instance(player))\n>```\n\n- Run three separate instances specifying the players:\n ```console\n $ python example_usage.py -p Alice\n $ python example_usage.py -p Bob\n $ python example_usage.py -p Charlie\n ```\nor\n- Run all three players in one Python instance:\n ```console\n $ python example_usage.py -p all\n ```\n",
"bugtrack_url": null,
"license": "Apache License, Version 2.0",
"summary": "Secure risk propagation using distributed Paillier",
"version": "2.2.3",
"project_urls": {
"Documentation": "https://docs.pet.tno.nl/mpc/protocols/risk_propagation/2.2.3",
"Homepage": "https://pet.tno.nl/",
"Source": "https://github.com/TNO-Mpc/protocols.risk_propagation"
},
"split_keywords": [
"tno",
" mpc",
" multi-party computation",
" protocols",
" risk propagation"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "0d709029e6bfc29cb9f9993792133e4f8b5d8f2049b0cc2ff62ef718684e39db",
"md5": "fd1e533a0ce630c11af53edcf995a5ef",
"sha256": "c0bdab3e696fbd4824b7d2a5a2da7afa9cb2afb2f11875a9cfc160c7f4cf757f"
},
"downloads": -1,
"filename": "tno.mpc.protocols.risk_propagation-2.2.3-py3-none-any.whl",
"has_sig": false,
"md5_digest": "fd1e533a0ce630c11af53edcf995a5ef",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 111834,
"upload_time": "2024-10-16T13:32:55",
"upload_time_iso_8601": "2024-10-16T13:32:55.306139Z",
"url": "https://files.pythonhosted.org/packages/0d/70/9029e6bfc29cb9f9993792133e4f8b5d8f2049b0cc2ff62ef718684e39db/tno.mpc.protocols.risk_propagation-2.2.3-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "887be8d74ae2e07280f02c83bd691f6be68fff6d93a6ecf60ee54f12e21fc879",
"md5": "e73698efb62888538cb8aafca00d5f6c",
"sha256": "897967d1ee92ac49c643267bd755fd5d7a870d97a9c9fc7eccf2d9c0bf87110a"
},
"downloads": -1,
"filename": "tno_mpc_protocols_risk_propagation-2.2.3.tar.gz",
"has_sig": false,
"md5_digest": "e73698efb62888538cb8aafca00d5f6c",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 116224,
"upload_time": "2024-10-16T13:32:56",
"upload_time_iso_8601": "2024-10-16T13:32:56.861794Z",
"url": "https://files.pythonhosted.org/packages/88/7b/e8d74ae2e07280f02c83bd691f6be68fff6d93a6ecf60ee54f12e21fc879/tno_mpc_protocols_risk_propagation-2.2.3.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-10-16 13:32:56",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "TNO-Mpc",
"github_project": "protocols.risk_propagation",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "tno.mpc.protocols.risk-propagation"
}