Expand description

umbral-pre is the Rust implementation of the Umbral threshold proxy re-encryption scheme.

Using umbral-pre, Alice (the data owner) can delegate decryption rights to Bob for any ciphertext intended to her, through a re-encryption process performed by a set of semi-trusted proxies or Ursulas. When a threshold of these proxies participate by performing re-encryption, Bob is able to combine these independent re-encryptions and decrypt the original message using his private key.

Available feature flags

  • default-rng - adds methods that use the system RNG (default).
  • serde-support - implements serde-based serialization and deserialization.
  • bindings-python - adds a bindings_python submodule allowing dependent crates to use and re-export some of the Python-wrapped Umbral types.
  • bindings-wasm - adds a bindings_wasm submodule allowing dependent crates to use and re-export some of the WASM-wrapped Umbral types.

Usage

use umbral_pre::*;

// 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)
let alice_sk = SecretKey::random();
let alice_pk = alice_sk.public_key();
let signer = Signer::new(SecretKey::random());
let verifying_pk = signer.verifying_key();

// Key Generation (on Bob's side)
let bob_sk = SecretKey::random();
let bob_pk = bob_sk.public_key();

// Now let's encrypt data with Alice's public key.
// Invocation of `encrypt()` returns both the ciphertext and a capsule.
// Note that anyone with Alice's public key can perform this operation.

let plaintext = b"peace at dawn";
let (capsule, ciphertext) = encrypt(&alice_pk, plaintext).unwrap();

// Since data was encrypted with Alice's public key, Alice can open the capsule
// and decrypt the ciphertext with her private key.

let plaintext_alice = decrypt_original(&alice_sk, &capsule, &ciphertext).unwrap();
assert_eq!(&plaintext_alice as &[u8], plaintext);

// 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 `shares` proxies or Ursulas.

let shares = 3; // how many fragments to create
let threshold = 2; // how many should be enough to decrypt
let verified_kfrags = generate_kfrags(&alice_sk, &bob_pk, &signer, threshold, shares, true, true);

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

// Simulate network transfer
let kfrag0 = KeyFrag::from_array(&verified_kfrags[0].to_array()).unwrap();
let kfrag1 = KeyFrag::from_array(&verified_kfrags[1].to_array()).unwrap();

// Bob collects the resulting cfrags from several Ursulas.
// Bob must gather at least `threshold` cfrags in order to open the capsule.

// Ursulas must check that the received kfrags are valid
// and perform the reencryption

// Ursula 0
let verified_kfrag0 = kfrag0.verify(&verifying_pk, Some(&alice_pk), Some(&bob_pk)).unwrap();
let verified_cfrag0 = reencrypt(&capsule, verified_kfrag0);

// Ursula 1
let verified_kfrag1 = kfrag1.verify(&verifying_pk, Some(&alice_pk), Some(&bob_pk)).unwrap();
let verified_cfrag1 = reencrypt(&capsule, verified_kfrag1);

// ...

// Simulate network transfer
let cfrag0 = CapsuleFrag::from_array(&verified_cfrag0.to_array()).unwrap();
let cfrag1 = CapsuleFrag::from_array(&verified_cfrag1.to_array()).unwrap();

// Finally, Bob opens the capsule by using at least `threshold` cfrags,
// and then decrypts the re-encrypted ciphertext.

// Bob must check that cfrags are valid
let verified_cfrag0 = cfrag0
    .verify(&capsule, &verifying_pk, &alice_pk, &bob_pk)
    .unwrap();
let verified_cfrag1 = cfrag1
    .verify(&capsule, &verifying_pk, &alice_pk, &bob_pk)
    .unwrap();

let plaintext_bob = decrypt_reencrypted(
    &bob_sk, &alice_pk, &capsule, [verified_cfrag0, verified_cfrag1], &ciphertext).unwrap();
assert_eq!(&plaintext_bob as &[u8], plaintext);

Structs

Encapsulated symmetric key used to encrypt the plaintext.

A reencrypted fragment of a Capsule created by a proxy.

Errors that can happen during deserializing an object from a bytestring of correct length.

A fragment of the encrypting party’s key used to create a CapsuleFrag.

A public key.

A container for secret data. Makes the usage of secret data explicit and easy to track, prevents the secret data from being put on stack, and zeroizes the contents on drop.

A secret key.

This class handles keyring material for Umbral, by allowing deterministic derivation of SecretKey objects based on labels.

ECDSA signature object.

An object used to sign messages. For security reasons cannot be serialized.

The provided bytestring is of an incorrect size.

Verified capsule fragment, good for dencryption. Can be serialized, but cannot be deserialized directly. It can only be obtained from CapsuleFrag::verify or CapsuleFrag::skip_verification.

Verified key fragment, good for reencryption. Can be serialized, but cannot be deserialized directly. It can only be obtained from KeyFrag::verify or KeyFrag::skip_verification.

Enums

Possible errors that can be returned by CapsuleFrag::verify.

Errors that can happend during symmetric decryption.

Errors that can happen during object deserialization.

Errors that can happen during symmetric encryption.

Possible errors that can be returned by KeyFrag::verify.

Errors that can happen when opening a Capsule using reencrypted CapsuleFrag objects.

Errors that can happen when decrypting a reencrypted ciphertext.

Traits

This is a helper trait for SecretBox, asserting that the type implementing it can either be zeroized (in which case ensure_zeroized_on_drop is implemented accordingly), or is zeroized on drop (in which case ensure_zeroized_on_drop does nothing). In other words, with this trait we are sure that one way or the other, on drop of SecretBox the contents are zeroized.

A trait denoting that the object can be deserialized from an array of bytes with size known at compile time.

A reflection trait providing access to the type’s name.

A trait denoting that the object can be represented as an array of bytes with size known at compile time.

A trait denoting that the object can be serialized to an array of bytes with size known at compile time.

A trait denoting that the object can be serialized to an array of bytes containing secret data.

Functions

Attempts to decrypt the ciphertext using the receiver’s secret key.

Decrypts the ciphertext using previously reencrypted capsule fragments.

encryptdefault-rng

A synonym for encrypt with the default RNG.

Encrypts the given plaintext message using a DEM scheme, and encapsulates the key for later reencryption. Returns the KEM Capsule and the ciphertext.

generate_kfragsdefault-rng

A synonym for generate_kfrags_with_rng with the default RNG.

Creates shares fragments of delegating_sk, which will be possible to reencrypt to allow the creator of receiving_pk decrypt the ciphertext encrypted with delegating_sk.

reencryptdefault-rng

A synonym for reencrypt_with_rng with the default RNG.

Reencrypts a Capsule object with a key fragment, creating a capsule fragment.