-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
270 additions
and
30 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,3 +3,4 @@ __pycache__ | |
*.so | ||
build/ | ||
dist/ | ||
docs/_build |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# Minimal makefile for Sphinx documentation | ||
# | ||
|
||
# You can set these variables from the command line, and also | ||
# from the environment for the first two. | ||
SPHINXOPTS ?= | ||
SPHINXBUILD ?= sphinx-build | ||
SOURCEDIR = . | ||
BUILDDIR = _build | ||
|
||
# Put it first so that "make" without argument is like "make help". | ||
help: | ||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) | ||
|
||
.PHONY: help Makefile | ||
|
||
# Catch-all target: route all unknown targets to Sphinx using the new | ||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). | ||
%: Makefile | ||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
# Configuration file for the Sphinx documentation builder. | ||
# | ||
# This file only contains a selection of the most common options. For a full | ||
# list see the documentation: | ||
# https://www.sphinx-doc.org/en/master/usage/configuration.html | ||
|
||
# -- Path setup -------------------------------------------------------------- | ||
|
||
# If extensions (or modules to document with autodoc) are in another directory, | ||
# add these directories to sys.path here. If the directory is relative to the | ||
# documentation root, use os.path.abspath to make it absolute, like shown here. | ||
# | ||
# import os | ||
# import sys | ||
# sys.path.insert(0, os.path.abspath('.')) | ||
|
||
|
||
# -- Project information ----------------------------------------------------- | ||
|
||
project = 'umbral-pre' | ||
copyright = '2020, Bogdan Opanchuk' | ||
author = 'Bogdan Opanchuk' | ||
|
||
# The full version, including alpha/beta/rc tags | ||
release = '0.0.1' | ||
|
||
|
||
# -- General configuration --------------------------------------------------- | ||
|
||
# Add any Sphinx extension module names here, as strings. They can be | ||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom | ||
# ones. | ||
extensions = [ | ||
] | ||
|
||
# Add any paths that contain templates here, relative to this directory. | ||
templates_path = ['_templates'] | ||
|
||
# List of patterns, relative to source directory, that match files and | ||
# directories to ignore when looking for source files. | ||
# This pattern also affects html_static_path and html_extra_path. | ||
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] | ||
|
||
|
||
# -- Options for HTML output ------------------------------------------------- | ||
|
||
# The theme to use for HTML and HTML Help pages. See the documentation for | ||
# a list of builtin themes. | ||
# | ||
html_theme = 'alabaster' | ||
|
||
# Add any paths that contain custom static files (such as style sheets) here, | ||
# relative to this directory. They are copied after the builtin static files, | ||
# so a file named "default.css" will overwrite the builtin "default.css". | ||
html_static_path = ['_static'] |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
Welcome to umbral-pre's documentation! | ||
====================================== | ||
|
||
.. toctree:: | ||
:maxdepth: 2 | ||
:caption: Contents: | ||
|
||
This package contains the Python bindings for `the main library <https://github.com/nucypher/rust-umbral/tree/master/umbral-pre>`_ written in Rust. It implements the `Umbral <https://github.com/nucypher/umbral-doc/blob/master/umbral-doc.pdf>`_ proxy reencryption scheme. | ||
|
||
Usage example | ||
------------- | ||
|
||
.. literalinclude:: ../example/example.py | ||
|
||
|
||
API reference | ||
------------- | ||
|
||
.. py:module:: umbral_pre | ||
.. py:class:: SecretKey | ||
An ``umbral-pre`` secret key object. | ||
|
||
.. py:staticmethod:: random() -> SecretKey | ||
Generates a new secret key. | ||
|
||
.. py:class:: PublicKey | ||
An ``umbral-pre`` public key object. | ||
|
||
.. py:staticmethod:: from_secret_key(sk: SecretKey) -> PublicKey | ||
Creates a public key corresponding to the given secret key. | ||
|
||
|
||
.. py:class:: Parameters() | ||
A scheme parameters object. | ||
|
||
|
||
.. py:class:: Capsule | ||
An encapsulated symmetric key. | ||
|
||
|
||
.. py:function:: encrypt(params: Parameters, pk: PublicKey, plaintext: bytes) -> Tuple[Capsule, bytes] | ||
Creates a symmetric key, encrypts ``plaintext`` with it, and returns the encapsulated symmetric key along with the ciphertext. ``pk`` is the public key of the recipient. | ||
|
||
.. py:function:: decrypt_original(sk: SecretKey, capsule: Capsule, ciphertext: bytes) -> bytes | ||
Decrypts ``ciphertext`` with the key used to encrypt it. | ||
|
||
.. py:function:: generate_kfrags(params: Parameters, delegating_sk: SecretKey, receiving_pk: PublicKey, signing_sk: SecretKey, threshold: int, num_kfrags: int, sign_delegating_key: bool, sign_receiving_key: bool) -> List[KeyFrag] | ||
Generates ``num_kfrags`` key fragments that can be used to reencrypt the capsule for the holder of the secret key corresponding to ``receiving_pk``. ``threshold`` fragments will be enough for decryption. | ||
|
||
If ``sign_delegating_key`` or ``sign_receiving_key`` are ``True``, include these keys in the signature allowing proxies to verify the fragments were created with a given key or for a given key, respectively. | ||
|
||
.. py:function:: reencrypt(capsule: Capsule, kfrag: KeyFrag, metadata: Optional[bytes]) -> CapsuleFrag | ||
Reencrypts a capsule using a key fragment. | ||
May include optional ``metadata`` in the resulting capsule fragment. | ||
|
||
|
||
.. py:function:: decrypt_reencrypted(decrypting_sk: SecretKey, delegating_pk: PublicKey, capsule: Capsule, cfrags: Sequence[CapsuleFrag], ciphertext: bytes) -> Optional[bytes] | ||
Attempts to decrypt the plaintext using the original capsule and reencrypted capsule fragments (at least ``threshold`` of them, see :py:func:`generate_kfrags`). | ||
|
||
.. py:class:: KeyFrag | ||
A fragment of a public key used by proxies during reencryption. | ||
|
||
.. py:method:: verify(signing_pk: PublicKey, delegating_pk: Optional[PublicKey], receiving_pk: Optional[PublicKey]) -> bool: | ||
Verifies the integrity of the fragment using the signing key and, optionally, the delegating and the receiving keys (if they were included in the signature in :py:func:`generate_kfrags`). | ||
|
||
.. py:class:: CapsuleFrag | ||
A reencrypted fragment of an encapsulated symmetric key. | ||
|
||
.. py:method:: verify(capsule: Capsule, signing_pk: PublicKey, delegating_pk: PublicKey, receiving_pk: PublicKey) -> bool | ||
Verifies the integrity of the fragment. | ||
|
||
|
||
Indices and tables | ||
================== | ||
|
||
* :ref:`genindex` | ||
* :ref:`modindex` | ||
* :ref:`search` |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
@ECHO OFF | ||
|
||
pushd %~dp0 | ||
|
||
REM Command file for Sphinx documentation | ||
|
||
if "%SPHINXBUILD%" == "" ( | ||
set SPHINXBUILD=sphinx-build | ||
) | ||
set SOURCEDIR=. | ||
set BUILDDIR=_build | ||
|
||
if "%1" == "" goto help | ||
|
||
%SPHINXBUILD% >NUL 2>NUL | ||
if errorlevel 9009 ( | ||
echo. | ||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx | ||
echo.installed, then set the SPHINXBUILD environment variable to point | ||
echo.to the full path of the 'sphinx-build' executable. Alternatively you | ||
echo.may add the Sphinx directory to PATH. | ||
echo. | ||
echo.If you don't have Sphinx installed, grab it from | ||
echo.http://sphinx-doc.org/ | ||
exit /b 1 | ||
) | ||
|
||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% | ||
goto end | ||
|
||
:help | ||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% | ||
|
||
:end | ||
popd |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,51 +1,86 @@ | ||
import umbral_pre | ||
|
||
# Generation of global parameters | ||
params = umbral_pre.Parameters() | ||
|
||
# Key Generation (Alice) | ||
delegating_sk = umbral_pre.SecretKey.random() | ||
delegating_pk = umbral_pre.PublicKey.from_secret_key(delegating_sk) | ||
# As in any public-key cryptosystem, users need a pair | ||
# of public and private keys. | ||
# Additionally, users that delegate access to their data | ||
# (like Alice, in this example) need a signing keypair. | ||
|
||
# Key Generation (on Alice's side) | ||
alice_sk = umbral_pre.SecretKey.random() | ||
alice_pk = umbral_pre.PublicKey.from_secret_key(alice_sk) | ||
signing_sk = umbral_pre.SecretKey.random() | ||
signing_pk = umbral_pre.PublicKey.from_secret_key(signing_sk) | ||
|
||
# Key Generation (Bob) | ||
receiving_sk = umbral_pre.SecretKey.random() | ||
receiving_pk = umbral_pre.PublicKey.from_secret_key(receiving_sk) | ||
# Key Generation (on Bob's side) | ||
bob_sk = umbral_pre.SecretKey.random() | ||
bob_pk = umbral_pre.PublicKey.from_secret_key(bob_sk) | ||
|
||
# Now let's encrypt data with Alice's public key. | ||
# Invocation of `encrypt()` returns both the ciphertext | ||
# and the encapsulated symmetric key use to encrypt it. | ||
# Note that anyone with Alice's public key | ||
# can perform this operation. | ||
|
||
# Encryption by an unnamed data source | ||
params = umbral_pre.Parameters() | ||
plaintext = b"peace at dawn" | ||
capsule, ciphertext = umbral_pre.encrypt(params, delegating_pk, plaintext) | ||
capsule, ciphertext = umbral_pre.encrypt( | ||
params, alice_pk, plaintext) | ||
|
||
# Since data was encrypted with Alice's public key, | ||
# Alice can open the capsule and decrypt the ciphertext | ||
# with her private key. | ||
|
||
# Decryption by Alice | ||
plaintext_alice = umbral_pre.decrypt_original(delegating_sk, capsule, ciphertext); | ||
plaintext_alice = umbral_pre.decrypt_original( | ||
alice_sk, capsule, ciphertext); | ||
assert plaintext_alice == plaintext | ||
|
||
threshold = 2 | ||
num_frags = threshold + 1 | ||
# When Alice wants to grant Bob access to open her encrypted | ||
# messages, she creates re-encryption key fragments, | ||
# or "kfrags", which are then sent to `n` proxies or Ursulas. | ||
|
||
n = 3 # how many fragments to create | ||
m = 2 # how many should be enough to decrypt | ||
|
||
# Split Re-Encryption Key Generation (aka Delegation) | ||
kfrags = umbral_pre.generate_kfrags( | ||
params, | ||
delegating_sk, | ||
receiving_pk, | ||
signing_sk, | ||
threshold, | ||
num_frags, | ||
True, | ||
True, | ||
params, alice_sk, bob_pk, signing_sk, m, n, | ||
True, # add the delegating key (alice_pk) to the signature | ||
True, # add the receiving key (bob_pk) to the signature | ||
) | ||
|
||
# Ursulas check that the received kfrags are valid | ||
assert all(kfrag.verify(signing_pk, delegating_pk, receiving_pk) for kfrag in kfrags) | ||
# 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, thus obtaining | ||
# a "capsule fragment", or cfrag. | ||
|
||
# Bob collects the resulting cfrags from several Ursulas. | ||
# Bob must gather at least `m` cfrags | ||
# in order to open the capsule. | ||
|
||
# Ursulas can optionally check that the received kfrags | ||
# are valid and perform the reencryption. | ||
|
||
metadata = b"metadata" | ||
|
||
# Ursula 0 | ||
assert kfrags[0].verify(signing_pk, alice_pk, bob_pk) | ||
cfrag0 = umbral_pre.reencrypt(capsule, kfrags[0], metadata) | ||
|
||
# Ursula 1 | ||
assert kfrags[1].verify(signing_pk, alice_pk, bob_pk) | ||
cfrag1 = umbral_pre.reencrypt(capsule, kfrags[1], metadata) | ||
|
||
# ... | ||
|
||
# Bob requests re-encryption to some set of `threshold` ursulas | ||
cfrags = [umbral_pre.reencrypt(capsule, kfrag, b"metadata") for kfrag in kfrags] | ||
# Finally, Bob opens the capsule by using at least `m` cfrags, | ||
# and then decrypts the re-encrypted ciphertext. | ||
|
||
# Bob checks that the received cfrags are valid | ||
assert all(cfrag.verify(capsule, delegating_pk, receiving_pk, signing_pk) for cfrag in cfrags) | ||
# Bob can optionally check that cfrags are valid | ||
assert cfrag0.verify(capsule, alice_pk, bob_pk, signing_pk) | ||
assert cfrag1.verify(capsule, alice_pk, bob_pk, signing_pk) | ||
|
||
# Decryption by Bob | ||
plaintext_bob = umbral_pre.decrypt_reencrypted(receiving_sk, delegating_pk, capsule, cfrags, ciphertext) | ||
plaintext_bob = umbral_pre.decrypt_reencrypted( | ||
bob_sk, alice_pk, capsule, [cfrag0, cfrag1], ciphertext) | ||
assert plaintext_bob == plaintext |