package tezos-crypto

  1. Overview
  2. Docs
Legend:
Library
Module
Module type
Parameter
Class
Class type

Timelock is a set of functions to handle time-locking a value and opening time-locked values.

A time-locked value can be opened slowly by anyone doing a fixed number of sequential operations.

In the interface of this module, this fixed number is consistently named time and is represented by an integer.

Once opened via the slow method a proof of opening can be produced to avoid having to do so again. This proof is verifiable in logarithmic time.

In order to time-lock an arbitrary sequence of bytes, we 1. encrypt the bytes with a symmetric key, and then 2. we time-lock the symmetric key itself.

This module implements a scheme inspired by: Time-lock puzzles and timed release - Rivest, Shamir, Wagner https://people.csail.mit.edu/rivest/pubs/RSW96.pdf

type symmetric_key

We will time-lock symmetric keys to then handle arbitrary bytes

type rsa_public

RSA public key to define a group in which we will work. The key is an integer n = p*q with p, q primes number. The group we work in is the set of inversible mod n.

type locked_value

Locked value that can be accessed with a number of sequential operations. It is concretely a member of the RSA group.

val to_locked_value_opt : string -> locked_value option

Function taking as input a string and returning Some locked_value if the element is in the RSA group with RSA2048 as modulus, None otherwise.

val to_locked_value_unsafe : string -> locked_value

Function taking as input a string and returning a locked_value with no check.

type unlocked_value

Member of the RSA group that we will lock. In our case it represents a symmetric key.

type vdf_proof

VDF proof (Wesolowski).

type ciphertext

A symmetric ciphertext and message authentication code, containing the bytes we want to protect

type vdf_tuple = {
  1. locked_value : locked_value;
  2. unlocked_value : unlocked_value;
  3. vdf_proof : vdf_proof;
}

Tuple of the RSA group comprising the locked and unlocked values as well as (Wesolowski) proof that the unlocked value indeed correspond to the locked one.

val to_vdf_tuple_opt : rsa_public -> time:int -> string -> string -> string -> vdf_tuple option

Function taking as input an rsa_public, a time and three strings representing a locked and unlocked value as well as a wesolowski proof and returning Some vdf_tuple if the elements are in the RSA group with rsa_public as modulus and the Wesolowski proof verifies, None otherwise.

val to_vdf_tuple_unsafe : string -> string -> string -> vdf_tuple

Function taking as input three strings representing a locked and unlocked value as well as a wesolowski proof and returning a vdf_tuple.

type timelock_proof = {
  1. vdf_tuple : vdf_tuple;
  2. nonce : Z.t;
}

Proof that the opening of a value is the claimed value. It is concretely an optional vdf_tuple and a member of the RSA group.

val rsa2048 : rsa_public

Default modulus for RSA-based timelock, chosen as 2048 bit RSA modulus challenge "RSA-2048".

val gen_locked_value_unsafe : rsa_public -> locked_value

Generates almost uniformly an integer mod n. It is in the RSA group with overwhelming probability. We use this since we want to lock symmetric keys, not pre-determined messages.

  • raises Failure

    if there is not enough entropy available.

val gen_locked_value_opt : rsa_public -> locked_value option

Returns None if rsa_public is not RSA2048, otherwise returns Some gen_locked_value_unsafe rsa_public.

val timelock_proof_to_symmetric_key : rsa_public -> timelock_proof -> symmetric_key

Hashes a number mod n to a symmetric key for authenticated encryption, where the number is unlocked_value**nonce mod rsa_public.

val unlock_and_prove : rsa_public -> time:int -> locked_value -> timelock_proof

Unlock a timelock value and produces a proof certifying that the result is indeed what had been locked.

val prove : rsa_public -> time:int -> locked_value -> unlocked_value -> timelock_proof

Produces a proof certifying that the result is indeed what had been locked.

val verify : rsa_public -> time:int -> locked_value -> timelock_proof -> bool

Verifies that locked_value indeed contains unlocked_value with parameters rsa_public and time:int.

val precompute_timelock : ?locked_value:locked_value option -> ?precompute_path:string option -> time:int -> unit -> vdf_tuple

Precomputes a vdf_tuple given a time:int and optionally locked_value. If precompute_path is given, it will instead read vdf_tuple locally and if not found, will write the newly computed vdf_tuple there.

val proof_of_vdf_tuple : rsa_public -> time:int -> vdf_tuple -> locked_value * timelock_proof

Randomizes a vdf_tuple given a rsa_public and a time:int (to verify the vdf_tuple is correct).

val locked_value_to_symmetric_key : rsa_public -> time:int -> locked_value -> timelock_proof -> symmetric_key option

Receives a claim opening with a proof and potentially secret. If the proof is valid hashes the opening using unlocked_value_to_symmetric_key, returns None otherwise.

val encrypt : symmetric_key -> bytes -> ciphertext

encrypt using authenticated encryption, i.e. ciphertext contains a ciphertext and a message authentication code.

val decrypt : symmetric_key -> ciphertext -> bytes option

Checks the message authentication code. If correct decrypt the ciphertext, otherwise returns None.

val ciphertext_encoding : ciphertext Data_encoding.t
val rsa_public_encoding : rsa_public Data_encoding.t
val vdf_tuple_encoding : vdf_tuple Data_encoding.t
val proof_encoding : timelock_proof Data_encoding.t
type chest = {
  1. locked_value : locked_value;
  2. rsa_public : rsa_public;
  3. ciphertext : ciphertext;
}

Contains a value (the decryption of the ciphertext) that can be provably recovered in time sequential operation.

val chest_encoding : chest Data_encoding.t
type chest_key = timelock_proof

Provably opens a chest in a short time.

val chest_key_encoding : chest_key Data_encoding.t

Result of the opening of a chest. The opening can fail in two ways which we distinguish to blame the right party. One can provide a false unlocked_value or unlocked_proof, in which case we return Bogus_opening and the provider of the chest key is at fault. Otherwise we return Correct payload where payload is the content that had originally been put in the chest.

type opening_result =
  1. | Correct of Stdlib.Bytes.t
  2. | Bogus_cipher
  3. | Bogus_opening
val open_chest : chest -> chest_key -> time:int -> opening_result

Takes a chest, chest key and time and tries to recover the underlying plaintext. See the documentation of opening_result.

val get_plaintext_size : chest -> int

Gives the size of the underlying plaintext in a chest in bytes. Used for gas accounting

val create_chest_and_chest_key : ?precompute_path:string option -> payload:Stdlib.Bytes.t -> time:int -> unit -> chest * chest_key

High level function which given a payload, time and optionally a precomputed_path, generates a chest and chest_key. The payload corresponds to the message to timelock while the time corresponds to the difficulty in opening the chest. Beware, it does not correspond to a duration per se but to the number of iteration needed. The optional precomputed_path is a local path where to read or write some auxiliary information to generate the chest quickly.

val create_chest_key : chest -> time:int -> chest_key

High level function which unlock the value and create the time-lock proof.

val chest_sampler : rng_state:Stdlib.Random.State.t -> plaintext_size:int -> time:int -> chest * chest_key

----- !!!!! Do not use for wallets: the RNG is not safe !!!!---- Sampler for the gasbenchmarks. Takes an Ocaml RNG state as arg for reproducibility.

OCaml

Innovation. Community. Security.