mirror of https://github.com/nucypher/pyUmbral.git
Update and test existing documentation with sphinx doctest
parent
d2d53d56b7
commit
89ec7a6f37
|
@ -14,26 +14,52 @@ Be careful when choosing a curve - the security of your application depends on i
|
|||
We provide SECP256K1 as a default because it is the basis for a number of crypto-blockchain projects;
|
||||
we don't otherwise endorse its security.
|
||||
|
||||
.. testsetup::
|
||||
|
||||
from umbral import config, keys
|
||||
from cryptography.hazmat.primitives.asymmetric import ec
|
||||
|
||||
|
||||
Setting a default curve
|
||||
--------------------------
|
||||
|
||||
Before you perform any ECC operations, you can set a default curve.
|
||||
|
||||
.. doctest::
|
||||
>>> config._CONFIG.___CONFIG__curve = None
|
||||
>>> config._CONFIG.___CONFIG__params = None
|
||||
>>> config.set_default_curve(ec.SECP256K1)
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from umbral import config
|
||||
from cryptography.hazmat.primitives.asymmetric import ec
|
||||
|
||||
config.set_default_curve(ec.SECP256K1)
|
||||
|
||||
If you don't set a default curve, then SECP256K1 will be set for you when you perform the first ECC
|
||||
operation. This causes a small one-time performance penalty.
|
||||
|
||||
|
||||
.. doctest::
|
||||
>>> config._CONFIG.___CONFIG__curve = None
|
||||
>>> config._CONFIG.___CONFIG__params = None
|
||||
>>> keys.UmbralPrivateKey.gen_key()
|
||||
RuntimeWarning: No default curve has been set. Using SECP256K1. A slight performance penalty has been incurred for only this call. Set a default curve with umbral.config.set_default_curve().
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
keys.UmbralPrivateKey.gen_key()
|
||||
RuntimeWarning: No default curve has been set. Using SECP256K1. A slight performance penalty has been incurred for only this call. Set a default curve with umbral.config.set_default_curve().
|
||||
from umbral import keys
|
||||
keys.UmbralPrivateKey.gen_key()
|
||||
RuntimeWarning: No default curve has been set. Using SECP256K1. A slight performance penalty has been incurred for only this call. Set a default curve with umbral.config.set_default_curve().
|
||||
|
||||
If you want SECP256K1 and want to avoid this penalty, you can simply call `set_default_curve()` with no argument:
|
||||
|
||||
.. doctest::
|
||||
>>> config._CONFIG.___CONFIG__curve = None
|
||||
>>> config._CONFIG.___CONFIG__params = None
|
||||
>>> config.set_default_curve()
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
config.set_default_curve()
|
||||
|
@ -41,9 +67,20 @@ If you want SECP256K1 and want to avoid this penalty, you can simply call `set_d
|
|||
Attempting to set the default curve twice in the same runtime will raise
|
||||
a `UmbralConfigurationError`.
|
||||
|
||||
|
||||
.. doctest::
|
||||
>>> config._CONFIG.___CONFIG__curve = None
|
||||
>>> config._CONFIG.___CONFIG__params = None
|
||||
>>> config.set_default_curve()
|
||||
>>> config.set_default_curve()
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
umbral.config._CONFIG.UmbralConfigurationError:
|
||||
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
config.set_default_curve()
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
umbral.config.UmbralConfigurationError: You can only set the default curve once. Do it once and then leave it alone.
|
||||
config.set_default_curve()
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
umbral.config.UmbralConfigurationError: You can only set the default curve once. Do it once and then leave it alone.
|
||||
|
|
|
@ -42,6 +42,7 @@ extensions = [
|
|||
'sphinx.ext.autodoc',
|
||||
'sphinx.ext.mathjax',
|
||||
'sphinx.ext.viewcode',
|
||||
'sphinx.ext.doctest',
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
|
|
|
@ -6,9 +6,17 @@ Using pyUmbral
|
|||
|
||||
Import umbral modules
|
||||
|
||||
.. testsetup::
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
sys.path.append(os.path.abspath(os.getcwd()))
|
||||
from umbral import pre, keys, config, signing
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from umbral import pre, keys, config
|
||||
from umbral import pre, keys, config, signing
|
||||
|
||||
|
||||
Configuration
|
||||
|
@ -20,25 +28,46 @@ Setting the default curve
|
|||
|
||||
The best way to start using pyUmbral is to decide on a elliptic curve to use and set it as your default.
|
||||
|
||||
.. doctest::
|
||||
>>> config._CONFIG.___CONFIG__curve = None
|
||||
>>> config._CONFIG.___CONFIG__params = None
|
||||
>>> from cryptography.hazmat.primitives.asymmetric import ec
|
||||
>>> config.set_default_curve(ec.SECP256K1)
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
config.set_default_curve(ec.SECP256K1)
|
||||
|
||||
|
||||
For more information on curves, see :doc:`choosing_and_using_curves`.
|
||||
|
||||
|
||||
Encryption and Encapsulation
|
||||
=============================
|
||||
Encryption
|
||||
==========
|
||||
|
||||
|
||||
Generate an Umbral key pair
|
||||
-----------------------------
|
||||
First, Let's generate an asymmetric key pair for Alice.
|
||||
First, Let's generate two asymmetric key pairs for Alice:
|
||||
A delegating key pair and a Signing key pair.
|
||||
|
||||
.. doctest::
|
||||
|
||||
>>> alices_private_key = keys.UmbralPrivateKey.gen_key()
|
||||
>>> alices_public_key = alices_private_key.get_pubkey()
|
||||
|
||||
>>> alices_signing_key = keys.UmbralPrivateKey.gen_key()
|
||||
>>> alices_verifying_key = alices_signing_key.get_pubkey()
|
||||
>>> alices_signer = signing.Signer(private_key=alices_signing_key)
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
alices_private_key = keys.UmbralPrivateKey.gen_key()
|
||||
alices_public_key = private_key.get_pubkey()
|
||||
alices_private_key = keys.UmbralPrivateKey.gen_key()
|
||||
alices_public_key = alices_private_key.get_pubkey()
|
||||
|
||||
alices_signing_key = keys.UmbralPrivateKey.gen_key()
|
||||
alices_verifying_key = alices_signing_key.get_pubkey()
|
||||
alices_signer = signing.Signer(private_key=alices_signing_key)
|
||||
|
||||
|
||||
Encrypt with a public key
|
||||
|
@ -48,11 +77,16 @@ Invocation of `umbral.encrypt` returns both the `ciphertext`,
|
|||
and a `capsule`, Anyone with Alice's public key can perform
|
||||
this operation.
|
||||
|
||||
|
||||
.. doctest::
|
||||
|
||||
>>> plaintext = b'Proxy Re-encryption is cool!'
|
||||
>>> ciphertext, capsule = pre.encrypt(alices_public_key, plaintext)
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
plaintext = b'Proxy Re-encryption is cool!'
|
||||
ciphertext, capsule = umbral.encrypt(alices_public_key,
|
||||
plaintext)
|
||||
plaintext = b'Proxy Re-encryption is cool!'
|
||||
ciphertext, capsule = pre.encrypt(alices_public_key, plaintext)
|
||||
|
||||
|
||||
Decrypt with a private key
|
||||
|
@ -60,15 +94,34 @@ Decrypt with a private key
|
|||
Since data was encrypted with Alice's public key,
|
||||
Alice can open the capsule and decrypt the ciphertext with her private key.
|
||||
|
||||
.. doctest::
|
||||
|
||||
>>> cleartext = pre.decrypt(ciphertext=ciphertext, capsule=capsule, decrypting_key=alices_private_key)
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
cleartext = umbral.decrypt(capsule, alices_private_key,
|
||||
ciphertext, alices_public_key)
|
||||
cleartext = pre.decrypt(ciphertext=ciphertext, capsule=capsule,
|
||||
decrypting_key=alices_private_key)
|
||||
|
||||
|
||||
Threshold split-key re-encryption
|
||||
==================================
|
||||
|
||||
Bob Exists
|
||||
-----------
|
||||
|
||||
.. doctest::
|
||||
|
||||
>>> bobs_private_key = keys.UmbralPrivateKey.gen_key()
|
||||
>>> bobs_public_key = bobs_private_key.get_pubkey()
|
||||
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Generate umbral keys for Bob.
|
||||
bobs_private_key = keys.UmbralPrivateKey.gen_key()
|
||||
bobs_public_key = bobs_private_key.get_pubkey()
|
||||
|
||||
|
||||
Alice grants access to Bob by generating kfrags
|
||||
-----------------------------------------------
|
||||
|
@ -80,13 +133,18 @@ which are next sent to N proxies or *Ursulas*.
|
|||
| `M` - Minimum threshold of key fragments needed to activate a capsule.
|
||||
| `N` - Total number of key fragments to generate.
|
||||
|
||||
.. doctest::
|
||||
|
||||
>>> kfrags = pre.split_rekey(delegating_privkey=alices_private_key, signer=alices_signer, receiving_pubkey=bobs_public_key, threshold=10, N=20)
|
||||
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
kfrags = umbral.split_rekey(alices_private_key,
|
||||
bobs_public_key,
|
||||
10, # M - Threshold
|
||||
20) # N - Total
|
||||
|
||||
kfrags = pre.split_rekey(delegating_privkey=alices_private_key,
|
||||
signer=alices_signer,
|
||||
receiving_pubkey=bobs_public_key,
|
||||
threshold=10,
|
||||
N=20)
|
||||
|
||||
Bob receives a capsule
|
||||
-----------------------
|
||||
|
@ -96,12 +154,8 @@ S3, IPFS, Google Cloud, Sneakernet, etc.
|
|||
|
||||
.. code-block:: python
|
||||
|
||||
# Generate a key pair for Bob
|
||||
bobs_private_key = keys.UmbralPrivateKey.gen_key()
|
||||
bobs_public_key = private_key.get_pubkey()
|
||||
|
||||
# Bob receives the capsule
|
||||
capsule = <fetch a capsule through side channel>
|
||||
# Bob receives the capsule through a side-channel
|
||||
capsule = capsule
|
||||
|
||||
|
||||
Bob fails to open the capsule
|
||||
|
@ -109,13 +163,11 @@ Bob fails to open the capsule
|
|||
If Bob attempts to open a capsule that was not encrypted for his public key,
|
||||
or re-encrypted for him by Ursula, he will not be able to open it.
|
||||
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
try:
|
||||
fail = umbral.decrypt(capsule,
|
||||
bobs_private_key,
|
||||
ciphertext,
|
||||
alices_public_key)
|
||||
fail = pre.decrypt(ciphertext=ciphertext, capsule=capsule, decrypting_key=bobs_private_key)
|
||||
except:
|
||||
print("Decryption failed!")
|
||||
|
||||
|
@ -132,17 +184,30 @@ Bob collects the resulting `cfrags` from several Ursulas.
|
|||
Bob must gather at least `M` `cfrags` in order to activate the capsule.
|
||||
|
||||
|
||||
.. doctest::
|
||||
|
||||
>>> import random
|
||||
>>> kfrags = random.sample(kfrags, 10)
|
||||
|
||||
>>> cfrags = list()
|
||||
>>> for kfrag in kfrags:
|
||||
... cfrag = pre.reencrypt(kfrag=kfrag, capsule=capsule)
|
||||
... cfrags.append(cfrag)
|
||||
|
||||
>>> assert len(cfrags) == 10
|
||||
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import random
|
||||
import random
|
||||
|
||||
kfrags = random.sample(kfrags, # All kfrags from above
|
||||
10) # M - Threshold
|
||||
kfrags = random.sample(kfrags, # All kfrags from above
|
||||
10) # M - Threshold
|
||||
|
||||
cfrags = list() # Bob's cfrag collection
|
||||
for kfrag in kfrags:
|
||||
cfrag = umbral.reencrypt(kfrag, capsule)
|
||||
cfrags.append(cfrag) # Bob collects a cfrag
|
||||
cfrags = list() # Bob's cfrag collection
|
||||
for kfrag in kfrags:
|
||||
cfrag = pre.reencrypt(kfrag=kfrag, capsule=capsule)
|
||||
cfrags.append(cfrag) # Bob collects a cfrag
|
||||
|
||||
|
||||
Bob attaches cfrags to the capsule
|
||||
|
@ -150,8 +215,16 @@ Bob attaches cfrags to the capsule
|
|||
Bob attaches at least `M` `cfrags` to the capsule;
|
||||
Then it can become *activated*.
|
||||
|
||||
.. doctest::
|
||||
>>> capsule.set_correctness_keys(delegating=alices_public_key, receiving=bobs_public_key, verifying=alices_verifying_key)
|
||||
(True, True, True)
|
||||
>>> for cfrag in cfrags:
|
||||
... capsule.attach_cfrag(cfrag)
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
capsule.set_correctness_keys(delegating=alices_public_key, receiving=bobs_public_key, verifying=alices_verifying_key)
|
||||
|
||||
for cfrag in cfrags:
|
||||
capsule.attach_cfrag(cfrag)
|
||||
|
||||
|
@ -161,7 +234,18 @@ Bob activates and opens the capsule
|
|||
Finally, Bob activates and opens the capsule,
|
||||
then decrypts the re-encrypted ciphertext.
|
||||
|
||||
.. doctest::
|
||||
|
||||
>>> capsule.set_correctness_keys(delegating=alices_public_key, receiving=bobs_public_key, verifying=alices_verifying_key)
|
||||
(True, True, True)
|
||||
>>> for cfrag in cfrags:
|
||||
... capsule.attach_cfrag(cfrag)
|
||||
>>> cleartext = pre.decrypt(ciphertext=ciphertext, capsule=capsule, decrypting_key=bobs_private_key)
|
||||
>>> assert cleartext == plaintext
|
||||
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
cleartext = umbral.decrypt(capsule, bobs_private_key,
|
||||
ciphertext, alices_public_key)
|
||||
cleartext = pre.decrypt(ciphertext=ciphertext,
|
||||
capsule=capsule,
|
||||
decrypting_key=bobs_private_key)
|
||||
|
|
Loading…
Reference in New Issue