Created
September 11, 2023 17:35
-
-
Save mg98/f1aebdc5b3b59905f24018569256bad1 to your computer and use it in GitHub Desktop.
Proof-of-Concept: Private Set Intersection
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"nbformat": 4, | |
"nbformat_minor": 0, | |
"metadata": { | |
"colab": { | |
"provenance": [] | |
}, | |
"kernelspec": { | |
"name": "python3", | |
"display_name": "Python 3" | |
}, | |
"language_info": { | |
"name": "python" | |
} | |
}, | |
"cells": [ | |
{ | |
"cell_type": "markdown", | |
"source": [ | |
"# Private Set Intersection (PSI)\n", | |
"\n", | |
"PSI computes the cardinality of the intersection of two sets between two parties, respectively, without revealing the contents of the sets to the other party.\n", | |
"This is achieved using [homomorphic encryption](https://en.wikipedia.org/wiki/Homomorphic_encryption), and the Paillier-system in particular, which has useful algebraic characteristics like *E(m_1 ⋅ m_2) = E(m_1) ⋅ E(m_2)* and others (cf. [Paillier 1999, Section 8](https://link.springer.com/content/pdf/10.1007/3-540-48910-X_16.pdf)).\n", | |
"\n", | |
"**Goal:** Build a proof of concept for the algorithms described as *Protocol II* in [Zeilemaker et al. (2013)](https://www.paolopalmieri.com/pdf/Zeilemaker_Erkin_Palmieri_et_al_WIFS2013.pdf) and or *PM-Semi-Honest Protocol* in [Freedman et al. (2004)](https://www.researchgate.net/publication/2869590_Efficient_Private_Matching_and_Set_Intersection).\n" | |
], | |
"metadata": { | |
"id": "ZVqApegX7TC8" | |
} | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"!pip install tenseal" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "yrkKqxrHLe-U", | |
"outputId": "e774499a-0f24-480e-b953-803edd9a9ee0" | |
}, | |
"execution_count": 2, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": [ | |
"Collecting tenseal\n", | |
" Downloading tenseal-0.3.14-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (4.9 MB)\n", | |
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m4.9/4.9 MB\u001b[0m \u001b[31m4.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", | |
"\u001b[?25hInstalling collected packages: tenseal\n", | |
"Successfully installed tenseal-0.3.14\n" | |
] | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 29, | |
"metadata": { | |
"id": "eElJToE5BUq6" | |
}, | |
"outputs": [], | |
"source": [ | |
"import tenseal as ts\n", | |
"import numpy as np\n", | |
"import random\n", | |
"\n", | |
"# Regarding the parameters: Bigger numbers allow for bigger polynomials with\n", | |
"# bigger numbers but will affect computational performance.\n", | |
"# Ref: https://github.com/OpenMined/TenSEAL/blob/main/tutorials/Tutorial%203%20-%20Benchmarks.ipynb\n", | |
"context = ts.context(ts.SCHEME_TYPE.BFV, poly_modulus_degree=32768, plain_modulus=270794753)\n", | |
"\n", | |
"# Alice's and Bob's secret sets\n", | |
"A = [1, 2, 4, 8, 16, 32, 64]\n", | |
"B = [2, 4, 6, 8, 10, 12, 32]\n", | |
"\n", | |
"# Alice computes and then encrypts her coefficients\n", | |
"coefficients = np.poly(A).tolist()\n", | |
"coefficients = [ts.bfv_vector(context, [int(coeff)]) for coeff in coefficients]\n", | |
"\n", | |
"# Bob proceeds with his calculations based on Alice's encrypted coefficients\n", | |
"bobs = []\n", | |
"for b in B:\n", | |
" p = sum(c * (b ** i) for i, c in enumerate(reversed(coefficients)))\n", | |
" r_vector = ts.bfv_vector(context, [random.randint(0, 1<<10)])\n", | |
" encrypted_result = r_vector * p\n", | |
" bobs.append(encrypted_result)\n", | |
"\n", | |
"random.shuffle(bobs)\n", | |
"\n", | |
"# Alice decrypts the results to get the final values\n", | |
"res = [bob.decrypt()[0] for bob in bobs]\n", | |
"\n", | |
"# The number of zeros in the result set determines the cardinality of the intersection between A and B.\n", | |
"assert len(set(A).intersection(set(B))) == sum(x == 0 for x in res)" | |
] | |
} | |
] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment