mirror of https://github.com/nucypher/pyUmbral.git
307 lines
8.4 KiB
Plaintext
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
|
|
}
|