{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# pyUmbral Python API" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Setting the default curve\n", "\n", "The first time you use umbral, you may want to specify an elliptic curve to use. If you do not specify a curve, secp256k1 will be used for all operations, with a slight performace hit for the lookup.\n", "\n", "To set the default curve use `umbral.config.set_default_curve()`\n", "\n", "Note: you can only set the dafault once, or `UmbralConfigurationError` will be raised." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "from umbral.config import set_default_curve\n", "\n", "set_default_curve()" ] }, { "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 keys, signing\n", "\n", "\n", "# Alice's Keys\n", "alices_private_key = keys.UmbralPrivateKey.gen_key()\n", "alices_public_key = alices_private_key.get_pubkey()\n", "\n", "alices_signing_key = keys.UmbralPrivateKey.gen_key()\n", "alices_verifying_key = alices_signing_key.get_pubkey()\n", "alices_signer = signing.Signer(private_key=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'#\\xebQ\\xd4\\xad\\x8ah,9\\x8f\\xc9\\x18\\x84[\\x95M\\x8e\\xb1\\x85\\xf9\\xbe\\x97\\x07\\xf3\\x80@\\x11\\xab\\x82\\xac\\xa1\\xbf\\xc0\\x00e\\xecpTq\\xef\\x94\\xd94\\x94\\x1a\\xdf\\xf0\\x04)\\xf5\\r\\xc4\\xbd/:\\x8c'\n" ] } ], "source": [ "from umbral import pre\n", "\n", "\n", "plaintext = b'Proxy Re-encryption is cool!'\n", "ciphertext, capsule = pre.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": [ "cleartext = pre.decrypt(ciphertext=ciphertext, \n", " capsule=capsule, \n", " decrypting_key=alices_private_key)\n", "print(cleartext)\n" ] }, { "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 = keys.UmbralPrivateKey.gen_key()\n", "bobs_public_key = bobs_private_key.get_pubkey()\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 = pre.decrypt(ciphertext=ciphertext, \n", " capsule=capsule, \n", " decrypting_key=bobs_private_key)\n", "except:\n", " print(\"Decryption failed! Bob doesn't has access granted yet.\")\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Proxy Re-encryption\n", "\n", "\"Proxy" ] }, { "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": [ "M, N = 10, 20\n", "kfrags = pre.generate_kfrags(delegating_privkey=alices_private_key, \n", " receiving_pubkey=bobs_public_key, \n", " signer=alices_signer,\n", " threshold=M, \n", " N=N)\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. Note that each Ursula must prepare the received capsule before re-encryption by setting the proper correctness keys. 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", " 10) # M - Threshold\n", "\n", "bob_capsule.set_correctness_keys(delegating=alices_public_key,\n", " receiving=bobs_public_key,\n", " verifying=alices_verifying_key)\n", "\n", "cfrags = list() # Bob's cfrag collection\n", "for kfrag in kfrags:\n", " cfrag = pre.reencrypt(kfrag=kfrag, capsule=bob_capsule)\n", " cfrags.append(cfrag) # Bob collects a cfrag\n", "\n", "assert len(cfrags) == 10\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Bob activates and opens the capsule; Decrypts data from Alice.\n", "The `capsule` can become *activated* once Bob attaches at least `M` `cfrags` to it. Note that it has to be prepared in advance with the necessary `correctness_keys` (specifically, Alice's public key, Alice's signature verification key and his own public key). \n", "\n", "Finally, Bob activates and opens the capsule, then decrypts the re-encrypted ciphertext." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "b'Proxy Re-encryption is cool!'\n" ] } ], "source": [ "bob_capsule.set_correctness_keys(delegating=alices_public_key,\n", " receiving=bobs_public_key,\n", " verifying=alices_verifying_key)\n", "\n", "for cfrag in cfrags:\n", " bob_capsule.attach_cfrag(cfrag)\n", " \n", "bob_cleartext = pre.decrypt(ciphertext=ciphertext, capsule=capsule, decrypting_key=bobs_private_key)\n", "print(bob_cleartext)\n", "assert bob_cleartext == plaintext\n", "\n" ] }, { "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.7.0" } }, "nbformat": 4, "nbformat_minor": 2 }