pyUmbral/docs/notebooks/pyUmbral Simple API.ipynb

307 lines
8.4 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# pyUmbral Python API"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Generate Umbral Keys for Alice\n",
"First, Let's generate two asymmetric key pairs for Alice:\n",
"A *delegating* key pair and a *signing* key pair.\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"from umbral import SecretKey, Signer\n",
"\n",
"\n",
"# Alice's Keys\n",
"alices_private_key = SecretKey.random()\n",
"alices_public_key = alices_private_key.public_key()\n",
"\n",
"alices_signing_key = SecretKey.random()\n",
"alices_verifying_key = alices_signing_key.public_key()\n",
"alices_signer = Signer(alices_signing_key)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Encrypt some data for Alice\n",
"Now let's encrypt data with Alice's public key. Invocation of `pre.encrypt` returns both the `ciphertext`,\n",
"and a `capsule`. Anyone with Alice's public key can perform this operation."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"tags": [
"nbval-ignore-output"
]
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"b'\\xfb\\xc3T\\xb2\\x89=\\x08X\\xb1<\\xd0G/\\xab\\x8c\\xac\\x7f\\xd4)\\xcbB\\xcb^\\x99;P\\x9c\\xbf\\xaaf\\x03\\xdd\\n\\x1f$\\x1b\\xfb\\x88\\xfa\\xcd\\xe2\\x11\\x8d\\xcf\\xe5\\x88\\xaf\\x00\\xfe\\xcb\\x9d\\xf83\\x17\\x9b\\xdd\\xba\\xab\\x8b\\x08\\xbe\\xb1M\\x80\\xf1<S#'\n"
]
}
],
"source": [
"from umbral import encrypt\n",
"\n",
"\n",
"plaintext = b'Proxy Re-encryption is cool!'\n",
"capsule, ciphertext = encrypt(alices_public_key, plaintext)\n",
"print(ciphertext)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Alice decrypts data for self\n",
"Since data was encrypted with Alice's public key, Alice can open the capsule and decrypt the ciphertext with her private key."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"b'Proxy Re-encryption is cool!'\n"
]
}
],
"source": [
"from umbral import decrypt_original\n",
"\n",
"\n",
"cleartext = decrypt_original(delegating_sk=alices_private_key,\n",
" capsule=capsule,\n",
" ciphertext=ciphertext)\n",
"print(cleartext)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Enter Bob\n",
"Apart from generating his keypair, we will also assume that Bob receives a capsule through a side channel (s3, ipfs, Google Cloud, etc). "
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"bobs_private_key = SecretKey.random()\n",
"bobs_public_key = bobs_private_key.public_key()\n",
"\n",
"bob_capsule = capsule"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Attempt Bob's decryption (fail)"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Decryption failed! Bob doesn't has access granted yet.\n"
]
}
],
"source": [
"try:\n",
" fail_decrypted_data = decrypt_original(delegating_sk=bobs_private_key,\n",
" capsule=capsule,\n",
" ciphertext=ciphertext)\n",
"except ValueError:\n",
" print(\"Decryption failed! Bob doesn't has access granted yet.\")\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Proxy Re-encryption\n",
"\n",
"<img src=\"https://cdn-images-1.medium.com/max/1200/0*yTKUeeuKPu-aIZdw.\" alt=\"Proxy Re-Encryption\" width=\"500\"/>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Alice grants access to Bob by generating KFrags \n",
"When Alice wants to grant Bob access to open her encrypted messages, she creates *re-encryption key fragments*, or \"kfrags\", which are next sent to N proxies or *Ursulas*. She uses her private key, and Bob's public key, and she sets a minimum threshold of 10, for 20 total shares\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"from umbral import generate_kfrags\n",
"\n",
"\n",
"M, N = 10, 20 # the threshold and the total number of fragments\n",
"kfrags = generate_kfrags(delegating_sk=alices_private_key,\n",
" receiving_pk=bobs_public_key,\n",
" signer=alices_signer,\n",
" threshold=M,\n",
" num_kfrags=N)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"## Ursulas Re-encrypt; Bob attaches fragments to `capsule`\n",
"Bob asks several Ursulas to re-encrypt the capsule so he can open it. Each Ursula performs re-encryption on the capsule using the `kfrag` provided by Alice, obtaining this way a \"capsule fragment\", or `cfrag`. Let's mock a network or transport layer by sampling `M` random `kfrags`, one for each required Ursula. Bob collects the resulting `cfrags` from several Ursulas. He must gather at least `M` `cfrags` in order to activate the capsule.\n"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"import random\n",
"kfrags = random.sample(kfrags, # All kfrags from above\n",
" M) # Threshold\n",
"\n",
"\n",
"from umbral import reencrypt\n",
"\n",
"\n",
"cfrags = list() # Bob's cfrag collection\n",
"for kfrag in kfrags:\n",
" cfrag = reencrypt(capsule=capsule, kfrag=kfrag)\n",
" cfrags.append(cfrag) # Bob collects a cfrag"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Bob checks the capsule fragments\n",
"If Bob received the capsule fragments in serialized form, he can verify that they are valid and really originate from Alice, using Alice's public keys."
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"from umbral import CapsuleFrag\n",
"\n",
"suspicious_cfrags = [CapsuleFrag.from_bytes(bytes(cfrag)) for cfrag in cfrags]\n",
"\n",
"cfrags = [cfrag.verify(capsule,\n",
" verifying_pk=alices_verifying_key,\n",
" delegating_pk=alices_public_key,\n",
" receiving_pk=bobs_public_key,\n",
" )\n",
" for cfrag in suspicious_cfrags]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Bob opens the capsule; Decrypts data from Alice.\n",
"Finally, Bob decrypts the re-encrypted ciphertext using his secret key."
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"b'Proxy Re-encryption is cool!'\n"
]
}
],
"source": [
"from umbral import decrypt_reencrypted\n",
"\n",
"bob_cleartext = decrypt_reencrypted(receiving_sk=bobs_private_key,\n",
" delegating_pk=alices_public_key,\n",
" capsule=capsule,\n",
" verified_cfrags=cfrags,\n",
" ciphertext=ciphertext)\n",
"\n",
"print(bob_cleartext)\n",
"assert bob_cleartext == plaintext"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"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.8.5"
}
},
"nbformat": 4,
"nbformat_minor": 2
}