mirror of https://github.com/nucypher/pyUmbral.git
Remove duplicated doc snippets, Create test execution groups.
parent
6e02037dcc
commit
16dd9f16aa
|
@ -14,73 +14,47 @@ 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 provide SECP256K1 as a default because it is the basis for a number of crypto-blockchain projects;
|
||||||
we don't otherwise endorse its security.
|
we don't otherwise endorse its security.
|
||||||
|
|
||||||
.. testsetup::
|
|
||||||
|
|
||||||
from umbral import config, keys
|
|
||||||
from cryptography.hazmat.primitives.asymmetric import ec
|
|
||||||
|
|
||||||
|
|
||||||
Setting a default curve
|
Setting a default curve
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
Before you perform any ECC operations, you can set 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
|
.. code-block:: python
|
||||||
|
|
||||||
from umbral import config
|
>>> from cryptography.hazmat.primitives.asymmetric import ec
|
||||||
from cryptography.hazmat.primitives.asymmetric import ec
|
>>> config.set_default_curve(ec.SECP256K1)
|
||||||
|
|
||||||
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
|
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.
|
operation. This causes a small one-time performance penalty.
|
||||||
|
|
||||||
|
|
||||||
.. doctest::
|
.. code-block:: python
|
||||||
>>> config._CONFIG.___CONFIG__curve = None
|
|
||||||
>>> config._CONFIG.___CONFIG__params = None
|
>>> from umbral import keys
|
||||||
>>> keys.UmbralPrivateKey.gen_key()
|
>>> private_key = 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().
|
|
||||||
|
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().
|
||||||
|
|
||||||
|
|
||||||
|
To use SECP256K1 and avoid this penalty, you can simply call `set_default_curve()` with no argument:
|
||||||
|
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
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()
|
>>> config.set_default_curve()
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
config.set_default_curve()
|
|
||||||
|
|
||||||
Attempting to set the default curve twice in the same runtime will raise
|
Attempting to set the default curve twice in the same runtime will raise
|
||||||
a `UmbralConfigurationError`.
|
a `UmbralConfigurationError`.
|
||||||
|
|
||||||
|
|
||||||
.. doctest::
|
.. code-block:: python
|
||||||
>>> config._CONFIG.___CONFIG__curve = None
|
|
||||||
>>> config._CONFIG.___CONFIG__params = None
|
>>> from umbral import config
|
||||||
>>> config.set_default_curve()
|
>>> config.set_default_curve()
|
||||||
>>> config.set_default_curve()
|
>>> config.set_default_curve()
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
umbral.config._CONFIG.UmbralConfigurationError:
|
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.
|
|
||||||
|
|
|
@ -6,17 +6,18 @@ Using pyUmbral
|
||||||
|
|
||||||
Import umbral modules
|
Import umbral modules
|
||||||
|
|
||||||
.. testsetup::
|
.. testsetup:: capsule_story
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
sys.path.append(os.path.abspath(os.getcwd()))
|
||||||
|
|
||||||
sys.path.append(os.path.abspath(os.getcwd()))
|
|
||||||
from umbral import pre, keys, config, signing
|
|
||||||
|
|
||||||
.. code-block:: python
|
.. testcleanup:: capsule_story
|
||||||
|
|
||||||
from umbral import pre, keys, config, signing
|
from umbral import config
|
||||||
|
config._CONFIG.___CONFIG__curve = None
|
||||||
|
config._CONFIG.___CONFIG__params = None
|
||||||
|
|
||||||
|
|
||||||
Configuration
|
Configuration
|
||||||
|
@ -28,17 +29,13 @@ 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.
|
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
|
.. doctest:: capsule_story
|
||||||
>>> config._CONFIG.___CONFIG__params = None
|
|
||||||
|
>>> from umbral import config
|
||||||
>>> from cryptography.hazmat.primitives.asymmetric import ec
|
>>> from cryptography.hazmat.primitives.asymmetric import ec
|
||||||
>>> config.set_default_curve(ec.SECP256K1)
|
>>> 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`.
|
For more information on curves, see :doc:`choosing_and_using_curves`.
|
||||||
|
|
||||||
|
|
||||||
|
@ -51,7 +48,9 @@ Generate an Umbral key pair
|
||||||
First, Let's generate two asymmetric key pairs for Alice:
|
First, Let's generate two asymmetric key pairs for Alice:
|
||||||
A delegating key pair and a Signing key pair.
|
A delegating key pair and a Signing key pair.
|
||||||
|
|
||||||
.. doctest::
|
.. doctest:: capsule_story
|
||||||
|
|
||||||
|
>>> from umbral import keys, signing
|
||||||
|
|
||||||
>>> alices_private_key = keys.UmbralPrivateKey.gen_key()
|
>>> alices_private_key = keys.UmbralPrivateKey.gen_key()
|
||||||
>>> alices_public_key = alices_private_key.get_pubkey()
|
>>> alices_public_key = alices_private_key.get_pubkey()
|
||||||
|
@ -60,15 +59,6 @@ A delegating key pair and a Signing key pair.
|
||||||
>>> alices_verifying_key = alices_signing_key.get_pubkey()
|
>>> alices_verifying_key = alices_signing_key.get_pubkey()
|
||||||
>>> alices_signer = signing.Signer(private_key=alices_signing_key)
|
>>> alices_signer = signing.Signer(private_key=alices_signing_key)
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
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
|
Encrypt with a public key
|
||||||
--------------------------
|
--------------------------
|
||||||
|
@ -78,31 +68,22 @@ and a `capsule`, Anyone with Alice's public key can perform
|
||||||
this operation.
|
this operation.
|
||||||
|
|
||||||
|
|
||||||
.. doctest::
|
.. doctest:: capsule_story
|
||||||
|
|
||||||
|
>>> from umbral import pre
|
||||||
>>> plaintext = b'Proxy Re-encryption is cool!'
|
>>> plaintext = b'Proxy Re-encryption is cool!'
|
||||||
>>> ciphertext, capsule = pre.encrypt(alices_public_key, plaintext)
|
>>> ciphertext, capsule = pre.encrypt(alices_public_key, plaintext)
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
plaintext = b'Proxy Re-encryption is cool!'
|
|
||||||
ciphertext, capsule = pre.encrypt(alices_public_key, plaintext)
|
|
||||||
|
|
||||||
|
|
||||||
Decrypt with a private key
|
Decrypt with a private key
|
||||||
---------------------------
|
---------------------------
|
||||||
Since data was encrypted with Alice's public key,
|
Since data was encrypted with Alice's public key,
|
||||||
Alice can open the capsule and decrypt the ciphertext with her private key.
|
Alice can open the capsule and decrypt the ciphertext with her private key.
|
||||||
|
|
||||||
.. doctest::
|
.. doctest:: capsule_story
|
||||||
|
|
||||||
>>> cleartext = pre.decrypt(ciphertext=ciphertext, capsule=capsule, decrypting_key=alices_private_key)
|
>>> cleartext = pre.decrypt(ciphertext=ciphertext, capsule=capsule, decrypting_key=alices_private_key)
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
cleartext = pre.decrypt(ciphertext=ciphertext, capsule=capsule,
|
|
||||||
decrypting_key=alices_private_key)
|
|
||||||
|
|
||||||
|
|
||||||
Threshold split-key re-encryption
|
Threshold split-key re-encryption
|
||||||
==================================
|
==================================
|
||||||
|
@ -110,19 +91,13 @@ Threshold split-key re-encryption
|
||||||
Bob Exists
|
Bob Exists
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
.. doctest::
|
.. doctest:: capsule_story
|
||||||
|
|
||||||
|
>>> from umbral import keys
|
||||||
>>> bobs_private_key = keys.UmbralPrivateKey.gen_key()
|
>>> bobs_private_key = keys.UmbralPrivateKey.gen_key()
|
||||||
>>> bobs_public_key = bobs_private_key.get_pubkey()
|
>>> 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
|
Alice grants access to Bob by generating kfrags
|
||||||
-----------------------------------------------
|
-----------------------------------------------
|
||||||
When Alice wants to grant Bob access to open her encrypted messages,
|
When Alice wants to grant Bob access to open her encrypted messages,
|
||||||
|
@ -133,19 +108,15 @@ which are next sent to N proxies or *Ursulas*.
|
||||||
| `threshold` - Minimum threshold of key fragments needed to activate a capsule.
|
| `threshold` - Minimum threshold of key fragments needed to activate a capsule.
|
||||||
| `N` - Total number of key fragments to generate.
|
| `N` - Total number of key fragments to generate.
|
||||||
|
|
||||||
.. doctest::
|
.. doctest:: capsule_story
|
||||||
|
|
||||||
>>> kfrags = pre.split_rekey(delegating_privkey=alices_private_key, signer=alices_signer, receiving_pubkey=bobs_public_key, threshold=10, N=20)
|
>>> 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 = pre.split_rekey(delegating_privkey=alices_private_key,
|
|
||||||
signer=alices_signer,
|
|
||||||
receiving_pubkey=bobs_public_key,
|
|
||||||
threshold=10,
|
|
||||||
N=20)
|
|
||||||
|
|
||||||
Bob receives a capsule
|
Bob receives a capsule
|
||||||
-----------------------
|
-----------------------
|
||||||
Next, let's generate a key pair for Bob, and pretend to send
|
Next, let's generate a key pair for Bob, and pretend to send
|
||||||
|
@ -163,22 +134,16 @@ Bob fails to open the capsule
|
||||||
If Bob attempts to open a capsule that was not encrypted for his public key,
|
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.
|
or re-encrypted for him by Ursula, he will not be able to open it.
|
||||||
|
|
||||||
.. doctest::
|
.. doctest:: capsule_story
|
||||||
|
|
||||||
>>> fail = pre.decrypt(ciphertext=ciphertext, capsule=capsule, decrypting_key=bobs_private_key)
|
>>> fail = pre.decrypt(ciphertext=ciphertext,
|
||||||
|
... capsule=capsule,
|
||||||
|
... decrypting_key=bobs_private_key)
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
cryptography.exceptions.InvalidTag
|
cryptography.exceptions.InvalidTag
|
||||||
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
try:
|
|
||||||
fail = pre.decrypt(ciphertext=ciphertext, capsule=capsule, decrypting_key=bobs_private_key)
|
|
||||||
except:
|
|
||||||
print("Decryption failed!")
|
|
||||||
|
|
||||||
|
|
||||||
Ursulas perform re-encryption
|
Ursulas perform re-encryption
|
||||||
------------------------------
|
------------------------------
|
||||||
Bob asks several Ursulas to re-encrypt the capsule so he can open it.
|
Bob asks several Ursulas to re-encrypt the capsule so he can open it.
|
||||||
|
@ -191,68 +156,49 @@ Bob collects the resulting `cfrags` from several Ursulas.
|
||||||
Bob must gather at least `threshold` `cfrags` in order to activate the capsule.
|
Bob must gather at least `threshold` `cfrags` in order to activate the capsule.
|
||||||
|
|
||||||
|
|
||||||
.. doctest::
|
.. doctest:: capsule_story
|
||||||
|
|
||||||
>>> import random
|
>>> import random
|
||||||
>>> kfrags = random.sample(kfrags, 10)
|
>>> kfrags = random.sample(kfrags, # All kfrags from above
|
||||||
|
... 10) # M - Threshold
|
||||||
|
|
||||||
>>> cfrags = list()
|
>>> cfrags = list() # Bob's cfrag collection
|
||||||
>>> for kfrag in kfrags:
|
>>> for kfrag in kfrags:
|
||||||
... cfrag = pre.reencrypt(kfrag=kfrag, capsule=capsule)
|
... cfrag = pre.reencrypt(kfrag=kfrag, capsule=capsule)
|
||||||
... cfrags.append(cfrag)
|
... cfrags.append(cfrag) # Bob collects a cfrag
|
||||||
|
|
||||||
|
.. doctest:: capsule_story
|
||||||
|
:hide:
|
||||||
|
|
||||||
>>> assert len(cfrags) == 10
|
>>> assert len(cfrags) == 10
|
||||||
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
import random
|
|
||||||
|
|
||||||
kfrags = random.sample(kfrags, # All kfrags from above
|
|
||||||
10) # M - Threshold
|
|
||||||
|
|
||||||
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
|
Bob attaches cfrags to the capsule
|
||||||
----------------------------------
|
----------------------------------
|
||||||
Bob attaches at least `threshold` `cfrags` to the capsule;
|
Bob attaches at least `threshold` `cfrags` to the capsule;
|
||||||
Then it can become *activated*.
|
Then it can become *activated*.
|
||||||
|
|
||||||
.. doctest::
|
.. doctest:: capsule_story
|
||||||
>>> capsule.set_correctness_keys(delegating=alices_public_key, receiving=bobs_public_key, verifying=alices_verifying_key)
|
|
||||||
|
>>> capsule.set_correctness_keys(delegating=alices_public_key,
|
||||||
|
... receiving=bobs_public_key,
|
||||||
|
... verifying=alices_verifying_key)
|
||||||
(True, True, True)
|
(True, True, True)
|
||||||
|
|
||||||
>>> for cfrag in cfrags:
|
>>> for cfrag in cfrags:
|
||||||
... capsule.attach_cfrag(cfrag)
|
... 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)
|
|
||||||
|
|
||||||
|
|
||||||
Bob activates and opens the capsule
|
Bob activates and opens the capsule
|
||||||
------------------------------------
|
------------------------------------
|
||||||
Finally, Bob activates and opens the capsule,
|
Finally, Bob activates and opens the capsule,
|
||||||
then decrypts the re-encrypted ciphertext.
|
then decrypts the re-encrypted ciphertext.
|
||||||
|
|
||||||
.. doctest::
|
.. doctest:: capsule_story
|
||||||
|
|
||||||
>>> 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)
|
>>> cleartext = pre.decrypt(ciphertext=ciphertext, capsule=capsule, decrypting_key=bobs_private_key)
|
||||||
|
|
||||||
|
.. doctest:: capsule_story
|
||||||
|
:hide:
|
||||||
|
|
||||||
>>> assert cleartext == plaintext
|
>>> assert cleartext == plaintext
|
||||||
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
cleartext = pre.decrypt(ciphertext=ciphertext,
|
|
||||||
capsule=capsule,
|
|
||||||
decrypting_key=bobs_private_key)
|
|
||||||
|
|
Loading…
Reference in New Issue