# Using pyUmbral¶

## Configuration¶

### Setting the default curve¶

The best way to start using pyUmbral is to decide on an elliptic curve to use and set it as your default.

```
>>> from umbral import config
>>> from umbral.curve import SECP256K1
>>> config.set_default_curve(SECP256K1)
```

For more information on curves, see Choosing and Using Curves.

## Encryption¶

### Generate an Umbral key pair¶

First, let’s generate two asymmetric key pairs for Alice: A delegating key pair and a signing key pair.

```
>>> from umbral import keys, signing
>>> 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¶

Now let’s encrypt data with Alice’s public key.
Invocation of `pre.encrypt`

returns both the `ciphertext`

and a `capsule`

.
Note that anyone with Alice’s public key can perform this operation.

```
>>> from umbral import pre
>>> plaintext = b'Proxy Re-encryption is cool!'
>>> ciphertext, capsule = pre.encrypt(alices_public_key, plaintext)
```

### 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.

```
>>> cleartext = pre.decrypt(ciphertext=ciphertext, capsule=capsule, decrypting_key=alices_private_key)
```

## Threshold Re-encryption¶

### Bob Exists¶

```
>>> from umbral import keys
>>> bobs_private_key = keys.UmbralPrivateKey.gen_key()
>>> bobs_public_key = bobs_private_key.get_pubkey()
```

### Alice grants access to Bob by generating kfrags¶

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*.

Alice must specify `N`

(the total number of kfrags),
and a `threshold`

(the minimum number of kfrags needed to activate a capsule).
In the following example, Alice creates 20 kfrags,
but Bob needs to get only 10 re-encryptions to activate the capsule.

```
>>> kfrags = pre.generate_kfrags(delegating_privkey=alices_private_key,
... signer=alices_signer,
... receiving_pubkey=bobs_public_key,
... threshold=10,
... N=20)
```

### Bob receives a capsule¶

Next, let’s generate a key pair for Bob, and pretend to send him the capsule through a side channel like S3, IPFS, Google Cloud, Sneakernet, etc.

```
# Bob receives the capsule through a side-channel: IPFS, Sneakernet, etc.
capsule = <fetch the capsule through a side-channel>
```

### 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.

```
>>> fail = pre.decrypt(ciphertext=ciphertext,
... capsule=capsule,
... decrypting_key=bobs_private_key)
Traceback (most recent call last):
...
cryptography.exceptions.InvalidTag
```

### Ursulas perform re-encryption¶

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 `threshold`

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.
Bob must gather at least `threshold`

cfrags in order to activate the capsule.

```
>>> import random
>>> kfrags = random.sample(kfrags, # All kfrags from above
... 10) # M - Threshold
>>> capsule.set_correctness_keys(delegating=alices_public_key,
... receiving=bobs_public_key,
... verifying=alices_verifying_key)
(True, True, True)
>>> 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 at least `threshold`

cfrags to the capsule,
which has to be prepared in advance with the necessary correctness keys.
Only then it can become *activated*.

```
>>> capsule.set_correctness_keys(delegating=alices_public_key,
... receiving=bobs_public_key,
... verifying=alices_verifying_key)
(False, False, False)
>>> for cfrag in cfrags:
... capsule.attach_cfrag(cfrag)
```

### Bob activates and opens the capsule¶

Finally, Bob decrypts the re-encrypted ciphertext using the activated capsule.

```
>>> cleartext = pre.decrypt(ciphertext=ciphertext, capsule=capsule, decrypting_key=bobs_private_key)
```