From 34fd8dab38551af8fb80319fdb94317b2b679bcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Dupressoir?= Date: Thu, 18 Jun 2026 09:26:50 +0100 Subject: [PATCH] [doc] start folding the tutorial in --- config/tests.config | 3 + doc/conf.py | 2 +- doc/index.rst | 5 +- doc/reference.rst | 8 + doc/{ => reference}/tactics.rst | 0 doc/{ => reference}/tactics/async-while.rst | 0 doc/{ => reference}/tactics/cfold.rst | 0 doc/{ => reference}/tactics/clear.rst | 0 doc/{ => reference}/tactics/hoare-split.rst | 0 doc/{ => reference}/tactics/if.rst | 0 doc/{ => reference}/tactics/proc.rst | 0 doc/{ => reference}/tactics/procstar.rst | 0 doc/{ => reference}/tactics/rnd.rst | 0 doc/{ => reference}/tactics/simplify-if.rst | 0 doc/{ => reference}/tactics/skip.rst | 0 doc/{ => reference}/tactics/splitwhile.rst | 0 doc/{ => reference}/tactics/swap.rst | 0 doc/tutorials.rst | 10 + doc/tutorials/encryption-from-prf.rst | 16 + .../encryption-from-prf/Construction.eca | 783 +++++++++++++ doc/tutorials/encryption-from-prf/IVbased.ec | 569 +++++++++ .../encryption-from-prf/Including.ec | 27 + doc/tutorials/encryption-from-prf/context.rst | 421 +++++++ .../going-further/layering-proofs.rst | 8 + .../reusing-proof-components.rst | 492 ++++++++ doc/tutorials/encryption-from-prf/proof.rst | 1031 +++++++++++++++++ .../encryption-from-prf/reduction.jpg | Bin 0 -> 70942 bytes .../encryption-from-prf/security.rst | 936 +++++++++++++++ .../introduction-itp-program-logics.rst | 51 + .../abstract-ind-ror.ec | 115 ++ .../abstract-ind-ror.png | Bin 0 -> 192897 bytes .../ambient-logic.ec | 428 +++++++ .../ambient-logic.png | Bin 0 -> 190271 bytes .../ambient-logic.rst | 384 ++++++ .../conclusion.rst | 16 + .../easycrypt.rst | 362 ++++++ .../hoare-logic.ec | 644 ++++++++++ .../hoare-logic.rst | 806 +++++++++++++ .../preface.rst | 208 ++++ .../relational-hoare-logic.ec | 478 ++++++++ .../relational-hoare-logic.rst | 421 +++++++ doc/tutorials/tutorials.rst | 49 + 42 files changed, 8270 insertions(+), 3 deletions(-) create mode 100644 doc/reference.rst rename doc/{ => reference}/tactics.rst (100%) rename doc/{ => reference}/tactics/async-while.rst (100%) rename doc/{ => reference}/tactics/cfold.rst (100%) rename doc/{ => reference}/tactics/clear.rst (100%) rename doc/{ => reference}/tactics/hoare-split.rst (100%) rename doc/{ => reference}/tactics/if.rst (100%) rename doc/{ => reference}/tactics/proc.rst (100%) rename doc/{ => reference}/tactics/procstar.rst (100%) rename doc/{ => reference}/tactics/rnd.rst (100%) rename doc/{ => reference}/tactics/simplify-if.rst (100%) rename doc/{ => reference}/tactics/skip.rst (100%) rename doc/{ => reference}/tactics/splitwhile.rst (100%) rename doc/{ => reference}/tactics/swap.rst (100%) create mode 100644 doc/tutorials.rst create mode 100644 doc/tutorials/encryption-from-prf.rst create mode 100644 doc/tutorials/encryption-from-prf/Construction.eca create mode 100644 doc/tutorials/encryption-from-prf/IVbased.ec create mode 100644 doc/tutorials/encryption-from-prf/Including.ec create mode 100644 doc/tutorials/encryption-from-prf/context.rst create mode 100644 doc/tutorials/encryption-from-prf/going-further/layering-proofs.rst create mode 100644 doc/tutorials/encryption-from-prf/going-further/reusing-proof-components.rst create mode 100644 doc/tutorials/encryption-from-prf/proof.rst create mode 100644 doc/tutorials/encryption-from-prf/reduction.jpg create mode 100644 doc/tutorials/encryption-from-prf/security.rst create mode 100644 doc/tutorials/introduction-itp-program-logics.rst create mode 100644 doc/tutorials/introduction-itp-program-logics/abstract-ind-ror.ec create mode 100644 doc/tutorials/introduction-itp-program-logics/abstract-ind-ror.png create mode 100644 doc/tutorials/introduction-itp-program-logics/ambient-logic.ec create mode 100644 doc/tutorials/introduction-itp-program-logics/ambient-logic.png create mode 100644 doc/tutorials/introduction-itp-program-logics/ambient-logic.rst create mode 100644 doc/tutorials/introduction-itp-program-logics/conclusion.rst create mode 100644 doc/tutorials/introduction-itp-program-logics/easycrypt.rst create mode 100644 doc/tutorials/introduction-itp-program-logics/hoare-logic.ec create mode 100644 doc/tutorials/introduction-itp-program-logics/hoare-logic.rst create mode 100644 doc/tutorials/introduction-itp-program-logics/preface.rst create mode 100644 doc/tutorials/introduction-itp-program-logics/relational-hoare-logic.ec create mode 100644 doc/tutorials/introduction-itp-program-logics/relational-hoare-logic.rst create mode 100644 doc/tutorials/tutorials.rst diff --git a/config/tests.config b/config/tests.config index a5762df7d9..9a4678f6a0 100644 --- a/config/tests.config +++ b/config/tests.config @@ -13,5 +13,8 @@ exclude = examples/MEE-CBC examples/old examples/old/list-ddh !examples/incomple [test-mee-cbc] okdirs = examples/MEE-CBC +[test-tutorials] +okdirs = !doc/tutorials + [test-unit] okdirs = tests tests/exception diff --git a/doc/conf.py b/doc/conf.py index 568857a10e..00c1b4cbd7 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -15,7 +15,7 @@ # -- Project information ----------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information -project = 'EasyCrypt refman' +project = 'EasyCrypt Documentation' copyright = '2026, EasyCrypt development team' author = 'EasyCrypt development team' diff --git a/doc/index.rst b/doc/index.rst index 8b6c7d9b2f..21136c71a5 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -1,7 +1,8 @@ -EasyCrypt reference manual +EasyCrypt Documentation ======================================================================== .. toctree:: :maxdepth: 2 - tactics + tutorials + reference diff --git a/doc/reference.rst b/doc/reference.rst new file mode 100644 index 0000000000..0e5cce7c7a --- /dev/null +++ b/doc/reference.rst @@ -0,0 +1,8 @@ +Reference Material +======================================================================== + +.. toctree:: + :maxdepth: 1 + :glob: + + reference/* diff --git a/doc/tactics.rst b/doc/reference/tactics.rst similarity index 100% rename from doc/tactics.rst rename to doc/reference/tactics.rst diff --git a/doc/tactics/async-while.rst b/doc/reference/tactics/async-while.rst similarity index 100% rename from doc/tactics/async-while.rst rename to doc/reference/tactics/async-while.rst diff --git a/doc/tactics/cfold.rst b/doc/reference/tactics/cfold.rst similarity index 100% rename from doc/tactics/cfold.rst rename to doc/reference/tactics/cfold.rst diff --git a/doc/tactics/clear.rst b/doc/reference/tactics/clear.rst similarity index 100% rename from doc/tactics/clear.rst rename to doc/reference/tactics/clear.rst diff --git a/doc/tactics/hoare-split.rst b/doc/reference/tactics/hoare-split.rst similarity index 100% rename from doc/tactics/hoare-split.rst rename to doc/reference/tactics/hoare-split.rst diff --git a/doc/tactics/if.rst b/doc/reference/tactics/if.rst similarity index 100% rename from doc/tactics/if.rst rename to doc/reference/tactics/if.rst diff --git a/doc/tactics/proc.rst b/doc/reference/tactics/proc.rst similarity index 100% rename from doc/tactics/proc.rst rename to doc/reference/tactics/proc.rst diff --git a/doc/tactics/procstar.rst b/doc/reference/tactics/procstar.rst similarity index 100% rename from doc/tactics/procstar.rst rename to doc/reference/tactics/procstar.rst diff --git a/doc/tactics/rnd.rst b/doc/reference/tactics/rnd.rst similarity index 100% rename from doc/tactics/rnd.rst rename to doc/reference/tactics/rnd.rst diff --git a/doc/tactics/simplify-if.rst b/doc/reference/tactics/simplify-if.rst similarity index 100% rename from doc/tactics/simplify-if.rst rename to doc/reference/tactics/simplify-if.rst diff --git a/doc/tactics/skip.rst b/doc/reference/tactics/skip.rst similarity index 100% rename from doc/tactics/skip.rst rename to doc/reference/tactics/skip.rst diff --git a/doc/tactics/splitwhile.rst b/doc/reference/tactics/splitwhile.rst similarity index 100% rename from doc/tactics/splitwhile.rst rename to doc/reference/tactics/splitwhile.rst diff --git a/doc/tactics/swap.rst b/doc/reference/tactics/swap.rst similarity index 100% rename from doc/tactics/swap.rst rename to doc/reference/tactics/swap.rst diff --git a/doc/tutorials.rst b/doc/tutorials.rst new file mode 100644 index 0000000000..3343f06fdc --- /dev/null +++ b/doc/tutorials.rst @@ -0,0 +1,10 @@ +Tutorials +======================================================================== + +.. toctree:: + :maxdepth: 0 + :glob: + + tutorials/tutorials.rst + tutorials/introduction-itp-program-logics.rst + tutorials/encryption-from-prf.rst diff --git a/doc/tutorials/encryption-from-prf.rst b/doc/tutorials/encryption-from-prf.rst new file mode 100644 index 0000000000..3ca3170712 --- /dev/null +++ b/doc/tutorials/encryption-from-prf.rst @@ -0,0 +1,16 @@ +Encryption from a PRF +===================== + +As a warm-up, we’ll consider a simple nonce-based symmetric encryption +scheme for fixed-length messages. [1]_ Here, we assume some familiarity +with cryptographic definitions and proofs, but not with the specific +definitions and proofs used in this tutorial. + +You may find it beneficial to step through the `proof +file `__ as you +read through the basic tutorial. The “Going Further” tutorials each come +with their own proof files, referred to where relevant. + +.. [1] + Note the similarities to The Joy of Cryptography’s `Construction + 7.4 `__. diff --git a/doc/tutorials/encryption-from-prf/Construction.eca b/doc/tutorials/encryption-from-prf/Construction.eca new file mode 100644 index 0000000000..35d3fb1d06 --- /dev/null +++ b/doc/tutorials/encryption-from-prf/Construction.eca @@ -0,0 +1,783 @@ +(* ****************** Requires/Imports ******************* *) +(* Built-in (i.e., standard library *) +require import AllCore Distr List. + + +(* ****************** Types (i.e., non-empty sets) ******************* *) +(* Keys, plaintexts and nonces *) +type key, ptxt, nonce. + +(* Ciphertexts (same set as for plaintexts) *) +type ctxt = ptxt. + + + +(* ****************** Operators ******************* *) +(* + A family of functions from nonces to plaintexts, indexed by + the set of keys. +*) +op f : key -> nonce -> ptxt. + +(* Binary operator over plaintexts *) +op (+) : ptxt -> ptxt -> ptxt. + +(* + Assumed associativity, commutativity, and "left self-cancellation" + properties of + operator, respectively. +*) +axiom addpA (x y z : ptxt) : x + y + z = x + (y + z). +axiom addpC (x y : ptxt) : x + y = y + x. +axiom addKp (x y : ptxt) : x + x + y = y. + +(* "Right self-cancellation" propery of + *) +lemma addpK (x y : ptxt) : x + y + y = x. +proof. +(* + Rewrite y + x + x as y + (x + x) + using above associativity axiom addpA +*) +rewrite addpA. +(* + Rewrite y + (x + x) as (x + x) + y (which is simply rendered as x + x + y) + using above commutativity axiom addpC +*) +rewrite addpC. +(* + Rewrite x + x + y as y + using above "left self-cancellation" axiom addKp +*) +rewrite addKp. +(* Trivially true: y = y *) +trivial. +qed. + + + +(* ****************** Distributions ******************* *) +(* (Sub)Distribution over keys **) +op dkey : key distr. + +(* + Proper, uniform distribution over the entire set of + plaintexts (and, hence, ciphertexts). +*) +op [lossless full uniform] dptxt : ptxt distr. + +(* + Alias to make it clear when we are conceptually considering + plaintexts and ciphertexts (even though they are really the same thing) +*) +op dctxt : ctxt distr = dptxt. + + + +(* ****************** Scheme ******************* *) +(* Module type (i.e., interface) for (symmetric) nonce-based encryption schemes *) +module type NBEncScheme = { + proc kgen() : key + proc enc(k : key, n : nonce, m : ptxt) : ctxt + proc dec(k : key, n : nonce, c : ctxt) : ptxt +}. + +(* Specification of the considered (symmetric) nonce-based encryption scheme *) +module E : NBEncScheme = { + proc kgen(): key = { + var k : key; + + (* Sample key k from (sub)distribution dkey *) + k <$ dkey; + + return k; + } + + proc enc(k : key, n : nonce, m : ptxt) : ctxt = { + (* + Compute f k n, combine it with the message using +, + and return the result + *) + return (f k n) + m; + } + + proc dec(k : key, n : nonce, c : ctxt) : ptxt = { + (* + Compute f k n, combine it with the ciphertext using +, + and return the result + *) + return (f k n) + c; + } +}. + + + +(* ****************** Security ******************* *) +(* + -- + INDistinguishability from RANDOM ciphertexts under Nonce-Respecting + Chosen-Plaintext Attacks (IND$-NRCPA) + + By observing ciphertext (supposedly) of chosen messages, it is hard + to determine whether the ciphertexts were honestly created by a + (symmetric nonce-based) encryption scheme or sampled uniformly at random. + -- +*) + +(* + Module type (i.e., interface) for oracles used in IND$-NRCPA game. + Note the "option" in "ctxt option" (the return type of enc); intuitively, + this means that enc can either return a valid ciphertext c (as Some c) or an + indication of failure (as None). This is needed as the oracles will indicate + a failure when being queried on a nonce that was already used in a previous + query. +*) +module type NRCPA_Oraclei = { + proc init() : unit + proc enc(n : nonce, m : ptxt) : ctxt option +}. + +(* + Module type (i.e., interface) for oracles provided to the adversaries + against the IND$-NRCPA game. Used to ensure we only expose the enc procedure + of the oracles to the adversaries, and not the init procedure. +*) +module type NRCPA_Oracle = { + (* Include only the enc procedure signature of the NRCPA_Oraclei module type *) + include NRCPA_Oraclei [enc] +}. + +(* + Real oracle used in IND$-NRCPA game (and, thus, of type NRCPA_Oraclei). + Defined with respect to an (abstract) nonce-based encryption scheme E that it + uses to encrypt messages. +*) +module O_NRCPA_real (S : NBEncScheme) : NRCPA_Oraclei = { + var k : key (* Secret key *) + var log : nonce list (* Log of queried nonces *) + + (* Perform necessary initialization *) + proc init() : unit = { + (* Generate secret key with key generation of provided scheme *) + k <@ S.kgen(); + + (* Initialize log to the empty list *) + log <- []; + } + + (* Encryption procedure exposed to the adversary *) + proc enc(n : nonce, m : ptxt) : ctxt option = { + var c : ctxt; + var r : ctxt option; (* return variable *) + + (* If the given nonce is not in the log of already queried nonces, ... *) + if (! (n \in log)) { + (* then prepend the current nonce to the log, ... *) + log <- n :: log; + + (* encrypt the message using the provided scheme, and ... *) + c <@ S.enc(k, n, m); + + (* store the resulting ciphertext in the return variable; ... *) + r <- Some c; + } else { + (* else, store an indication of failure in the return variable. *) + r <- None; + } + + return r; + } +}. + +(* + Ideal oracle used in IND$-NRCPA game (and, thus, of type NRCPA_Oraclei). + Instead of encrypting messages with an encryption scheme, it produces + ciphertexts by sampling them uniformly at random. +*) +module O_NRCPA_ideal : NRCPA_Oraclei = { + var log : nonce list (* Log of queried nonces *) + + (* Perform necessary initialization *) + proc init() : unit = { + (* Initialize log to the empty list *) + log <- []; + } + + (* Encryption procedure exposed to the adversary *) + proc enc(n : nonce, m : ptxt) : ctxt option = { + var c : ctxt; + var r : ctxt option; (* return variable *) + + (* If the given nonce is not in the log of already queried nonces, ... *) + if (! (n \in log)) { + (* then prepend the current nonce to the log, ... *) + log <- n :: log; + + (* sample a ciphertext from dctxt, and ... *) + c <$ dctxt; + + (* store the resulting ciphertext in the return variable; ... *) + r <- Some c; + } else { + (* else, store an indication of failure in the return variable. *) + r <- None; + } + + return r; + } +}. + +(* + Module type (i.e., interface) for adversaries (or distinguishers) against IND$-NRCPA. + In essence, this defines the relevant class of adversaries, containing + any algorithm that expects a NR-CPA oracle and defines a + procedure returning a boolean. +*) +module type Adv_IND_NRCPA (O : NRCPA_Oracle) = { + proc distinguish() : bool +}. + +(* IND$-NRCPA game/experiment *) +module Exp_IND_NRCPA (O : NRCPA_Oraclei) (D : Adv_IND_NRCPA) = { + proc run() : bool = { + var b : bool; + + (* Initialize oracle O *) + O.init(); + + (* + Call distinguish procedure of adversary D, providing oracle O. + Note that, even though O is of type NRCPA_Oraclei, providing it + to D does not expose the init procedure to D. This because D itself + only expects the provided oracle to have the enc procedure, due to + the type of D being defined with respect to a module of type NRCPA_Oracle. + *) + b <@ D(O).distinguish(); + + return b; + } +}. + + +(* + -- + "Nonce-Respecting" Pseudo-Random Function family (NR-PRF) + + By observing outputs (supposedly) of unique chosen inputs (nonces), it is hard to + distinguish whether the function is a randomly sampled function from the domain + of functions with the considered domain (nonce) and co-domain (ptxt), or + a randomly selected function from the hash function family f (i.e., a f k + where k is randomly sampled from the domain of (indexing) keys). + -- +*) +(* + Module type (i.e., interface) for oracles used in NR-PRF game. + Again, note the "option" in "ptxt option" (the return type of get) to + model that the oracle can return either valid plaintexts (as Some p) or + an indication of failure (as None). +*) +module type NRPRF_Oraclei = { + proc init() : unit + proc get(n : nonce) : ptxt option +}. + +(* + Module type (i.e., interface) for oracles used in NR-PRF game. + Used to ensure we only expose the get procedure of the oracles + to the advesaries, and not the init procedure. +*) +module type NRPRF_Oracle = { + (* Include only the get procedure signature of the NRCPA_Oraclei module type *) + include NRPRF_Oraclei [get] +}. + +(* + Real oracle used in NR-PRF game (and, thus, of type NRPRF_Oraclei). + Creates plaintexts by mapping a given nonce under f k, where k is a + secret key randomly sampled during initialization. +*) +module O_NRPRF_real : NRPRF_Oraclei = { + var k : key (* Secret key *) + var log : nonce list (* Log of queried nonces *) + + (* Perform necessary initialization *) + proc init() : unit = { + (* Sample secret key at random *) + k <$ dkey; + (* Initialize log to the empty list *) + log <- []; + } + + (* Get procedure exposed to the adversary *) + proc get(n : nonce) : ptxt option = { + var r : ptxt option; (* return variable *) + + (* If the given nonce is not in the log of already queried nonces, ... *) + if (! (n \in log)) { + (* then prepend the current nonce to the log and ... *) + log <- n :: log; + + (* compute f k n and store the result in the return variable; ... *) + r <- Some (f k n); + } else { + (* else, store an indication of failure in the return variable. *) + r <- None; + } + + return r; + } +}. + +(* + Ideal oracle used in NR-PRF game (and, thus, of type NRPRF_Oraclei). + Instead of mapping given nonces under f k, it produces + plaintexts by sampling them uniformly at random. +*) +module O_NRPRF_ideal : NRPRF_Oraclei = { + var log : nonce list (* Log of queried nonces *) + + (* Perform necessary initalization *) + proc init() = { + (* Initialize log to the empty list *) + log <- []; + } + + (* Get procedure exposed to the adversary *) + proc get(n : nonce) = { + var y : ptxt; + var r : ptxt option; (* return variable *) + + (* If the given nonce is not in the log of already queried nonces, ... *) + if (! (n \in log)) { + (* then prepend the current nonce to the log and ... *) + log <- n :: log; + + (* sample a plaintext from dptxt, and ... *) + y <$ dptxt; + + (* store the resulting plaintext in the return variable; ... *) + r <- Some y; + } else { + (* else, store an indication of failure in the return variable. *) + r <- None; + } + + return r; + } +}. + +(* Module type (i.e., interface) for adversaries (or distinguishers) against NR-PRF. *) +module type Adv_NRPRF (O : NRPRF_Oracle) = { + proc distinguish() : bool +}. + +(* NR-PRF game/experiment *) +module Exp_NRPRF (O : NRPRF_Oraclei) (D : Adv_NRPRF) = { + proc run() : bool = { + var b : bool; + + (* Initialize oracle O *) + O.init(); + + (* + Call distinguish procedure of adversary D, providing oracle O. + Again, even though O is of type NRPRF_Oraclei, providing it + to D does not expose the init procedure to D as it expects an oracle + of type NRPRF_Oracle (i.e., an oracle that is only guaranteed to + implement get). + *) + b <@ D(O).distinguish(); + + return b; + } +}. + + +(* + Reduction adversary that, given an adversary against IND$-NRCPA, plays in the + NR-PRF game. As such, it takes a (adversary) module of type Adv_IND_NRCPA and + a (oracle) module of type NRPRF_Oracle and implements a distinguish procedure. + Here, the order of the module arguments is crucial for obtaining a module + of the correct type. Namely, a module of type Adv_NRPRF should only be defined w.r.t. + a module of type NRPRF_Oracle, and not w.r.t. both a module of type Adv_IND_NRCPA *and* + a module of type NRPRF_Oracle. Since we can instantiate the module parameters partially + (yet only from left to right), the module parameter of type Adv_IND_NRCPA should come before + the module parameter of type NRPRF_Oracle. Then, only instantiating the first module parameter + (e.g., R_NRPRF_IND_NRCPA(D), where D is a concrete module of type Adv_IND_NRCPA) results + in a module that is only still defined w.r.t. a module of type NRPRF_Oracle, as desired. + Lastly, note that the explicit typing of R_NRPRF_IND_NRCPA (D : Adv_IND_NRCPA) is not necessary + and, hence, the module signature of the reduction adversary could equivalently be written as + "module R_NRPRF_IND_NRCPA (D : Adv_IND_NRCPA) (O_NRPRF : NRPRF_Oracle)". However, even though + types can often be inferred, it is good practice to state the types explicitly for documentation + purposes. +*) +module (R_NRPRF_IND_NRCPA (D : Adv_IND_NRCPA) : Adv_NRPRF) (O_NRPRF : NRPRF_Oracle) = { + (* + Using the provided NRPRF oracle, construct a NRCPA oracle to provide + to the given adversary. + *) + module O_NRCPA : NRCPA_Oracle = { + (* Encryption procedure exposed to the given adversary *) + proc enc(n : nonce, m : ptxt) : ctxt option = { + var p : ptxt option; + var r : ctxt option; (* return variable *) + + (* + Get plaintext (or failure indication) corresponding to n + by querying given NRPRF oracle + *) + p <@ O_NRPRF.get(n); + + (* + Compute a ciphertext or failure indication as follows: + If p is a failure indication (i.e., p = None), + r is also a failure indication (i.e., r = None); + else (i.e., p = Some x for some x of type ptxt), + r is Some (x + m). + *) + r <- if p = None then None else Some (oget p + m); + + return r; + } + } + + (* Distinguish procedure called by the NR-PRF game/experiment *) + proc distinguish() : bool = { + var b : bool; (* return variable *) + + (* + Call the distinguish procedure of the given adversary, providing + the above-defined NRCPA oracle O_NRCPA + *) + b <@ D(O_NRCPA).distinguish(); + + return b; + } +}. + + +(* + Start a section for the security proof. + Although we could perform the entire proof without a section, this would + require us to define the considered adversary module (and all the corresponding + restrictions) anew for each (intermediate) lemma we prove. Furthermore, + every intermediate lemma we prove would become a permanent part of the theory + (defined by the file), even if it is completely useless outside the proof. + A section allows us, among others, to "declare" the relevant modules (with restrictions) + once and have them available throughout the entire section (but not outside the section). + Additionally, we can define local types, operators, module types, modules, and lemmas; + these are only available/visible within the section and, as such, can be used to perform + any auxiliary intermediate proof steps without any of it being exposed to the outside. + Any non-local lemmas inside the section (i.e., lemmas that are exposed to the outside + after closing the section) are extended with a universal quantification over module types + of the modules declared earlier in the section. +*) +section E_IND_NRCPA. + +(* + Declare the relevant adversary module. + Note that, by default, a module can access any other module's variables. + So, to prevent the adversary from illegally sabotaging the games that it is used in, + we need to restrict the adversary from accessing the variables of the modules used in + these games. +*) +declare module D <: Adv_IND_NRCPA { -O_NRCPA_real, -O_NRCPA_ideal, -O_NRPRF_real, -O_NRPRF_ideal }. + +(* + Lemma. + The probability of D returning true in the IND$-NRCPA game when given the + real NR-CPA oracle is equal to the probability of R_NRPRF_IND_NRCPA returning true + when given D and the real NR-PRF oracle. + + This lemma is local (indicated by the "local" keyword), meaning that it is only + useable inside the section and, as such, can depend on local entities. +*) +local lemma EqPr_IND_NRCPA_NRPRF_real &m: + Pr[Exp_IND_NRCPA(O_NRCPA_real(E), D).run() @ &m : res] + = + Pr[Exp_NRPRF(O_NRPRF_real, R_NRPRF_IND_NRCPA(D)).run() @ &m : res]. +proof. +(* + Prove the equality of probabilities by showing the pRHL equivalence of the programs + where the programs start out with adversary D having the same + environment (precondition) and end up with the same result (postcondition). + + We can combine tactics using a semicolon. + Specifically, "t1; t2." first applies tactic t1 on the goal and, afterward, + applies tactic t2 on all of the subgoals generated by applying t1. + So, here, "; trivial" applies trivial to all subgoals generated by applying byequiv, + solving/closing all generated trivial subgoals. +*) +byequiv (_ : ={glob D} ==> ={res}); trivial. +(* + Since both procedures in the pRHL equivalence are concrete, + prove the equivalence by reasoning about the actual code of the procedures. +*) +proc. +(* + In both programs, replace all calls to concrete procedures by the corresponding code + to be able to reason about the concrete code. +*) +inline *. +(* + Since both programs are sufficiently similar and call to the same abstract procedure + that only differ in the implementation of the provided oracles, we can use the sim tactic. + To infer the correct equality of program variables from the postcondition, we provide an + explicit equality in form of an invariant that should be maintained throughout oracles + calls. (in this case: the keys and logs of the oracles are equal) +*) +sim (_ : ={k}(O_NRCPA_real, O_NRPRF_real) /\ ={log}(O_NRCPA_real, O_NRPRF_real)). +(* + Goal generated by sim tactic. + pRHL equivalence between the enc procedures of the provided oracles + where, as a precondition, we have equality of the inputs and the truth of + the invariant, and, as a postcondition, we need to prove the equality + of the (distribution of the) outputs as well as the truth of the + invariant. +*) +(* proc, and inline * tactics used similarly to above. *) +proc. +inline *. +(* + Although it looks convoluted, the programs in the current goal can be trivially + seen to be equivalent and, hence, solved by straightforward manipulations (e.g., + unfolding definitions). The auto tactic uses various program logic tactics in attempt + to reduce the goal and in is suffient to solve it in this case. + We could also use wp. skip. trivial. to solve the goal. These tactics are used + and explained in the next proof. +*) +auto. +qed. + +(* + Lemma. + The probablity of D returning true in the IND$-NRCPA game when given the + ideal NR-CPA oracle is equal to the probability of R_NRPRF_IND_NRCPA returning true + when given D and the ideal NR-PRF oracle. + + This lemma is local (indicated by the "local" keyword), meaning that it is only + useable inside the section and, as such, can depend on local entities. +*) +local lemma EqPr_IND_NRCPA_NRPRF_ideal &m: + Pr[Exp_IND_NRCPA(O_NRCPA_ideal, D).run() @ &m: res] + = + Pr[Exp_NRPRF(O_NRPRF_ideal, R_NRPRF_IND_NRCPA(D)).run() @ &m: res]. +proof. +(* + Most of the tactics and their application in this proof + are similar to those in the previous proof. As such, we do not provide + comments for each and every tactic, but rather only wherever novel + concepts arise. +*) +(* + The trailing "=> //" is semantically equivalent to "; trivial", but syntactically + more convenient/clean (especially when specifying more introduction patterns; + see below for more information on these patterns). +*) +byequiv (_ : ={glob D} ==> ={res}) => //. +proc; inline *. +(* + From the end of the programs, consume all statements for which we know how to + adapt the postcondition as to reflect the execution of the statements without + actually executing them. In other words, transform the current pRHL equivalence + to a new one that implies the current one by removing as many statements + from the end of the programs as possible while accordingly adapting the postcondition. +*) +wp. +(* + Since both programs end with calls to the same abstract procedure that only differ + in the implementation of the provided oracles, argue that the procedure + must behave the same (and, hence, with the same probability produce the same + output) as long as the module's view remains equal on both sides during the call. + This requires the following: + - The module's environment (in this case: glob D) is the same in both programs + at the start of the call. + - The procedure's arguments (in this case: none) are the same on both sides. + - The (distribution of the) oracle outputs is the same on both sides; this may + require some invariant (in this case: the logs of the oracles are equal) + to be maintained throughout oracles calls. + The first two requirements are proved based on the code preceding the calls; the final + requirement is proved with a separate pRHL equivalence on the oracle procedures (using + the invariant that is supplied to the call tactic, following the colon). +*) +call (_ : ={log}(O_NRCPA_ideal, O_NRPRF_ideal)). + (* + First subgoal generated by call tactic. + pRHL equivalence between the enc procedures of the provided oracles + where, as a precondition, we have equality of the inputs and the truth of + the invariant, and, as a postcondition, we need to prove the equality + of the (distribution of the) outputs as well as the truth of hte + invariant. + *) +- proc; inline *. + (* + Analogous to wp, but removes statements from the beginning of the programs + (instead of the end) and accordingly adjusts the precondition (instead of the + postcondition). + *) + sp. + (* + Since both programs *start* with an if-statement, we can prove this + pRHL equivalence by showing the following: + - The guards of the if-statements are equivalence (i.e., the if-guard of the left program + evaluates to true iff the if-guard of the right program evaluates to true); this means + the left and right program go into the same branch. + - An appropriate pRHL equivalence where both programs take the then branch. + - An appropriate pRHL equivalence where both programs take the else branch. + + As the equivalence of the guards is trivial, we clear the corresponding subgoal + using "=> //". + *) + if => //. + (* First subgoal generated by if tactic. *) + - wp. + (* + Whenever both programs end with a sampling from the same distribution (remember, dctxt is + simply an alias for dptxt), we oftentimes want to assume that the same value is sampled + on both sides using the rnd tactic. This tactic removes the samplings and adjusts the + postcondition to capture that the sampled values are the same. (This produces some + additional proof obligations in the postcondition that make sure this is actually + sound.) + However, since in the postcondition we do not require the equality of the sampled values, + but rather of a random value and the addition of a random value with a fixed value, + we want to "uniquely link" two sampled values that satisfy this equivalence. + In other words, if + we can specify a bijection (defined by, say, f and g = f^-1) between elements from + the distribution of the left program and elements from the distribution of + the right program (in this case: "a bijection on the set of plaintexts/ciphertexts"), + we can assume that if we sample an element p in the left program, we sample f p in the + right program. + + To perform sampling that uses a certain bijection, we can provide f and g to the rnd + tactic (syntax: rnd f g). If f = g, then we can leave out the g (syntax: rnd f). + This latter case is applicable here. + *) + rnd (fun (p : ptxt) => p + m{2}). + wp. + (* + The skip tactic proves the pRHL equivalence where both programs are empty by showing that, + for all possible program memories, the precondition implies the postcondition. + Here, "=> /> &2 _" does several things. Foremost, "=>" after a tactic allows us + to specify several so-called "introduction patterns" (such as the "//" seen earlier) + that will be applied to all subgoals generated by the preceding tactics (in this + case: skip, only generating a single subgoal). Then, the first introduction pattern, + />, simplfies the resulting subgoal as much as possible; the second introduction + pattern, &2, specifies the name for the arbitrary memory introduced into the + context, removing the "forall memory" quantification in the subgoal's conclusion; + lastly, _ deletes the foremost antecedent of the subgoal's conclusion (we don't + need it to prove the remainder). + *) + skip => />. + move => &2 _. + (* + We prove a conjunction of predicates by splitting up the goal and + proving each of the predicates individually. + *) + split. + (* First subgoal generated by split tactic. *) + (* + The move tactic does nothing, but still allows us to use + introduction patterns (with "=>") + *) + - move => y _. + (* + The rewrite tactic allows for some nice syntactic sugar. + Instead of "rewrite lemma1; rewrite lemma2.", we can use "rewrite lemma1 lemma2.". + Similarly, instead of "rewrite lemma1 => //", we can use "rewrite lemma1 //.". + *) + rewrite addpK //. + (* Second subgoal generated by split tactic. *) + move => _ c _. + rewrite addpK //. + (* Second subgoal generated by if tactic. *) + auto. +(* Second subgoal generated by call tactic. *) +auto. +qed. + + +(* + Lemma. + The advantage of D against IND$-NRCPA of E is equal to the advantage of + R_NRPRF_IND_NRCPA against NRPRF of f (when given D). + + This lemma is non-local, meaning it will be exposed outside the section and + will be preceded by a universal quantification for each module declared in + the section. Moreover, it cannot depend on local entities (as these are + non-existant outside the section). +*) +lemma EqAdvantage_IND_NRCPA_NRPRF &m: + `| Pr[Exp_IND_NRCPA(O_NRCPA_real(E), D).run() @ &m: res] + - Pr[Exp_IND_NRCPA(O_NRCPA_ideal, D).run() @ &m: res] | + = + `| Pr[Exp_NRPRF(O_NRPRF_real, R_NRPRF_IND_NRCPA(D)).run() @ &m: res] + - Pr[Exp_NRPRF(O_NRPRF_ideal, R_NRPRF_IND_NRCPA(D)).run() @ &m: res] |. +proof. +(* + The by keyword can be put in front of (a sequence of) tactics to try and + close all subgoals generated by the (sequence of) tactics. This will + only be successful if the generated subgoals are trivially solvable. + + The minuses in front of lemma names in a rewrite tactic + indicate that the rewriting should occur in the opposite direction + of the equality/equivalence denoted by the lemma. For example, + suppose we have a lemma eqXY that shows X = Y. Then, rewrite eqXY + rewrites all X in the goal's conclusion to Y, and rewrite -eqXY rewrites + all Y in the goal's conclusion to X. +*) +by rewrite EqPr_IND_NRCPA_NRPRF_real EqPr_IND_NRCPA_NRPRF_ideal. +qed. + +end section E_IND_NRCPA. + +(** +(** BONUS: A cost logic **) +require import Xint CHoareTactic. + +clone import AllCore.Cost. + +op t_oplus: { int | 0 < t_oplus } as gt0_t_oplus. + +op t_prf: { int | 0 < t_prf } as gt0_t_prf. + +(** Assumptions on cost **) +schema cost_omap `{P} {f : 'a -> 'b } { o : 'a option }: + cost [P : omap f o] = cost [P : f (oget o)]. + +schema cost_transpose `{P} {f : 'a -> 'b -> 'c } { x : 'a } { y : 'b }: + cost [P : transpose f y x] = cost [P : f x y]. + +schema cost_oplus `{P} { x y : ptxt }: + cost[P : x + y] = cost[P : x] + cost[P : y] + N t_oplus. + +schema cost_prf `{P} { k : key } { n : nonce }: + cost[P : f k n] = cost[P : k] + cost [P : n] + N t_prf. + +section. +declare op q_enc : { int | 0 < q_enc } as gt0_q_enc. +declare op t_distinguish : { int | 0 < t_distinguish } as gt0_t_distinguish. + +declare module D <: CPA_Distinguisher { -NR_CPA_Experiment, -PRF_Experiment, -CPA_Real, -PRF_Real } [distinguish : `{N t_distinguish, #O.enc : q_enc }]. + +lemma cost_return: + cost(_: {m : ptxt, n : nonce, r : ptxt option}) [true : omap (transpose Top.(+) m) r] + = N (t_oplus + 1). +proof. +instantiate -> := (cost_omap {m : ptxt, n : nonce, r : ptxt option } `(true) (fun x=> x + m) r). +instantiate -> := (cost_transpose {m : ptxt, n : nonce, r : ptxt option } `(true) (+) (oget r) m). +instantiate -> := (cost_oplus {m : ptxt, n : nonce, r : ptxt option } `(true) (oget r) m). +instantiate -> := (cost_oget {m : ptxt, n : nonce, r : ptxt option } `(true) r). +have ->: cost (_ : {m : ptxt, n : nonce, r : ptxt option})[true : r] = N 0 by auto. +have ->: cost (_ : {m : ptxt, n : nonce, r : ptxt option})[true : m] = N 0 by auto. +by rewrite -!N_D /#. +qed. + +lemma reduction_cost (P <: PRF_Oracle { -D, -R } [f : `{N t_prf}]): + choare[R(D, P).distinguish] time [N (t_distinguish + q_enc * (t_oplus + 1)); P.f : q_enc]. +proof. +proc true: time [R(D, P).E.enc : [N (t_oplus + 1); P.f: 1]]=> //. ++ by auto=> />; rewrite Bigxint.bigi_constz 2:StdBigop.Bigint.bigi_constz 1,2:ltzW 1,2:gt0_q_enc /#. +move=> k Hk; proc=> //. ++ by right; rewrite cost_return. +by call (: true; time []); auto=> />; rewrite cost_return. +qed. +end section. +**) diff --git a/doc/tutorials/encryption-from-prf/IVbased.ec b/doc/tutorials/encryption-from-prf/IVbased.ec new file mode 100644 index 0000000000..6011457925 --- /dev/null +++ b/doc/tutorials/encryption-from-prf/IVbased.ec @@ -0,0 +1,569 @@ +require import AllCore List Distr FSet. +require (* *) Construction Birthday. + +(** Non-empty sets for keys, plaintexts and nonces **) +type key, ptxt, rndness. +type ctxt = ptxt. + +(** Some (arbitrary, here) distribution over keys **) +op [lossless] dkey: key distr. + +(** Some (arbitrary, here) distribution over randomness **) +op [lossless full uniform] drndness: rndness distr. + +(** Some (arbitrary, here) distribution over plaintexts/ciphertexts **) +op [lossless full uniform] dptxt : ptxt distr. +op dctxt = dptxt. + +(** And a family of functions from nonces to plaintexts, indexed by + the set of keys **) +op f: key -> rndness -> ptxt. + +(** Some associative, commutative, self-cancelling operator over + plaintexts **) +op (+): ptxt -> ptxt -> ptxt. +axiom addpA x y z: x + y + z = x + (y + z). +axiom addpC x y: x + y = y + x. +axiom addKp x y: x + x + y = y. + +lemma addpK x y: y + x + x = y. +proof. by rewrite addpA addpC addKp. qed. + +(** The scheme!! **) +module type Enc_Scheme = { + proc kgen(): key + proc enc(k : key, r : rndness, m : ptxt): ctxt + proc dec(k : key, r : rndness, c : ctxt): ptxt +}. + +module E : Enc_Scheme = { + proc kgen(): key = { + var k; + + k <$ dkey; + return k; + } + + proc enc(k : key, r : rndness, m : ptxt) : ctxt = { + var x; + + x <- f k r; + return x + m; + } + + proc dec(k : key, r : rndness, c : ctxt) : ptxt = { + var x; + + x <- f k r; + return x + c; + } +}. + +clone import Construction as C with + type key <- key, + type ptxt <- ptxt, + type nonce <- rndness, + op f <- f, + op (+) <- (+), + op dkey <- dkey, + op dptxt <- dptxt + (* Why can't I do E <- E, they are literally the same. I do not want duplicates. *) +proof *. +realize addpA by exact/addpA. +realize addpC by exact/addpC. +realize addKp by exact/addKp. +realize dptxt_ll by exact/dptxt_ll. +realize dptxt_uni by exact/dptxt_uni. +realize dptxt_fu by exact/dptxt_fu. + +(** CPA security **) +module type CPA_Oracle_IV_i = { + proc init(): unit + proc enc(m : ptxt) : rndness * ctxt +}. + +module O_IV_ideal : CPA_Oracle_IV_i = { + proc init() : unit = { + } + + proc enc(m : ptxt) : rndness * ctxt = { + var r, c; + + r <$ drndness; + c <$ dctxt; + return (r, c); + } +}. + +module O_IV_real (E : Enc_Scheme) : CPA_Oracle_IV_i = { + var k : key + + proc init() : unit = { + k <@ E.kgen(); + } + + proc enc(m : ptxt) : rndness * ctxt = { + var r, c; + + r <$ drndness; + c <@ E.enc(k, r, m); + return (r, c); + } +}. + +(** The type of encryption oracles **) +module type CPA_Oracle_IV = { + include CPA_Oracle_IV_i [enc] +}. + +module type CPA_Distinguisher_IV (O : CPA_Oracle_IV) = { + proc distinguish() : bool +}. + +module Exp_IV_CPA (D : CPA_Distinguisher_IV) (O : CPA_Oracle_IV_i) = { + proc run() = { + var b; + + O.init(); + b <@ D(O).distinguish(); + return b; + } +}. + +module Counting_O (O : CPA_Oracle_IV_i) : CPA_Oracle_IV_i = { + var counter : int + var log : rndness list + + proc init() : unit = { + O.init(); + Counting_O.log <- []; + } + + proc enc(m : ptxt) : rndness * ctxt = { + var rc; + + counter <- counter + 1; + + rc <@ O.enc(m); + log <- rc.`1 :: log; + + return rc; + } +}. + +(* +module (Counting_D (D : CPA_Distinguisher_IV) : CPA_Distinguisher_IV) (O : CPA_Oracle_IV) = { + var counter : int + + module O_Counting : CPA_Oracle_IV = { + proc enc(m : ptxt) : rndness * ctxt = { + var rc; + + counter <- counter + 1; + + rc <@ O.enc(m); + + return rc; + } + } + + proc distinguish() = { + var b : bool; + + b <@ D(O_Counting).distinguish(); + + return b; + } +}.*) + +module (Reduction (D : CPA_Distinguisher_IV) : Adv_IND_NRCPA) (O: NRCPA_Oracle) = { + module IV_Oracle : CPA_Oracle_IV = { + var log : rndness list + + proc enc(m : ptxt) : rndness * ctxt = { + var r : rndness; + var c : ctxt option; + + r <$ drndness; + log <- r :: log; + + c <@ O.enc(r, m); + + return (r, oget c); + } + } + + proc distinguish() : bool = { + var b : bool; + + IV_Oracle.log <- []; + + b <@ D(IV_Oracle).distinguish(); + + return b /\ uniq IV_Oracle.log; + } +}. + +(** Proof for security of IV-based encryption **) +section. + +declare module D <: CPA_Distinguisher_IV{ -O_NRCPA_real, -O_NRCPA_ideal, -O_IV_real, -O_IV_ideal, -O_NRPRF_ideal, -O_NRPRF_real, -Reduction, -Counting_O }. + +lemma Counting_real &m: + Pr[Exp_IV_CPA(D, O_IV_real(E)).run() @ &m: res] = + Pr[Exp_IV_CPA(D, Counting_O(O_IV_real(E))).run() @ &m: res]. +proof. +byequiv (: ={glob D} ==> ={res})=> //. +proc; inline *. +call (: ={O_IV_real.k}). ++ by proc; inline *; auto. +by auto. +qed. + +lemma Counting_ideal &m: + Pr[Exp_IV_CPA(D, O_IV_ideal).run() @ &m: res] = + Pr[Exp_IV_CPA(D, Counting_O(O_IV_ideal)).run() @ &m: res]. +proof. +byequiv => //; proc; inline *. sp. +call (: true). +proc. inline *. auto. skip => //=. +qed. + +declare axiom D_ll (O <: CPA_Oracle_IV {-D}): islossless O.enc => islossless D(O).distinguish. + +(** maximal number of queries to the encryption oracle **) +declare op q : { int | 0 <= q } as ge0_q. + +local clone import Birthday as BB with + op q <- q, + type T <- rndness, + op uT <- drndness +proof *. +realize ge0_q by exact: ge0_q. +(*realize maxuP. by move=> x; rewrite (drndness_uni x maxu) 1,2:drndness_fu. qed. (* change that in birthday theory! *)*) + +declare axiom D_bounded (O <: CPA_Oracle_IV_i {-D}) : + hoare[D(Counting_O(O)).distinguish : Counting_O.counter = 0 ==> Counting_O.counter <= q]. + +local lemma Counting_bounded_real : + hoare[Exp_IV_CPA(D, Counting_O(O_IV_real(E))).run : Counting_O.counter = 0 ==> Counting_O.counter <= q]. +proof. proc; inline *. seq 3 : #pre. auto. call (D_bounded (O_IV_real(E))) => //=. qed. + +local lemma Counting_bounded_ideal : + hoare[Exp_IV_CPA(D, Counting_O(O_IV_ideal)).run : Counting_O.counter = 0 ==> Counting_O.counter <= q]. +proof. proc; inline *. call (D_bounded (O_IV_ideal)) => //=. auto. qed. + +local module O_IV_S_real (S: Sampler) (E: Enc_Scheme) : CPA_Oracle_IV_i = { + var k : key + + proc init() : unit = { + k <@ E.kgen(); + S.init(); + } + + proc enc(m : ptxt) : rndness * ctxt = { + var r : rndness; + var c : ctxt; + + r <@ S.s(); + c <@ E.enc(O_IV_S_real.k, r, m); + + return (r, c); + } +}. + +local module O_IV_S_ideal (S: Sampler) : CPA_Oracle_IV_i = { + var k : key + + proc init() : unit = { + S.init(); + } + + proc enc(m : ptxt) : rndness * ctxt = { + var r : rndness; + var c : ctxt; + + r <@ S.s(); + c <$ dctxt; + + return (r, c); + } +}. + +local lemma Sample_real &m: + Pr[Exp_IV_CPA(D, O_IV_real(E)).run() @ &m: res] = + Pr[Exp_IV_CPA(D, O_IV_S_real(Sample, E)).run() @ &m: res]. +proof. +byequiv => //. +proc; inline *. +sim (: ={k}(O_IV_real, O_IV_S_real)). +proc; inline *. +by wp; rnd; skip. +qed. + +local lemma Sample_ideal &m: + Pr[Exp_IV_CPA(D, O_IV_ideal).run() @ &m: res] = + Pr[Exp_IV_CPA(D, O_IV_S_ideal(Sample)).run() @ &m: res]. +proof. +byequiv => //. +proc; inline *. +call(: true). ++ proc; inline *. + by wp; rnd; wp; rnd; skip. +by wp. +qed. + +local lemma IV_S_real_uniq &m: + Pr[Exp_IV_CPA(D, O_IV_S_real(Sample, E)).run() @ &m: res /\ uniq Sample.l] + = + Pr[Exp_IND_NRCPA(O_NRCPA_real(E), Reduction(D)).run() @ &m: res]. +proof. +byequiv => //. +proc; inline *. +wp. +call (: ! uniq Reduction.IV_Oracle.log, + ={k}(O_IV_S_real, O_NRCPA_real) + /\ Sample.l{1} = Reduction.IV_Oracle.log{2} + /\ Reduction.IV_Oracle.log{2} = O_NRCPA_real.log{2}, + uniq Sample.l{1} = uniq Reduction.IV_Oracle.log{2}) => //=. ++ apply D_ll. ++ proc; inline *. + seq 2 2 : ( ={m} + /\ r0{1} = r{2} + /\ O_IV_S_real.k{1} = O_NRCPA_real.k{2} + /\ Sample.l{1} = Reduction.IV_Oracle.log{2} + /\ Reduction.IV_Oracle.log{2} = r{2} :: O_NRCPA_real.log{2}). + - wp. rnd. skip => //. + case (uniq Reduction.IV_Oracle.log{2}); last first. + - conseq (: _ ==> true) => />. + by wp. + rcondt{2} 3; 1: by move=> ?; wp; skip. + by wp; skip. ++ move=> &2 uql. + proc; inline *. + wp; rnd; skip => />. + rewrite uql => &1 -> /=. + by rewrite drndness_ll. ++ move=> &1. + proc; inline *. + wp; rnd; skip => />. + by rewrite drndness_ll. +by wp; rnd; skip => /> /#. +qed. + +local lemma IV_S_ideal_uniq &m: + Pr[Exp_IV_CPA(D, O_IV_S_ideal(Sample)).run() @ &m: res /\ uniq Sample.l] + = + Pr[Exp_IND_NRCPA(O_NRCPA_ideal, Reduction(D)).run() @ &m: res]. +proof. +byequiv => //. +proc; inline *. +wp. +call (: ! uniq Reduction.IV_Oracle.log, + Sample.l{1} = Reduction.IV_Oracle.log{2} + /\ Reduction.IV_Oracle.log{2} = O_NRCPA_ideal.log{2}, + uniq Sample.l{1} = uniq Reduction.IV_Oracle.log{2}) => //=. ++ apply D_ll. ++ proc; inline *. + seq 2 2 : ( ={m} + /\ r0{1} = r{2} + /\ Sample.l{1} = Reduction.IV_Oracle.log{2} + /\ Reduction.IV_Oracle.log{2} = r{2} :: O_NRCPA_ideal.log{2}). + - by wp; rnd; skip. + case (uniq Reduction.IV_Oracle.log{2}); last first. + - conseq (: _ ==> true) => />. + wp; sp. + if{2} => /=. + * by wp; rnd; wp; skip. + by rnd{1}; wp; skip. + rcondt{2} 3; 1: by move=> ?; wp; skip. + by wp; rnd; wp; skip. ++ move=> &2 uql. + proc; inline *. + rnd; wp; rnd; skip => />. + rewrite uql => &1 -> /=. + by rewrite dptxt_ll drndness_ll. ++ move=> &1. + proc; inline *. + wp. + seq 1 : #pre => //. + - by rnd; skip; rewrite drndness_ll. + - sp; if. + * wp; rnd; wp; skip. + by rewrite dptxt_ll /#. + by wp; skip => />. + hoare => /=. + by rnd; skip. +by wp; skip => /> /#. +qed. + +local module S' (S : ASampler) = { + include S + + proc init() = {} +}. + +local module (BB_Reduction_real (E : Enc_Scheme) : Adv) (S : ASampler) = { + proc a() = { + O_IV_S_real(S'(S), E).init(); + + D(O_IV_S_real(S'(S), E)).distinguish(); + } +}. + +local module (BB_Reduction_ideal : Adv) (S : ASampler) = { + proc a() = { + O_IV_S_ideal(S'(S)).init(); + + D(O_IV_S_ideal(S'(S))).distinguish(); + } +}. + +local equiv blop: + D(O_IV_S_real(S'(Sample), E)).distinguish + ~ D(Counting_O(O_IV_S_real(S'(Sample), E))).distinguish: + ={glob D, O_IV_S_real.k, Sample.l} /\ (size Sample.l = Counting_O.counter){2} + ==> ={res, O_IV_S_real.k, Sample.l} /\ (size Sample.l = Counting_O.counter){2}. +proof. +proc (={O_IV_S_real.k, Sample.l} /\ (size Sample.l = Counting_O.counter){2})=> //. +by proc; inline *; auto=> /> &2 _ _; rewrite addzC. +qed. + +local equiv blopii: + D(O_IV_S_ideal(S'(Sample))).distinguish + ~ D(Counting_O(O_IV_S_ideal(S'(Sample)))).distinguish: + ={glob D, O_IV_S_ideal.k, Sample.l} /\ (size Sample.l = Counting_O.counter){2} + ==> ={res, O_IV_S_ideal.k, Sample.l} /\ (size Sample.l = Counting_O.counter){2}. +proof. +proc (={O_IV_S_ideal.k, Sample.l} /\ (size Sample.l = Counting_O.counter){2})=> //. +by proc; inline *; auto=> /> &2 _ _; rewrite addzC. +qed. + +local lemma Counting_BB_Reduction_real : + hoare[BB_Reduction_real(E, Sample).a : size Sample.l = 0 ==> size Sample.l <= q]. +proof. +proc; inline *; seq 2 : #pre; auto. +call (: size Sample.l = 0 ==> size Sample.l <= q)=> //. +conseq blop (: Counting_O.counter = 0 ==> Counting_O.counter <= q)=> />. ++ move=> &1 size_0; exists (glob D){1} 0 O_IV_S_real.k{1} Sample.l{1}=> />. +by conseq (D_bounded (O_IV_S_real(S'(Sample), E))). +qed. + +local lemma Counting_BB_Reduction_ideal : + hoare[BB_Reduction_ideal(Sample).a : size Sample.l = 0 ==> size Sample.l <= q]. +proof. +proc; inline *. +call (: size Sample.l = 0 ==> size Sample.l <= q)=> //. +conseq blopii (: Counting_O.counter = 0 ==> Counting_O.counter <= q)=> />. ++ move=> &1 size_0; exists (glob D){1} 0 O_IV_S_ideal.k{1} Sample.l{1}=> />. +by conseq (D_bounded (O_IV_S_ideal(S'(Sample)))). +qed. + +local lemma help1 &m: + Pr[Exp_IV_CPA(D, O_IV_S_real(Sample, E)).run() @ &m : ! uniq Sample.l] = + Pr[Exp(Sample, BB_Reduction_real(E)).main() @ &m : ! uniq Sample.l]. +proof. +byequiv (: _ ==> ={Sample.l}) => //=. +proc; inline *. +call (: ={O_IV_S_real.k, Sample.l}) => //. +* proc; inline *. + by wp; rnd; skip. +by wp; rnd; wp; skip. +qed. + +local lemma help2 &m: + Pr[Exp_IV_CPA(D, O_IV_S_ideal(Sample)).run() @ &m : ! uniq Sample.l] = + Pr[Exp(Sample, BB_Reduction_ideal).main() @ &m : ! uniq Sample.l]. +proof. +byequiv (: _ ==> ={Sample.l}) => //=. +proc; inline *. +call (: ={Sample.l}) => //. +- proc; inline *. + by rnd; wp; rnd; skip. +by wp; skip. +qed. + + +lemma IV_security_NR &m: + `| Pr[Exp_IV_CPA(D, O_IV_real(E)).run() @ &m: res] + - Pr[Exp_IV_CPA(D, O_IV_ideal).run() @ &m: res] | + <= + `| Pr[Exp_IND_NRCPA(O_NRCPA_real(E), Reduction(D)).run() @ &m: res] + - Pr[Exp_IND_NRCPA(O_NRCPA_ideal, Reduction(D)).run() @ &m: res] | + + (q * (q - 1))%r / 2%r * mu1 drndness witness. +proof. +rewrite Sample_real Sample_ideal Pr[mu_split (uniq Sample.l)]. +have ->: + Pr[Exp_IV_CPA(D, O_IV_S_ideal(Sample)).run() @ &m : res] + = + Pr[Exp_IV_CPA(D, O_IV_S_ideal(Sample)).run() @ &m : res /\ uniq Sample.l] + + Pr[Exp_IV_CPA(D, O_IV_S_ideal(Sample)).run() @ &m : res /\ ! uniq Sample.l]. ++ by rewrite Pr[mu_split uniq Sample.l]. +rewrite StdOrder.RealOrder.Domain.opprD -StdOrder.RealOrder.Domain.addrCA. +apply (StdOrder.RealOrder.ler_trans + (`| Pr[Exp_IV_CPA(D, O_IV_S_real(Sample, E)).run() @ &m : res /\ uniq Sample.l] - + Pr[Exp_IV_CPA(D, O_IV_S_ideal(Sample)).run() @ &m : res /\ uniq Sample.l] | + + `| Pr[Exp_IV_CPA(D, O_IV_S_real(Sample, E)).run() @ &m : res /\ ! uniq Sample.l] - + Pr[Exp_IV_CPA(D, O_IV_S_ideal(Sample)).run() @ &m : res /\ ! uniq Sample.l] |)). ++ smt(StdOrder.RealOrder.ler_norm_add). +rewrite StdOrder.RealOrder.ler_add 1:StdOrder.RealOrder.ler_eqVlt. ++ by rewrite IV_S_real_uniq IV_S_ideal_uniq. +apply (StdOrder.RealOrder.ler_trans + (StdOrder.RealOrder.maxr + Pr[Exp_IV_CPA(D, O_IV_S_real(Sample, E)).run() @ &m : res /\ ! uniq Sample.l] + Pr[Exp_IV_CPA(D, O_IV_S_ideal(Sample)).run() @ &m : res /\ ! uniq Sample.l])). ++ by rewrite StdOrder.RealOrder.ler_norm_maxr Pr[mu_ge0]. +rewrite StdOrder.RealOrder.maxrE (: mu1 drndness witness = mu1 drndness maxu). ++ by rewrite (drndness_uni witness maxu) 1,2:drndness_fu. +case (Pr[Exp_IV_CPA(D, O_IV_S_ideal(Sample)).run() @ &m : res /\ ! uniq Sample.l] <= + Pr[Exp_IV_CPA(D, O_IV_S_real(Sample, E)).run() @ &m : res /\ ! uniq Sample.l]) => ?. ++ apply (StdOrder.RealOrder.ler_trans + (Pr[Exp_IV_CPA(D, O_IV_S_real(Sample, E)).run() @ &m : ! uniq Sample.l])). + - byequiv (: ={glob D} ==> ={Sample.l}) => //. + proc; inline *. + call (: ={O_IV_S_real.k, Sample.l}). + * proc; inline *. + by wp; rnd; skip. + by wp; rnd; skip. + rewrite help1. + apply (pr_collision (BB_Reduction_real(E))); 1: move=> T Tll. + - proc; inline *. + call (: true); 1: by apply D_ll. + * proc; inline *. + by wp; call(: true). + by wp; rnd; skip; rewrite dkey_ll. + by apply Counting_BB_Reduction_real. +apply (StdOrder.RealOrder.ler_trans + (Pr[Exp_IV_CPA(D, O_IV_S_ideal(Sample)).run() @ &m : ! uniq Sample.l])). ++ byequiv (: ={glob D} ==> ={Sample.l}) => //. + proc; inline *. + call (: ={Sample.l}). + - proc; inline *. + by rnd; wp; rnd; skip. + by wp; skip. +rewrite help2. +apply (pr_collision (BB_Reduction_ideal)); 1: move=> T Tll. ++ proc; inline *. + call (: true) => //; 1: by apply D_ll. + proc; inline *. + by rnd; call(: true); skip; rewrite dptxt_ll. +by apply Counting_BB_Reduction_ideal. +qed. + +lemma IV_security_PRF &m: + `| Pr[Exp_IV_CPA(D, O_IV_real(E)).run() @ &m: res] + - Pr[Exp_IV_CPA(D, O_IV_ideal).run() @ &m: res] | + <= + `| Pr[Exp_NRPRF(O_NRPRF_real, R_NRPRF_IND_NRCPA(Reduction(D))).run() @ &m: res] + - Pr[Exp_NRPRF(O_NRPRF_ideal, R_NRPRF_IND_NRCPA(Reduction(D))).run() @ &m: res] | + + (q * (q - 1))%r / 2%r * mu1 drndness witness. +proof. +apply (StdOrder.RealOrder.ler_trans + (`| Pr[Exp_IND_NRCPA(O_NRCPA_real(E), Reduction(D)).run() @ &m: res] + - Pr[Exp_IND_NRCPA(O_NRCPA_ideal, Reduction(D)).run() @ &m: res] | + + (q * (q - 1))%r / 2%r * mu1 drndness witness)). ++ by apply IV_security_NR. +by rewrite (EqAdvantage_IND_NRCPA_NRPRF (Reduction(D))). +qed. + +end section. diff --git a/doc/tutorials/encryption-from-prf/Including.ec b/doc/tutorials/encryption-from-prf/Including.ec new file mode 100644 index 0000000000..facc9bfcfa --- /dev/null +++ b/doc/tutorials/encryption-from-prf/Including.ec @@ -0,0 +1,27 @@ +require import AllCore BitEncoding. + +require BitWord Construction. + +clone import BitWord as Bitstring with + op n <- 256 +proof gt0_n by trivial +rename + "word" as "bits" + "dunifin" as "dbits". +import DWord. + +clone import Construction as C with + type ptxt <- bits, + type nonce <- bits, + op (+) <- (+^), + op dptxt <- dbits +proof *. +realize addpA. proof. move => x y z. by rewrite xorwA. qed. +realize addpC. proof. move => x y. by rewrite xorwC. qed. +realize addKp. proof. move => x y. by rewrite xorwK xorwC xorw0. qed. +realize dptxt_ll by exact/dbits_ll. +realize dptxt_uni by exact/dbits_uni. +realize dptxt_fu by exact/dbits_fu. + + +print E. diff --git a/doc/tutorials/encryption-from-prf/context.rst b/doc/tutorials/encryption-from-prf/context.rst new file mode 100644 index 0000000000..12424dffda --- /dev/null +++ b/doc/tutorials/encryption-from-prf/context.rst @@ -0,0 +1,421 @@ +Defining the Preliminaries/Context +================================== + +We will start off by defining the preliminaries and context of our +security proof, both mathematically (“pen-and-paper”) and in EasyCrypt. +This includes everything from the relevant sets and functions to the +actual scheme; this does not yet include anything regarding security. + +Defining the Basics, Pen-and-Paper +---------------------------------- + +We assume the existence of the following artifacts; these artifacts will +be used to construct the encryption scheme. - A set :math:`\mathcal{K}` +of keys called the *key space*. - A set :math:`\mathcal{P}` of +plaintexts called the *plaintext space*. - A set :math:`\mathcal{N}` of +nonces called the *nonce space*. - A set :math:`\mathcal{C}` of +ciphertexts called the *ciphertext space*. In this case, the ciphertext +space happens to be equal to the plaintext space; that is, +:math:`\mathcal{C} = \mathcal{P}`. - An associative and commutative +binary operator :math:`\oplus : \mathcal{P} + \times \mathcal{P} \rightarrow \mathcal{P}` such that +:math:`x \oplus x + \oplus y = y` for any :math:`x, y \in \mathcal{P}`. - A family of +functions +:math:`\left(f_{k} : \mathcal{N} \rightarrow \mathcal{P}\right)_{k \in \mathcal{K}}` +from nonces (in :math:`\mathcal{N}`) to plaintexts (in +:math:`\mathcal{P}`), indexed by keys (in :math:`\mathcal{K}`). - A +distribution :math:`\mathcal{D}_{\mathcal{K}}` over +:math:`\mathcal{K}`. [1]_ + +Defining the Scheme, Pen-and-Paper +---------------------------------- + +The (symmetric) encryption scheme we consider is a straightforward one; +we call it nonce-based because it uses a nonce (that it takes as an +input) to perform its encryption and decryption procedures. Formally, we +define the encryption scheme as a triple of algorithms +:math:`\mathcal{E} = \left(\mathsf{KGen}, \mathsf{Enc}, \mathsf{Dec}\right)`, +the implementations of which are provided below. + +.. math:: + + + \begin{align*} + \begin{align*} + & \underline{\smash{\mathsf{KGen}()}}\\ + & \left\lfloor~ + \begin{align*} + & k \operatorname{\smash{\overset{\$}{\leftarrow}}} \mathcal{D}_{\mathcal{K}}\\ + & \mathsf{return}\ k + \end{align*} + \right. + \end{align*} + &&&& + \begin{align*} + & \underline{\smash{\mathsf{Enc}(k, n, m)}}\\ + & \left\lfloor~ + \begin{align*} + & \mathsf{return}\ f_{k}(n) \oplus m + \end{align*} + \right.\\ + & + \end{align*} + &&&& + \begin{align*} + & \underline{\smash{\mathsf{Dec}(k, n, c)}}\\ + & \left\lfloor~ + \begin{align*} + & \textsf{return}\ f_{k}(n) \oplus c + \end{align*} + \right.\\ + & + \end{align*} + \end{align*} + +As you can see, this is a relatively basic nonce-based encryption +scheme, not containing more than a single sampling and a handful of +simple function/operator evaluations. Correctness of the scheme—that is, +whether the decryption of any encryption returns the original +message—can be seen to hold as follows. + +.. math:: + + + \begin{align*} + \forall_{k \in \mathcal{D}_{\mathcal{K}}, n \in \mathcal{N}, m \in \mathcal{M}}: + &\ \mathcal{E}.\mathsf{Dec}(k, n, \mathcal{E}.\mathsf{Enc}(k, n, m)) =\\ + &\ \mathcal{E}.\mathsf{Dec}(k, n, f_{k}(n) \oplus m) =\\ + &\ f_{k}(n) \oplus (f_{k}(n) \oplus m) =\\ + &\ f_{k}(n) \oplus f_{k}(n) \oplus m =\\ + &\ m + \end{align*} + +Here, the first two equalities are obtained by respectively replacing +the identifiers of the encryption and decryption procedures by their +specifications; the final two equalities are a consequence of the +assumed associativity and “self-inverse” properties of :math:`\oplus`. + +If you want to get an overview first before you dive into the +formalization in EasyCrypt, you can directly jump to the `paper-based +definition of the security model `__ from here. + +:::note From pen-and-paper to computer + +In standard cryptographic practice, :math:`\mathcal{K}`, +:math:`\mathcal{P}`, :math:`\mathcal{N}`, +:math:`\mathcal{D}_{\mathcal{K}}`, and :math:`\oplus` would be given +concrete definitions. In EasyCrypt, we tend to make proofs as generic as +possible, only afterward instantiating the proof with concrete types. +For example, anything we prove on the construction above will also hold +in the case where :math:`\mathcal{K} = \mathcal{N} = \{0,1\}^{\lambda}` +(for some key length :math:`\lambda`), +:math:`\mathcal{P} = \{0,1\}^{\ell}` (for some plaintext length +:math:`\ell`), :math:`\mathcal{D}_{\mathcal{K}}` is the uniform +distribution over :math:`\mathcal{K}`, and :math:`\oplus` is bitwise XOR +over :math:`\{0,1\}^{\ell}`. We will elaborate on this in a later +section. ::: + +Interlude: EasyCrypt’s Languages +-------------------------------- + +EasyCrypt provides a combination of two specification languages for the +formalization of (pen-and-paper) definitions such as the above. +Specifically, it provides the following two languages. + Expression +language. This is a polymorphic lambda calculus used to describe +mathematical structure. + :math:`\texttt{pWhile}` language. This is a +simple probabilistic imperative language used to describe any +(potentially probabilistic) program. + +Programmatic constructs in these languages are wrapped inside +*theories*. For now, to keep things simple, we will use a single +monolithic theory containing specialized definitions. At a later stage, +we will explain how developments in EasyCrypt can be split across +multiple theories, some of which can even be generalized for reuse +across multiple proofs. + +Defining the Basics, EasyCrypt +------------------------------ + +Starting from scratch, we formalize the above pen-and-paper definitions +in EasyCrypt as follows. [2]_ + +:: + + (* Types for keys, plaintexts, nonces, respectively *) + type key, ptxt, nonce. + + (* Type for ciphertexts *) + type ctxt = ptxt. + + (* Binary infix operator on plaintexts *) + op (+) : ptxt -> ptxt -> ptxt. + + (* Family of functions from nonces to plaintexts, indexed by keys *) + op f : key -> nonce -> ptxt. + + (* Subdistribution over keys *) + op dkey : key distr. + + (* Associativity, commutativity, and "self-inverse" property of the binary operator, respectively *) + axiom addpA (x y z : ptxt) : x + y + z = x + (y + z). + axiom addpC (x y : ptxt) : x + y = y + x. + axiom addKp (x y : ptxt) : x + x + y = y. + +Foremost, note that each declaration is terminated by a full stop ``.``, +which marks the end of a “formal sentence” (e.g., declarations, +definitions, axioms, lemmas, or atomic proof steps) in EasyCrypt. Let us +now discuss the various kinds of declarations that appear in this +preamble. + +:::note From pen-and-paper to computer + +On paper, we often refer to the formal description of an artifact as a +“definition”. However, when talking about the corresponding descriptions +in EasyCrypt, we deliberately make a distinction between *declarations* +and *definitions*. Intuitively, a *declaration* is a (formal) sentence +that describes some abstract artifact, but does not provide a particular +realization of this artifact. For example, most (formal) sentences in +the above snippet are declarations: they merely specify the existence of +a certain type/function/distribution, but do not specify this +type/function/distribution concretely. Contrarily, a *definition* is a +(formal) sentence that describes some artifact with a specific +realization. One can turn a declaration into a definition by providing a +realization (that still satisfies the restrictions imposed by the +declaration, e.g., the types). This can be done by either (1) directly +changing the code and appending a “=” followed by a definition to the +declaration (e.g., ``type key = int.``), or (2) cloning the theory and +providing instantiations of the abstract artifact(s). [3]_ This latter +approach will be explained at a later stage of the tutorial. ::: + +Types +~~~~~ + +First, we *declare* three *types* (which can be thought of as non-empty +sets): ``key`` (denoting :math:`\mathcal{K}`), ``ptxt`` (denoting +:math:`\mathcal{P}`) and ``nonce`` (denoting :math:`\mathcal{N}`). We +also *define* a type of ciphertexts, ``ctxt``—in this case, it is +defined to be the same as the type of plaintexts (corresponding to the +fact that :math:`\mathcal{C} = \mathcal{P}`). + +Operators and Distributions +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Following, we *declare* the operators using the ``op`` keyword (standing +for operator). + +The first operator we declare is :math:`\oplus`, specifying we want to +use it as an infix by enclosing it in parentheses. More specifically, by +declaring the operator ``(+)``, we can subsequently use it as ``a + b`` +(where ``a`` and ``b`` are operands of the appropriate type). After the +colon, we specify the type of the declared operator; so, ``(+)`` is of +type ``ptxt -> ptxt -> ptxt``. This might strike you as strange, since +this type intuitively corresponds to a (pen-and-paper) function +:math:`\oplus : \mathcal{P} \rightarrow \mathcal{P} \rightarrow \mathcal{P}`. +However, since ``->`` is right associative, i.e., +``ptxt -> ptxt -> ptxt`` is equal to ``ptxt -> (ptxt -> ptxt)``, we have +that ``ptxt -> ptxt -> ptxt`` is actually equal to +``ptxt * ptxt -> ptxt`` (which corresponds to the pen-and-paper +:math:`\mathcal{P} \times \mathcal{P} \rightarrow \mathcal{P}`). This +translation of functions that take multiple arguments into sequences of +functions that each take a single argument is called +`currying `__. In computer-based +treatments, the curried form of the type (i.e., the type corresponding +to sequences of functions that each take a single argument) is more +customary, mainly because it eases the manipulation of individual +operands and the partial application of operators. + +As a second operator, we declare the function family :math:`f`, giving +it the ``key -> nonce -> ptxt`` type. As desired, this type intuitively +corresponds to the (pen-and-paper) set :math:`\mathcal{K} \rightarrow +(\mathcal{N} \rightarrow \mathcal{P})` of functions from nonces to +plaintexts, indexed by keys. (Note that +:math:`f : \mathcal{K} \rightarrow (\mathcal{N} \rightarrow \mathcal{P})` +is just a less fancy way of writing +:math:`\left(f_{k} : \mathcal{N} \rightarrow \mathcal{P}\right)_{k \in \mathcal{K}}`.) + +Finally, the `(sub)distribution `__ +:math:`\mathcal{D}_{\mathcal{K}}` is simply declared as a constant +``dkey`` of type ``key distr``, the type of (sub)distributions over +elements in type ``key``. [4]_ Here, ``distr`` is a so-called *type +constructor*; such constructors can be instantiated (in prefix notation) +by any type to construct another type. We discuss the details of +parameterized (or polymorphic) types at a later stage, as they are not +useful/necessary yet. + +Axioms +~~~~~~ + +With the operators declared, it remains to restrict the set of valid +candidates for :math:`\oplus` or, equivalently, state the properties we +want/assume :math:`\oplus` to satisfy. We achieve this by declaring the +appropriate *axioms*. + +More precisely, we restrict our infix ``+`` operator by declaring three +axioms, each capturing one of the properties we want :math:`\oplus` to +satisfy: ``addpC`` captures commutativity, ``addpA`` captures +associativity, and ``addKp`` captures the “self-inverse” property. + +The general shape of an axiom declaration is +``axiom < name > < parameters > : < boolean expression >.``, where the +parameters are universally quantified (typed) variables. For example, +axiom ``addpC`` formally states + +.. math:: + + + \forall x, y \in \mathcal{P}.\ x \oplus y = y \oplus x + +Interpreting Declarations +~~~~~~~~~~~~~~~~~~~~~~~~~ + +So far, we have laid down formal declarations, but how should they be +interpreted? In essence, everything in the remainder of the file +(including definitions and proofs) can be thought of as *parameterized* +by the declared artifacts. So, in this case, everything in the remainder +of the file can be applied to (and is valid for) any set of keys, +plaintext and nonces, and any operators and distributions that meet the +axioms. + +We’ll discuss how to actually instantiate constructions and proofs at a +later point. + +Defining the Scheme, EasyCrypt +------------------------------ + +With these preliminaries laid down formally, we can now use them to +formalize the (minimal) *syntax* of (symmetric) nonce-based encryption +schemes—that is, the signatures of the procedures that any such scheme +is expected to implement and, thus, can be called from other code that +has access to such a scheme by using the appropriate call statements—as +well as the specification of :math:`\mathcal{E}`. The following snippet +presents these formalizations in EasyCrypt using `module types and +modules `__. + +:: + + (* + Module type for (symmetric) nonce-based encryption schemes. + Intuitively, this specifies the interface that such + encryption schemes are expected to implement. + *) + module type NBEncScheme = { + proc kgen(): key + proc enc(k : key, n : nonce, m : ptxt): ctxt + proc dec(k : key, n : nonce, c : ctxt): ptxt + }. + + (* + Specification of the considered nonce-based encryption scheme. + Because the module implements all the procedures specified in the NBEncScheme + module type, the module has this type (making it valid to give it this type). + *) + module E : NBEncScheme = { + proc kgen() : key = { + var k; + + k <$ dkey; + + return k; + } + + proc enc(k : key, n : nonce, m : ptxt) : ctxt = { + return (f k n) + m; + } + + proc dec(k : key, n : nonce, c : ctxt) : ptxt = { + return (f k n) + c; + } + }. + +Here, we start by defining a module type called ``NBEncScheme`` which +defines the (minimal) *syntax* of nonce-based encryption schemes. More +precisely, it states that any module of type ``NBEncScheme`` *must* +implement the following three procedures (but may implement more). + +- A procedure ``kgen`` which takes no arguments and outputs a value of + type ``key``. +- A procedure ``enc`` which, given a value of type ``key``, a value of + type ``nonce`` and a value of type ``ptxt``, outputs a value of type + ``ctxt``. +- A procedure ``dec`` which, given a value of type ``key``, a value of + type ``nonce`` and a value of type ``ctxt`` produces a value of type + ``ptxt``. + +As a result, code that has access to a module of type ``NBEncScheme`` +(which may be abstract) can always call these procedures by using the +appropriate call statements. + +Surely, the above formalization of nonce-based encryption schemes +accurately captures the corresponding generic pen-and-paper definition +we gave earlier: any triple of algorithms consisting of a key generation +algorithm, taking no inputs and producing a key; an encryption +algorithm, taking a key, nonce, and plaintext, and producing a +ciphertext; and a decryption algorithm, taking a key, nonce, and +ciphertext, and producing a plaintext. + +After defining the module type, we formalize the considered encryption +scheme :math:`\mathcal{E}` as the module ``E``. As expected, this module +is of type ``NBEncScheme`` and, hence, provides an implementation of all +the procedures specified by this module type. Other code can issue calls +to these procedures; for example, the encryption procedure may be called +as ``idc <@ E.enc(idk, idn, idm)`` (or ``E.kgen(idk, idn, idm)`` when +you do not want to store the return value of the procedure), where +``idc``, ``idk``, ``idn``, and ``idm`` are identifiers for variables of +type ``ctxt``, ``key``, ``nonce``, and ``ptxt``, respectively. [5]_ In +this case, ``E`` does not implement more procedures than specified by +``NBEncScheme``, so its concrete syntax is fully captured by the generic +syntax defined by its module type. However, if ``E`` would implement +more procedures, other code would also be able to issue direct calls to +these procedures through the corresponding call statements, even though +these procedures would not be part of the module type definition. + +The procedures’ *bodies* then specify the scheme’s operation. In this +particular case, ``E.kgen`` samples a key from ``dkey``, the +formalization of distribution :math:`\mathcal{D}_{\mathcal{K}}`, into a +*local variable* ``k`` and returns this value; ``E.enc`` and ``E.dec`` +straightforwardly use ``f`` and ``+``, the formalization of +:math:`\left(f_{k} : \mathcal{N} \rightarrow \mathcal{P}\right)_{k \in \mathcal{K}}` +and :math:`\oplus`, to behave as specified mathematically. Note that, in +the syntax of expressions, spaces rather than parentheses are used to +denote operator application: ``f k n`` denotes the value obtained by +applying the operator ``f`` to ``k`` and further applying the resulting +value (an operator of type ``nonce -> ptxt``) to ``n``. Indeed, this is +where the aforementioned currying comes into play: Instead of taking a +``key``-``input`` two-tuple and returning a ``ptxt`` value, ``f`` takes +a ``key`` value and returns an operator that takes a ``nonce`` value and +returns a ``ptxt`` value. + +.. [1] + There are subtleties with this; in certain cases, we might instead + want to only assume a key generation algorithm—which may not directly + define a distribution (for example, if it involves interaction). We + keep these discussions for a subsequent tutorial. + +.. [2] + In EasyCrypt, ``(*`` and ``*)`` delimit a (potentially multi-line) + comment. + +.. [3] + Oftentimes, the realizations given to artifacts in a definition are + based on other declarations (i.e., other abstract artifacts). + Nevertheless, we refer to these as definitions since the artifact is + technically still given a realization (even though this realization + is based on other abstract artifacts). + +.. [4] + In this context, the use of the word “constant” might be a bit + confusing: Wasn’t the ``op`` keyword used to declare/define + operators? The answer is *yes, but operators are constants.* For + example, when you declare an operator ``op g : ptxt -> ctxt``, you + denote a *single, fixed* function (abstract perhaps, but fixed) from + plaintexts to ciphertexts. Surely, this is the same as defining a + (potentially abstract) constant of type ``ptxt -> ctxt``. Similarly, + we can use the ``op`` keyword to declare/define constants of any + type, including non-function types such as ``key`` or ``key distr``. + +.. [5] + When calling a module’s procedure from other code, it is not + necessary to have the identifiers of the provided arguments match the + identifiers in the syntax definition; these are merely placeholders + that may be used for documentation purposes. diff --git a/doc/tutorials/encryption-from-prf/going-further/layering-proofs.rst b/doc/tutorials/encryption-from-prf/going-further/layering-proofs.rst new file mode 100644 index 0000000000..223762c0f0 --- /dev/null +++ b/doc/tutorials/encryption-from-prf/going-further/layering-proofs.rst @@ -0,0 +1,8 @@ +Layering Proofs: Towards Counter Mode +===================================== + +Multi-Block Plaintexts +---------------------- + +Padding and Parsing +------------------- diff --git a/doc/tutorials/encryption-from-prf/going-further/reusing-proof-components.rst b/doc/tutorials/encryption-from-prf/going-further/reusing-proof-components.rst new file mode 100644 index 0000000000..e6082477a7 --- /dev/null +++ b/doc/tutorials/encryption-from-prf/going-further/reusing-proof-components.rst @@ -0,0 +1,492 @@ +Reusing Proof Components +======================== + +A huge advantage of using tools to machine-check cryptographic proofs +lies in their ability to argue about generic and modularized proof +elements. We can therefore easily define or reason about cryptographic +primitives and properties in a reusable way. This reusability is also +supported by EasyCrypt and therefore topic of this more advanced +tutorial. + +In the following sections, we will dive into the concept of abstract +theories in EasyCrypt and explore how they can be effectively reused in +different proofs. + +Using Reusable Definitions +-------------------------- + +In EasyCrypt we can write so-called abstract theories that for example +include formal representations of mathematical concepts (rings, groups, +…) or security definitions (CPA security, PRF assumption, …). Abstract +theories allow for the generalization of underlying primitives such that +we can reason for a whole category of the same structure. An abstract +theory does not define concrete objects unless it is instantiated in +another theory. It can then be applied to various cryptographic +scenarios, reducing the need to recreate formal definitions and proofs +for commonly used primitives. The difference between a concrete and an +abstract theory is that we cannot import an abstract theory without +copying it. This is solved by cloning abstract theories in EasyCrypt +which also allows us to set abstract types and operators in this theory +to concrete values from the theory one is currently working in. + +:: + + clone import AbstractTheory as AT with + type a <- b, + op f <- 1. + +In this tutorial, we are going to show two examples how to reuse the +abstract ``Construction`` theory that is introduced in the basic +tutorial. In contrast to the basic tutorial, we introduce most of the +definitions directly in EasyCrypt. + +Example: Nonce-Based Security of a Concrete Construction +-------------------------------------------------------- + +Until now our construction gives generic results for a nonce-based +encryption scheme without specifying the exact types or functions used +for encryption. It is straight forward to reason that if something is +secure for all types and functions fulfilling some axioms, it should be +especially secure for one specific instantiation of those types and +functions. In our case of a nonce-based encryption scheme we could for +example want to choose our plaintexts and ciphertexts to be bitstrings +of a certain length and the ``(+)`` operator to be the XOR operator. To +do so in EasyCrypt, we first need to define what a bitstring is in +general before we can have fixed length bitstrings. Luckily there exists +already an abstract theory in the standard library called ``BitWord`` +which we can use for defining strings of 256 bits. We will use the +cloning mechanism of EasyCrypt as mentioned above. Make sure you first +require the ``BitWord`` theory to make it available in your theory. + +:: + + clone import BitWord as Bitstring with + op n <- 256 + proof gt0_n by trivial + rename + "word" as "bits" + "dunifin" as "dbits". + import DWord. + +In the ``BitWord`` theory the operator n determines the length of a word +(same as a string) consisting of bits. In the instantiation we set this +operator to the specific value of 256 bits. To be able to apply the +theorems from that theory, we have to fulfill the assumptions stated for +this operator. In this case the only condition of ``n`` is to be greater +than zero. We prove the axiom ``gt0_n`` by using the ``trivial`` tactic. +The renaming to bits is more cosmetic and used to be consistent in +naming of lemmas. As last step we import the ``DWord`` theory which +makes lemmas about the distribution of bitstrings we imported available. +Those are used in the next clone to have a distribution that satisfies +all axioms for the distribution of ciphertexts. + +Additionally, we require the ``BitEncoding`` theory for the definition +of the XOR operator. With that we have all types and operators to +instantiate the nonce-based encryption scheme in the basic tutorial. + +:: + + clone import Construction as C with + type ptxt <- bits, + type nonce <- bits, + op (+) <- (+^), + op dctxt <- dbits + proof *. + realize addpA. proof. move => x y z. by rewrite xorwA. qed. + realize addpC. proof. move => x y. by rewrite xorwC. qed. + realize addKp. proof. move => x y. by rewrite xorwK xorwC xorw0. qed. + realize dctxt_ll by exact/dbits_ll. + realize dctxt_uni by exact/dbits_uni. + realize dctxt_fu by exact/dbits_fu. + +As described above we clone the ``Construction`` using ``bits`` and the +XOR operator denoted as ``(+^)``. To get an overview which assumptions +of the ``Construction`` we need to prove, we can use ``proof *`` +here. [1]_ It is not necessary to use it, but it helps to not forget +about realizing any of the assumptions and checks whether all +assumptions are consistent. In this case we get six assumptions we have +to show. The first three of them are axioms about the ``(+)`` operator +and are proven by using axioms about the XOR operator we can find in the +``BitEncoding`` theory. The latter three are the assumptions about the +distribution of ciphertexts which are exactly met by the axioms about +the distribution of bitstrings. + +Since this new definition if a scheme using bitstrings and the XOR +operator satisfies all assumptions of the ``Construction`` we get that +all proofs about the security also hold in this case. o8 + +Example: IV-Based Security from Nonce-Based Security +---------------------------------------------------- + +In the ``Construction`` we looked at the security of nonce-based +encryption guaranteeing that the nonce is not reused. The example above +illustrated how to use this abstract definition to apply the results to +a more concrete scheme. In contrast to that, this second example +instantiates the ``Construction`` in a more conceptual way to build a +bigger abstract theory about IV-based security and its relations to +nonce-based security. + +We start by defining the preliminaries for the security of IV-based +encryption schemes and giving an overview of the reasoning in the +security proof. Then we will present the detailed steps of the proof in +EasyCrypt. + +Difference between IV-Based and Nonce-Based Security +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Both IV-based and nonce-based encryption are techniques to randomize the +encryption process. The randomization is necessary to be able to ensure +the security when we encrypt multiple messages using the same key. +Instead of letting the adversary choose a nonce as input to the oracle, +the IV (Initialization Vector) is a fixed-length random value generated +inside the oracle. The encryption algorithm is not changed and expects +still a random value as input. We can illustrate the difference between +IV-based and nonce-based by looking on the real oracles (nr stands for +nonce respecting). + +.. math:: + + + \begin{align*} + \begin{align*} + & \smash{\mathcal{CPA}^{nr\textrm{-}real}_{\Sigma_{NR}}}\\ + \\ + & \begin{align*} + & \underline{\smash{\mathsf{init}()}}\\ + & \left\lfloor~ + \begin{align*} + & k \operatorname{\smash{\overset{\$}{\leftarrow}}} \Sigma_{NR}.\mathsf{KGen}()\\ + & U \leftarrow \emptyset + \end{align*} + \right. + \end{align*} + \\ + & \begin{align*} + & \underline{\smash{\mathsf{enc}(n, m)}}\\ + & \left\lfloor~ + \begin{align*} + & \textsf{if}\ n \notin U\\ + & \left\lfloor~ + \begin{align*} + & U \leftarrow U \cup \{n\}\\ + & c \leftarrow \Sigma_{NR}.\mathsf{Enc}(k, n, m)\\ + & \textsf{return}\ c + \end{align*} + \right.\\ + & \textsf{else}\\ + & \left\lfloor~ + \begin{align*} + & \textsf{return}\ \bot + \end{align*} + \right. + \end{align*} + \right. + \end{align*} + \end{align*} + &&&&&&&& + \begin{align*} + & \smash{\mathcal{CPA}^{iv\textrm{-}real}_{\Sigma_{IV}}}\\ + \\ + & \begin{align*} + & \underline{\smash{\mathsf{init}()}}\\ + & \left\lfloor~ + \begin{align*} + & k \operatorname{\smash{\overset{\$}{\leftarrow}}} \Sigma_{IV}.\mathsf{KGen}() + \end{align*} + \right. + \end{align*} + \\ + & \begin{align*} + & \underline{\smash{\mathsf{enc}(m)}}\\ + & \left\lfloor~ + \begin{align*} + & r \operatorname{\smash{\overset{\$}{\leftarrow}}} \mathcal{R}\\ + & c \leftarrow \Sigma_{IV}.\mathsf{Enc}(k, r, m)\\ + & \textsf{return}\ (r, c) + \end{align*} + \right. + \end{align*} + \end{align*} + \end{align*} + +Since the adversary is not allowed to input the randomness for the +encryption anymore, we can omit the check whether the given nonce is +unique and the initialization of the log. The randomness r is sampled +from a uniform distribution on the set :math:`\mathcal{R}` called the +*randomness space*. To make the randomness used in the encryption +accessible, we return this time both the value r and c. All changes also +apply for the ideal case. + +Definitions for IV-Based Security in EasyCrypt +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +We start the same way as in the ``Construction`` before by defining all +needed types and operators with the needed axioms in an EasyCrypt +theory. To be more precise, we reuse the same types except for the +``nonce`` type (see the code). Instead, we introduce the ``rndness`` +type and a full and uniform distribution ``drndness`` for it. Since +those types are abstract, this mainly changes the name and our +understanding. + +:: + + type rndness. + op [lossless full uniform] drndness: rndness distr. + +As mentioned before the encryption scheme does not change except for the +type of the second parameter to the ``enc`` and ``dec`` procedures that +is set to ``rndness``. Similarly, we rewrite the definitions for the +oracles, the distinguisher and the experiment to adapt to the setting of +the IV-based scheme. The interesting changes are in the oracles for the +CPA security for the IV-based encryption scheme and therefore presented +here. + +:: + + module type CPA_Oracle_IV_i = { + proc init(): unit + proc enc(m : ptxt) : rndness * ctxt + }. + + module O_IV_ideal : CPA_Oracle_IV_i = { + proc init() : unit = { + } + + proc enc(m : ptxt) : rndness * ctxt = { + var r, c; + + r <$ drndness; + c <$ dctxt; + return (r, c); + } + }. + + module O_IV_real (E : Enc_Scheme) : CPA_Oracle_IV_i = { + var k : key + + proc init() : unit = { + k <@ E.kgen(); + } + + proc enc(m : ptxt) : rndness * ctxt = { + var r, c; + + r <$ drndness; + c <@ E.enc(k, r, m); + return (r, c); + } + }. + +This corresponds to the changes we saw in the pen-and-paper version of +the section above. Since the oracle has different return values, we +first define a new module type that describes the interface of an +IV-based oracle. + +The last definition we include in this section is the instantiation of +the ``Construction``. This is crucial to be able to define a reduction +from an IV-based adversary to a nonce-based adversary in the later +sections. We clone the ``Construction`` using our new types and +operators. We especially want to match the ``nonce`` type with the new +defined ``rndness`` type in the clone. + +:: + + clone import Construction as C with + type key <- key, + type ptxt <- ptxt, + type nonce <- rndness, + op f <- f, + op (+) <- (+), + op dkey <- dkey, + op dctxt <- dctxt + proof *. + realize addpA by exact/addpA. + realize addpC by exact/addpC. + realize addKp by exact/addKp. + realize dctxt_ll by exact/dctxt_ll. + realize dctxt_uni by exact/dctxt_uni. + realize dctxt_fu by exact/dctxt_fu. + +This time the cloning of the ``Construction`` theory is straight forward +since we have formulated the same axioms for the operators in this +theory as well. Therefore, we can prove them by saying exact and then +the name of the axiom in this theory. + +Note that this does not mean we get around to prove those axioms for a +concrete instantiation. When cloning the ``IVbased`` theory to apply its +results we still need to prove all assumptions and axioms. This is why +we write this as an abstract theory as well. + +Proof Overview +~~~~~~~~~~~~~~ + +For the IV-based encryption scheme the advantage of :math:`\mathcal{D}` +distinguishing ciphertexts produced using the encryption scheme +:math:`\Sigma_{IV}` from random ciphertexts is given by: + +.. math:: + + + \mathsf{Adv}^{\mathsf{iv\textrm{-}cpa}}_{\mathcal{E}}(\mathcal{D}) + = \left|\mathsf{Pr}\left[\mathsf{Exp}^{\mathsf{iv\textrm{-}cpa}}_{\mathcal{CPA}^{\mathit{iv\textrm{-}real}}_{\Sigma_{IV}}}(\mathcal{D}): 1\right] + - \mathsf{Pr}\left[\mathsf{Exp}^{\mathsf{iv\textrm{-}cpa}}_{\mathcal{CPA}^{\mathit{iv\textrm{-}ideal}}}(\mathcal{D}): 1\right]\right| + +Our goal with this theory is to prove the relation between the IND-CPA +security of IV-based encryption schemes and nonce-based schemes. In +particular, we show that the result from the ``Construction`` implies +IV-based security. + +To make the implication more clear, we start by comparing the real +oracles. So in both the NR and the IV real oracle, we call the ``enc`` +procedure of the scheme with some random value of type ``rndness``. Note +that we set ``nonce`` to match ``rndness``. The difference is that we +did not restrict the IV to be unique. Informally, that should not +compromise the security, since the adversary has no influence on the +sampling on the randomness and the case that the same random value is +sampled is very unlikely for a large set :math:`\mathcal{R}`. We can be +more precise and say that the probability that the sampling is returning +the same value twice is bounded by the so-called Birthday bound, which +is known to be negligible for large sets. + +So with a great certainty we can assume that the random values sampled +are unique. In that case the IV-based security is directly related to +the nonce-based security since the nonces are restricted to be unique. +This gives us the following inequality we aim to prove. + +.. math:: + + + \mathsf{Adv}^{\mathsf{iv\textrm{-}cpa}}_{\mathcal{E}}(\mathcal{D}) + \leq \left|\mathsf{Pr}\left[\mathsf{Exp}^{\mathsf{nr\textrm{-}cpa}}_{\mathcal{CPA}^{\mathit{nr\textrm{-}real}}_{\Sigma_{NR}}}(\mathcal{D'}): 1\right] + - \mathsf{Pr}\left[\mathsf{Exp}^{\mathsf{nr\textrm{-}cpa}}_{\mathcal{CPA}^{\mathit{nr\textrm{-}ideal}}}(\mathcal{D'}): 1\right]\right| + + \frac{(q \cdot (q-1))}{2N} + +The last term is the Birthday bound where :math:`q` denotes the number +of oracle queries by the adversary and :math:`N` is the size of the set +:math:`\mathcal{R}`. Note that we used :math:`\mathcal{D'}` in the +nonce-based setting since :math:`\mathcal{D}` is not a nonce-respecting +CPA distinguisher. :math:`\mathcal{D'}` defines a reduction turning the +IV adversary :math:`\mathcal{D}` into a distinguisher against a +nonce-based encryption scheme :math:`\Sigma_{NR}`. + +In EasyCrypt we can state our goal that we want to show in the following +lemma. Since we do not know the number of distinct elements of type +``rndness``, we instead use the probability of drawing an element which +is implemented as ``mu1 drndness witness``. [2]_ We denote the reduction +by ``Reduction(D)``. This module which has an IV distinguisher as +parameter is presented in the reduction section. + +:: + + lemma IV_security_NR &m: + `| Pr[Exp_IV_CPA(D, O_IV_real(E)).run() @ &m: res] + - Pr[Exp_IV_CPA(D, O_IV_ideal).run() @ &m: res] | + <= + `| Pr[Exp_NR_CPA(CPA_real(E), Reduction(D)).run() @ &m: res] + - Pr[Exp_NR_CPA(CPA_ideal, Reduction(D)).run() @ &m: res] | + + (q * (q - 1))%r / 2%r * mu1 drndness witness. + +What are the steps for that in EasyCrypt to be able to prove the lemma +above? [//]: # (Will write this at the end) + +Sampling +~~~~~~~~ + +The first step we take is to import the ``Birthday`` theory to be able +to use the lemmas stated about the birthday bound. More precisely, we +clone the theory to adapt it to the types we need. The operator q is +used to denote the number of queries made to the oracle. + +Note that we write our proof inside a section to quantify all lemmas +over ``D`` - an IV distinguisher with restricted access to the memories +of oracles and the reduction. Therefore, we also use declare for the +operator ``q`` and local for the following modules and lemmas. + +:: + + declare op q : { int | 0 <= q } as ge0_q. + + local clone import Birthday as BB with + op q <- q, + type T <- rndness, + op uT <- drndness + proof *. + realize ge0_q by exact: ge0_q. + +The lemma about the birthday theory argues about an adversary against a +Sampler. [//]: # (Link to standard library) In order to apply this we +have to wrap an oracle around a sampler of the type ``Sampler``. +Therefore, we define new oracles for both the real and ideal side that +instead of sampling the randomness itself calls the sampler ``S``. The +code shows the real oracle, the ideal is defined respectively. + +:: + + local module O_IV_S_real (S: Sampler) (E: Enc_Scheme) : CPA_Oracle_IV_i = { + var k : key + + proc init() : unit = { + k <@ E.kgen(); + S.init(); + } + + proc enc(m : ptxt) : rndness * ctxt = { + var r : rndness; + var c : ctxt; + + r <@ S.s(); + c <@ E.enc(O_IV_S_real.k, r, m); + + return (r, c); + } + }. + +So the first lemma that we actually proof in EasyCrypt states that +pushing the sampling into another module as we do in this oracle is +equivalent to the original oracle. So if we have the same key as +invariant between the modules ``O_IV_real`` and ``O_IV_S_real``, and we +relate the sampled randomness (from same distribution) the behavior +should be identical. + +:: + + local lemma Sample_real &m: + Pr[Exp_IV_CPA(D, O_IV_real(E)).run() @ &m: res] = + Pr[Exp_IV_CPA(D, O_IV_S_real(Sample, E)).run() @ &m: res]. + proof. + byequiv => //. + proc; inline *. + sim (: ={k}(O_IV_real, O_IV_S_real)). + proc; inline *. + by auto. + qed. + +The lemma is stated using an equality between probability statements. +The proof works as described above. The important steps are the ``sim`` +tactic to introduce the invariant and the ``rnd`` tactic that relates +the distributions of the sampled random values. [//]: # (need to explain +sim and auto tactic (Fix EC code)) + +Reduction +~~~~~~~~~ + +Counting +~~~~~~~~ + +Security statement +~~~~~~~~~~~~~~~~~~ + +Final lemma +~~~~~~~~~~~ + +.. [1] + ``proof *.`` This line in a clone import will return all open + assumptions of the cloned theory that we have to prove. They are + displayed as a list in another buffer when using proof general in + emacs. + +.. [2] + ``mu1 dtype element`` The operator ``mu1`` is defined in the theory + of distributions in the standard library. It gives the probability to + sample the ``element`` of some type from a distribution ``dtype`` + over that type. diff --git a/doc/tutorials/encryption-from-prf/proof.rst b/doc/tutorials/encryption-from-prf/proof.rst new file mode 100644 index 0000000000..4aab06db60 --- /dev/null +++ b/doc/tutorials/encryption-from-prf/proof.rst @@ -0,0 +1,1031 @@ +Proving Security +================ + +Having formalized the relevant context and the more general +security-related definitions (which, arguably, can also be considered +part of the context), we move on to the proof-specific aspects of the +formalization, culminating in the formal verification of the proof +itself. + +High-Level Proof Sketch +----------------------- + +Before diving into the details, we provide a high-level sketch or +intuition of the proof and its structure. + +Foremost, recall that our aim is to show that our symmetric nonce-based +encryption scheme is IND$-NRCPA secure as long as the function family it +uses is a NRPRF. The predominant approach to proving such a statement +*reduces* the problem of breaking the NRPRF property of the function +family *to* the problem of breaking the IND$-NRCPA security of the +encryption scheme; proofs of this type are often referred to as +*reductionist proofs*. In our case, such a proof would essentially boil +down to defining, for every adversary :math:`\mathcal{D}` against the +IND$-NRCPA security of the encryption scheme, an adversary +:math:`\mathcal{R}^{\mathcal{D}}` against the NRPRF property of the +function family that “outperforms” :math:`\mathcal{D}` (i.e., the +advantage of :math:`\mathcal{R}^{\mathcal{D}}` is greater than or equal +to the advantage of :math:`\mathcal{D}`). Then, if there would exist any +adversary that is “unacceptably effective” at breaking the IND$-NRCPA +security of the encryption scheme, it immediately follows that there +also exists an adversary that is “unacceptably effective” in breaking +the NRPRF property of the employed function family. However, since it is +assumed (or “conjectured”) that a latter such adversary does not exist, +one can conclude that a former such adversary also does not exist and, +hence, that the encryption scheme is IND$-NRCPA secure. + +As it turns out, EasyCrypt is specifically designed for the formal +verification of such reductionist proofs; for this reason, we stick to +this type of proof here. Particularly, we build a reduction adversary +(against the NRPRF property of +:math:`\left(f_{k} : \mathcal{N} \rightarrow \mathcal{P}\right)_{k \in \mathcal{K}}`) +that, given any (black-box) adversary against the IND$-NRCPA security of +:math:`\mathcal{E}`, simulates a regular run of the IND$-NRCPA +experiment in a way that allows the reduction adversary to win whenever +the given adversary “wins” the simulated run. A high-level illustration +of this dynamic is provided in the following image. + +.. figure:: reduction.jpg + :alt: alt text + + alt text + +Here, the left-hand side depicts a regular run of the IND$-NRCPA +experiment where the IND$-NRCPA adversary directly interacts with the +given NRCPA oracle; the right-hand side depicts a run of the NRPRF +experiment where the environment—particularly, oracle interactions—of +the IND$-NRCPA adversary is fully controlled by the reduction adversary, +who uses its NRPRF oracle to perfectly simulate the +environment—particularly, answers to oracle queries—in a way that +matches the environment of a regular run of the IND$-NRCPA experiment +and simultaneously allows making use of the eventual return value of the +given adversary. + +Setup and Security Statements +----------------------------- + +Prior to proving or formally verifying anything, we go over the +definition and formalization of the necessary proof-specific and +relevant security statements. Here, we take a top-down approach, +starting with the final goal and moving toward the lower-level steps. + +The Main Result: IND$-NRCPA Security +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Once again, intuitively, the end goal is to demonstrate that +:math:`\mathcal{E}` is IND$-NRCPA secure based on the assumption that +:math:`\left(f_{k} : \mathcal{N} \rightarrow \mathcal{P}\right)_{k \in \mathcal{K}}` +is a NRPRF. More formally, the end goal is to prove the following +(pen-and-paper) theorem. + +**Theorem 1.** *For all adversaries :math:`\mathcal{D}` against +IND$-NRCPA of :math:`\mathcal{E}`, there exists an adversary +:math:`\mathcal{B}` against NRPRF of +:math:`\left(f_{k} : \mathcal{N} \rightarrow \mathcal{P}\right)_{k \in \mathcal{K}}` +— with a running time close to that of :math:`\mathcal{D}` — such that +the following holds:* + +.. math:: + + + \mathsf{Adv}^{\mathrm{IND\$\textrm{-}NRCPA}}_{\mathcal{E}}(\mathcal{D}) \leq \mathsf{Adv}^{\mathrm{NRPRF}}(\mathcal{B}) + +As alluded to before, we prove this theorem using a proof by +construction: Given any adversary :math:`\mathcal{D}` against IND$-NRCPA +security of :math:`\mathcal{E}`, we construct a reduction adversary +:math:`\mathcal{R}` against NRPRF of +:math:`\left(f_{k} : \mathcal{N} \rightarrow \mathcal{P}\right)_{k \in \mathcal{K}}` +— with a running time close to that of :math:`\mathcal{D}` — that +obtains an advantage that is *equal to* the advantage of the given +adversary. In fact, having defined such a reduction adversary, say +:math:`\mathcal{R}^{\mathcal{D}}`, the following theorem implies the one +above. + +**Theorem 2.** *For all adversaries :math:`\mathcal{D}` against +IND$-NRCPA of :math:`\mathcal{E}`, the following holds.* + +.. math:: + + + \mathsf{Adv}^{\mathrm{IND\$\textrm{-}NRCPA}}_{\mathcal{E}}(\mathcal{D}) = \mathsf{Adv}^{\mathrm{NRPRF}}(\mathcal{R}^{\mathcal{D}}) + +In EasyCrypt, there is no notion of running time; consequently, there is +also no way to formalize the restriction “with a running time close to +that of some algorithm”. For this reason, we typically formalize +theorems akin to **Theorem 2**, where the reasonableness of the +operations performed by the considered reduction adversary (i.e., in +terms of running time) is to be manually evaluated (by humans). + +Before advancing to the formalization of **Theorem 2**, `recall that we +cannot formalize short-hands for the advantage expressions like we do on +paper `__; therefore, we +directly formalize the absolute difference in probabilities that these +advantages define. For convenience, the (pen-and-paper) definitions of +the relevant advantage expressions are restated below. + +.. math:: + + + \mathsf{Adv}^{\mathrm{IND\$\textrm{-}NRCPA}}_{\mathcal{E}}(\mathcal{D}) + = \left|\mathsf{Pr}\left[\mathsf{Exp}^{\mathrm{IND\$\textrm{-}NRCPA}}_{\mathcal{D}, \mathcal{O}^{CPA\textrm{-}real}_{\mathcal{E}}} = 1\right] + - \mathsf{Pr}\left[\mathsf{Exp}^{\mathrm{IND\$\textrm{-}NRCPA}}_{\mathcal{D}, \mathcal{O}^{CPA\textrm{-}ideal}} = 1\right]\right| + +.. math:: + + + \mathsf{Adv}^{\mathrm{NRPRF}}(\mathcal{R}^{\mathcal{D}}) + = \left|\mathsf{Pr}\left[\mathsf{Exp}^{\mathrm{NRPRF}}_{\mathcal{R}^{\mathcal{D}}, \mathcal{O}^{PRF\textrm{-}real}} = 1\right] + - \mathsf{Pr}\left[\mathsf{Exp}^{\mathrm{NRPRF}}_{\mathcal{R}^{\mathcal{D}}, \mathcal{O}^{PRF\textrm{-}ideal}} = 1\right]\right| + +Here, `remember that these probability statements are only well-defined +if the initial memory/context are fixed and that, in EasyCrypt, we +explicitly indicate this initial +memory/context `__. Then, in +actuality, we want the above theorems to hold for any initial +memory/context. Apart from this explicit memory indication, the +formalization of `probability statements in +EasyCrypt `__ closely follows +the pen-and-paper definitions. Essentially, given some specific initial +memory (variable) ``&m``, we can formalize the probability expressions +by replacing all algorithms by their formalized counterparts, appending +``@ &m`` (indicating that the execution starts in memory ``&m``), +writing a colon instead of an equality sign, and formalizing the +relevant event (where the special keyword ``res`` may be used to refer +to the output of the considered procedure). For example, for some +initial memory corresponding to ``&m``, + +.. math:: \mathsf{Pr}\left[\mathsf{Exp}^{\mathrm{IND\$\textrm{-}NRCPA}}_{\mathcal{D}, \mathcal{O}^{CPA\textrm{-}real}_{\mathcal{E}}} = 1 \right] + +is formalized as +``Pr[Exp_IND_NRCPA(O_NRCPA_real(E), D).run() @ &m : res]``. (Here, since +the output of ``Exp_IND_NRCPA(O_NRCPA_real(E), D).run()``—and, hence, +``res``—is a boolean, ``res`` is equivalent to ``res = true``.) + +Finally, theorems/lemmas are formalized `similarly to +axioms `__, merely replacing the ``axiom`` keyword by +the ``lemma`` keyword. [1]_ Combining everything, we can formalize +**Theorem 2** as follows. + +:: + + lemma EqAdvantage_IND_NRCPA_NRPRF &m: + `| Pr[Exp_IND_NRCPA(O_NRCPA_real(E), D).run() @ &m: res] + - Pr[Exp_IND_NRCPA(O_NRCPA_ideal, D).run() @ &m: res] | + = + `| Pr[Exp_NRPRF(O_NRPRF_real, R_NRPRF_IND_NRCPA(D)).run() @ &m: res] + - Pr[Exp_NRPRF(O_NRPRF_ideal, R_NRPRF_IND_NRCPA(D)).run() @ &m: res] |. + +In this lemma, ``D`` denotes the formalization of :math:`\mathcal{D}` +(i.e., an arbitrary IND$-NRCPA adversary); where and how we declare this +arbitrary/abstract module will be discussed in one of the upcoming +sections on the formal verification of the statements. Furthermore, +``R_NRPRF_IND_NRCPA(D)`` denotes the formalization of +:math:`\mathcal{R}^{\mathcal{D}}`, which we discuss imminently. + +Reduction Adversary +~~~~~~~~~~~~~~~~~~~ + +The main proof-specific artifact we must formalize is the reduction +adversary. This reduction adversary is given an IND$-NRCPA adversary but +is a NRPRF adversary itself, meaning it also gains access to a NRPRF +oracle. As touched upon in `the high-level proof +sketch `__, the crux of the argument is +that the reduction adversary perfectly simulates a run of the IND$-NRCPA +experiment for the given adversary using the NRPRF oracle in a way that +allows for the reduction adversary to win the NRPRF experiment whenever +the given adversary would have won the simulated IND$-NRCPA experiment. +Somewhat more precisely, the reduction adversary executes the given +adversary while simulating the NRCPA oracle by encrypting each of the +queried plaintexts using the values returned from the NRPRF oracle (when +querying it on the same plaintexts). If done properly, the view of the +given adversary is (distributed) exactly the same as the view it would +have in a regular run of its own experiment. Consequently, the behavior +of the given adversary—and, hence, (the distribution of) its +output—matches the behavior it would exhibit in a regular run of its own +experiment. Furthermore, since the encryptions returned to the given +adversary were constructed using the NRPRF oracle, the reduction +adversary can directly translate a correct (or incorrect) choice by the +given adversary regarding the validity of the provided encryptions into +a correct (or incorrect) choice regarding the validity of the values +provided by the NRPRF oracle. As such, the reduction adversary will +invariably be correct (and incorrect) with the exact same probability as +the given adversary, *independent of the actual implementation of the +given adversary*. + +Because the reduction adversary itself is a NRPRF adversary, we +formalize it as a module of type ``Adv_NRPRF``. To indicate that the +module formalizes the ``R``\ eduction adversary that reduces from +``NRPRF`` to ``IND_NRCPA``, we name the module ``R_NRPRF_IND_NRCPA``. +However, because a module of type ``Adv_NRPRF`` *only* expects a module +of type ``NRPRF_Oracle`` as parameter, the module parameter of type +``Adv_IND_NRCPA`` (formalizing the given IND$-NRCPA adversary) must come +first. Indeed, loosely speaking, a module is of type ``Adv_NRPRF`` *only +if* it still expects a single module parameter of type ``NRPRF_Oracle``; +if there are any other module parameters, these must first be +instantiated before the module “becomes” of type ``Adv_NRPRF``. This is +reflected in the (module) type annotations of the module definition, +provided in the snippet below. + +:: + + module (R_NRPRF_IND_NRCPA (D : Adv_IND_NRCPA) : Adv_NRPRF) (O_NRPRF : NRPRF_Oracle) = { + module O_NRCPA : NRCPA_Oracle = { + proc enc(n : nonce, m : ptxt) : ctxt option = { + var p : ptxt option; + var r : ctxt option; + + p <@ O_NRPRF.get(n); + + r <- if p = None then None else Some (oget p + m); + + return r; + } + } + + proc distinguish() : bool = { + var b : bool; + + b <@ D(O_NRCPA).distinguish(); + + return b; + } + }. + +Here, we see that the reduction adversary defines a *sub-module* +``O_NRCPA`` of type ``NRCPA_Oracle``; as the type enforces, this +sub-module implements an ``enc`` procedure. In this ``enc`` procedure, +the reduction adversary directly queries the provided NRPRF oracle +module (``O_NRPRF``) on ``n``. Subsequently, if the value ``p`` returned +by the NRPRF oracle is a failure indication, then the reduction +adversary returns a failure indication as well; else, if the value ``p`` +returned by the NRPRF oracle contains a valid plaintext, the reduction +adversary returns the ciphertext obtained by mapping this plaintext and +``m`` using the ``+`` operator. (Indeed, the ``oget`` operator takes a +value of any option type and, if the value equals ``Some x``, it returns +``x``; else, it returns an arbitrary value of the original type.) + +In its ``distinguish`` procedure, the reduction adversary uses its +sub-module as the NRCPA oracle that is exposed to the given adversary. +This formalizes the simulation of oracle interactions by the reduction +adversary for the given adversary. In the end, the reduction adversary +simply returns the value returned by the given adversary. + +Intermediate Results: Equal Probabilities in Real and Ideal Cases +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To separate concerns, we break the main part of the proof down into two +independent pieces: equality of the “real case” probabilities and +equality of the “ideal case” probabilities. More formally, we proceed by +separately proving the following two equalities. + +.. math:: + + + \mathsf{Pr}\left[\mathsf{Exp}^{\mathrm{IND\$\textrm{-}NRCPA}}_{\mathcal{D}, \mathcal{O}^{CPA\textrm{-}real}_{\mathcal{E}}} = 1\right] + = \mathsf{Pr}\left[\mathsf{Exp}^{\mathrm{NRPRF}}_{\mathcal{R}^{\mathcal{D}}, \mathcal{O}^{PRF\textrm{-}real}} = 1\right] + +.. math:: + + + \mathsf{Pr}\left[\mathsf{Exp}^{\mathrm{IND\$\textrm{-}NRCPA}}_{\mathcal{D}, \mathcal{O}^{CPA\textrm{-}ideal}} = 1\right] + = \mathsf{Pr}\left[\mathsf{Exp}^{\mathrm{NRPRF}}_{\mathcal{R}^{\mathcal{D}}, \mathcal{O}^{PRF\textrm{-}ideal}} = 1\right] + +At this point, it might be good to note (and convince yourself) that the +defined reduction adversary indeed does what we want in both of the +considered cases (“real” and “ideal”); in particular, it properly +simulates the NRCPA oracle in either case. If the provided NRPRF oracle +module is the real one (``O_NRPRF_real``), then ``get(n)`` returns a +failure indication if ``n`` was already queried, and a plaintext +obtained by applying the function ``f`` to ``k`` and ``n`` otherwise. In +the former case, the reduction adversary returns a failure indication as +well. In the latter case, the reduction adversary returns a ciphertext +constructed by mapping the received plaintext and ``m`` using ``+``. +Certainly, that is equivalent to the real NRCPA oracle module +``O_NRPRF_real`` using the encryption scheme ``NBEncScheme`` to obtain +the same ciphertext given that the input and the key are the same. +Meaning that the reduction adversary perfectly simulates the real NRCPA +oracle module (O_NRCPA_real) when it is given the real NRPRF oracle +module (O_NRPRF_real). When providing the ideal oracle ``O_NRCPA_ideal`` +to the reduction adversary the intresting case is again, when the nonce +was not queried before and the ``get(n)`` procedure returns a randomly +(uniformly) sampled plaintext. Again the reduction adversary returns a +ciphertext constructed by mapping the received plaintext and ``m`` using +``+``. Since the received plaintext is uniformly distributed, it +essentially functions as a one-time pad in this mapping; hence, the +resulting ciphertext is uniformly distributed as well. Following, even +though the ideal NRCPA oracle module (``O_NRCPA_ideal``) does not +perform this mapping (but instead directly samples a ciphertext +uniformly at random and returns this), the distribution of the returned +ciphertext is identical. As a result, the reduction adversary simulates +the ideal case perfectly. + +The veracity of these equalities almost immediately follows from the +previous discussion concerning the reduction adversary. That is, in +either case, :math:`\mathcal{R}^{\mathcal{D}}` perfectly simulates the +corresponding case for :math:`\mathcal{D}`, meaning (the distribution +of) the output of :math:`\mathcal{D}` is identical to what it would be +in a run of its own game. Then, since :math:`\mathcal{R}^{\mathcal{D}}` +directly returns the value returned by :math:`\mathcal{D}`, the +probability of this value being 1 is trivially equal to the probability +of the value returned by :math:`\mathcal{D}` being 1 in a run of its own +game. + +In EasyCrypt, the equality of the “real case” probabilites is formalized +as the lemma shown in the snippet below. + +:: + + lemma EqPr_IND_NRCPA_NRPRF_real &m: + Pr[Exp_IND_NRCPA(O_NRCPA_real(E), D).run() @ &m : res] + = + Pr[Exp_NRPRF(O_NRPRF_real, R_NRPRF_IND_NRCPA(D)).run() @ &m : res]. + +Similarly, the equality of the “ideal case” probabilites is formalized +as follows. + +:: + + lemma EqPr_IND_NRCPA_NRPRF_ideal &m: + Pr[Exp_IND_NRCPA(O_NRCPA_ideal, D).run() @ &m: res] + = + Pr[Exp_NRPRF(O_NRPRF_ideal, R_NRPRF_IND_NRCPA(D)).run() @ &m: res]. + +Following `the previous discussion about lemmas in +EasyCrypt `__, these +formalizations should be relatively easy to interpret and understand. +Nevertheless, some more details including the declaration of the +arbitrary/abstract module ``D``, will be covered +`momentarily `__. + +Formal Verification +------------------- + +At last, we advance to the formal verification of the security +statements. That is, in the remainder, we go over the process of proving +the previously formalized lemmas in EasyCrypt. As before, we take a +top-down approach to the discussion, starting with the formal +verification of the main result (temporarily assuming the veracity of +the intermediate result) and only then proceeding to the formal +verfication of the intermediate lemmas. Nevertheless, before anything, +we introduce the concept of sections in Easycrypt, elucidating several +aspects that we skimmed over previously (e.g., the declaration of an +arbitrary/abstract module and the ``local`` keyword). + +Sections +~~~~~~~~ + +Oftentimes, instead of formally verifying the main result(s) at once, it +is more convenient and more manageable (both for the prover and the +reader) to first formally verify some useful auxiliary results, and then +combining these to formally verify the main result(s). These auxiliary +results are generally quite proof-specific, so much so that you wouldn’t +really want them (or any related auxiliary artifacts) to be +saved/exposed after you have used them for their specific purpose. +Furthermore, these auxiliary results frequently pertain to/quantify over +the same artifacts as the eventual main result(s) (e.g., an adversary); +it is cumbersome to repeat the precise declaration/quantification of +these artifacts over and over for each individual result. + +A useful and convenient feature of EasyCrypt that alleviates the above +issues is the (proof) section environment; this environment is delimited +by the sentences ``section X.`` and ``end section X.`` (where ``X`` is +an optional name for the section). Inside of a section, we can “declare” +modules with the desired restrictions using the ``declare`` keyword. +Afterward, we can refer to these declared modules throughout the entire +remainder of the section; without this feature, we would need to +declare/quantify these modules (and the restrictions) anew everywhere we +need to use them. In our case, all our results (both intermediate and +final) quantify over IND$-NRCPA adversaries. As such, in the beginning +of our section, we ``declare`` a module ``D`` of type ``Adv_IND_NRCPA`` +with the appropriate restrictions; see the following snippet. + +:: + + section E_IND_NR_CPA. + + declare module D <: Adv_IND_NRCPA { -O_NRCPA_real, -O_NRCPA_ideal, -O_NRPRF_real, -O_NRPRF_ideal }. + + (* Can use D anywhere here *) + + end section E_IND_NR_CPA. + +By default, any module in EasyCrypt has access to the module variables +of other modules (as well as its own, of course). This also holds for +modules that are declared in sections. However, we do not want +adversaries to have access to the state of the oracles used in the +experiments. (In pen-and-paper proofs, this is also always a given.) To +specify the modules of which a declared module may not access the +variables, we provide a a comma-separated list of the names of these +exempted modules (preceded by a ``-``) in between curly brackets +following the type annotation. + +In addition to declaring modules, a section allows us to mark +definitions of types, operators, module types, modules and lemmas as +local (using the ``local`` keyword) such that they are only accessible +inside the section (i.e., they are not exposed outside the section). As +we see +`later `__, +we mark our two intermediate lemmas as ``local``; this is because these +lemmas are proof-specific auxiliary results used to make the formal +verification of the main result more manageable. Contrarily, the lemma +for the main result is not marked as ``local`` since it is the primary +result that we would like to be available outside the section. +Nevertheless, this lemma still refers to ``D``, the module declared +inside of the section (and that is not exposed outside of the section). +As a result, after closing the section, the lemma for the main result +will be extended with the appropriate quantification over modules of +type ``Adv_IND_NRCPA`` (including the desired restrictions). + +.. _the-main-result-ind-nrcpa-security-1: + +The Main Result: IND$-NRCPA Security +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +At this point, we really have everything in place to start formally +verifying our security statements. Following a top-down approach to the +discussion, we start with the formal verification of the main result. To +this end, assume (for now) that we have already formally verified the +intermediate results and, hence, have them at our disposal in the formal +verification of the main result. + +Everytime we write down a lemma statement, we are expected to prove +(“formally verify”) the statement immediately. In fact, the tool will +not continue processing any further commands until a full proof is +provided. Once the proof is complete, the lemma is saved and is +available for us to use in any subsequent proofs. To start proving a +lemma, we write the sentence ``proof.``; to save a lemma after proving +it, we write the sentence ``qed.``. Considering the lemma for our main +result, this looks as follows. + +:: + + lemma EqAdvantage_IND_NRCPA_NRPRF &m: + `| Pr[Exp_IND_NRCPA(O_NRCPA_real(E), D).run() @ &m: res] + - Pr[Exp_IND_NRCPA(O_NRCPA_ideal, D).run() @ &m: res] | + = + `| Pr[Exp_NRPRF(O_NRPRF_real, R_NRPRF_IND_NRCPA(D)).run() @ &m: res] + - Pr[Exp_NRPRF(O_NRPRF_ideal, R_NRPRF_IND_NRCPA(D)).run() @ &m: res] |. + proof. + (* Proof *) + qed. + +Between ``proof.`` and ``qed.``, we provide the actual proof of the +considered statement. + +Throughout any proof in EasyCrypt, the tool maintains a so-called *proof +state*, a sequence of one or more *proof goals*. Each proof goal +consists of a *context* and a *conclusion*: the context contains all +locally (i.e., goal-specific) considered variables and properties +(“hypotheses”); the conclusion is a boolean expression that is to be +shown to evaluate to true. Initially, for any proof, the proof state +consist only of a single proof goal: the one corresponding to the +original lemma statement. As a proof progresses, already existing goals +change and new goals may appear. Whenever a goal’s conclusion is shown +to be true, the goal is “closed” (i.e., removed from the proof state); +after closing all goals, the proof is complete and the original lemma +may be saved. + +In interactive mode (which is practically required for developing), +EasyCrypt can display the proof state and update it as the proof +progresses. By default, only the currently considered proof goal of the +proof state (i.e., the first goal in the sequence of goals in the state) +is displayed. For example, the following is what is initially displayed +for our main result (which can be reached by processing up to and +including ``proof.``). + +:: + + Current goal + + Type variables: + + &m: {} + ---------------------------------------------------------------------------------------------- + `|Pr[Exp_IND_NRCPA(O_NRCPA_real(E), D).run() @ &m : res] + - Pr[Exp_IND_NRCPA(O_NRCPA_ideal, D).run() @ &m : res]| + = + `|Pr[Exp_NRPRF(O_NRPRF_real, R_NRPRF_IND_NRCPA(D)).run() @ &m : res] + - Pr[Exp_NRPRF(O_NRPRF_ideal, R_NRPRF_IND_NRCPA(D)).run() @ &m : res]| + +Here, everything above the dotted line is part of the goal’s context, +and everything below the dotted line is part of the goal’s conclusion. +In an initial proof goal like this one, the context always only contains +the (type) variables declared between the lemma’s name and the lemma’s +statement; indeed, in this case, this is only the memory variable +``&m``. Furthermore, the conclusion of such an initial goal always +equals the lemma’s statement. + +To go from opening the initial proof goal to closing the final proof +goal and saving the lemma, we repeatedly apply *tactics*. In essence, a +tactic represents a reasoning principle that may be applied to make +progress in a proof. EasyCrypt provides many tactics, covering a wide +range of scenarios; we will introduce and elaborate on the ones we use +in this tutorial as we go. For a comprehensive overview of the tactics +and their individual variations, consult the reference manual. + +Assuming we have access to the intermediate results (i.e., lemmas +``EqPr_IND_NRCPA_NRPRF_real`` and ``EqPr_IND_NRCPA_NRPRF_ideal``), +proving the above goal is rather straightforward: we can simply use that +the left-hand side minuend and subtrahend are respectively equal to +their right-hand side counterparts. To do so, we make use of the +``rewrite`` tactic. Given the name of a lemma/axiom that defines an +equality (say ``X = Y``), this tactic searches the current goal’s +conclusion for ``X`` and replaces it with ``Y``. Thus, in our case, +issuing ``rewrite EqPr_IND_NRCPA_NRPRF_real.`` should replace +``Pr[Exp_IND_NRCPA(O_NRCPA_real(E), D).run() @ &m : res]`` with +``Pr[Exp_NRPRF(O_NRPRF_real, R_NRPRF_IND_NRCPA(D)).run() @ &m : res]``. +Certainly, doing so changes the proof goal to the following. + +:: + + Current goal + + Type variables: + + &m: {} + ---------------------------------------------------------------------------------------------- + `|Pr[Exp_NRPRF(O_NRPRF_real, R_NRPRF_IND_NRCPA(D)).run() @ &m : res] + - Pr[Exp_IND_NRCPA(O_NRCPA_ideal, D).run() @ &m : res]| + = + `|Pr[Exp_NRPRF(O_NRPRF_real, R_NRPRF_IND_NRCPA(D)).run() @ &m : res] + - Pr[Exp_NRPRF(O_NRPRF_ideal, R_NRPRF_IND_NRCPA(D)).run() @ &m : res]| + +Subsequently issuing ``rewrite EqPr_IND_NRCPA_NRPRF_real.`` results in +the proof goal below. + +:: + + Current goal + + Type variables: + + &m: {} + ---------------------------------------------------------------------------------------------- + `|Pr[Exp_NRPRF(O_NRPRF_real, R_NRPRF_IND_NRCPA(D)).run() @ &m : res] + - Pr[Exp_NRPRF(O_NRPRF_ideal, R_NRPRF_IND_NRCPA(D)).run() @ &m : res]| + = + `|Pr[Exp_NRPRF(O_NRPRF_real, R_NRPRF_IND_NRCPA(D)).run() @ &m : res] + - Pr[Exp_NRPRF(O_NRPRF_ideal, R_NRPRF_IND_NRCPA(D)).run() @ &m : res]| + +Obviously, this goal’s conclusion is true: the right-hand side and +left-hand side are literally the same. For these kind of trivial goals, +we can use the ``trivial`` tactic to try and close the goal. Indeed, +issuing ``trivial.`` closes the goal and, since this was the only proof +goal left in the proof state, completes the proof. Everything combined, +we obtain the following for our main result. + +:: + + lemma EqAdvantage_INDNRCPA_NRPRF &m: + `|Pr[Exp_IND_NRCPA(O_NRCPA_real(E), D).run() @ &m: res] + - Pr[Exp_IND_NRCPA(O_NRCPA_ideal, D).run() @ &m: res]| + = + `|Pr[Exp_NRPRF(O_NRPRF_real, R_NRPRF_INDNRCPA(D)).run() @ &m: res] + - Pr[Exp_NRPRF(O_NRPRF_ideal, R_NRPRF_INDNRCPA(D)).run() @ &m: res]|. + proof. + rewrite EqPr_INDNRCPA_NRPRF_real. + rewrite EqPr_INDNRCPA_NRPRF_ideal. + trivial. + qed. + +To make this proof a bit cleaner, we can make use of the *tactical* +``by`` and a particular feature of the ``rewrite`` tactic. First, a +tactical combines or modifies (a sequence of) tactics in some way. In +the case of ``by``, it executes the tactic(s) directly following it and +then attempts to close the resulting goal(s) using ``trivial``. If the +goal(s) cannot be closed after applying ``trivial``, ``by`` will throw +an error. Second, rewrite can be given multiple lemma/axiom names. For +example, issuing ``rewrite Lemma1 Lemma2.``, the tactic will first +rewrite the current goal’s conclusion according to ``Lemma1``, and then +rewrite according to ``Lemma2`` in the conclusion of the goal(s) +generated by the rewriting of ``Lemma1``. Employing these features, we +can reduce the proof to the following one-liner. + +:: + + proof. + by rewrite EqPr_INDNRCPA_NRPRF_real EqPr_INDNRCPA_NRPRF_ideal. + qed. + +Intermediate Result 1: Equal Probabilities in Real Case +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +*We strongly recommend you follow the explanation in this section while +stepping through the code yourself (in interactive mode)* + +In the formal verification of the main result, we assumed that we had +already formally verified the intermediate results. Now, we actually go +over the formal verification of these intermediate results, starting +with the one concerning the equality of the “real case” probabilities. +The following snippet the corresponding lemma together with a complete +proof in EasyCrypt. Note that we declare the lemma using the keyword +``local`` as discussed `before `__. + +:: + + local lemma EqPr_IND_NRCPA_NRPRF_real &m: + Pr[Exp_IND_NRCPA(O_NRCPA_real(E), D).run() @ &m : res] + = + Pr[Exp_NRPRF(O_NRPRF_real, R_NRPRF_IND_NRCPA(D)).run() @ &m : res]. + proof. + byequiv (_ : ={glob D} ==> ={res}); trivial. + proc. + inline *. + sim (_ : ={k}(O_NRCPA_real, O_NRPRF_real) /\ ={log}(O_NRCPA_real, O_NRPRF_real)). + proc. + inline *. + auto. + qed. + +The initial sentence of the proof consists of two tactics, ``byequiv`` +and ``trivial``, combined through the tactical ``;``. Combining two +tactics by means of ``;``, as in ``t1; t2.``, first applies tactic +``t1`` to the current goal, and then applies tactic ``t2`` to the +goal(s) generated by the application of ``t1``. In our case, we combine +``byequiv`` and ``trivial`` to immediately close some of the trivial +goals generated by the application of ``byequiv``. The ``byequiv`` +tactic is more interesting. Namely, this tactic allows us to prove +certain (in)equalities of probabilities concerning program executions by +demonstrating a particular *equivalence* between the considered +programs. This equivalence of programs is always with respect to a +certain pre and postcondition, which are specified in the argument +provided to ``byequiv``; the format of this argument is +``(_ : pre ==> post)``, where ``pre`` and ``post`` respectively denote +the pre and postcondition. In our case, the precondition is +``={glob D}`` (which is syntactic sugar for +``(glob D){1} = (glob D){2}``), [2]_ i.e., we require the accessible +module variables (read: environment/view) of module ``D`` to start out +the same in both executions; the postcondition is ``={res}``, i.e., we +require the output of the programs to be (distributed) the same. +Processing this intial sentence results in a goal that precisely +corresponds to the program equivalence with this pre and postcondition. + +In the second sentence of the proof, we apply the ``proc`` tactic; this +tactic can be used on goals with a conclusion corresponding to a program +logic statement on procedure identifiers (i.e., not on actual code). The +program logics of EasyCrypt are Hoare Logic (HL), probabilistic Hoare +Logic (pHL), and probabilistic Relation Hoare Logic (pRHL). The current +goal’s conclusion denotes a pRHL statement with identifiers of +*concrete* procedures; in such a case, ``proc`` simply replaces the +identifiers by the code of the procedures. + +After applying ``proc``, we see that the code of the procedures contains +several calls to various concrete procedures. To get a better view of +what actually happens, we inline all of these concrete procedure calls +by applying the ``inline`` tactic. In particular, since we want to +inline *all* concrete procedure calls, we apply ``inline *``. (If we +wanted to inline only a particular concrete procedure call, say +``O_NRCPA_real(E).init``, we could’ve used +``inline O_NRCPA_real(E).init``.) + +Looking at the programs in the goal, we notice that they are really +quite similar. Essentially, ignoring auxiliary assignments, the only +difference is the oracle that is provided to the adversary ``D`` when +calling its (abstract) ``distinguish`` procedure. By construction, we +know that these oracles should behave identically *provided* that they +have the same keys and logs throughout the execution. For cases like +this, EasyCrypt provides the convenient higher-level ``sim`` tactic. +Reasoning backward from the end of the programs, this tactic attempts to +prove a program equivalence by keeping track of (and +extending/adjusting) a conjunction of equalities that implies the +original postcondition; if the tactic manages to work through both +programs completely, it tries to show that the original precondition +implies the final conjunction of equalities, which proves the original +equivalence. Indeed, for the current goal, it suffices to maintain the +fact that ``k`` and ``log`` of ``O_NRCPA_real`` and ``O_NRPRF_real`` are +equal throughout the execution of the programs to guarantee that the +oracles provided to ``D`` behave identically and, hence, that ``D`` +outputs the same value (distribution) in both programs as well. Although +``sim`` can be used without any arguments to let EasyCrypt infer the +invariant from the postcondition, this is not sufficient in the current +case; therefore, we provide the invariant explicitly as +``(_ : ={k}(O_NRCPA_real, O_NRPRF_real) /\ ={log}(O_NRCPA_real, O_NRPRF_real))``, +where ``={x}(M, N)`` is syntactic sugar for ``M.x{1} = N.x{2}``. +Applying the ``sim`` tactic with this invariant leaves us with a +*single* goal asking us to prove an equivalence of the ``enc`` +procedures of the oracles provided to ``D``; specifically, the goal asks +us to prove that, whenever the inputs to the oracles are the same *and* +the above invariant holds, the outputs of the oracles are (distributed) +the same *and* the invariant still holds. This shows that the +application of ``sim`` managed to close the original goal *under the +assumption that* the oracles behave identically and maintain the +invariant when called. Now, we are expected to still prove this +assumption to complete the proof. + +Once again, the current goal concerns a pRHL equivalence on concrete +procedure identifiers; so, we apply ``proc``. Then, since the resulting +code contains several calls to concrete procedure, we inline all of them +by applying ``inline *``. Considering the definition of the ``omap`` +operator, the programs are almost trivially seen to be semantically +identical. Furthermore, the code merely contains assignment statements +and if-then-else constructs. As such, this goal is a good target for +another relatively high-level tactic called ``auto``. This tactic +applies a sequence of several basic program logic tactics, afterward +solving the goal if it is trivial. In this case, ``auto`` manages to +solve the goal and, thereby, complete the proof. + +Intermediate Result 2: Equal Probabilities in Ideal Case +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +*We strongly recommend you follow the explanation in this section while +stepping through the code yourself (in interactive mode)* + +Bringing everything to a close, we discuss the formal verification of +the second intermediate result: the equality of the “ideal case” +probabilities. Here, we focus on novel (uses of) tactics that did not +occur in the previous formal verifications. The following snippet +presents the corresponding lemma along with a full proof in EasyCrypt. +Again we use the keyword ``local`` as discussed +`before `__. + +:: + + local lemma EqPr_INDNRCPA_NRPRF_ideal &m: + Pr[Exp_IND_NRCPA(O_NRCPA_ideal, D).run() @ &m: res] + = + Pr[Exp_NRPRF(O_NRPRF_ideal, R_NRPRF_INDNRCPA(D)).run() @ &m: res]. + proof. + byequiv (_ : ={glob D} ==> ={res}) => //. + proc; inline *. + wp. + call (_ : ={log}(O_NRCPA_ideal, O_NRPRF_ideal)). + - proc; inline *. + sp. + if => //. + - wp. + rnd (fun (p : ptxt) => p + m{2}). + wp. + skip => />. + move => &2 _. + split. + - move => y _. + rewrite addpK //. + move => _ c _. + rewrite addpK //. + auto. + auto. + qed. + +As in the formal verification of the first equality of probabilities, we +start off with an application of the ``byequiv`` tactic with equality on +the initial environment of ``D`` and (distribution of the) outputs as +pre and postcondition, respectively. However, instead of combining this +with the ``trivial`` tactic by means of ``;``, we append the +semantically equivalent, but slightly cleaner, ``=> //``. In EasyCrypt, +the ``=>`` can be tacked onto any (sequence of) tactic(s) to start a +sequence of so-called “introduction patterns”. In order, each of the +introduction patterns in the sequence is applied to the goal(s) +generated by the preceding (sequence of) tactic(s) and introduction +pattern(s). An important application of introduction patterns is the +*introduction* of universally quantified variables and hypothesis *from* +a goal’s conclusion *to* a goal’s context. For example, if a goal’s +conclusion starts with ``forall (i : int), ...``, the introduction +pattern ``=> j`` will remove the quantification from the goal’s +conclusion and add ``j: int`` to the goal’s context (note that the +introduced variable’s identifier does not need to match the auxiliary +identifier in the quantification). Similarly, if a goal’s conclusion +starts with, e.g., ``x <> y => ...``, then the introduction pattern +``=> H`` will remove the ``x <> y`` antecedent (and the corresponding +implication arrow) from the goal’s conclusion and add ``H: x <> y`` to +the goal’s context. In the remainder of the proof for that goal, ``H`` +is available as if it were a regular axiom/lemma. + +After applying ``byequiv``, we obtain a single goal denoting a pRHL +equivalence on procedure identifiers, as desired. We replace the +procedure identifiers with the code of the procedures and immediately +inline all calls to concrete procedures in the resulting programs by +applying ``proc; inline *``. This leaves us with two programs that are +nearly identical, only differing in the oracle provided to ``D`` and an +auxiliary assignment. Now, the right-hand side program ends in a simple +assignment; we would like to get rid of this statement so that we can +reason about and relate the abstract procedure calls on both sides +(which requires these calls to be the very last statement in both +programs). To do so, we apply the “weakest precondition” tactic, ``wp``. +In essence, this tactic consumes assignment statements from the end of +the programs while adapting the postcondition in a way that reflects the +execution of these statements; the pRHL equivalence that results from +this implies the original one. + +At this point, both programs end with a call to the same abstract +procedure, i.e., ``distinguish`` of ``D``; however, the exposed oracles +differ and the equivalence between them cannot be proven using the +``sim`` tactic. So, the main points we want to argue is that (1) the +adversary starts out with the same view/environment on both sides, and +(2) even though the provided oracles differ, their behavior is +identical. In turn, the adversary’s view—and, hence, its behavior—is the +same on both sides throughout its execution; particularly, this means +that the adversary’s output (distribution) is the same on both sides. +For this kind of reasoning, we use the ``call`` tactic in EasyCrypt. +This tactic removes the abstract procedure calls and allows us to claim +that the returned value is equally distributed on both sides. However, +to make sure this is sound, it produces two goals that formally +encompass the two previously mentioned conditions. One asks us to prove +that, right before the procedure calls are made, the environment of the +considered module (i.e., ``glob D`` in this case) is equal on both +sides; the other asks us to prove a pRHL equivalence essentially +capturing that, given the same input, the exposed oracles produce the +same output (distribution) on both sides. To assist in (or even make +possible at all) proving the latter, the ``call`` tactic takes an +invariant (as ``(_ : invariant)``) that is maintained throughout the +oracle calls. Naturally, the fact that this invariant holds at the start +*and* is maintained throughout becomes part of the goals. Indeed, all we +need as an invariant in this case is equality of the logs +(``={log}(O_NRCPA_ideal, O_NRPRF_ideal)``), guaranteeing that the +exposed oracles are synchronized with respect to failure indication. + +In the interest of keeping our code somewhat clean and readable (to +those who can understand EasyCrypt code in the first place), we indent +our proof code whenever the previous tactic application more than one +goal, hence resulting in a proof state with more goals than before the +application. (Similarly, we unindent whenever the previous tactic +application closed a goal.) In our case, since the application of +``call`` resulted in the generation of two goals, we indent the next +sentence of proof code by starting it with the indentation symbol ``-`` +and a single whitespace. This sentence will apply to the first goal +generated by ``call``, and we indent all subsequent sentences applying +to this first goal by two whitespaces. After closing this goal and +arriving at the last goal generated by ``call``, we return to the same +indentation level we used for the ``call`` tactic itself. Of course, we +use this styling rule recursively; for example, if, during the proof of +the first goal, we were to apply a tactic that again generated more than +one goal, we indent another level in the same manner as before. + +The first goal generated by the ``call`` tactic concerns the behavioral +equivalence of the exposed oracles. As per usual, we apply ``proc`` and +``inline *`` to first change this pRHL equivalence on procedure +identifiers to one on the code of the procedures, and subsequently +inlining all concrete procedure calls in this code. This leaves us with +two programs for which we want to show, among others, that their output +value (``r``) is (distributed) the same, as indicated by the ``={r}`` +term in the postcondition. Inspecting the programs (and keeping the +precondition in mind), we foremost note that the same branch of the +if-statement will be executed on both sides due to the inputs and logs +being equal. Now, if the else-branch is taken, the equality of (the +distribution of) ``r`` trivially holds; namely, ``r`` will simply be +``None`` on both sides (recall that ``omap`` outputs None if its second +argument is ``None``). However, if the then-branch is taken, the +(distributions of the) return values are not trivially identical: On the +left-hand side, the return value is the value sampled in the +then-branch; on the right-hand side, the return value is the value +obtained from mapping the value sampled in the then-branch (with the +input plaintext) using ``+``. Surely, since the sampled value +essentially functions as a one-time pad in this mapping, the +distribution of the return values is still the same on both sides; +nevertheless, this is not trivial (at least not for the tool) and, +therefore, we will need to do some more work than simply applying some +of the higher-level automated tactics. + +Following from the above, one approach to proving the current goal is +showing that (1) both sides invariably execute the same branch of the +if-statement, and (2) the equivalence holds independent of the executed +branch. Fortunately, the ``if`` tactic enables us to take this exact +approach. However, this tactic is only applicable when the if-statements +are the first statement in both programs. So, to achieve this, we need +to get rid of the assignment statement preceding the if-statement in the +right-hand side program. In turn, we achieve this by means of the +“strongest precondition” tactic, ``sp``, which is basically the dual of +``wp``. As you might have guesses, ``sp`` consumes assignment statements +from the beginning of both programs while accordingly adapting the +precondition. After applying ``sp``, we apply ``if``, and immediately +close one of the trivial goals it generates by appending ``=> //``. +Specifically, this trivial goal concerns the equivalence of the +if-guards on both sides, i.e., the fact that both sides invariably enter +the same branch; this is a trivial goal in this case because the +equality of the variables stated in the precondition makes the guards +exactly the same. Of course, the other goals generated by the ``if`` +tactic concern the veracity of the pRHL equivalence when executing the +different branches. + +Since the application of ``if => //`` generated more than one goal, we +indent the code another level, as before. The current goal is the first +goal generated by ``if => //`` and regards the equivalence of the +programs when executing the then-branch of the if-statement. Starting +off, we apply ``wp`` to consume the assignment statements at the end of +the programs; this results in both of the programs ending with a +sampling from the same distribution (recall that ``dctxt`` and ``dptxt`` +refer to the same *uniform* distribution over all +plaintexts/ciphertexts) that we want to relate somehow. Now, whenever we +want to relate samplings, we use the ``rnd`` tactic. [3]_ Oftentimes, we +use this tactic without any arguments, which essentially assumes that +the *same* value is sampled on both sides. However, sometimes, we want +to say that whenever we sample a certain value on the left-hand side, we +sample a uniquely-linked value on the right-hand side. Surely, as long +as all of the linked values have the same probability of being sampled +on each side, this is sound. For such cases, the ``rnd`` tactic takes +two more arguments that, together, form a bijection between the supports +of the considered distributions. Indeed, this bijection is what +establishes the unique link between the values from the distributions; +of course, you must then still prove that the probability of each of the +linked values in their respective distribution is identical. As some +nice syntactic sugar, whenever the bijection consists of the same +function twice, you only have to provide it once as the first argument. +Looking at the postcondition of our current goal, we see that the value +sampled on the right-hand side (``c``) should be equal to the value +sampled on the left-hand side (``y``) after combining it with the input +plaintext (``m``) using ``+``. So, if the sampling on the left-hand side +gives us ``x``, we want the sampling on the right-hand side to give us +``x + m{2}``, and vice versa. The bijection that captures this link is +defined by two identical functions, viz., ``fun (p : ptxt) => p + m{2}`` +(written as lambda/anonymous function). Therefore, we apply +``rnd (fun (p : ptxt) => p + m{2})``, which consumes the samplings and +adjust the postcondition accordingly. + +After removing the samplings, both programs only have assignments +statements left; once again, we remove these statements using ``wp``, +leaving a goal with empty programs. Now, a pRHL equivalence with empty +programs is true if, for all possible program memories (for both +programs), the precondition implies the postcondition. The ``skip`` +tactic captures this reasoning principle, and transforms a pRHL +equivalence with empty programs into the appropriate, universally +quantified implication. To make our lives a bit easier, we ask the tool +to automatically simplify the expresssion generated by ``skip`` as much +as it can; specifically, we do so using the introduction pattern +commonly referred to as “crush”, ``/>``. + +The application of ``skip => />`` produces a goal that, intuitively, +asks us to show that for any possible program memory, the bijection that +we provided to the ``rnd`` tactic is actually a bijection on the support +of the considered distribution (``dctxt`` or, equivalently, ``dptxt``). +Contemplating the experession following the universal quantification, we +see that it contains an antecedent that is useless in proving the actual +consequent (i.e., the validity of the bijection). To remove the +universal quantification as well as the useless antecedent without doing +anything else, we combine the “identity tactic” ``move`` with the +introduction patterns ``&2`` and ``_`` as ``move => &2 _``. Being the +“identity tactic”, ``move`` does absolutely nothing, but the subsequent +introduction patterns respectively introduce a program memory variable +``&2`` into the context (removing the universal quantification from the +goal’s conclusion) and remove the first (and only) antecedent from the +goal’s conclusion. + +Looking past some of the technical details (e.g., useless antecedents), +we notice that the goal we are left with basically asks us to prove same +thing twice: given any plaintext ``m``, it holds that ``x = x + m + m`` +for each plaintext ``x``. But this is just a “right self-cancellation” +property of ``+``, which we can prove generically as the following lemma +that follows directly from the axioms stated in the context. + +:: + + lemma addpK (x y : ptxt) : x + y + y = x. + proof. + by rewrite addpA addpC addKp. + qed. + +(Note that, in order to use this ``addpK`` in the current proof, it must +be saved beforehand.) With this lemma at our disposal, we continue the +proof by applying the ``split`` tactic. As its name suggests, this +tactic “splits up” a goal whose conclusion constitutes a conjunction +into two goals, each having a different term of the conjuction as its +conclusion (but the same context). We close both of the generated goals +by, first, removing universal quantification and useless antecedents as +before, and subsequently applying ``rewrite addpK //``; the latter is +syntactic sugar for ``rewrite addpK => //``. Naturally, we indent and +unindent according to the aforementioned styling rules as we go. + +The preceding closed the first goal generated by the application of +``if => //`` a while back; hence, we now arrive at the second goal +generated by this application. As discussed before, this goal +corresponds to the equivalence of the programs when the else-branch of +the if-statement executed which, because both return values equal +``None`` and the logs are not changed, is obviously true. Because the +programs merely comprise assignment statements, simply applying ``auto`` +closes the goal; we unindent and proceed to the final goal of the proof. + +Finally, we arrive at the last goal of the proof: the second goal +generated by the application of the ``call`` tactic all the way in the +beginning. Intuitively, this goal now asks us to prove that, when the +adversary is called in the original programs, (1) the environment/view +of the adversary is equal on both sides, (2) the invariant given to the +``call`` tactic holds (i.e., the oracles’ logs are equal), and (3) the +equality of (the distribution of the) return values as well as the +veracity of the invariant imply the original postcondition (i.e., the +postcondition of the goal the ``call`` tactic was applied to). Now, +first, because the equality on the adversary’s environment is assumed by +the precondition and not affected by the remaining statements of the +programs, the first proof obligation is trivial. Second, because the +remaining statements initialize the logs on both sides to the empty +list, the second proof obligation is trivial. Lastly, because the +original postcondition merely required the return value of ``D`` to be +equal on both sides, the third proof obligation is also trivial. +Concluding, since the remaining statements of the programs only concern +assignments, a simple application of ``auto`` closes the goal and +finishes the proof. + +.. [1] + Naturally, as opposed to axioms, lemmas require a proof/formal + verification; these proofs are given directly succeeding the + formalization of the lemma statement. Nevertheless, the formalization + of the statements themselves are identical between lemmas and axioms + (barring the used keyword). + +.. [2] + For the record, variables annotated with ``{1}``, as in ``x{1}``, are + given values according to the memory corresponding to the *left-hand + side* program; similarly, variables annotated with ``{2}``, as in + ``x{2}``, are given values according to the memory corresponding to + the *right-hand side* program. + +.. [3] + The samplings you want to compare should be the final statements in + the considered programs. diff --git a/doc/tutorials/encryption-from-prf/reduction.jpg b/doc/tutorials/encryption-from-prf/reduction.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4943598cb767d7bd7efc642cfc346d805bd0f4ad GIT binary patch literal 70942 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 XwJ||{0}R98_Sb*z|BiSh_^tP^F55_V literal 0 HcmV?d00001 diff --git a/doc/tutorials/encryption-from-prf/security.rst b/doc/tutorials/encryption-from-prf/security.rst new file mode 100644 index 0000000000..66f8cfadc9 --- /dev/null +++ b/doc/tutorials/encryption-from-prf/security.rst @@ -0,0 +1,936 @@ +Defining Security +================= + +Now that we have a scheme, we can define its security. For the time +being, EasyCrypt exclusively allows exact—rather than +asymptotic—security definitions. As such, we will only consider exact +security definitions. Furthermore, we will be a bit more generic than +necessary, starting with a definition of security for *any* symmetric +nonce-based encryption scheme, not just for the particular scheme we are +currently interested in. As alluded to before, in general, we aim to be +rather generic when formalizing and proving security in EasyCrypt. The +reason for this is that, if done properly, this can significantly +increase (and cannot decrease) the strength and reusability of the +result. Nevertheless, at this point, we will keep things somewhat more +concrete than usual for clarity purposes. Later on, we will cover +writing and reusing fully generic proof components. + +IND$-NRCPA Security for Symmetric Nonce-Based Encryption Schemes, Pen-and-Paper +------------------------------------------------------------------------------- + +For the security property, we consider INDistinguishability from RANDOM +ciphertexts under Nonce-Respecting Chosen-Plaintext Attacks +(IND$-NRCPA): An adversary with access to a chosen-plaintext +oracle—which takes a nonce and plaintext as input, outputs a ciphertext, +and does not allow for repeating nonces—should not be able to +distinguish (except with a “small” probability) the actual encryption +scheme with a fixed and properly generated secret key from an oracle +that returns freshly and uniformly sampled ciphertexts. Intuitively, +this property captures the extent to which the ciphertexts of a +(symmetric nonce-based) encryption scheme can be distinguished from +uniformly random ciphertexts: The smaller this extent, the better the +security of the scheme. For defining this indistinguishability property, +it’s crucial to ensure that nonces are not used more than once, as this +could trivially break security; indeed, if we would not impose this +restriction, the adversary could distinguish by simply reusing a nonce. + +More formally, consider the two oracles shown below, +:math:`\mathcal{O}^{CPA\textrm{-}real}_{\Sigma}` (which is defined with +respect to an abstract symmetric nonce-based encryption scheme +:math:`\Sigma`, instantiable by any concrete such scheme) and +:math:`\mathcal{O}^{CPA\textrm{-}ideal}`. + +.. math:: + + + \begin{align*} + \begin{align*} + & \underline{\smash{\mathcal{O}^{CPA\textrm{-}real}_{\Sigma}}}\\ + & \begin{align*} + & \underline{\smash{\mathsf{init}()}}\\ + & \left\lfloor~ + \begin{align*} + & k \operatorname{\smash{\overset{\$}{\leftarrow}}} \Sigma.\mathsf{KGen}()\\ + & \mathrm{log} \leftarrow [\ ] + \end{align*} + \right. + \end{align*} + \\ + & \begin{align*} + & \underline{\smash{\mathsf{enc}(n, m)}}\\ + & \left\lfloor~ + \begin{align*} + & \textsf{if}\ n \notin \mathrm{log}\\ + & \left\lfloor~ + \begin{align*} + & \mathrm{log} \leftarrow n\ ||\ \mathrm{log}\\ + & c \leftarrow \Sigma.\mathsf{Enc}(k, n, m)\\ + & \textsf{return}\ c + \end{align*} + \right.\\ + & \textsf{else}\\ + & \left\lfloor~ + \begin{align*} + & \textsf{return}\ \bot + \end{align*} + \right. + \end{align*} + \right. + \end{align*} + \end{align*} + &&&&&&&& + \begin{align*} + & \underline{\smash{\mathcal{O}^{CPA\textrm{-}ideal}}}\\ + & \begin{align*} + & \underline{\smash{\mathsf{init}()}}\\ + & \left\lfloor~ + \begin{align*} + & \\ + & \mathrm{log} \leftarrow [\ ] + \end{align*} + \right. + \end{align*} + \\ + & \begin{align*} + & \underline{\smash{\mathsf{enc}(n, m)}}\\ + & \left\lfloor~ + \begin{align*} + & \textsf{if}\ n \notin \mathrm{log}\\ + & \left\lfloor~ + \begin{align*} + & \mathrm{log} \leftarrow n\ ||\ \mathrm{log}\\ + & c \operatorname{\smash{\overset{\$}{\leftarrow}}} \mathcal{U}_{\mathcal{C}}\\ + & \textsf{return}\ c + \end{align*} + \right.\\ + & \textsf{else}\\ + & \left\lfloor~ + \begin{align*} + & \textsf{return}\ \bot + \end{align*} + \right. + \end{align*} + \right. + \end{align*} + \end{align*} + \end{align*} + +Evidently, these oracles are extremely similar: The only difference +between the two concerns the creation of ciphertexts (and the +corresponding initialization differences). Then, we capture the +“insecurity” of a (symmetric nonce-based) encryption scheme +:math:`\Sigma` against a nonce-respecting chosen-plaintext distinguisher +:math:`\mathcal{D}`—i.e., a (potentially probabilistic) algorithm +:math:`\mathcal{D}` with the appropriate interface—as the (absolute) +difference between the likelihood of (1) :math:`\mathcal{D}` outputting +:math:`\texttt{true}` when given access to (the :math:`\mathsf{enc}` +procedure of) :math:`\mathcal{O}^{CPA\textrm{-}real}_{\Sigma}` and (2) +:math:`\mathcal{D}` outputting :math:`\texttt{true}` when given access +to (the :math:`\mathsf{enc}` procedure of) +:math:`\mathcal{O}^{CPA\textrm{-}ideal}`. Conceptually, the truth value +output by the distinguisher can be interpreted as the distinguisher’s +“guess” of which oracle it was given. In general terms, this (absolute) +difference is often called *the advantage of :math:`\mathcal{D}` in +distinguishing :math:`\Sigma` from random*; however, since we have +already established a slick name for the exact security property, we +will be more precise and refer to it as *the advantage of +:math:`\mathcal{D}` against IND$-NRCPA of :math:`\Sigma`*. +Mathematically, this advantage is expressed as follows. + +.. math:: + + + \mathsf{Adv}^{\mathrm{IND\$\textrm{-}NRCPA}}_{\Sigma}(\mathcal{D}) + = \left|\mathsf{Pr}\left[\mathsf{Exp}^{\mathrm{IND\$\textrm{-}NRCPA}}_{\mathcal{D}, \mathcal{O}^{CPA\textrm{-}real}_{\Sigma}} = 1\right] + - \mathsf{Pr}\left[\mathsf{Exp}^{\mathrm{IND\$\textrm{-}NRCPA}}_{\mathcal{D}, \mathcal{O}^{CPA\textrm{-}ideal}} = 1\right]\right| + +Here, the experiment + +.. math:: \mathsf{Exp}^{\mathrm{IND\$\textrm{-}NRCPA}}_{\mathcal{D}, \mathcal{O}} + +\ is defined below. This experiment is rather straightforward: It +initializes the given oracle, runs the distinguisher while providing +access to the :math:`\mathsf{enc}` function of the oracle, and directly +outputs the return value received from the distinguisher. + +.. math:: + + + \begin{align*} + & \underline{\smash{\mathsf{Exp}^{\mathrm{IND\$\textrm{-}NRCPA}}_{\mathcal{D}, \mathcal{O}}}}\\ + & \left\lfloor + \begin{align*} + & \mathcal{O}.\mathsf{init}()\\ + & b \operatorname{\smash{\overset{\$}{\leftarrow}}} \mathcal{D}^{\mathcal{O}.\mathsf{enc}}.\mathsf{distinguish}()\\ + & \textsf{return}\ b + \end{align*} + \right. + \end{align*} + +Surely, with these oracle and game definitions, + +.. math:: \mathsf{Adv}^{\mathrm{IND\$\textrm{-}NRCPA}}_{\Sigma}(\mathcal{D}) + +matches the intuitive description of insecurity we gave earlier. Namely, +because + +.. math:: \mathsf{Exp}^{\mathrm{IND\$\textrm{-}NRCPA}}_{\mathcal{D}, \mathcal{O}^{CPA\textrm{-}real}_{\Sigma}} + +and + +.. math:: \mathsf{Exp}^{\mathrm{IND\$\textrm{-}NRCPA}}_{\mathcal{D}, \mathcal{O}^{CPA\textrm{-}ideal}} + +merely differ in the oracle they provide to :math:`\mathcal{D}`, a +difference in probability of :math:`\mathcal{D}` outputting a certain +truth value (arbitrarily chosen to be 1, or :math:`\texttt{true}`, here) +between the experiments must be a consequence of distinguishing the +oracles somehow. Certainly, this is precisely what + +.. math:: + + \left|\mathsf{Pr}\left[\mathsf{Exp}^{\mathrm{IND\$\textrm{-}NRCPA}}_{\mathcal{D}, \mathcal{O}^{CPA\textrm{-}real}_{\Sigma}} = 1\right] - + \mathsf{Pr}\left[\mathsf{Exp}^{\mathrm{IND\$\textrm{-}NRCPA}}_{\mathcal{D}, \mathcal{O}^{CPA\textrm{-}ideal}} = 1\right]\right| + +captures. + +Finally, we say that a (symmetric nonce-based encryption) scheme +:math:`\Sigma` is IND$-NRCPA secure if, for any nonce-respecting +chosen-plaintext adversary :math:`\mathcal{D}`, + +.. math:: \mathsf{Adv}^{\mathrm{IND\$\textrm{-}NRCPA}}_{\Sigma}(\mathcal{D}) + +\ is “small”. Because we exclusively consider exact security, “small” +essentially means “bounded by other *concrete values/probabilities* that +we believe are small in practice”. + +To directly read further on the security definitions of PRFs for the pen +and paper setting, jump +`here <#nonce-respecting-pseudo-random-function-family-property-pen-and-paper>`__. + +IND$-NRCPA Security for Symmetric Nonce-Based Encryption Schemes, EasyCrypt +--------------------------------------------------------------------------- + +To formalize the above-discussed oracles, adversary class, and +experiment in EasyCrypt, we will make use of `module types and +modules `__, as +well as several libraries from the *standard library*. Specifically, we +will make use of the ``AllCore.ec``, ``List.ec``, and ``Distr.ec`` +libraries for the definitions and properties of basic concepts, lists, +and distributions, respectively. To have those theories available, we +issue the following command at the beginning of the file. + +:: + + require import AllCore List Distr. + +The keyword ``require`` loads the content of a library and the +``import`` keyword makes all the symbols available without +qualification. For more information regarding loading and importing, +`click here `__. + +NRCPA Oracle Type +~~~~~~~~~~~~~~~~~ + +Before formalizing the oracles, we will formalize their type. From the +pen-and-paper definition of the oracles, we can see that they implement +two algorithms: + +.. math:: \mathsf{init()} + +\ and + +.. math:: \mathsf{enc}(n, m) + +, where + +.. math:: n + +is a nonce, + +.. math:: m + +is a plaintext, and + +.. math:: \mathsf{enc}(n, m) + +outputs either a valid ciphertext or an indication of failure ( + +.. math:: \bot + +). The module type that captures this is shown below. + +:: + + module type NRCPA_Oraclei = { + proc init() : unit + proc enc(n : nonce, m : ptxt) : ctxt option + }. + +Here, notice that the procedures’ output types. First, the output type +of ``init`` is ``unit``, which is a built-in type that only contains a +single value. Among others, this type is used as the type of the return +value of procedures that do not return an actual value. Certainly, we do +not expect the initialization procedure of a NRCPA oracle to return +anything; as such, we use ``unit`` to denote its output type. Second, +the output type of ``enc`` is ``ctxt option`` (instead of the ``ctxt`` +type you might have expected). ``option`` is an example of a *type +constructor* (as is ``distr``, which we briefly mentioned +`earlier `__). Such constructors +can be used to construct types by instantiating them (using prefix +notation) with already-existing types. In the specific case of +``option``, any type—say ``t``—can be used to create a corresponding +option type that is denoted by ``t option``. This option type contains a +value ``Some x`` for each value ``x`` of type ``t``, and an additional +value ``None``. In the formalization of the oracles, we use the +``ctxt option`` type as a convenient way to let ``enc`` return either a +valid ciphertext (as ``Some c`` where ``c`` is a ciphertext) or an +indication of failure (as ``None``). + +Real NRCPA Oracle +~~~~~~~~~~~~~~~~~ + +Next, we formalize + +.. math:: \mathcal{O}^{CPA\textrm{-}real}_{\Sigma} + +, the real oracle. Particularly, we do so using a module of type +``NRCPA_Oraclei``. However, in contrast to the encryption scheme we +formalized as a module +`before `__, + +.. math:: \mathcal{O}^{CPA\textrm{-}real}_{\Sigma} + +is defined with respect to some other entity :math:`\Sigma` from a +certain class; in this case, this is the class of symmetric nonce-based +encryption schemes. In EasyCrypt, we formalize this using a so-called +`functor or higher-order +module `__—i.e., +a module parameterized on other module(s)—that takes a module of the +type that represents this class; indeed, here this is the +`previously-defined `__ +``NBEncScheme`` module type. So, we can formalize + +.. math:: \mathcal{O}^{CPA\textrm{-}real}_{\Sigma} + +as follows. + +:: + + module O_NRCPA_real (S : NBEncScheme) : NRCPA_Oraclei = { + var k : key + var log : nonce list + + proc init() : unit = { + k <@ S.kgen(); + + log <- []; + } + + proc enc(n : nonce, m : ptxt) : ctxt option = { + var c : ctxt; + var r : ctxt option; + + if (! (n \in log)) { + log <- n :: log; + + c <@ S.enc(k, n, m); + + r <- Some c; + } else { + r <- None; + } + + return r; + } + }. + +Intuitively, the definition of ``O_NRCPA_real`` can be interpreted as +follows: Given any scheme ``S`` that implements the expected procedures +(or minimal syntax) of a symmetric nonce-based encryption scheme, we can +construct a NRCPA oracle by implementing the expected procedures (or +minimal syntax) in the following way, using (the expected procedures of) +``S``. Certainly, this means that the procedures of ``O_NRCPA_real`` can +formally only be given a meaning (and, hence, be referred/called from +other code) if the module parameter is instantiated. In other words, +``O_NRCPA_real.init`` and ``O_NRCPA_real.enc`` are not well-defined +procedures, but ``O_NRCPA_real(M).init`` and ``O_NRCPA_real(M).enc`` are +(where ``M`` is a module of type ``NBEncScheme``). Contrarily, the +module variables of ``O_NRCPA_real`` (i.e., ``k`` and ``log``) are +independent of the instantiation of its module parameter: there is only +ever one ``O_NRCPA_real.k`` and one ``O_NRCPA_real.log``, even if +``O_NRCPA_real`` is instantiated multiple times with different modules. +Therefore, it is possible to refer to ``O_NRCPA_real.k`` and +``O_NRCPA_real.log``, but not to ``O_NRCPA_real(M).k`` and +``O_NRCPA_real(M).log`` (again, where ``M`` is a module of type +``NBEncScheme``). + +:::note From pen-and-paper to computer Looking at the actual code of +``O_NRCPA_real``, we can see that it is a relatively straightforward +translation from the pen-and-paper definition of which the novel +concepts may seem rather self-explanatory. Regardless, we briefly go +over these concepts for clarity and completeness. + ``list`` is a type +constructor (defined in ``List.ec``) that can be used to construct the +type of lists over a certain type. In other words, for any type ``t``, +``t list`` is the type of lists containing elements of type ``t``. + +``[]`` is a value (defined in ``List.ec``) that denotes the empty list. ++ ``\in`` is an abbreviation (defined in ``List.ec``) that can be used +an infix operator, and checks whether the left-hand side operand (of +some type, say ``t``) is an element of the right-hand side operand (of +type ``t list``). + ``::`` is an infix operator (defined in ``List.ec``) +that prepends the left-hand side operand (of some type, say ``t``) to +the right-hand side operand (of type ``t list``). + In EasyCrypt, +procedures can only have a single return statement. The main reason for +this is to keep the complexity of the program logics (used for proofs) +somewhat in check. For this reason, to formalize procedures that contain +multiple return statements, we accordingly replace all return statements +by assignments to a return variable and a single return statement at the +end. ::: + +Ideal NRCPA Oracle +~~~~~~~~~~~~~~~~~~ + +Having dealt with the formalization of + +.. math:: \mathcal{O}^{CPA\textrm{-}real}_{\Sigma} + +, we continue with the formalization of + +.. math:: \mathcal{O}^{CPA\textrm{-}ideal} + +. Certainly, as one would expect from the pen-and-paper definitions, the +latter essentially only differs from the former in that it samples +ciphertexts uniformly at random instead of legitimately generating them +(i.e., via an actual encryption scheme). As a result, the module +formalizing the ideal oracle does not need to be parameterized on +another module (representing an actual encryption scheme), nor does it +need to maintain a secret key. However, it does require a uniform +distribution over the complete ciphertext space to sample from. So, +before formalizing the oracle, we need to define this distribution; we +do so as follows. + +:: + + op [lossless full uniform] dctxt : ctxt distr. + +In this code, we define a (sub)distribution ``dctxt`` over the ``ctxt`` +type, similar to how we defined the (sub)distribution ``dkey`` over the +``key`` type `before `__. +However, in contrast to ``dkey``, ``dctxt`` is assumed to have several +properties, each of which is denoted by one of the keywords in the +square brackets. First, we assume ``dctxt`` to be ``lossless``; that is, +we assume ``dctxt`` is proper distribution (the sum of its probabilities +exactly equals 1). Second, we assume ``dctxt`` to be ``full``; that is, +we assume ``dctxt`` assigns a non-zero probability to each value of type +``ctxt``. Lastly, we assume ``dctxt`` to be ``uniform``; that is, we +assume ``dctxt`` assigns either a probability of 0 or a constant +probability to each value of type ``ctxt`` (this constant probability is +the same for all values). Note that the combination of the ``full`` and +``uniform`` properties mean that ``dctxt`` assigns the same non-zero +probability to each value of type ``ctxt``. Adding the ``lossless`` +property on top of this results in ``dctxt`` assigning each value of +type ``ctxt`` a probability of + +.. math:: 1 / \left| \mathcal{C} \right| + +(where + +.. math:: \left| \mathcal{C} \right| + +denotes the cardinality of the ciphertext space). In other words, +combining the ``lossless``, ``full``, and ``uniform`` properties results +in the distribution that is usually referred to as the “uniform +distribution”. For more information about distributions in EasyCrypt, +`click here `__. + +Having the required ciphertext distribution at our disposal, we can go +ahead and formalize the ideal oracle. As mentioned before, this +formalization is essentially identical to the formalization of the real +oracle, merely replacing the legitimate generation of ciphertexts by the +appropriate sampling operation (and, of course, removing anything +related to the legitimate generation of ciphertext, as this is +redundant). More precisely, we formalize + +.. math:: \mathcal{O}^{CPA\textrm{-}ideal} + +\ as the module given below. + +:: + + module O_NRCPA_ideal : NRCPA_Oraclei = { + var log : nonce list + + proc init() : unit = { + log <- []; + } + + proc enc(n : nonce, m : ptxt) : ctxt option = { + var c : ctxt; + var r : ctxt option; + + if (! (n \in log)) { + log <- n :: log; + + c <$ dctxt; + + r <- Some c; + } else { + r <- None; + } + + return r; + } + }. + +IND$-NRCPA Experiment and Security +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +At this point, it remains to formalize the considered class of +adversaries and security experiment before finally being able to +formalize the security property of a (symmetric nonce-based) encryption +scheme :math:`\Sigma`. + +Starting off, recall that a class of adversaries contains any (possibly +probabilistic) algorithm that implements a certain interface, +potentially requiring access to a number of oracles. Notice that if we +would be able to specify access to modules of other types in a module +type, adversary classes (with potential oracle access) could easily be +formalized using module types. Namely, the only requirement for a module +``A`` to be of a certain module type ``AT`` is that ``A`` implements the +procedures defined by ``AT``; otherwise, there are no restrictions on +``A``. Indeed, this precisely matches our concept of (a class of) +adversaries: All algorithms that satisfy the expected interface +constitute valid adversaries and, hence, belong to the considered class +of adversaries. So, to formalize a class of adversaries that do not +expect access to any oracle, it suffices to use module types as we have +already gone over before. However, to formalize a class of adversaries +that does expect access to an oracle(s), we require some additional +functionality. Fortunately, EasyCrypt allows for module types that, in +addition to specifying a set of procedures that is to be implemented, +also indicate a sequence of module parameter(s), so-called `functor +types or higher-order module +types `__. + +Applying the above to our currently case, we first create a module type +formalizing the interface of the NRCPA oracles provided *to the +adversaries*. This is necessary because ``NRCPA_Oraclei``, the module +type formalizing the interface of the NRCPA oracles given *to the +experiment*, include the ``init`` procedure, which we do not want to +expose to the adversaries. Therefore, we create a separate module type +for the oracles actually given to the adversary; indeed, this type +should only specify the ``enc`` procedure of the ``NRCPA_Oraclei`` type. +Luckily, EasyCrypt allows for the direct inclusion of procedure +signatures from other module types, so we do not have to copy-paste; see +the snippet below. + +:: + + module type NRCPA_Oracle = { + include NRCPA_Oraclei [enc] + }. + +Using this newly defined module type, we can formalize the class of +adversaries with a module type as follows. + +:: + + module type Adv_IND_NRCPA (O : NRCPA_Oracle) = { + proc distinguish() : bool + }. + +Intuitively, the ``Adv_IND_NRCPA`` module type encompasses all modules +that expect a module of type ``NRCPA_Oracle`` and, *after* being given +such a module, implement ``distinguish`` procedure that takes no input +and outputs a value of type ``bool`` (i.e., a boolean). + +Based on the above, we can formalize the IND$-NRCPA experiment/game, +which is nothing more than a (probabilistic) program that is defined +with respect to a NRCPA oracle and an IND$-NRCPA adversary. In EasyCrypt +terms, the IND$-NRCPA experiment/game is a module that takes two module +parameters: one of type ``NRCPA_Oraclei`` and one of type +``Adv_IND_NRCPA``. Here, a technicality is that—because EasyCrypt allows +code to be written exclusively inside of procedures—we must encapsulate +the actual code of the experiment/game in a procedure (which we +arbitrarily name ``run``), even though there is no corresponding +(explicit) procedure/algorithm signature in the pen-and-paper +definition. Otherwise, the formalization, provided in the following +snippet, is a verbatim translation of the pen-and-paper definition. + +:: + + module Exp_IND_NRCPA (O : NRCPA_Oraclei) (D : Adv_IND_NRCPA) = { + proc run() : bool = { + var b : bool; + + O.init(); + + b <@ D(O).distinguish(); + + return b; + } + }. + +At last, we can express the advantage of an (IND$-NRCPA) adversary +:math:`\mathcal{D}` against IND$-NRCPA of a symmetric nonce-based +encryption scheme :math:`\Sigma`. Recall that the pen-and-paper +definition of this advantage is the following. + +.. math:: + + + \mathsf{Adv}^{\mathrm{IND\$\textrm{-}NRCPA}}_{\Sigma}(\mathcal{D}) + = \left|\mathsf{Pr}\left[\mathsf{Exp}^{\mathrm{IND\$\textrm{-}NRCPA}}_{\mathcal{D}, \mathcal{O}^{CPA\textrm{-}real}_{\Sigma}} = 1\right] + - \mathsf{Pr}\left[\mathsf{Exp}^{\mathrm{IND\$\textrm{-}NRCPA}}_{\mathcal{D}, \mathcal{O}^{CPA\textrm{-}ideal}} = 1\right]\right| + +Formally, these probability expressions are not fully defined unless the +initial memory/context is fixed. More precisely, the experiment only +defines a distribution over its (state and) output value—which allows us +to talk about things such as the probability of the output of the +experiment being 1—if the initial memory is fixed; otherwise, it would +define a set of distributions (one distribution for each possible +initial memory). To keep flexibility in reasoning, EasyCrypt makes the +choice of letting programs run in arbitrary initial memories, and those +need to be specified as part of the probability statements/advantages. +At present, it is impossible to define operators that are parameterized +by memories in EasyCrypt, and we must always explicitly write out the +advantage expressions when they are present. This means that the +advantage expressions will only be formalized within the formalization +of the corresponding security statements. For this reason, we postpone +the discussion concerning the formalization of the advantage expressions +to when we start formalizing the relevant security statements. + +“Nonce-Respecting” Pseudo-Random Function Family Property, Pen-and-Paper +------------------------------------------------------------------------ + +In cryptography, it is common to base security of a scheme on +computational hardness assumptions that can somehow be linked to (parts +of) the scheme; we also do this here. Particularly, we base the +IND$-NRCPA security of + +.. math:: \mathcal{E} + +\ on the (assumed) “Nonce-Respecting” Pseudo-Random Function family +(NRPRF) property [1]_ of the function family used to map nonces to +plaintexts (i.e., + +.. math:: \left(f_{k} : \mathcal{N} \rightarrow \mathcal{P}\right)_{k \in \mathcal{K}} + +). Intuitively, this property captures the extent to which an (unknown) +random function from the function family is indistinguishable from a +truly random function of the same type (i.e., from nonces to plaintexts) +by observing the outputs corresponding to unique/non-repeating inputs. + +More formally, consider the two oracles given below, +:math:`\mathcal{O}^{PRF\textrm{-}real}` and +:math:`\mathcal{O}^{PRF\textrm{-}ideal}`. [2]_ + +.. math:: + + + \begin{align*} + \begin{align*} + & \underline{\smash{\mathcal{O}^{PRF\textrm{-}real}}}\\ + & \begin{align*} + & \underline{\smash{\mathsf{init}()}}\\ + & \left\lfloor~ + \begin{align*} + & k \operatorname{\smash{\overset{\$}{\leftarrow}}} \mathcal{D}_{\mathcal{K}}\\ + & \mathrm{log} \leftarrow [\ ] + \end{align*} + \right. + \end{align*} + \\ + & \begin{align*} + & \underline{\smash{\mathsf{get}(n)}}\\ + & \left\lfloor~ + \begin{align*} + & \textsf{if}\ n \notin \mathrm{log}\\ + & \left\lfloor~ + \begin{align*} + & \mathrm{log} \leftarrow n\ ||\ \mathrm{log}\\ + & m \leftarrow f_k(n)\\ + & \textsf{return}\ m + \end{align*} + \right.\\ + & \textsf{else}\\ + & \left\lfloor~ + \begin{align*} + & \textsf{return}\ \bot + \end{align*} + \right. + \end{align*} + \right. + \end{align*} + \end{align*} + &&&&&&&& + \begin{align*} + & \underline{\smash{\mathcal{O}^{PRF\textrm{-}ideal}}}\\ + & \begin{align*} + & \underline{\smash{\mathsf{init}()}}\\ + & \left\lfloor~ + \begin{align*} + & \\ + & \mathrm{log} \leftarrow [\ ] + \end{align*} + \right. + \end{align*} + \\ + & \begin{align*} + & \underline{\smash{\mathsf{get}(n)}}\\ + & \left\lfloor~ + \begin{align*} + & \textsf{if}\ n \notin \mathrm{log}\\ + & \left\lfloor~ + \begin{align*} + & \mathrm{log} \leftarrow n\ ||\ \mathrm{log}\\ + & m \operatorname{\smash{\overset{\$}{\leftarrow}}} \mathcal{U}_{\mathcal{P}}\\ + & \textsf{return}\ m + \end{align*} + \right.\\ + & \textsf{else}\\ + & \left\lfloor~ + \begin{align*} + & \textsf{return}\ \bot + \end{align*} + \right. + \end{align*} + \right. + \end{align*} + \end{align*} + \end{align*} + +As we can see, :math:`\mathcal{O}^{PRF\textrm{-}real}` and +:math:`\mathcal{O}^{PRF\textrm{-}ideal}` effectively only differ in the +way they create plaintexts: The former creates plaintexts by mapping the +provided nonces with a random function (that is fixed during +initialization) from +:math:`\left(f_{k} : \mathcal{N} \rightarrow \mathcal{P}\right)_{k \in \mathcal{K}}`; +the latter creates plaintexts by sampling them uniformly at random, +independent of the provided nonces. Then, akin to what we did for +IND$-NRCPA security, we define the advantage of a nonce-respecting +pseudo-random function distinguisher :math:`\mathcal{D}` against +:math:`\left(f_{k} : \mathcal{N} \rightarrow \mathcal{P}\right)_{k \in \mathcal{K}}` +as the following (absolute) difference. + +.. math:: + + + \mathsf{Adv}^{\mathrm{NRPRF}}(\mathcal{D}) + = \left|\mathsf{Pr}\left[\mathsf{Exp}^{\mathrm{NRPRF}}_{\mathcal{D}, \mathcal{O}^{PRF\textrm{-}real}} = 1\right] + - \mathsf{Pr}\left[\mathsf{Exp}^{\mathrm{NRPRF}}_{\mathcal{D}, \mathcal{O}^{PRF\textrm{-}ideal}} = 1\right]\right| + +In this equation, +:math:`\mathsf{Exp}^{\mathrm{NRPRF}}_{\mathcal{D}, \mathcal{O}}` refers +to the experiment defined below. + +.. math:: + + + \begin{align*} + & \underline{\smash{\mathsf{Exp}^{\mathrm{NRPRF}}_{\mathcal{O}}(\mathcal{D})}}\\ + & \left\lfloor + \begin{align*} + & \mathcal{O}.\mathsf{init}()\\ + & b \operatorname{\smash{\overset{\$}{\leftarrow}}} \mathcal{D}^{\mathcal{O}.\mathsf{get}}.\mathsf{distinguish}()\\ + & \textsf{return}\ b + \end{align*} + \right. + \end{align*} + +Notice that this experiment takes the exact same approach as the one we +defined for IND$-NRCPA security: The only difference between these +experiments concerns the class of adversaries and the class of oracles +they consider. + +Lastly, we say that +:math:`\left(f_{k} : \mathcal{N} \rightarrow \mathcal{P}\right)_{k \in \mathcal{K}}` +is a NRPRF if, for any nonce-respecting pseudo-random function family +adversary :math:`\mathcal{D}`, +:math:`\mathsf{Adv}^{\mathrm{NRPRF}}(\mathcal{D}`) is “small”. Again, +because we only consider exact security, “small” basically means +“bounded by other *concrete values/probabilities* that we believe are +small in practice”. + +Again, if you are interested in seeing the paper-based security proof +before diving into the EasyCrypt formalization, you can read further on +the `proving security part `__. + +“Nonce-Respecting” Pseudo-Random Function Family Property, EasyCrypt +-------------------------------------------------------------------- + +Evidently, on a conceptual level, the definitions for IND$-NRCPA and +NRPRF experiment and oracles are almost identical. Accordingly, the +corresponding EasyCrypt formalization are also going to be almost +identical. As such, we go over the formalization of NRPRF at a faster +pace, primarily highlighting the differences with the formalization of +IND$-NRCPA and reiterating important aspects. The preceding material +discussing IND$-NRCPA most likely contains explanations of +subjects/concepts left untouched here. + +NRPRF Oracle Type +~~~~~~~~~~~~~~~~~ + +Once again, we start by defining the type for the oracles; as before, we +do so using a module type that specifies a procedure signature for each +algorithm defined expected to be implemented by NRPRF oracles. Looking +at the definitions of :math:`\mathcal{O}^{PRF\textrm{-}real}` and +:math:`\mathcal{O}^{PRF\textrm{-}ideal}`, we can see what (type of) +algorithms these are. The following snippet presents the corresponding +formalization. + +:: + + module type NRPRF_Oraclei = { + proc init() : unit + proc get(n : nonce) : ptxt option + }. + +Real NRPRF Oracle +~~~~~~~~~~~~~~~~~ + +Using the newly defined module type, we formalize the real NRPRF oracle +using a (by now) straightforward translation from the pen-and-paper +definition; see the snippet below. Recall that an EasyCrypt procedure +can only have one ``return`` statement, which is why we employ a return +variable instead of having multiple ``return`` statements. Furthermore, +remember that, since we are using an ``option`` type to represent +successes and failures, the outputs are of the form ``Some p`` (where +``p`` is of type ``ptxt``; this represents a success) or ``None`` (this +represents a failure). + +:: + + module O_NRPRF_real : NRPRF_Oraclei = { + var k : key + var log : nonce list + + proc init() : unit = { + k <$ dkey; + + log <- []; + } + + proc get(n : nonce) : ptxt option = { + var r : ptxt option; + + if (! (n \in log)) { + log <- n :: log; + + r <- Some (f k n); + } else { + r <- None; + } + + return r; + } + }. + +Ideal NRPRF Oracle +~~~~~~~~~~~~~~~~~~ + +For the ideal NRPRF oracle, the formalization is similar to that of the +real NRPRF oracle, only differing in (analogous) ways the pen-and-paper +definitions also differ. + +The only novelty here is that we define and use an alias for the +``dctxt`` distribution, called ``dptxt``. In its definition, this alias +is explicitly indicated to be a distribution over the type of +plaintexts. Naturally, this is only possible because ``ptxt`` and +``ctxt`` are actually the same type. Semantically, this makes no +difference at all; the only reason we do this is to increase readability +by matching the notation with the conceptual meaning. (Recall that NRPRF +oracles conceptually produce plaintexts, not ciphertexts.) The specific +alias definition is provided in the snippet below. + +:: + + op dptxt : ptxt distr = dctxt. + +Then, we formalize the ideal NRPRF oracle as follows. + +:: + + module O_NRPRF_ideal : NRPRF_Oraclei = { + var log : nonce list + + proc init() : unit = { + log <- []; + } + + proc get(n : nonce) : ptxt option= { + var y : ptxt; + var r : ptxt option; + + if (! (n \in log)) { + log <- n :: log; + + y <$ dptxt; + + r <- Some y; + } else { + r <- None; + } + + return r; + } + }. + +NRPRF Experiment and Security +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Having formalized the relevant oracles, we continue by formalizing the +(NRPRF) adversary class. Once again, we formalize this adversary class +using a module type with a single module parameter modeling the expected +NRPRF oracle. Notice that, akin to before, the current module type we +have for NRPRF oracles—``NRPRF_Oraclei``—specifies (the signature of) an +initialization procedure, which we do not want to expose to adversaries. +As such, we create a separate module type for NRPRF oracles given to +adversaries, which only expose the ``get`` procedure. + +:: + + module type NRPRF_Oracle = { + include NRPRF_Oraclei [get] + }. + + module type Adv_NRPRF (O : NRPRF_Oracle) = { + proc distinguish() : bool + }. + +At this point, we have everything required to formalize the NRPRF +experiment, shown. Recall that, even though the adversary is given an +oracle of type ``NRPRF_Oraclei``, the ``init`` procedure of this module +is not actually exposed to the adversary due to the way we specified its +module type. + +:: + + module Exp_NRPRF (O : NRPRF_Oraclei) (D : Adv_NRPRF) = { + proc run() : bool = { + var b : bool; + + O.init(); + + b <@ D(O).distinguish(); + + return b; + } + }. + +.. [1] + NRPRF is not a conventional property; rather, it is a variant of the + more customary Pseudo-Random Function family (PRF) property. For + educational purposes, we have specifically devised this variant to + simplify the current proof. + +.. [2] + Typically, the NRPRF experiment and oracles would first be defined + with respect to an abstract function family of the correct type + before being instantiated with the actual relevant function family + for the proof. This is analogous to how we first defined IND$-NRCPA + with respect to an abstract (symmetric) nonce-respecting encryption + scheme before instantiating it with the actual relevant encryption + scheme for the proof. However, for educational purposes, we decide to + keep it simple and stick with the description that matches the + EasyCrypt formalization the best; for this reason, we immediately + consider the concrete NRPRF property of + :math:`\left(f_{k} : \mathcal{N} \rightarrow \mathcal{P}\right)_{k \in \mathcal{K}}`. diff --git a/doc/tutorials/introduction-itp-program-logics.rst b/doc/tutorials/introduction-itp-program-logics.rst new file mode 100644 index 0000000000..be5b10bae2 --- /dev/null +++ b/doc/tutorials/introduction-itp-program-logics.rst @@ -0,0 +1,51 @@ +Introduction to Computer-Aided Cryptographic Proofs +=================================================== + +.. note:: + + This guide is reproduced and updated, with permission, from `Tejas + Shah `__\ ’s `Joy of + EasyCrypt `__. + + We are grateful to Tejas and Dominique Unruh for developing it and + allowing us to use it here. + +This repo consists of learning material for EasyCrypt, a toolset for +reasoning about cryptographic proofs. It inspired by and written in the +style of `Software +Foundations `__, a series of +electronic textbooks that explain the mathematical underpinnings of +reliable software. For concepts related to cryptography we aim to track +`The Joy of Cryptography `__ (JoC), an +open-source undergrad textbook for cryptography. + +Target audience +--------------- + +Anyone curious about cryptography and who wants to understand formal +verification and computer-aided cryptography in the computational +approach to design-level security [1]_. In line with that, we assume +that the reader is completely new to the field of cryptography, and for +some concepts, the reader will be referred to JoC when needed. We will +offer simplified explanations of concepts required for formal +verification as we go. We expect familiarity with discrete mathematics, +data structures and algorithms, a basic familiarity with the command +line and the ability to work with the Emacs text editor. Essentially, if +you have a little programming experience, then you should be able to +work your way through the ideas presented in this work. + +Although Emacs is pretty complex, we only expect the reader to know how +to open files and navigate them to begin with. These skills can be +learnt quickly with the tutorial that is presented upon a fresh install +of Emacs. Additionally, the `guided tour of +Emacs `__ is helpful for those +who want to know more about what Emacs is capable of and don’t want to +go through the entire tutorial. + +As with the original text, joy is not guaranteed. Formal verification +can be challenging, so we ask you to be patient and keep working with +the material. A tip that we can provide is to start and learn as you go. + +.. [1] + If you do not understand what that means, it is alright, we develop + the required background. diff --git a/doc/tutorials/introduction-itp-program-logics/abstract-ind-ror.ec b/doc/tutorials/introduction-itp-program-logics/abstract-ind-ror.ec new file mode 100644 index 0000000000..02ea38e7f5 --- /dev/null +++ b/doc/tutorials/introduction-itp-program-logics/abstract-ind-ror.ec @@ -0,0 +1,115 @@ +(* +Welcome to ProofGeneral, the front-end that we use to +work with EasyCrypt. ProofGeneral runs on top of Emacs, +so most of keybindings of Emacs work as expected. + +In this file, we go through an illustrative example of +modelling an IND-RoR game with EasyCrypt. + +To interactively evaluate the script, you can either use the +toolbar at the top or use the following keybindings: +1. ctrl + c and then ctrl + n to evaluate one line/block of code (Next) +2. ctrl + c and then ctrl + u to undo evaluation of one line/block of code (Undo) +3. ctrl + x ctrl + s to save the file +4. ctrl + x ctrl + c to exit Emacs + +We will look at more keybindings in the next file. +Evaluting the first line will split the interface to show three panes. + +1. EasyCrypt script pane (left pane) +2. Goals pane (top right) +3. Response pane (bottom right) + +Keep evaluating until the end of the file +and see how things change. +*) + +(* We first import some core theory files *) +require import Real Bool DBool. + +(* We define abstract data-types and operations *) +type msg. +type cip. + +(* Encrypt and decrypt operations. *) +op enc: msg -> cip. +op dec: cip -> msg. + +(* Compute operations for the adversary. *) +op comp: cip -> bool. + +(* +Next we define the module types. +These are blueprints for concrete types +that we instantiate right after we define them. +*) + +module type Challenger = { + proc encrypt(m:msg): cip + proc decrypt(c:cip): msg +}. + +module C:Challenger = { + + proc encrypt(m:msg): cip = { + return enc(m); + } + + proc decrypt(c:cip): msg = { + return dec(c); + } +}. + +(* Similarly we define an adversary. *) +module type Adversary = { + proc guess(c:cip): bool +}. +(* and an instance of the same. *) +module Adv:Adversary = { + + proc guess(c:cip): bool = { + return comp(c); + } +}. + +(* The game module and the claims related to it. *) +module Game(C:Challenger, Adv:Adversary) = { + + proc ind_ror(): bool = { + var m:msg; + var c:cip; + var b,b_adv:bool; + b <$ {0,1}; (* Pick b uniformly at random. *) + if(b=true){ + (* Set m to be an authentic message. *) + } else { + (* Set m to be a random string. *) + } + c <@ C.encrypt(m); + b_adv <@ Adv.guess(c); + return (b_adv=b); + } +}. + +(* +At this point EasyCrypt will throw a warning +complaining about how there may be an uninitialized +variable. This happens because in our current +program definition, we haven't initialized +"m" to anything. +We skim past this warning, since this example +is only to illustrate the structure of EasyCrypt scripts. +Go ahead and keep evaluating the script. +Make sure to undo some evaluations as well, +just to get the keystrokes into your muscle memory. +*) + +axiom ind_ror_pr_le1: +phoare [Game(C,Adv).ind_ror: true ==> res] <= 1%r. + +lemma ind_ror_secure: +phoare [Game(C,Adv).ind_ror: true ==> res] <= (1%r/2%r). +(* Notice the changes in the goals pane *) +proof. + admit. +qed. diff --git a/doc/tutorials/introduction-itp-program-logics/abstract-ind-ror.png b/doc/tutorials/introduction-itp-program-logics/abstract-ind-ror.png new file mode 100644 index 0000000000000000000000000000000000000000..99e9faee9cf013e97d2736a977a45ae7eff51c7c GIT binary patch literal 192897 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/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 +using EasyCrypt in the Proof General + Emacs environment. However, +simply reading through this chapter will also provide you with a working +knowledge of ambient logic and the tactics that we use in this chapter. + +Navigation +---------- + +As noted earlier, the official Emacs tutorial covers the basics of +working with Emacs. The tutorial is presented as an option on the splash +screen on fresh installs of Emacs. It can also be accessed by starting +Emacs and then pressing (Ctrl + h), followed by t. + +All the keybindings begin either with Ctrl key, denoted by “C”, or the +META or Alt key, denoted by “M”. + +So, “C-c C-n” simply means: Ctrl + c and then Ctrl + n. + +Apart from all the basic keybindings of Emacs, we have a few more +bindings that are used specifically for interactive theorem proving in +EasyCrypt. We list some of the most common commands here: + ++----+--------------+--------------------------------------------------+ +| # | Keystroke | Command | ++====+==============+==================================================+ +| 1. | C-c C-n | Evaluate next line or block of code | ++----+--------------+--------------------------------------------------+ +| 2. | C-c C-u | Go back one line or block of code | ++----+--------------+--------------------------------------------------+ +| 3. | C-c C-ENTER | Evaluate until the cursor position | ++----+--------------+--------------------------------------------------+ +| 4. | C-c C-l | To reset the Proof-General layout | ++----+--------------+--------------------------------------------------+ +| 5. | C-c C-r | Begin evaluating from the start (Reset) | ++----+--------------+--------------------------------------------------+ +| 6. | C-c C-b | Evaluate until the end of the file | ++----+--------------+--------------------------------------------------+ +| 7. | C-x C-s | Save file | ++----+--------------+--------------------------------------------------+ +| 8. | C-x C-c | Exit Emacs (Pay attention to the prompts) | ++----+--------------+--------------------------------------------------+ + +Most formal proofs are written interactively, and the proof-assistant, +EasyCrypt in our case, will keep track of the goals (context and +conclusions) for us. The front-end, Proof-General + Emacs in our case, +will show us the goals and messages from the assistant in the goals pane +and response pane, respectively. Our objective is to use different +tactics to prove or “discharge” the goal. + +.. figure:: ambient-logic.png + :alt: The different panes in EasyCrypt + + The different panes in EasyCrypt + +Basic tactics and theorem proving +--------------------------------- + +EasyCrypt has a typed expression language, so everything we declare +should either explicitly have a type or be inferable from the context. +As we saw earlier, EasyCrypt comes with basic built-in data types. These +can be accessed by importing them into the current environment. In this +file, we will be working with the ``Int`` theory file, and we also want +EasyCrypt to print out all the goals. For this, we provide a directive +to EasyCrypt using a ``pragma``. + +:: + + require import Int. + pragma Goals: printall. + +Generally, the first steps in our files will be importing theories and +setting the pragma. + +Before we dive into cryptography, we need to understand how to direct +EasyCrypt to modify the goals and make progress. As we mentioned, this +is achieved by using tactics. In general, the proofs for lemmas take the +following form: + +:: + + lemma name ... : ... . + proof. + tactic_1. + ... + tactic_n. + qed. + +Tactic: ``trivial`` +~~~~~~~~~~~~~~~~~~~ + +To begin with, we will look at a few properties of integers and +introduce how some of the tactics work. + +Reflexivity is simply the property that an integer is equal to itself. +Mathematically, we would write it like so: + +.. math:: \forall x \in \mathbb{Z}, x=x + +We can express this in EasyCrypt with a lemma and prove it like so: + +:: + + lemma int_refl: forall (x: int), x = x. + proof. + trivial. + qed. + +Once we state our lemma and evaluate it, EasyCrypt populates the goal +pane with what needs to be proved. In our case, it presents the +following in the goal. + +:: + + Current goal + + Type variables: + ------------------------------------------ + forall (x : int), x = x + +We start the proof script with the ``proof``, and then EasyCrypt expects +tactics to close the goal. In this case, we use ``trivial``, to prove +our ``int_refl`` lemma. Upon evaluating ``trivial``, the goal pane is +cleared since using this tactic closes the goal. Once there are no more +goals, we can end the proof with ``qed``, and EasyCrypt saves the lemma +for further use and sends us this message in the response pane. Like so: + +:: + + + added lemma: `int_refl' + +``trivial`` tries to solve the goal using various tactics. So it can be +hard to understand when to apply it, but the good news is that +``trivial`` never fails. It either solves the goals or leaves the goal +unchanged. So you can always try it without harm. + +Tactic: ``apply`` +~~~~~~~~~~~~~~~~~ + +Now EasyCrypt knows the lemma ``int_refl`` and allows us to use it to +prove other lemmas. This can be done using the ``apply`` tactic. For +instance: + +:: + + lemma forty_two_equal: 42 = 42. + proof. + apply int_refl. + qed. + +``apply`` tries to match the conclusion of what we are applying (the +proof term) with the goal’s conclusion. If there is a match, it replaces +the goal with the subgoals of the proof term. + +In our case, EasyCrypt matches ``int_refl`` to the goal’s conclusion, +sees that it matches, and replaces the goal with what needs to be proven +for ``int_refl``, which is nothing, and it concludes the proof. + +EasyCrypt comes with many predefined lemmas and axioms that we can use. +For instance, it has axioms related to commutativity and associativity +for integers. They are by the names ``addzC``, and ``addzA``. + +We can ask EasyCrypt to print using: ``print addzC.`` + +EasyCrypt responds with: +``axiom nosmt addzC: forall (x y : int), x + y = y + x.`` + +Tactic: ``simplify`` +~~~~~~~~~~~~~~~~~~~~ + +In the proofs, sometimes tactics yield something that can be simplified. +We use the tactic ``simplify`` to carry out the simplification. +``simplify`` reduces the goal to a normal form using lambda calculus. We +don’t need to worry about the specifics of how, but it is important to +understand that EasyCrypt can simplify the goals given it knows how to. +It will leave the goal unchanged if the goal is already in a normal +form. + +For instance, here is an example that illustrates the idea. + +:: + + lemma x_plus_comm (x: int): x + 2*3 = 6 + x. + proof. + simplify. + (* Simplifies the goal to x + 6 = 6 + x. *) + + simplify. + trivial. + (* These make no progress, but don't fail either. *) + + apply addzC. + (* Discharges the goal *) + qed. + +Tactics: ``move``, ``rewrite``, ``assumption`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +So far, we saw lemmas without any assumptions except for specifying the +type of a variable. More often than not, we will have assumptions +regarding variables. We need to treat these assumptions as a given and +introduce them into the context. This is done by using ``move =>`` +followed by the name you want to give the assumption. Additionally, when +these assumptions show up as goals, instead of applying the assumptions, +we can call the tactic ``assumption`` to discharge the goal directly. +EasyCrypt will automatically look for assumptions that match the goal +when we use ``assumption``. + +In the following example, we use ``addz_gt0``, which is this result: + +``axiom nosmt addz_gt0: forall (x y : int), 0 < x => 0 < y => 0 < x + y.`` + +:: + + lemma x_pos (x: int): 0 < x => 0 < x+1. + proof. + move => x_ge0. + (* + Moves the assumption 0 < x into the + context, and names it x_ge0. + *) + + rewrite addz_gt0. + (* Splits into two goals. *) + + (* Goal 1: 0 < x *) + assumption. + + (* Goal 2: 0 < 1 *) + trivial. + qed. + +The tactics ``rewrite`` and ``apply`` are very similar, they try to +pattern match the goal with the term that is supplied to them. However, +there can be some subtle differences which aren’t exactly clear. For +instance, with the simple example: + +:: + + lemma forty_two_equal: 42 = 42. + proof. + apply int_refl. + qed. + +``apply int_refl.`` discharges the goal, but ``rewrite int_refl.`` +doesn’t make any progress. So sometimes, trial and error are required to +make progress. + +We might have a lemma or an axiom that we can rewrite to the goal, but +the LHS and RHS might be flipped, and EasyCrypt will complain that they +don’t match to apply them. To rewrite a lemma or axiom in reverse, we +simply add the “-” in front of the lemma to switch the sides like so: + +:: + + lemma int_assoc_rev (x y z: int): x + y + z = x + (y + z). + proof. + rewrite -addzA. + trivial. + qed. + +These tactics form the basics of theorem proving and working with +EasyCrypt at the level of ambient logic. + +A point to note here is that there are many more options and intricacies +even within these simple tactics. For instance, there are many +introduction patterns with the ``move =>`` tactic, and the keyword +``move`` can be replaced by other tactics as well. Presenting these +introduction patterns with good examples could be an important addition +to this chapter on the basic tactics. + +Commands: ``search`` and ``print`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Often when it comes to working with theorems, we need the ability to +search through results that are already in the environment. We saw a few +examples of printing in the content that we have covered so far. Let us +take a slightly more detailed look at this part of EasyCrypt that we use +from time to time. + +The ``print`` command prints out the request in the response pane. We +can print types, modules, operations, lemmas etc., using the print +keyword. Here are some examples: + +:: + + print op (+). + (* Response: abbrev (+) : + int -> int -> int = CoreInt.add. *) + print op min. + (* Response: op min (a b : int) : int + = if a < b then a else b. *) + print axiom Int.fold0. + (* Response: lemma fold0 ['a]: + forall (f : 'a -> 'a) (a : 'a), fold f a 0 = a. *) + +The keywords simply act as qualifiers and filters. You can print even +without those. The qualifiers simply help us to narrow the results. + +The ``search`` command allows us to search for axioms and lemmas +involving a list of operators. It accepts arguments enclosed in the +following braces: 1. ``[ ]`` - Square brackets for unary operators 2. +``( )`` - Rounded brackets for binary operators 3. Combination of these +separated by a space + +:: + + search [-]. + search (+). + (* Shows lemmas and axioms that + include the specified operators. *) + search ( * ). + (* Notice the extra space for the "*" operator. + We need that since (* *) also indicates comments. *) + + search (+) (=) (=>). + (* Shows lemmas and axioms which have + all the listed operators *) + +In the file, we have peppered some exercises that require the reader to +search for specific results to make progress. + +External SMT solvers: ``smt`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +An important point to understand is that EC was built to work with +cryptographic properties and more complex things. So although general +mathematical theorems and claims can be proven in EC, it will be quite +painful to do so. We will employ powerful automated tools to take care +of some of these low-level tactics and logic. EC offers this in the form +of the ``smt`` tactic. When we run ``smt``, EC sends the conclusion and +the context to external smt solvers like ``Z3``, ``Alt-Ergo`` etc., that +have been configured to be used by EasyCrypt. If they can solve the +goal, then ``smt`` will discharge the specific sub-goal that it was +invoked on. If not, ``smt`` fails, and the burden of the proof is still +on us. + +For example, if we wish to prove the result: + +.. math:: \forall x \in \mathbb{R}, \forall a, b \in \mathbb{Z}, \text{ and } x \neq 0 \implies x^a * x^b = x^{a+b} + +We would do it like so: + +:: + + lemma exp_product (x: real) (a b: int): + x <> 0%r + => x^a * x^b = x^(a + b). + proof. + move => x_pos. + rewrite -RField.exprD. + assumption. + trivial. + qed. + +However, it can be simplified to: + +:: + + lemma exp_product_smt (x: real) (a b: int): + x <> 0%r + => x^a * x^b = x^(a + b). + proof. + smt(). + qed. + +The key takeaway is that we will rely on external solvers to do a fair +amount of heavy lifting when it comes to results related to low-level +math. + +That concludes this chapter on ambient logic. In this chapter we covered +the basic tactics like ``apply``, ``simplify``, ``move``, ``rewrite`` +etc, we also saw how to use the ``search`` and ``print`` commands and +learnt to work with external solvers. We have also provided exercises +that help the reader practice using these tactics. We will introduce +more tactics and other techniques as we progress in the subsequent +chapters. diff --git a/doc/tutorials/introduction-itp-program-logics/conclusion.rst b/doc/tutorials/introduction-itp-program-logics/conclusion.rst new file mode 100644 index 0000000000..f6e44abd4e --- /dev/null +++ b/doc/tutorials/introduction-itp-program-logics/conclusion.rst @@ -0,0 +1,16 @@ +Working through the material should give you a basic grasp of how +EasyCrypt works, and the ability to work with some of the tactics. +Admittedly, this work is by no means complete since we barely scratched +the surface of what EasyCrypt is capable of doing and the current state +of the art when it comes to cryptography. + +A good next step if you are interested in learning more about +formalising game-based cryptographic security proofs in EasyCrypt is to +simply follow our main tutorial—referring to this one for concepts or +ideas that may not have been cemented. + +If you already know what you want to formalize, you may also be +interested in the `Crypto Proof +Ladders `__ project created under the +umbrella of the High-Assurance Cryptographic Software (HACS) +`community `__. diff --git a/doc/tutorials/introduction-itp-program-logics/easycrypt.rst b/doc/tutorials/introduction-itp-program-logics/easycrypt.rst new file mode 100644 index 0000000000..cd3ff86a00 --- /dev/null +++ b/doc/tutorials/introduction-itp-program-logics/easycrypt.rst @@ -0,0 +1,362 @@ +As we saw earlier, the security properties of cryptosystems can be +modelled as games being played by challengers (Alice, Bob) and +adversaries (Eve). EasyCrypt is a proof assistant that allows us to +model and verify these game-based cryptographic proofs. + +EasyCrypt environment +--------------------- + +EasyCrypt is written in OCaml and uses many external tools and +libraries. However, the components that we will be interacting with the +most are the following: 1. **Emacs and Proof General**: Emacs is an +open-source text editor, and Proof General is a generic interface for +proof assistants based on Emacs. Together these form the front-end for +working with EasyCrypt. When working with EasyCrypt, we generally prove +statements interactively using the Emacs + Proof General environment. + +:: + + *Note*: EasyCrypt also has a batch processing mode which doesn't need the + Emacs + Proof General front-end and only requires a terminal. However, this + mode is used to check multiple files and not to write proofs. + +2. **External Provers and Why3**: Often called SMT (Satisfiability + Modulo Theory) provers or SMT solvers are powerful tools that try to + solve the problem of satisfiability of a formula given a set of + conditions. With EasyCrypt, there is a possibility to use multiple + external provers like `Alt-Ergo `__, + `Z3 `__ and + `CVC4 `__, and + `Why3 `__ is used as the platform for all the + provers. + + These provers can take care of a lot of the low-level and often + gruelling work of proving some mathematical results, as we will see. + +.. note:: + + Since there are a lot of external dependencies setting up the + environment can be quite time-consuming, and doing it right might + involve quite a bit of choice. If you don’t want to have to make + choices, we offer an opinionated `installation + guide `__. + +Now without delving too much into the theory, let us start with a quick +motivating example. + +Abstract example: IND-RoR game +------------------------------ + +Let us model a game to prove that a cryptographic protocol possesses the +property of ciphertexts being indistinguishable from random. It is often +abbreviated as IND-RoR (Indistinguishability - Real or Random). The +notion of indistinguishability is considered to be one of the most basic +security assurances that are expected from cryptosystems. + +Intuitively, the idea is that if an adversary cannot tell apart an +encrypted message from encrypted randomness, then they can’t obtain any +information from intercepted ciphertexts that they wouldn’t be able to +obtain purely by chance. Hence, the system can be thought to be secure. + +To model it mathematically, let us assume we have a cryptographic +protocol, :math:`CP`, that consists of an encryption function, +:math:`Enc`, and a decryption function, :math:`Dec`, known to the +challengers. The adversary gets access to the output of :math:`Enc`. In +this simplified example, we don’t worry about the specifics of these +functions. + +So the game for IND-RoR under the protocol, :math:`CP`, would proceed as +follows: 1. Pick :math:`b \in \{0,1\}`, uniformly at random. 2. If +:math:`b = 0`, the challengers encrypt a real message using :math:`Enc`. +Let us call it :math:`c_0 = Enc(m_{\textit{real}})` 3. If :math:`b = 1`, +the challengers encrypt a random bitstring using :math:`Enc`. Let us +call it :math:`c_1 = Enc(m_{\textit{random}})` 4. If :math:`b=0`, send +:math:`c_0` to the adversary, else send :math:`c_1` 5. Adversary is +allowed to perform its computations on the provided ciphertext and is +expected to output :math:`b_{\textit{adv}}` 6. Now, the adversary is +said to win the game if they have a non-negligible advantage in +correctly guessing which ciphertext (real or random) they were supplied +with. Mathematically, the adversary wins the game if: + +.. math:: + + \mathbb{P}[b_{adv}==b] + = \dfrac{1}{2} + \epsilon, \text{ where } \epsilon \text{ is non-negligible} + +Now, if we come up with a proof that +:math:`P[b_{adv}==b] = \frac{1}{2} + \epsilon`, where :math:`\epsilon` +is negligible, regardless of what the adversary does, then we can claim +that the protocol is secure under the IND-RoR paradigm. + +Most cryptographic protocols rely on game-based proofs like these to +prove the protocol’s security properties. Our game, although simplified +to a large extent, can already be modelled in EasyCrypt. + +Modelling the IND-RoR game with EasyCrypt +----------------------------------------- + +Let us develop an EasyCrypt `proof +sketch `__ +for the game that we defined above. + +Every EasyCrypt proof consists of the following major steps: + +Defining the objects +~~~~~~~~~~~~~~~~~~~~ + +We first need to establish the context we would like to work in. +EasyCrypt comes with several predefined types, operators and functions, +such as integers, real numbers, etc. Hence we begin by loading +(``require``) and importing (``import``) the theories into the current +environment (files that contain these definitions are called theory +files or just theories) that we need. + +In this example, we will only need the ``Real Bool DBool`` theory files. +``Real`` and ``Bool`` are needed to work with real and boolean types, +and we need the ``DBool`` (boolean distribution) to pick a boolean value +at random. Importing these theories works like so: + +:: + + require import Real Bool DBool. + +Notice how the statement ends with a “.”; this is how statements are +terminated in EasyCrypt. + +In addition to the built-in types, we might need custom data types and +operations. EasyCrypt allows us to do so using the keywords ``type`` and +``op``. + +Let us define a ``msg`` type for messages, and ``cip`` type for +ciphertexts. Then let us define the operation ``enc: msg -> cip`` which +defines a function called ``enc`` mapping ``msg`` to ``cip``, and a +function called ``dec`` to go back from ``cip`` to ``msg``. +Additionally, let us also define a function called ``comp`` to model the +adversary performing some computation upon receiving a ``cip`` and +returning a ``bool``. + +:: + + type msg. + type cip. + + (* Encrypt and decrypt operations. *) + op enc: msg -> cip. + op dec: cip -> msg. + + (* Compute operations for the adversary. *) + op comp: cip -> bool. + +Note that these are only abstract definitions, and we haven’t specified +the details of these types or functions. The interesting thing about +EasyCrypt is that we can already go pretty far with the abstract types +and operations. + +Let us keep going and define custom module types and modules. Module +types can be thought of as blueprints, while modules can be thought of +as concrete instances of module types. For those familiar with +object-oriented programming, this is similar to interfaces for classes +and the classes that implement those interfaces. + +In our example, the challengers have the ability to encrypt and decrypt +messages. We can model this by creating a module type called +``Challenger``, which needs to have two procedures called ``encrypt`` +and ``decrypt``. As we said, a module type is simply a blueprint. To +work with the module types, we could create a concrete instance of the +``Challenger`` type and fill out the procedures. In our example, we +create a module, ``C``, of type ``Challenger``. ``C`` has to implement +the procedures ``encrypt`` and ``decrypt``. This can be achieved like +so. + +:: + + module type Challenger = { + proc encrypt(m:msg): cip + proc decrypt(c:cip): msg + }. + + module C:Challenger = { + proc encrypt(m:msg): cip = { + return enc(m); + } + proc decrypt(c:cip): msg = { + return dec(c); + } + }. + + (* Similarly, we define an adversary *) + module type Adversary = { + proc guess(c:cip): bool + }. + (* and a concrete instance of an adversary *) + module Adv:Adversary = { + proc guess(c:cip): bool = { + return comp(c); + } + }. + +.. note:: + + Module types and modules need to begin with a capital letter. + +We now have all the ingredients required to model the IND-RoR game +outlined above. A game can be defined as a module in EasyCrypt like so: + +:: + + module Game(C:Challenger, Adv:Adversary) = { + proc ind_ror(): bool = { + var m:msg; + var c:cip; + var b,b_adv:bool; + b <$ {0,1}; (* Sample b uniformly at random *) + if(b){ + (* Set m to be an authentic message *) + } else { + (* Set m to be a random string *) + } + c <@ C.encrypt(m); + b_adv <@ Adv.guess(c); + return (b_adv = b); + } + }. + +Here, we leave the ``if`` and ``else`` blocks empty since we don’t want +to introduce too much complexity in this motivating example. + +Making claims +~~~~~~~~~~~~~ + +Once we have the objects defined, we can make claims related to these +objects. We can either state these claims as axioms with the ``axiom`` +keyword, in which case EasyCrypt will not expect a proof or a lemma with +the ``lemma`` keyword, and EasyCrypt will expect a proof for the +statement. For our running example, a claim that we can state is that +the probability of ``(b_adv=b)`` or the result, ``res``, holding is +certainly less than or equal to 1. This statement about the probability +of an event is universally true. Hence we can state it as an axiom like +so: + +``{Stating an axiom}{list:axiom} axiom ind_ror_pr_le1: phoare [Game(C,Adv).ind_ror: true ==> res] <= 1%r.`` + +This code can be read in the following way: We state the axiom, +``ind_ror_pr_le1``, which says that the probability (``phoare``) of the +result (``res``) holding upon running the ``ind_ror`` game with ``C`` +and ``Adv`` is less than or equal to 1. (The trailing ``\%r`` after +``1`` is how we cast an integer to a real number.) + +We will look at the components in more detail as we go along. However, +the key takeaway here is that axioms don’t require proofs. + +Next, let us claim that the cryptosystem is indeed IND-RoR secure. +Statements like these are what we intend to prove and are the main +reason we go through the whole setup. + +.. note:: + + We skip the detail about the negligible advantage and + :math:`\epsilon` since this is only an illustrative example. We’d pay + more attention to the details when we work with an actual protocol. + +:: + + lemma ind_ror_secure: + phoare [Game(C,Adv).ind_ror: true ==> res]<=(1%r/2%r). + +Proofs +~~~~~~ + +Once we state a lemma, EasyCrypt expects a proof for the same. It is +good practice to start a proof script with the ``proof`` keyword, but it +is not strictly necessary. A proof script is a sequence of tactics that +transform the goal into zero or more sub-goals. A proof is said to be +complete or discharged once we get to zero sub-goals. Upon completing a +proof, we end the script with ``qed``, and EasyCrypt adds the lemma to +the environment. + +Since we haven’t filled out the details in our running example, we can’t +really make progress with the proof of ``lemma ind_ror_secure``, so for +this example, we will ``admit`` it. Admitting a result is akin to +axiomatizing it. Ideally, we wouldn’t want to axiomatize a lemma. +However, we use this example to illustrate the structure of EasyCrypt +proofs in general. + +:: + + lemma ind_ror_secure: + phoare [Game(C,Adv).ind_ror: true ==> res]<=(1%r/2%r). + proof. + admit. + qed. + +The complete code of the example can be found in ``abstract-ind-ror.ec`` +file. Most proof scripts are developed interactively. To get a taste of +how this works, you can open ``abstract-ind-ror.ec`` in Emacs. This +should happen automatically if you open any ``.ec`` file. Once you open +the file, you can step through the proof line by line using the +following keystrokes. + +1. Ctrl + c and then Ctrl + n to evaluate one line/block of code +2. Ctrl + c and then Ctrl + u to go back one line/block of code +3. Ctrl + x Ctrl + s to save the file +4. Ctrl + x Ctrl + c to exit Emacs.\* + +.. note:: + + Emacs will prompt you to save the file if you modified it and remind + you that there is an active easycrypt process running. So please pay + attention to the prompts. You need to respond with a “yes” to the + prompt about killing the easycrypt process to exit Emacs. + +These four keybindings should be enough to get you through this file. We +will return to more navigation and other important keybindings in the +next chapter. We include these instructions in the file as well, so you +don’t have to keep switching back and forth. Upon evaluating the first +instructions, the screen should look like so: + +.. figure:: abstract-ind-ror.png + :alt: Working with ``abstract-ind-ror.ec`` + + Working with ``abstract-ind-ror.ec`` + +We will develop the concepts required to work with it in the following +chapters. However, we encourage you to get started working with the tool +and try it out right away. + +Different logics in EasyCrypt +----------------------------- + +Now that we understand that overarching structure of what we can achieve +with EasyCrypt let us get down to the details. + +EasyCrypt allows us to work with mathematical objects and results of +different types. To work with these different results, EasyCrypt has the +following logics: + +1. **Ambient logic**: This is the higher-order logic that allows us to + reason with the proof objects and terms. +2. **Hoare logic and its variants**: + + 1. **Hoare Logic (HL)**: Allows us to reason about a set of + instructions or a single program. + 2. **Relational Hoare Logic (RHL)**: Allows us to reason about a pair + of programs. + 3. **Probabilistic Hoare Logic (pHL)**: When we have a program with + elements of probabilistic behaviour, we need to modify Hoare Logic + to work with the elements of probability. EasyCrypt supports + working with these kinds of programs as well. + 4. **Probabilistic Relational Hoare Logic (pRHL)**: Similarly, pRHL + allows us to reason with pairs of programs with probabilistic + behaviour. + +With these logics, EasyCrypt allows us to verify the security properties +of cryptographic protocols. Most cryptographic proofs are game-based, +implying that we need the ability to work with pairs of programs, as we +saw earlier in the IND-RoR example. This is essentially why we need RHL +and pRHL. + +Apart from these logics, EasyCrypt relies on external SMT solvers to +provide a fair degree of automation. SMT solvers are tools that help to +determine whether a mathematical formula is satisfiable or not. We will +learn to work with these logics and also how to use the external solvers +in the following chapters. diff --git a/doc/tutorials/introduction-itp-program-logics/hoare-logic.ec b/doc/tutorials/introduction-itp-program-logics/hoare-logic.ec new file mode 100644 index 0000000000..d7fbec32d1 --- /dev/null +++ b/doc/tutorials/introduction-itp-program-logics/hoare-logic.ec @@ -0,0 +1,644 @@ +pragma Goals: printall. + +require import AllCore. + +(* +Let us start small and first work with some examples that we saw in the text. +Please pay attention to the syntax of the modules, and capitalization of names. +EasyCrypt (EC) expects the first letters of module names, +and module type names to be capitalized. +*) + +module Func1 = { + proc add_1 (x:int) : int = { return x+1; } + + (* + proc stands for procedure. + Since EC is typed, we are required to mention the + return type of procedures in the definition. + *) + + proc add_2 (x: int) : int = { x<- x + 2; return x; } +}. + +(* +EC allows us to define concretely defined procedures like we did above. +But since we want to model adversaries about whom we know nothing, +we can also define abstract procedures like an eavesdrop procedure. +of an adversary. Like so: +*) +module type Adv = { + proc eavesdrop () : bool +}. + +(* +We don't know what the procedure does, but we do know its return type. +Also notice that now we have a module type and not just a module. +This is because Adv is a type that we will need to instantiate. +We had similar ideas in the abstract-ind-ror.ec +Where the Adversary module type had a "guess" procedure. +We will return to this later when we start working with cryptographic protocols. +But this is an important fact that we need to keep in mind. +*) + +(* +Let us return to hoare triples and take a look at some triples and +try to prove them in EC. +A triple denoted by {P} C {Q} in theory is expressed as +hoare [C : P ==> Q ] in EC, with the usual definitions. +Additionally, the return value of the program C, is stored in a special +keyword called res. +*) + +lemma triple1: hoare [ Func1.add_1 : x = 1 ==> res = 2]. +proof. +(* +When working with hoare logic, or its variants, the goal will be different from +what a goal in ambient logic looks like. We need to start stepping through +the procedure or program that is being reasoned about and change the +preconditions and postconditions according to the axioms and lemmas that we have. +To make progress here, we first need to tell EC what Func1.add_1 is. +The way to do that is by using the "proc" tactic. +It simply fills in the definitions of the procedures that we define. +*) + proc. + +(* +When the goal’s conclusion is a statement judgement whose program is empty, +like we have now the "skip" tactic reduces it to the goal whose conclusion +is the ambient logic formula P => Q, +where P is the original conclusion’s precondition, +and Q is its postcondition. + +Visually, skip works in the following way: + + P => Q + ----------------- skip + {P} skip; {Q} + +skip; denotes an empty program. +While skip next to the line is the tactic itself. +*) + skip. + +(* +Now we are back in familiar territory, except the fact that +we have an interesting "&hr" lurking in the goal. +This refers to the memory in which the program acts. +When we deal with multiple programs, there is a possibility +that the variables come from different memories. So EC provides us +different namespaces to deal with them. +To introduce memory into the context we need to prepend "&" to a variable name. +Like so: +*) + move => &m H1. + + subst. +(* The "subst" tactic simply substitutes variables *) + trivial. +qed. + + +lemma triple2: hoare [ Func1.add_2 : x = 1 ==> res = 3 ]. +proof. + proc. + +(* +Now we have a program which is not empty, +so we can't use the "skip" tactic directly. +Thankfully we learnt about the different axioms in hoare logic. + +When we are faced with +{P} S1; S2; S3; {Q} (with the usual definitions) +applying the "wp" tactic consumes as many ordinary statements as possible from +the end. Then it replaces the postcondition Q, with the weakest precondition R. +R is such that R in conjunction with the consumed statements and the original +post condition hold. It is easier to visualize this in a proof-tree. +For instance, when we have +{P} S1; S2; S3; {Q} and +S2; S3 are statements that can be dealt with some axioms or logical deductions, +then wp does the following: + + -----------------(Other rules) + {P} S1; {R} {R} S2; S3; {Q} + --------------------------------------seq + {P} S1; S2; S3 {Q} + +The triple {R} S2; S3; {Q} is guaranteed to hold, and +hence the goal transforms to +just {P} S1; {R} +*) + +(* +Let us see what happens in our context. +The "wp" tactic consumes the only statement in the program. +In this case an assignment, and replaces the variable like we'd expect. +When we have an empty program, we can simply use the "skip" tactic +and continue with our proof. + + x = 1 => x+2=3 + -------------------------------skip + {x = 1} skip; {x+2=3} + -------------------------------wp + {x = 1} x:= x+2 {x=3} +*) + + wp. + skip. + move => &m x. + subst. + trivial. +qed. + +(* +Let us define some more simple functions and hoare triples to work with. +*) +module Func2 = { + proc x_sq (x:int) : int = { return x*x; } + proc x_0 (x:int) : int = { x <- x*x; x<- x-x; return x; } + proc x_15 (x:int) : int = { x <- 15; return x; } +}. + +(* +Exercises: +Define a few triples relating the behaviour of these functions. +For instance try to define the following triples and prove them: +1. {x = 2} Func2.x_sq {res = 4} +2. {x = 10} Func2.x_0 {res = 0} +3. {true} Func2.x_15 {res = 15} +*) + +(* Using some automation *) + +(* +We generally don't want to be dealing with the low-level proofs, +so we will be combining Hoare logic with the external solvers +that we saw earlier. One thing to remember is that the external +solvers work only with ambient logic goals. +So we need to get the goals state to something that the smt solvers +can work with. +*) + +lemma triple3: hoare [ Func2.x_sq : 4 <= x ==> 16 <= res ]. +proof. +proc. +skip. +move => &m H1. +(* +Here this conclusion is trivial for us to understand and prove on paper +however it can be quite hard to do with EC, so we will simply outsource it to smt. +The external provers are quite powerful, and can make our life easier. +*) +smt. +qed. + +(* +Now let us look at the special cases that we had in the text. +Namely: {true} C {Q}, and {false} C {Q}. +*) +lemma triple4: hoare [ Func2.x_0 : true ==> res=0 ]. +proof. +proc. +wp. +skip. +move => &m T x. +by simplify. +(* Prepending the "by" keyword to a tactic +tries to close the goals by applying trivial +to the result of the tactic, and fails if the goal can't be closed *) +qed. + +(* +"by" is called a tactical. Tacticals are commands that can work with +other tactics. We will see more later. +*) + +(* +So far so good, that was pretty much what we expected. +However let us take a look at the next lemma. Now we are looking at the triple: +{false} x:=15 {x = 0}. +This shouldn't hold, but watch what happens. +*) + +lemma triple5: hoare [ Func2.x_15 : false ==> res=0 ]. +proof. +proc. +wp. +skip. +move => _ f. + +(* +The underscore essentially is a pattern for introduction +which tells EC to ignore whatever is in that position. +Here since we have a "forall _" in the goal already, we tell EC to ignore it. +You could also use a "?", to let EC decide what to call the variable being moved +to the assumptions. +*) + +(* +Pause here for a moment and ponder about what the goal currently says. +It says that assuming that "false" holds, we want to prove that 15 = 0. +As absurd as it is, we know that "false" is the strongest statement there is. +And we have arrived at a state where "false" holds. +This would imply that anything and everything can be derived from false. +Hence we can actually "prove" that 15 = 0. +*) +trivial. +qed. + +(* +The point to understand here is that we could only do this +because we moved "false" into the context manually when we used the "move" tactic. +So our math is still consistent and the world hasn't exploded yet. +The way to think about this triple is assuming "false" holds implies that 15 = 0. +*) + + +(* +Let us now work with some more interesting functions and triples. +The flipper function simply returns the opposite of the boolean +value that it gets. +*) + +module Flip = { + +proc flipper (x: bool) : bool = + { + var r: bool; + if (x = true) + { r <- false; } + else + { r <- true; } + return r; + } +}. + +lemma flipper_correct_t: hoare [ Flip.flipper : x = true ==> res = false ]. +proof. + proc. + (* + When the first statement of the program is an if condition, we can use the + "if" tactic to branch into two different goals with appropriate truth values for + the if condition. + In our case, the goal branches into x = true, and x <> true based, and these + conditions are added to the preconditions. + *) + if. + (*Goal 1: x = true *) + auto. + + (* + If the current goal is a HL, pHL, pRHL statement the "auto" tactic + uses various program logic tactics in an attempt to reduce the goal + to a simpler one. It never fails, but may fail to make any progress. + In this usage, it replaces "wp. skip. and trivial." + *) + + (* Goal 2: x <> true. + Yields a contradiction in the assumptions. + Since our precondition states that x = true /\ x <> true + We will use some automation to deal with it. + *) + auto. + smt. +qed. + +(* +Notice the repetition of proof steps in the branches. +This can be reduced by using tacticals. +In order to tell EC to repeatedly use certain tactics on all +resulting goals, we use the ";" tactical. +So, we can simplify the above proof like so: +*) + +lemma flipper_correct_f: hoare [ Flip.flipper : x = false ==> res = true ]. +proof. + proc. + if; auto; smt. +qed. + +(* +However, since this program is quite simple we can actually make the proof +shorter. We can also make the logic more abstract like so. Please note how we do this, +since we will use it again. +*) + +lemma flipper_correct (x0:bool): + hoare [ Flip.flipper : x = x0 ==> res <> x0 ]. +proof. + proc. + auto. + smt. +qed. + +(* +This is how proofs are polished and made shorter. We first write a verbose proof, +then keep experimenting to find shorter and more elegant proofs. +*) + +(* +Let us define the exponentiation function that we saw in the text. +*) + +module Exp = { + proc exp (x n: int) : int = + { + var r, i; + r <- 1; + i <- 0; + while (i < n){ + r <- r*x; + i <- i+1; + } + return r; + } +}. + + +(* +Let us formulate a hoare triple that says that exp(10, 2) = 100. +The triple would be: +{x = 10 /\ n=2} Exp.exp {res=100} +and in EC, we would write it like so. +*) + +lemma ten_to_two: hoare [ Exp.exp : x = 10 /\ n = 2 ==> res = 100 ]. +proof. + proc. + +(* +When working with tuples EC has the syntax of using backticks (`) to address the tuple. +So (x,n).`1 refers to x. +Often the output from EC can be quite hard to read, simplifying it can sometimes help. +*) + simplify. + +(* +Now we want to reason with a while loop in the program. +Thankfully, we can see that the loop only runs twice, since n=2. +To get a feel of how the program runs we can step through a loop +using the "unroll" tactic. We need to mention the line number of the +program where we want the tactic to apply. Like so: +*) + unroll 3. + unroll 4. + +(* +At this point, we now have two if conditions which we know will hold, +and a while loop for which the condition will not hold. To reason with +loops and conditions like these EC provides two tactics +rcondt, and rcondf. +You can read them as: remove condition with a true/false assignment. +Since here we know that the condition will evaluate to false, we will use the +rcondf version. +*) + + rcondf 5. +(* +Notice how the postcondition now requires the condition for the while loop +to be false. +Since it would evaluate to false, EC gets rid of the loop. +Now we can either use the if tactic that we used earlier to work with the +if conditions here, but wp is generally strong enough to reason with if conditions. +So let us make our lives a little easier and use that instead. +Here, since the program is quite simple, the smt solvers can complete the proof. +However, pay attention to how hard it gets to read the output +after the application of wp, and skip. +*) + wp. + skip. + smt. + +(* +Goal #2: +Again, we have two "if" conditions, that we need to work with. +The proof proceeds the same way as before. wp is strong enough to reason with it. +*) + + wp. + skip. + smt. +qed. + +(* +As usual we could have used some tacticals to shorten the proof. +So let us do that, to clean up the previous proof. +*) + +lemma ten_to_two_clean: hoare [ Exp.exp : x = 10 /\ n = 2 ==> res = 100 ]. +proof. + proc. + unroll 3. + unroll 4. + rcondf 5; auto. +qed. + +(* +For a loop that unrolls twice it is easy to do it manually. +However, this strategy wouldn't work for a different scenario. +For instance in order to prove that the program works correctly we need to prove +the correctness for every number, so we would prefer to work with abstract symbols +and not concrete numbers like 10^2. +In order to work up to it, let us prove that 2^10 works as intended. +But first, we need to understand that EC was not built for computations. +It can handle small calculations like we've seen so far but asking EC to do 2^10 +doesn't work as we'd like it to. +For instance, take a look at the following lemma, and our attempt to prove it. +*) + +lemma twototen: 2^10 = 1024. +proof. + trivial. + simplify. + auto. +(* +None of those tactics do anything +Even smt doesn't work. +You can try it as well. +Again, the point here is that, these kinds of tasks aren't what EC was +built for. +For the time being we will admit this lemma, since we know that +2^10 is in fact 1024. +We need this to prove the next few lemmas relating to hoare triples. +*) + admit. +qed. + +lemma two_to_ten: hoare [ Exp.exp : x = 2 /\ n = 10 ==> res = 1024 ]. +proof. + proc. + simplify. +(* +To get rid of the loop, we need to understand the behavior of the program, and +figure out a loop invariant. This is because we have the tactic: +"while I" +Where "I" is the loop invariant, that holds before and after the loop. +This essentially means thinking about what the loop actually does, +and the conditions that hold before and after the execution of the loop. +We want the invariant to help us prove the goal that we have. +Which is r = 1024. Let us try to see how we can get there. +Let us start small and say that we know that (x = 2) holds before +and after the execution of the loop. +*) + while ( x = 2 ). +(* +Observe how the goals have changed. +In Goal #1, the invariant that we propose is in both the pre and post conditions. +The burden of the proof still lies on us however. Of course, since we don't +change x, this should hold quite naturally. And we can discharge Goal #1 quite +easily. +*) + wp. + auto. + +(* +Now let us pay attention to what we have left. +The second part of the postcondition says +forall (i0, r0 : int), +given that i0 is greater than or equal to n, and x = 2 +then r0 = 1024. +That is clearly incorrect, since r0 isn't bound or related to x or i0. +You are welcome to experiment and try to see how far you can get in +the proof. However in our attempt, the goal simply becomes harder to read. +Using wp, and skip introduces memory into the context making it quite difficult to +read. We will "abort" this attempt here, and try to think of a stronger invariant. +*) +abort. + +lemma two_to_ten: hoare [ Exp.exp : x = 2 /\ n = 10 ==> res = 1024 ]. +proof. + proc. + +(* +As an additional invariant, we know that the loop runs until our +loop variable i goes from 0, to n. So as an invariant, we have +0 <= i <= n, and the control exits the loop when ! (i < n). +Let us try to see what happens if we add this in. +*) + while ( x = 2 /\ 0 <= i <= n). + wp. + auto. + smt. + +(* +Let us read what the goal says now. +Again it says something about r0 without bounding what r0 can be. +This attempt will also fail. +So we need to understand what happens to the variable r0, at the end of every +iteration of the loop. +*) +abort. + + +lemma two_to_ten: hoare [ Exp.exp : x = 2 /\ n = 10 ==> res = 1024 ]. +proof. + proc. +(* +We know that after every iteration, the variable r is multiplied by x. +So in this case, since we have x = 2, essentially at the end of +i iterations of the loop we have the fact that r = 2^i. +This is an invariant, and it binds r to the variables that are passed to the +loop. Let us see if this attempt works. +*) + while (x = 2 /\ 0 <= i <= n /\ r = 2^i). + +(* +Again, Goal #1 will go through quite easily. +*) + wp. + skip. + smt. + +(* Goal #2 *) + wp. + simplify. + auto. +(* +When the goal is too complicated to read, we can apply the tactic "progress". +"progress" breaks the goals into simpler ones by repeatedly applying the +"split", "subst" and "move =>" tactics and trying to solve trivial goals automatically. +*) + progress. + +(* 2 ^ 0 = 1 *) + smt. + +(* 2^10 = 1024 *) + smt. +qed. + +(* +A point to note here: +Had we not admitted the lemma twototen the proof would get stuck +You are welcome to comment it out and try the proof again. +*) + +(* +So finally, we have an invariant that works. +Let us clean up the proof, and also if we think about it, +the condition (x=2) isn't really needed, since the program never +modifies the value of x. So let us get rid of that condition as well. +*) + +lemma two_to_ten_clean: hoare [ Exp.exp : x = 2 /\ n = 10 ==> res = 1024 ]. +proof. + proc. + simplify. + while ( r = x^i /\ 0 <= i <= n); auto; smt. +qed. + +(* +Now the proof seems so innocuous and straightforward. +However, it is important to understand that these proofs and +figuring out the loop invariants always take a few tries, and +sometimes crafting the right invariant can be an art by itself. +This also gets quite hard when there are a lot of variables +to keep track of. So it is good practice to work with smaller examples first. +*) + + +(* +Now let us try to work with abstract symbols, the stuff that EC +was actually built for. Here we mentioned in the text, in order to claim +that the exp function is correct, we need to have the condition that +the exponent that we provide is greater than zero. +We use x0, and n0, in order to differentiate from the program variables. +*) +lemma x0_to_n0_correct (x0 n0: int): + 0 <= n0 => + hoare [ Exp.exp : x = x0 /\ n = n0 ==> res = x0 ^ n0 ]. +proof. + move => Hn0. + proc. + while (r=x^i /\ 0 <= i <= n). + wp. + skip. + smt. + + wp. + skip. + progress. + smt. + smt. +qed. + + +(* +Again, we can clean up the proof like so: +Notice that we omit the type declaration of x0 and n0, +since EasyCrypt can figure it out by itself. +*) +lemma x0_to_n0_correct_clean x0 n0: + 0 <= n0 => + hoare [ Exp.exp : x = x0 /\ n = n0 ==> res = x0 ^ n0 ]. +proof. + move => Hn0. + proc. + while (r=x^i /\ 0 <= i <= n); auto; smt. +qed. + +(* +As an exercise, you can do similar proofs for the following mathematical functions: +1. A program to decide if a given number is even or odd. +2. A program to compute the factorial of a given number. +*) diff --git a/doc/tutorials/introduction-itp-program-logics/hoare-logic.rst b/doc/tutorials/introduction-itp-program-logics/hoare-logic.rst new file mode 100644 index 0000000000..2434c8897a --- /dev/null +++ b/doc/tutorials/introduction-itp-program-logics/hoare-logic.rst @@ -0,0 +1,806 @@ +Working through the chapter on ambient logic should give you a good +grasp of the ambient logic and tactics for reasoning with simple math. +Up until now, we were working with mathematical proofs that only used +logical reasoning. However, when working with programs and procedures we +need a way to reason with what the programs do. + +For instance, let us think about an exponentiation program for integers +like so: + +:: + + exp(x, n): + r = 1 + i = 0 + while (i < n): + r = r * x + i = i + 1 + return r + +When presented with a program like this, our objective is to figure out +if the program behaves correctly. At first glance, this program seems +correct. However, a glaring mistake here is that the program will always +return :math:`1` as a result if we pass any negative integer as the +second argument. That isn’t the behaviour we expect from an +exponentiation function. So saying that the program is correct would be +a false claim. So to make claims about the behaviour of the program, +mathematically, we would say something like: + +.. math:: \text{Given } \underbrace{x \in \mathbb{Z}, n \in \mathbb{Z} \text{ and } n \ge 0 }_a \ \ \ \underbrace{exp(x, n)}_b \text{ returns } \underbrace{r = x ^{n}}_c + +.. math:: \text{Where } a \text{ is the precondition}, b \text{ is the program}, c \text{ is the postcondition} + +The Hoare triple +---------------- + +As marked in the statement above, claims that we make generally have +three distinct parts: preconditions, the program and postconditions. +Hoare logic formalises these three parts and introduces them as a +**Hoare triple**. + +A Hoare triple is denoted like so: + +.. math:: \{ P \} \ C \ \{ Q \} + +Here :math:`P,Q`, are conditions on the program variables used in +:math:`C`. Conditions on program variables are written using standard +mathematical notations together with logical operators like +:math:`\wedge` (‘and’), :math:`\vee` (‘or’), :math:`\neg` (‘not’) and +:math:`\implies` (‘implies’). Additionally, we have special conditions +:math:`true` or :math:`T` which always holds, and :math:`false` or +:math:`F` which never holds. + +:math:`C` is a program in some specified language. + +We say that a Hoare triple, :math:`\{P\} \ C \ \{Q\}`, holds if whenever +:math:`C` is executed from a state satisfying :math:`P` and if the +execution of :math:`C` terminates, then the state in which :math:`C`\ ’s +execution terminates satisfies :math:`Q`. We will limit our discussion +to programs which terminate. + +Examples +~~~~~~~~ + +1. :math:`\{ x = n \} \ x:= x+1 \ \{ x = n+1 \}` holds. ( :math:`:=` is + the assignment operator) +2. :math:`\{ x = n \} \ x:= x+1 \ \{ x = n+ 2 \}` doesn’t hold. +3. :math:`\{ true \} \ C \ \{ Q \}` is a triple in which the + precondition always holds. So we’d say that this triple holds for + every :math:`C` that satisfies the postcondition :math:`Q`. +4. :math:`\{ P \} \ C \ \{ true \}`, similarly, this triple holds for + every precondition :math:`P` that is satisfied, and every program + :math:`C`. +5. :math:`\{ false \} \ C \ \{ Q \}`, is an interesting triple which, + according to our definitions, doesn’t hold since false is a statement + that never holds. However, this is a slightly special case, as we + will see in EasyCrypt. + +Exercises +~~~~~~~~~ + +1. Does :math:`\{ x=1 \} \ x:=x+2 \ \{ x=3 \}` hold? +2. How about :math:`\{ true \} \ exp(x,a) \ \{ r=x^a \}`? Why? +3. What about :math:`\{ 2=3 \} \ x:=1 \ \{ x=1 \}`? + +Strength of statements +---------------------- + +Informally, if a statement can be deduced from another, then the +statement that was deduced is a weaker statement. + +Mathematically if we have :math:`P \implies Q`, we say that :math:`P` is +a stronger statement than :math:`Q`. + +For example, + +.. math:: x = 5 \implies x \ge 5 + +.. math:: x = 5 \text{ is a stronger statement than } x \ge 5 + +As discussed earlier, we have two special statements, :math:`true`, +which always holds, and :math:`false`, which never holds. These are the +weakest and the strongest statements there are, respectively. + +Since any statement that holds can imply that :math:`true` holds. The +reason is that it always holds, :math:`true` is the weakest statement +there is. + +Similarly, :math:`false` never holds. So, no statement can imply +:math:`false`; hence, it is the strongest statement there is. + +Proof trees +----------- + +So far, we looked at Hoare triples for simple statements, these can be +thought of “programs” with a single instruction as well. However, we +need to be able to work with multiple statements and more complex +statements. We achieve this by formalizing a set of axioms that we +believe to be true, and then we combine these axioms to make claims +about complex statements. We often visualize these series of steps in +which we put the axioms together into *schemas* or *proof trees*. + +For example: For a statement :math:`S`, we say it is or provable by +denoting it with a turnstile (:math:`\vdash`) symbol like so +:math:`\vdash S`, and its proof can be denoted by: + +.. math:: \dfrac{\vdash S_1, \vdash S_2, \dots ,\vdash S_n}{\vdash S} + +This says the conclusion :math:`S` may be deduced from the +:math:`S_1, \dots, S_n` which are the hypotheses of the rule. The +hypotheses can either all be theorems or axioms of Hoare Logic or +mathematics. + +Now, we will take a look at some of the axioms of Hoare logic with +examples to give you a flavour of how they work. One of the reasons we +cover these is because these axioms form the basis for the tactics we +use in Hoare logic in EasyCrypt. Of course, the main idea is to +familiarize the reader with the basics since the main goal is for the +machine to take care of the specifics. + +Axioms of Hoare logic +--------------------- + +1. **Assignment**: + + .. math:: \vdash \{P[E/V ]\} \ V :=E \ \{P\} + + Where :math:`V` is any variable, :math:`E` is any expression, + :math:`P` is any statement, and the notation :math:`P[E/V]` denotes + the result of substituting the term :math:`E` for all occurrences of + the variable :math:`V` in the statement :math:`P`. + + Example: :math:`\vdash \{ y = 5 \} \, x := 5 \,\{ y = x \}` + +2. **Precondition strengthening**: When we have a Hoare triple + :math:`\{ P ' \}\ C \ \{ Q \}`, where :math:`P'` is a statement that + follows from a stronger statement, :math:`P`. Then we can say, + + .. math:: \dfrac{\vdash P \implies P', \vdash \{P'\}\ C \ \{Q\}} {\vdash \{P\} \ C \ \{Q\}} + + Example: Let + + .. math:: C = [x:=x+2] + + .. math:: P = \{x = 5\} + + .. math:: P' = \{x \ge 5\} \text{ , and} + + .. math:: Q = \{x \ge 7\} + + Using the precondition strengthening axiom we have, + + .. math:: \dfrac{\vdash \{x = 5\} \implies \{x \ge 5\} ,\ \vdash \{x \ge 5\} \ x:=x+2 \ \{x \ge 7\} } {\vdash \{x=5\} \ x:= x + 2 \ \{x \ge 7\}} + +3. **Postcondition weakening**: Similarly, when we have a Hoare triple + :math:`\{P\}\, + C \,\{Q'\}`, where :math:`Q'` is a strong statement, and if :math:`Q` + follows from :math:`Q'`. Then we can say, + + .. math:: \dfrac{\vdash \{P\}\ C \ \{Q'\}, \ \vdash Q' \implies Q}{ \vdash \{P\} \ C \ \{Q\}} + + Example: Let + + .. math:: C = [x:=x+2] + + .. math:: P = \{x = 5\} + + .. math:: Q' = \{x = 7\} \text{ , and} + + .. math:: Q = \{x \ge 7\} + + With the postcondition weakening axiom, we have, + + .. math:: \dfrac{\vdash \{x = 5\}\ x:=x+2 \ \{x =7\}, \ \vdash x = 7 \implies x \ge 7 } {\vdash \{x=5\} \ x:= x + 2 \ \{x \ge 7\}} + + Together the precondition strengthening and postcondition weakening + axioms are known as the + + .. math:: \textbf{consequence rules} + + . + +4. **Sequencing**: For two programs :math:`C_1, C_2`, we have + + .. math:: \dfrac{ \vdash \{P\}\ C_1 \ \{Q'\}, \ \vdash \{Q'\}\ C_2 \ \{Q\}, }{ \vdash \{P\}\ C_1;C_2 \ \{Q\} } + + Example: Let + + .. math:: C_1 = [x:=x+2] + + .. math:: C_2 = [x:=x*2] + + .. math:: P = \{x = 5\} + + .. math:: Q' = \{x = 7\} \text{ , and} + + .. math:: Q = \{x = 14\} + + Using the sequencing axiom, we have, + + .. math:: \dfrac{ \vdash \{x = 5\} \ x:=x+2 \ \{x =7\}, \ \vdash \{x = 7\}\ x:=x * 2 ,\{x =14\} } {\vdash \{x=5\} \ x:= x + 2, x:= x * 2 \ \{x =14\}} + +We go through these examples to get a sense of what formal proof trees +look like and the theory that formal verification is based on. The proof +trees that we’ve used are already simplified to exclude the assignment +axiom and steps that we as humans can easily understand and gloss over. +Proof trees get quite large and unwieldy as soon as we do anything +non-trivial. This is exactly where formal verification tools come into +the picture. So, let us now switch to EasyCrypt and work with Hoare +triples. + +Hoare logic has been studied quite extensively, and there are plenty of +good textbooks (`Textbook 1 `__, +`Texbook +2 `__) +that one can refer to for mathematical rigour and completeness. The +objective here is to give the reader an intuitive understanding of the +math, and enough working knowledge required to work with EasyCrypt. + +HL in EasyCrypt +--------------- + +With a basic understanding of HL, we can now proceed to work with it in +EasyCrypt. We will work through the file +```hoare-logic.ec`` `__. +As before, it is recommended to work with the file in the Proof General ++ Emacs environment. However, reading through this section provides the +basic ideas developed in the practice file. + +Basic Hoare triples +~~~~~~~~~~~~~~~~~~~ + +Let us start small and first work with some examples that we saw +earlier. We first define a module to define two procedures for the +programs. + +:: + + module Func1 = { + proc add_1 (x:int) : int = { return x+1; } + proc add_2 (x: int) : int = { x <- x + 2; return x; } + }. + +A Hoare triple denoted by :math:`\{P\} \ C\ \{Q\}` in theory is +expressed as ``hoare [C : P ==> Q ]`` in EasyCrypt, with the usual +definitions. Additionally, the return value of the program, :math:`C`, +is stored in a special keyword called ``res``. + +So the triple, :math:`\{x=1 \} \ \text{Func1.add}\_\text{1} +\ \{x=2\}`, would be expressed in EasyCrypt like so: + +:: + + lemma triple1: hoare [ Func1.add_1 : x = 1 ==> res = 2]. + +When working with Hoare logic or its variants, the goal will be +different from what a goal in ambient logic looks like. For instance, +evaluating the ``lemma triple1`` produces the following goal. + +:: + + Current goal + Type variables: + --------------------------------------------- + pre = x = 1 + + Func1.add_1 + + post = res = 2 + +We need to start stepping through the procedure or program that is being +reasoned about and change the preconditions and postconditions according +to axioms and lemmas that we have. + +To make progress here, we first need to tell EasyCrypt what +``Func1.add_1`` is. The way to do that is by using the ``proc`` tactic. +It simply fills in the definitions of the procedures that we define. +Since ``Func1.add_1`` is made up of only a return statement, ``proc`` +replaces ``res`` with the return value. This leaves us with an empty +program. This is what we want to work towards; using different tactics +we would like to change the preconditions and postconditions depending +on what the programs that we are reasoning with do. Once we have +consumed all the program statements, we can transform the goal from a HL +goal to a goal in ambient logic using the ``skip`` tactic. ``skip`` does +the following: + +.. math:: \dfrac{ P \implies Q}{\{P\} \text{ skip; } \{Q\}}\texttt{skip} + +.. math:: \text{skip;} + +\ signifies an empty program, while + +.. math:: \texttt{skip} + +is the tactic itself. + +This puts us back in the familiar territory of ambient logic, and we can +use all the tactics that we learnt in ``ambient-logic.ec``. The only +difference is that transitioning a goal from Hoare logic to ambient +logic introduces some qualifiers about the memory that the program works +on. Hence, we need to handle those as well. In this example, the goal +after evaluating ``skip`` will simply read: +``forall &hr, x{hr} = 1 => x{hr} + 1 = 2``. The proof for which follows +pretty trivially. The only difference is that we need to move the memory +into the assumption by prepending the & character in the ``move =>`` +tactic. + +So the full proof for this simple example looks like so: + +:: + + lemma triple1: hoare [ Func1.add_1 : x = 1 ==> res = 2]. + proof. + proc. + skip. + move => &m H1. (* &m moves memory to the assumption *) + subst. (* Substitutes variables from the assumptions *) + trivial. + qed. + +Now let us work with a program where the body is not empty. + +:: + + lemma triple2: hoare [ Func1.add_2 : x = 1 ==> res = 3 ]. + +Using ``proc`` produces the following goal. + +:: + + Current goal + Type variables: + --------------------------------------------- + Context : Func1.add_2 + + pre = x = 1 + + (1) x <- x + 2 + + post = x = 3 + +When we are faced with :math:`\\{P\\} S1; S2; S3; \\{Q\\}` with the +usual definitions, applying the ``wp`` tactic consumes as many ordinary +statements as possible from the end. Then it replaces the postcondition +:math:`Q`, with a precondition :math:`R`. :math:`R` is chosen such that +it holds in conjunction with the consumed statements and the original +postcondition and it is as weak as possible (*w*\ eakest +*p*\ recondition). It is easier to visualize this in a proof tree. + +For instance, when we have :math:`\{P\} S1; S2; S3; \{Q\}` and +:math:`S2; S3;` are statements that can be dealt with some axioms or +logical deductions, then ``wp`` does the following: + +.. math:: \dfrac{\{P\} S1; \{R\} \ \ \dfrac{...}{\{R\} S2; S3; \{Q\}}\text{\tiny{(Other rules)}}}{\{P\} S1; S2; S3; \{Q\}}\texttt{seq} + +The judgement :math:`\{R\} S2; S3; \{Q\}` is guaranteed to hold, and +hence the goal transforms to just :math:`\{P\} S1; \{R\}`. + +In our context, ``wp`` consumes the only instruction that we have in the +program and produces the judgement +:math:`\{x = 1\} \ \text{skip;} \ \{x+2=3\}` to which we apply ``skip``. +This gives us the following proof-tree: + +.. math:: \dfrac{x = 1 \implies x+2=3}{ \dfrac{ \{x = 1\} \ \text{skip;} \ \{x+2=3\} }{ \{x = 1\} \ x:= x+2 \ \{x=3\} }\texttt{wp}}\texttt{skip} + +Putting us back in familiar territory, and the proof follows quite +easily. + +:: + + lemma triple2: hoare [ Func1.add_2 : x = 1 ==> res = 3 ]. + proof. + proc. + wp. + skip. + move => &m x. + subst. + trivial. + qed. + +Automation, and special cases +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Now that we have an understanding of how we can make progress, let us +take a look at how we can use automation since we still have powerful +external solvers at our disposal and we would like to use them whenever +we can. We will be working with the following procedures in this +section. + +:: + + module Func2 = { + proc x_sq (x:int) : int = { return x*x; } + proc x_0 (x:int) : int = { x <- x*x; x <- x-x; return x; } + proc x_15 (x:int) : int = { x <- 15; return x; } + }. + +For instance, let us take a look at a triple, which states that if you +square any integer greater than or equal to 4, the result is greater +than or equal to 16. Pretty trivial and straightforward when you think +about it. However, the proof for something simple like this becomes +quite tiresome, hence we will simply ask ``smt`` to handle it. The only +issue however is that smt solvers can only work on goals in ambient +logic. So it is up to us to bring the goal to a state that doesn’t +involve Hoare logic. In this example, since ``x_sq`` consists of a +single ``return`` statement, ``proc`` and ``skip`` are enough. + +:: + + lemma triple3: hoare [ Func2.x_sq : 4 <= x ==> 16 <= res ]. + proof. + proc. + skip. + smt(). + qed. + +Let us now look at the triple +:math:`\{\text{false}\} \ x:=15 \ \{x = 0\}.` + +Theoretically, we know that this triple doesn’t hold, since ``false`` +never holds. We have the ``proc x_15`` in the ``module Func2`` that we +can use to express that triple in EasyCrypt. The interesting thing is +that we can actually write proof for the triple in question. + +:: + + lemma triple4: hoare [ Func2.x_15 : false ==> res=0 ]. + proof. + proc. + wp. + skip. + move => _ f. + trivial. + qed. + +The reason we can do this is that we essentially force the assumption +that ``false`` holds and we want to prove the postcondition +:math:`15 = 0`. As absurd as it is, we know that ``false`` is the +strongest statement there is. By getting EasyCrypt to the state where +``false`` holds would imply that anything and everything can be derived +from it. Hence we can actually “prove” that :math:`15 = 0`. + +The point to understand here is that we could only do this because we +moved ``false`` into the context manually when we used the ``move =>``. +So our math is still consistent and the world hasn’t exploded yet. The +way to think about this triple is assuming ``false`` holds implies that +:math:`15 = 0`. + +Conditionals and loops +~~~~~~~~~~~~~~~~~~~~~~ + +Let us now work with some more interesting functions and triples. We +define a flipper function which simply returns the opposite of the +boolean value that it gets. + +:: + + module Flip = { + + proc flipper (x: bool) : bool = + { + var r: bool; + if (x) + { r <- false; } + else + { r <- true; } + return r; + } + }. + +Let us say that we would like to prove the fact related to this program, +that if the input is :math:`\{\text{true}\}`, +:math:`\texttt{Flip.flipper}` returns :math:`\{\text{false}\}`. + +We use a slightly verbose proof here to demonstrate how to open up an +``if`` block. Using the ``if`` tactic in the proof script gives us two +goals, one in which the ``if`` condition holds, and another in which it +doesn’t. In our case, it splits into one goal with ``x = true``, and +another with ``x <> true``. Additionally, when the current goal is a HL, +pHL, pRHL statement the ``auto`` tactic uses various tactics in an +attempt to reduce the goal to a simpler one automatically. It never +fails, but it may fail to make any progress. For instance, in this first +usage of the tactic, it does the job of the ``wp, skip, and trivial`` +tactics. + +:: + + lemma flipper_correct_t: + hoare [ Flip.flipper : x = true ==> res = false ]. + proof. + proc. + if. + (* Goal 1: x = true *) + auto. + + (* Goal 2: x <> true. *) + auto. + smt. + qed. + +Notice the repetition of proof steps in the branches. This can be +reduced by using tacticals. In order to tell EasyCrypt to repeatedly use +certain tactics on all resulting goals, we use the “;” tactical. So, we +can simplify the above proof like so + +:: + + lemma flipper_correct_f: + hoare [ Flip.flipper : x = false ==> res = true ]. + proof. + proc. + if; auto; smt. + qed. + +However, since this program is quite simple we can actually make the +proof shorter. We can also make the logic more abstract like so: + +:: + + lemma flipper_correct (x0: bool): + hoare [ Flip.flipper : x = x0 ==> res <> x0 ]. + proof. + proc. + auto. + smt. + qed. + +This is how proofs are polished and made shorter. We first write a +verbose proof, then keep experimenting to find shorter and more elegant +proofs. + +Let us now increase the difficulty and work with a slightly more +involved example. We define the exponentiation function that we saw +earlier in EasyCrypt. + +:: + + module Exp = { + proc exp (x n: int) : int = + { + var r, i; + r <- 1; + i <- 0; + while (i < n){ + r <- r*x; + i <- i+1; + } + return r; + } + }. + +Let us formulate a Hoare triple that says that ``exp(10, 2) = 100``, +since of course :math:`10^2 = 100`. + +We would have the triple + +.. math:: \{x = 10 \wedge n=2 \}\ \text{Exp.exp}\ \{\text{res}=100\} + +. In EasyCrypt we would state the lemma like we have done earlier. For +the proof, we will employ loop unrolling. We adopt this method since we +know that the while loop will be executed twice, and we can work through +those manually. To unroll a loop with ``unroll n``, where ``n`` is the +line of code with the loop statement, a ``while`` loop in our case. With +the loops unrolled, we get two if conditions which we know will hold, +and a while loop for which the condition will not hold. To reason with +loops and conditions like these EasyCrypt provides two tactics +``rcondt``, and ``rcondf``. They can be read as “remove the condition +with a true/false assignment”. We will use the ``rcondf`` version. This +forces us to prove that the boolean in the ``while`` block, ``(i res = 100 ]. + proof. + proc. + simplify. (* Makes the goal more readable *) + unroll 3. + unroll 4. + rcondf 5. + (* post = !(i res = 100 ]. + proof. + proc. + unroll 3. + unroll 4. + rcondf 5; auto. + qed. + +For a loop that unrolls twice, it is easy to do it manually. However, +this strategy wouldn’t work for a different scenario. For instance, in +order to prove that the program works correctly, we need to prove the +correctness for every number, so we would prefer to work with abstract +symbols and not concrete numbers like :math:`10^2`. In order to work up +to it, let us try to prove that :math:`2^{10}` works as intended. But +first, we need to understand that EasyCrypt was not built for +computations. It can handle small calculations like we’ve seen so far +but asking EasyCrypt to do :math:`2^{10}` doesn’t work as we’d like it +to. For instance, take a look at the following lemma, and our attempt to +prove it. + +:: + + lemma twototen: 2^10 = 1024. + proof. + (* We can't make any progress with these. *) + trivial. + simplify. + auto. + (* + smt fails as well, we will admit this result, + since we know it is true. + *) + admit. + qed. + +Again, the point here is that EasyCrypt wasn’t built for tasks like +these. For the time being, we will admit this lemma, since we know that +:math:`2^{10}` is in fact 1024. We need this to prove the next few +lemmas relating to Hoare triples. + +At this point, we’d like to prove that ``exp(2,10)`` works as expected, +however, we can’t do so with direct computation since it would be +painful and also not the purpose of using EasyCrypt, so to reason with +loops, we need to be able to think of loop invariants and think about +the program variables which change. For instance, we know that the +variable ``x`` remains the same throughout the computation. So let us +try to get rid of the ``while`` loop stating that this is the only +invariant. We know that this is obviously not enough, since doing this +will in a sense forget about what happens to the other variables. +However, examples that get stuck are instructive as well as they allow +us to understand what we did wrong. The following proof reaches a point +in which the postcondition states: + +``post = ... forall (i0 r0 : int), ! i0 < n => x = 2 => r0 = 1024}`` + +This can’t hold since it states that the result ``r0`` is 1024 for every +``r0``, hence we abort this attempt. + +:: + + lemma two_to_ten: + hoare [ Exp.exp : x = 2 /\ n = 10 ==> res = 1024 ]. + proof. + proc. + simplify. + while ( x = 2 ). + wp. + auto. + abort. + +Similarly, we try another invariant which helps, but still gets stuck +since it doesn’t account for how the variable ``r`` changes after every +iteration of the loop. We abort this attempt as well. + +:: + + lemma two_to_ten: + hoare [ Exp.exp : x = 2 /\ n = 10 ==> res = 1024 ]. + proof. + proc. + while ( x = 2 /\ 0 <= i <= n). + wp. + auto. + smt. + abort. + +We know that after every iteration, the variable ``r`` is multiplied by +``x``. So in this case, since we have ``x = 2``, essentially at the end +of ``i`` iterations of the loop we have the fact that +:math:`\text{r} = 2^\text{i}`. This is an invariant, and it binds r to +the variables that are passed to the loop. With this, we finally have +all the ingredients for the invariant and we complete the proof, like +so: + +:: + + lemma two_to_ten: + hoare [ Exp.exp : x = 2 /\ n = 10 ==> res = 1024 ]. + proof. + proc. + while (x = 2 /\ 0 <= i <= n /\ r = 2^i). + + wp. + skip. + smt. + + wp. + simplify. + auto. + + (* + Sometimes, the goal can be quite complicated, and we + can use "progress" to break it down into smaller goals + *) + progress. + + (* 2 ^ 0 = 1 *) + smt. + + (* 2^10 = 1024 *) + smt. + qed. + +Finally, we have an invariant that works. Let us clean up the proof, and +also if we think about it, the condition ``x=2`` isn’t really needed, +since the program never modifies the value of ``x``. Let us get rid of +that condition while we are at it. + +:: + + lemma two_to_ten_clean: hoare [ Exp.exp : x = 2 /\ n = 10 ==> res = 1024 ]. + proof. + proc. + simplify. + while ( r = x^i /\ 0 <= i <= n); auto; smt. + qed. + +Now the proof seems so innocuous and straightforward. However, it is +important to understand that these proofs and figuring out the loop +invariants always takes a few tries, and sometimes crafting the right +invariant can be an art by itself. This also gets quite hard when there +are a lot of variables to keep track of. So it is good practice to work +with smaller examples first. + +Now let us try to work with abstract symbols, the stuff that EC was +actually built for. In order to claim that the ``exp`` function is +correct, we need to have the condition that the exponent that we provide +is greater than zero. We use ``x0``, and ``n0``, in order to +differentiate from the program variables. + +:: + + lemma x0_to_n0_correct (x0 n0: int): + 0 <= n0 => + hoare [ Exp.exp : x = x0 /\ n = n0 ==> res = x0 ^ n0 ]. + proof. + move => Hn0. + proc. + while (r=x^i /\ 0 <= i <= n). + wp. + skip. + smt. + + wp. + skip. + progress. + smt. + smt. + qed. + +Again, we can clean up the proof like so: + +:: + + lemma x0_to_n0_correct_clean x0 n0: + 0 <= n0 => + hoare [ Exp.exp : x = x0 /\ n = n0 ==> res = x0 ^ n0 ]. + proof. + move => Hn0. + proc. + while (r=x^i /\ 0 <= i <= n); auto; smt. + qed. + +With that we conclude this chapter on Hoare logic. In this chapter we +first presented the theory of Hoare logic, and we saw how to work with +HL in EasyCrypt. Starting with simple Hoare triples we worked our way up +to reasoning with more advanced Hoare triples, and along the way we +learnt some new tactics that allowed us to work with the HL goals. diff --git a/doc/tutorials/introduction-itp-program-logics/preface.rst b/doc/tutorials/introduction-itp-program-logics/preface.rst new file mode 100644 index 0000000000..3cf3f807cb --- /dev/null +++ b/doc/tutorials/introduction-itp-program-logics/preface.rst @@ -0,0 +1,208 @@ + .. rubric:: “Program testing can be used to show the presence of + bugs, but never to show their absence!” + :name: program-testing-can-be-used-to-show-the-presence-of-bugs-but-never-to-show-their-absence + + .. rubric:: - Edsger W. Dijkstra + :name: edsger-w.-dijkstra + +Building reliable software is extremely tough. In order to guarantee the +reliability of software, there are plenty of different approaches that +can be employed, ranging from testing to various software building +methodologies. However, these are among the weakest guarantees we can +provide or are simply best practices that can ensure some level of +reliability. + +With the explosion of software applications being used, bad software has +also been the source of literal explosions. For instance, NASA lost its +`Mars Climate +Orbiter `__ +in 1998 due to a bug in converting units from the Imperial system to the +SI system. More recently, bad software led to the death of 346 people +onboard `two Boeing 737 MAX airplanes that crashed in 2018 and +2019 `__. +Bad software has proven to be extremely costly. + +On the opposite end of the spectrum of software reliability guarantees +lies the field of formal verification. The core idea behind formal +verification of software is to provide mathematical guarantees of +program behaviour based on specifications. It grew out of the field of +formal methods in mathematics and later computer-aided mathematical +proofs. So, formal verification rests on the firm foundations of formal +logic and reasoning. + +Cryptography also follows the same pattern when it comes to reliability +guarantees. Testing and following best practices are still the go-to +methods to ensure the reliability of most cryptographic protocols; these +methods provide the weakest guarantees, as we discussed above. To +provide stronger guarantees, the ideas of formal verification have been +applied to cryptography, giving rise to the field of formally verified +cryptography. As these fields advanced and became more and more complex, +software tools that could aid us in this process were built. There are +several approaches to formal verification of cryptography, as we will +see. We will focus on one approach to the field (design-level security) +and work with EasyCrypt, a toolset that allows us to verify game-based +cryptographic proofs. + +Formal verification: A brief history +------------------------------------ + +The ideas of formal verification can be traced back to Leibniz’s ideas +about *characteristica universalis* back in the 17th century. He +imagined it to be a universal conceptual language that could be used to +solve logical problems. However, we do not need to go that far back; for +our intents and purposes, formal methods and later computer-aided math +came into the limelight with the famous four-colour theorem being proven +with the help of computers by Appel and Haken (`Part +I `__, +`Part +II `__) +in 1977. + +The hypothesis of the four-colour theorem is quite simple and elegant. +It says, “Any planar map can be coloured with only four colours”. The +computer-aided proof by Appel and Haken attracted plenty of criticism +since it was done by performing an exhaustive case analysis of a billion +cases. An exhaustive case analysis means that the computer went through +every single case that could arise when trying to colour a map and came +back saying that four colours are all it takes. For an elegant problem, +the proposed computer-aided proof felt like using a sledgehammer to +crack a seemingly innocent nut, and this style of theorem proving +polarised the research community. + +Nevertheless, the computer-aided proof of the four-colour theorem is a +significant milestone, and it set off more work and efforts in the field +of computer-aided mathematics. The field has grown considerably since +then, and there are a multitude of tools available for use. For +instance, one can use theorem provers like Coq or Isabelle to formally +prove general mathematical statements with the help of a computer. Or, +one can use specialised tools like EasyCrypt or Tamarin to work with +specific domains of formal verification, like cryptography in this case. +As for the four-colour theorem, a fully computer-free proof is yet to be +discovered. + +Formal verification in cryptography +----------------------------------- + +As the field of formal verification in math took off and got established +over the years, there was a problem brewing in the academic circles +dealing with cryptography. At its core, modern cryptography is based on +math, and to demonstrate different security properties of protocols, we +come up with mathematical proofs and guarantees about them. As the field +advanced, these proofs started getting fairly complex and often too +complicated for humans to go through. This problem can be best +illustrated with this excerpt from a `paper by Shai +Halevi `__: + +“The problem is that as a community, we generate more proofs than we +carefully verify (and as a consequence some of our published proofs are +incorrect). I became acutely aware of this when I wrote my `EME\* +paper `__. After spending a +considerable effort trying to simplify the proof, I ended up with a +23-page proof of security for a — err — marginally useful +mode-of-operation for block ciphers. Needless to say, I do not expect +anyone in his right mind to even read the proof, let alone carefully +verify it.” + +In the paper, Halevi highlights that cryptography as a field has +advanced to the point where the proofs are so complex that the field +could benefit from automation or, at the very least, some help from +machines. In a way, automated and computer-assisted are the two +approaches that are possible in the field of formal verification of +cryptography. + +What is computer-aided cryptography? +------------------------------------ + +At this point, it is a good idea to read `Sec 1.1 of +JoC `__ to understand what +cryptography is and is not. To summarise and add to the ideas from JoC, +modern cryptography deals with three main problems related to the +security of communication. They are the following: + +1. **Privacy**: Protecting information from being accessed by + unauthorised parties +2. **Integrity**: Protecting information from being tampered with or + altered +3. **Authenticity**: Making sure the information is from an authentic + source + +Each of these properties can be defined as a mathematical property of +information, and claiming that a cryptographic protocol protects a +certain property is equivalent to proving that the information possesses +that mathematical property. Given that the proofs can be complicated and +hard to follow, the idea of using computers to verify the proofs comes +in here. + +To illustrate this idea better, let us first meet Alice, Bob and Eve. We +assume that Alice wants to send a message to Bob and wants the +communication to be private. While Eve wants to eavesdrop on their +communication. One way to prove that a system of communication is secure +is to think of Alice, Bob and Eve playing a game where the objective of +the game for Alice and Bob is to communicate in a way that Eve can’t +differentiate between the messages and a random string of characters. +This would mean that Eve can extract just as much information from an +intercepted message as they can extract from random noise, implying that +the communication is private. This game can be modelled mathematically, +and we can prove that the communication was private. Proofs written in +this style are called game-based cryptographic proofs. + +These ideas of representing information security properties as +mathematical properties and the games that Alice, Bob and Eve play +(game-based cryptographic proofs) are essentially the cornerstones of +provable and verifiable security. Depending on the definition of the +games and conditions related to them, the proofs can turn out to be +fairly intricate, as we established earlier. In the worst case, +handwritten proofs could even be wrong. Incorrect proofs translate to +significant security risks and reaffirm the need for the field of +formally verified cryptography. The complexity and difficulty of +verifying these proofs translate to a need for more automation and +computer-aided verification – tools like EasyCrypt are built to do just +that. + +Criticism of computer-aided cryptography +---------------------------------------- + +Although the need for the field has been well established, it faces many +challenges and has its own shortcomings. + +Only a few important protocols, such as Bluetooth, and TLS, are formally +verified, and it is less likely that verifying these protocols uncovers +serious flaws. This is because they are subject to extensive testing and +attacks. Whereas the protocols that aren’t used to support major +industrial applications generally aren’t subject to the same level of +scrutiny. They only receive limited manual testing, which leaves them +prone to errors. This is where formal verification can actually be used +to improve them significantly. The complexity of using the tools poses a +significant hurdle, and these protocols are left unverified. + +Additionally, a high barrier to entry to the field compounds the problem +of protocols being left unverified. This is because teams developing +protocols can’t spend the time and effort required to go through the +process of formally verifying them. + +In the end, the benefits of formal verification can seem marginal as the +tools themselves can have flaws, leading to the philosophical conundrum +of “Who will guard the guards themselves?” + +As a response to these challenges, the field offers the following +rebuttals: 1. The field is still new, and the tooling is undergoing +active development. Once the tools mature and are easier to use, we can +expect the industry to move in the direction of requiring formal +verification for protocols to be put into use. For instance, the +development of the 5G protocol happened in close `collaboration with the +formal verification community `__ +and is an encouraging move in the right direction 2. Even though the +tools might have flaws, the point to note here is that it would be +exceptionally hard for a mathematical proof to be wrong and also getting +past a formal verification check. So a flawed tool already provides +better security compared to a human-verified proof. The standard to beat +remains a highly specialised set of human eyes verifying a mathematical +proof. The argument of who guards the guards themselves already applies +to the current situation, and formal verification is, in fact, a +significant improvement. 3. The high barrier to entry remains a problem +with no simple solutions. However, this argument is akin to saying that +nuclear physics has a high barrier to entry. Although true, this +situation arises from the fact that these fields are highly specialised +and require years of training to reach a certain level of competence. + +All in all there is plenty of work left to do in the field. diff --git a/doc/tutorials/introduction-itp-program-logics/relational-hoare-logic.ec b/doc/tutorials/introduction-itp-program-logics/relational-hoare-logic.ec new file mode 100644 index 0000000000..c28c94d2eb --- /dev/null +++ b/doc/tutorials/introduction-itp-program-logics/relational-hoare-logic.ec @@ -0,0 +1,478 @@ +pragma Goals: printall. + +require import AllCore. + +(* +Let us work with Relational Hoare Logic and see how +to handle it in EasyCryt. As usual let us start simple and +define two functions that swap variables. +*) + +module Jumbled = { + proc swap1 (x y: int) : int*int = { + var z; + z <- x; + x <- y; + y <- z; + return (x,y); + } + + proc swap2 (x y: int) : int*int = { + var z; + z <- y; + y <- x; + x <- z; + return (x,y); + } +}. + +(* +A couple of things to observe in the definitions. +Firstly, they infact swap variables, however the order in which +they swap them is different. +Secondly, the return type of the functions is a tuple. +Notice the syntax of how it is done. (int*int) + +On paper we define hoare quadruples like so: +{P} C1 ~ C2 {Q} +While in EC, we use the following syntax to say the same: +equiv [C1 ~ C2 : P ==> Q] +As with Hoare triples in EC, we access the results of +both the programs using the "res" keyword. +Let us first prove that swap1 is equivalent to itself. +*) + +lemma swap1_equiv_swap1: +equiv [Jumbled.swap1 ~ Jumbled.swap1 : + x{1}=x{2} /\ y{1}=y{2} ==> res{1} = res{2}]. +(* +The numbers in the curly braces are identifiers +for programs. So res{1} should be read as result +from program 1, and res{2} is the result from program 2. +*) +proof. + proc. + simplify. + auto. +qed. + +(* +Let us now prove that both the swap functions are equivalent. +Notice the shorthand that we use for the conditions. +The eagle-eyed readers would've noticed this +shorthand in the goals pane in the previous exercise. +*) + +lemma swaps_equivalent: +equiv [Jumbled.swap1 ~ Jumbled.swap2 : ={x, y} ==> ={res} ]. +proof. +proc. + simplify. +(* +Now we have different programs, and the way we work with them is by +using similar tactics that we used for HL. +The only difference now is that we have to add identifiers +to the tactics for them to target specific sides and lines of code. +For instance, for the sake of a demonstration let us use the wp tactic +in an asymmetric way. +*) + wp 2 3. +(* +The tactic "wp n1 n2" will try to consume code +up to the n1-th line from the left program, +up to the n2-th line from the right program. +As you can see here, using "wp 2 3" +knocks off the 3rd line from the left program, +and leaves the right program untouched. +Try C-c C-u to undo and then C-c C-n +to redo and notice how things change. +*) + wp 2 2. + wp 0 1. + wp 0 0. + skip. + trivial. +qed. + +(* +Let us clean up the proof since we will never use +wp in the way we did above. In general we will rely +on EC to automatically work with whatever it can. +*) + +lemma swaps_equivalent2: +equiv [Jumbled.swap1 ~ Jumbled.swap2 : ={x, y} ==> ={res} ]. +proof. + proc. + wp. + skip. + simplify. + trivial. +qed. + +(* +Now that we see the complete proof relies only on +"wp, skip, and trivial" tactics, we can replace them with "auto". +Let us clean up the proof further with auto. +*) + +lemma swaps_equivalent_clean: +equiv [Jumbled.swap1 ~ Jumbled.swap2 : ={x, y} ==> ={res} ]. +proof. + proc. + auto. +qed. + +(* +Now let us take a small detour here and build on the the module types +that we briefly introduced in the exercise file of HL. +When working with cryptography, we generally don't know about the +inner workings of an adversary or an oracle. +In order to model these in EC we have the module types. +*) + +module type Adv = { + proc eavesdrop_one(): bool + proc eavesdrop_two(): bool +}. + +(* +By defining the module type Adv, we are instructing EC that any +concrete module which is of the Adv type has to, at the very least, +implement eavesdrop_one, and eavesdrop_two procedures. +What is interesting is that EC allows us to reason with the +abstract module types as well. For example let us define a module +which expects an Adv as input, and has a procedure +*) + +module Abstract_game(A:Adv) = { + proc one(): bool = { + var x; + x <@ A.eavesdrop_one(); + return x; + } +}. + +(* +At this stage, we don't know what A.eavesdrop_one does. +Neither does EC. However, we can still prove certain facts +related to it. Let us take a look at a simple reflexivity +example to understand how that works. +Notice that we have a new term glob A, in the precondition. +It stands for the global variable of the module A. +So in this next lemma we claim that, if the global state of the A +which is of type Adv is equal at the beginning of the program +then running the same program yields us the same result. +Quite a simple lemma, however the point to note here is +that we haven't defined what the function is. +*) + +lemma eavesdrop_reflex(A<:Adv): +equiv [Abstract_game(A).one ~ Abstract_game(A).one : + ={glob A} ==> res{1} = res{2} ]. +proof. + proc. + call (_: true). +(* +the call tactic does a few complicated things under the hood, +but at this point of time, what we can take away is that +if there is a call to the same abstract function on both +sides, call (_: true), knocks them both off. +*) + auto. +qed. + +(* +However, let us also define a concrete instantiation of Adv, +and work with it. A is quite basic, and either always returns +true or always returns false. +*) + +module A : Adv = { + proc eavesdrop_one() = { + return true; + } + + proc eavesdrop_two() = { + return false; + } +}. + +module Games = { + proc t(): bool = { var x; x <@ A.eavesdrop_one(); return x; } + proc f(): bool = { var x; x <@ A.eavesdrop_two(); return x; } +}. + +lemma games_quadruple (A<:Adv): + equiv [Games.t ~ Games.f : ={glob A} ==> res{1} <> res{2}]. +proof. + proc. + inline *. + wp. + simplify. + trivial. +(* auto can replace wp. simplify. trivial *) +qed. + +(* +The point of this detour is that, +when we work with cryptographic proofs we will +be dealing with adversaries both concrete and abstract ones. +With these exercises are warming up and building up those concepts. +*) + +(* +Before we move on to other things, let us take a look at +something non-trivial in RHL. +As we discussed earlier, one of the use cases of RHL +is to ensure that compiler optimisations preserve program behaviour. +Let us take a look at an example of this with a simple compiler +optimisation called "invariant hoisting". +Take a look at the programs defined below. +*) + +module Compiler = { + proc unoptimised (x y z: int) : int*int = { + while (y < z){ + y <- y + 1; + x <- z + 1; + } + return (x,y); + } + + (* + As you can observe, if the condition of the while loops holds + for even one iteration the variable x is set to z+1. + However every subsequent iteration of the loop doesn't change x, + since z is also constant. Hence to save on computation, + the compiler hoists that line out of the scope of the while loop. + Like so: + *) + + proc optimised (x y z: int) : int*int = { + if(y < z){ + x <- z + 1; + } + while (y < z){ + y <- y + 1; + } + return (x,y); + } +}. + +(* +Now let us try to prove the fact that +the behaviour of both the programs is equivalent. +At this point there can be two possibilities: +1. !(y < z) => (y = z) \/ (z < y): +In this case neither the while loop, nor the if condition are satisfied. +So both the programs effectively do nothing to the variables. + +or + +2. (y < z): +The while loop and the if condition executed at least once. +In this case the variables are modified. + +So in order to prove that the optimisation is indeed correct, we can +break our proof into these two cases, prove them independently +and then put them back together. + +An important point to note here is that, this proof took multiple attempts +and a fair amount of time to polish. It is important to understand +that this is a normal process, and takes practice to be able +to work with logic. Anyway, let us trudge on. + +Let us work with the first part in which the loops are never executed. +*) +lemma optimisation_correct_a: +equiv [Compiler.unoptimised ~ Compiler.optimised: + ={x, y ,z} /\ !(y{1} < z{1}) ==> ={res} ]. +proof. + proc. + simplify. +(* +At this point we introduce the seq tactic. +The seq tactic does the following: + + {P} A1; A2; A3 ~ B1; B2; B3 {Q} + ----------------------------------------------- seq 1 2: (R) + {P} A1; ~ B1; B2; {R} /\ {R} A2; A3; ~ B3; {Q} + +In general, the idea behind using the seq tactic is to +break the programs into manageable chunks, and deal with them +separately. +In our program, we have an if condition, that +we can effectively deal with and then work with the while +conditions. + +In this part of the proof, we know that the code inside the conditions +is not executed. Hence know that +R will simply have the variables unchanged +*) + seq 0 1: ( ={x, y ,z} /\ !(y{1} < z{1}) ). +(* Pause and see how the goal changed and now we have two goals to prove *) + auto. +(* +Now we know that neither of the while conditions +hold. So like we did earlier, we will use the rcondf to work with them. +rcondf breaks the goal into two, first part keeps everything before the while +intact. In our case, there is nothing so it adds a "skip", and a post-condition +which is the negation of the boolean expression of the while. +So in our case !(y < z). +When working with RHL, we have to use program identifiers, so that +EC can target the correct side and lines of code. +*) + rcondf {1} 1. + auto. + + (* Similarly, we work with the right program. *) + rcondf {2} 1. + auto. + + auto. +qed. + +(* +Now let us work with the second part of the proof which deals with +the part where the loops are executed. +The only complex part of this proof is the while loop. +So please pause before and after to ponder about the invariant. +*) + +lemma optimisation_correct_b: +equiv [Compiler.unoptimised ~ Compiler.optimised: + ={x, y ,z} /\ y{1} ={res} ]. +proof. + proc. +(* +As we did earlier, we will get rid of the if, +but this time we know that it will be executed, +hence we have x{2} = z{2} + 1 in the condition. +*) + seq 0 1: (={y,z} /\ y{1} ={res} ]. +proof. + proc*. +(* +Here we introduce "proc*", +proc* modifies the goal in a way similar to "proc", but +without losing the fact that the code is infact a procedure call. +With proc, we usually lose this connection to the procedures. +*) + +(* +Now we split on the boolean expression of the while loop. +Although we can't see it in the goal explicitly, we know this +is what we need to do since we put together two parts earlier. +*) + case (y{1} ={res} ]. +proof. +admit. +qed. + +(* +Now we define two more code blocks with similar deadcode, +except this time the variables y,z are not fixed like in +the previous code. +Prove that both these code blocks acheive the same result. +You could make progress by breaking the proof into +two parts, one in which the while loop is never +executed, and another in which it is executed at least once. +After that you could put them together. +*) +module Compiler3 = { + proc unoptimised (x y z: int) : int = { + while(z`__. +As usual, we start with some simple exercises. + +Basic Hoare quadruples +~~~~~~~~~~~~~~~~~~~~~~ + +We begin with two functions, ``swap1`` and ``swap2``, which swap +variables. However, the way they swap variables is slightly different, +and we’d like to establish the fact that they accomplish the same task. +We define ``swap1`` and ``swap2`` like so: + +:: + + module Jumbled = { + proc swap1 (x y: int) : int*int = { + var z; + z <- x; + x <- y; + y <- z; + return (x,y); + } + + proc swap2 (x y: int) : int*int = { + var z; + z <- y; + y <- x; + x <- z; + return (x,y); + } + }. + +In both functions, ``z`` is the temporary variable. In ``swap1``, ``x`` +is first stored in ``z``, while in ``swap2`` ``y`` is stored first. +However, both the functions accomplish the task of swapping variables. + +A Hoare quadruple, :math:`\{P\} \ C_1 \sim C_2 \ \{Q\}`, is expressed +in EasyCrypt with the statement ``equiv [C1 ~ C2 : P ==> Q].`` As with +Hoare triples, we access the results of both the programs using the +``res`` keyword. However, since we now have two programs, we need to add +identifiers to the variables that we use and also to the results to +convey the program that we are speaking about. For instance, to prove +that ``swap1`` is equivalent to itself, we would have the following +lemma. + +:: + + lemma swap1_equiv_swap1: + equiv [Jumbled.swap1 ~ Jumbled.swap1 : x{1}=x{2} /\ y{1}=y{2} ==> res{1} = res{2}]. + proof. + proc. + simplify. + auto. + qed. + +The proof for this lemma is quite straightforward and since there isn’t +much to reason ``auto`` is strong enough to complete the proof. Next we +prove that ``swap1`` is equivalent to ``swap2``. Now we have different +programs, and the way we work with them is by using similar tactics that +we used for HL. The only difference now is that we have to add +identifiers to the tactics for them to target specific sides and lines +of code. For instance, for the sake of a demonstration, we use the +``wp`` in an asymmetric way. + +``wp n1 n2`` will try to consume code up to the +``n1``\ :math:`^\textsf{th}` line from the left program, up to the +``n2``\ :math:`^{\textsf{th}}` line from the right program and will +modify the postconditions depending on the instructions that have been +consumed. The logic is similar to what we saw in HL. + +:: + + lemma swaps_equivalent: + equiv [Jumbled.swap1 ~ Jumbled.swap2 : ={x, y} ==> ={res}]. + proof. + proc. + simplify. + wp 2 3. + wp 2 2. + wp 0 1. + wp 0 0. + skip. + trivial. + qed. + +Since we will never really use ``wp`` the way we did above, we can +replace the large block of different calls to ``wp n1 n2.`` with just +``wp`` and EasyCrypt accomplishes the same automatically. Further, we +also notice that the proof only uses ``wp, skip`` and ``trivial`` +tactics, so we can use ``auto`` instead. This gives us a fairly trivial +proof for the lemma of the swap functions being equivalent. + +:: + + lemma swaps_equivalent_clean: + equiv [Jumbled.swap1 ~ Jumbled.swap2 : ={x, y} ==> ={res}]. + proof. + proc. + auto. + qed. + +Abstract modules and adversaries +-------------------------------- + +Now let us take a small detour here and build on the module types that +we saw earlier when modelling the abstract IND-RoR game. When working +with cryptography, we generally don’t know about the inner workings of +an adversary or an oracle. In order to model these in EasyCrypt, we have +the module types. + +:: + + module type Adv = { + proc eavesdrop_one(): bool + proc eavesdrop_two(): bool + }. + +By defining the module type Adv, we are instructing EasyCrypt that any +concrete module which is of the ``Adv`` type has to, at the very least, +implement ``eavesdrop_one`` and ``eavesdrop_two`` procedures. What is +interesting is that EasyCrypt allows us to reason with the abstract +module types as well. For example, let us define a module which expects +an Adv as input. + +:: + + module Abstract_game(A:Adv) = { + proc one(): bool = { + var x; + x <@ A.eavesdrop_one(); + return x; + } + }. + +At this stage, we don’t know what ``A.eavesdrop_one`` does and neither +does EasyCrypt. However, we can still prove certain facts related to it. +Just for a demonstration, we provide a reflexivity example. + +Notice that we have a new term ``glob A`` in the precondition. It stands +for the global variables of the module ``A``. So in this following +lemma, we claim that if the global state of the ``A`` which is of type +``Adv`` is equal at the beginning of the program, then running the same +program yields us the same result. Quite a simple lemma, however the +point to note here is that we haven’t defined what the procedure is. + +:: + + lemma eavesdrop_reflex(A<:Adv): + equiv [Abstract_game(A).one ~ Abstract_game(A).one : + ={glob A} ==> res{1} = res{2} ]. + proof. + proc. + call (_: true). + auto. + qed. + +``call`` does a few complicated things under the hood, but at this point +of time, we can think that ``call (_: true)``, knocks off a call to the +same abstract function on both sides. + +Let us also define a concrete instantiation of ``Adv`` called ``A`` and +work with it. Module ``A`` is quite basic, and either always returns +true or always returns false. + +:: + + module A : Adv = { + proc eavesdrop_one() = { + return true; + } + + proc eavesdrop_two() = { + return false; + } + }. + + module Games = { + proc t(): bool = + { var x; x <- A.eavesdrop_one(); return x; } + proc f(): bool = + { var x; x <- A.eavesdrop_two(); return x; } + }. + +Now we can reason with these concrete instances with the tactics that +we’ve seen so far. For instance, since we know that ``Games.t`` and +``Games.f`` return different values, we can make a claim like the +following and prove it. In this proof, we use ``inline *``, which simply +fills in (or “inlines”) the concrete code of ``Games.t`` and +``Games.f``. The ``*`` in the tactic is a selector to select everything +that can be inlined. + +:: + + lemma games_quadruple (A<:Adv): equiv [Games.t ~ Games.f : + ={glob A} ==> res{1} <> res{2} ]. + proof. + proc. + inline *. + wp. + simplify. + trivial. + qed. + +The key takeaway of this detour is that when we work with cryptographic +proofs, we will be dealing with both concrete and abstract adversaries. +We can now go back to working with some more challenging Hoare +quadruples. + +Advanced Hoare quadruples +~~~~~~~~~~~~~~~~~~~~~~~~~ + +As we discussed earlier, one of the use cases of RHL is to ensure that +compiler optimisations preserve program behaviour. Let us take a look at +an example of this with a simple compiler optimisation called *invariant +hoisting*. Take a look at the programs defined below. + +:: + + module Compiler = { + proc unoptimised (x y z: int) : int*int = { + while (y < z){ + y <- y + 1; + x <- z + 1; + } + return (x,y); + } + proc optimised (x y z: int) : int*int = { + if(y < z){ + x <- z + 1; + } + while (y < z){ + y <- y + 1; + } + return (x,y); + } + }. + +As you can observe, if the condition of the ``while`` loop in +``unoptimised`` holds for even one iteration the ``x`` is set to +``z+1``. However, the subsequent iterations of the loop don’t change +``x``. Hence to save on computation, the compiler hoists that line out +of the scope of the ``while`` loop, giving us ``optimised``. + +Now let us try to prove the fact that the behaviour of both the programs +is equivalent. At this point, there can be two possibilities: 1. +``!(y < z)``: In this case, neither the ``while`` loop nor the ``if`` +condition is satisfied. So, both the programs effectively do nothing to +the variables. 2. ``(y < z)}``: The ``while`` loop and the ``if`` +condition are executed at least once. In this case, the variables are +modified. + +So to prove that the optimisation is correct, we can break our proof +into these two cases, work on them independently and then put them back +together. + +Let us work with the first part in which the loops are never executed. +In this proof, we will use the ``seq`` tactic. It does the following: + +.. math:: \dfrac{\{P\} A1; \sim B1; B2; \{R\} \ \ \{R\} A2; A3; \sim B3; \{Q\}}{\{P\} A1; A2; A3 \sim B1; B2; B3 \{Q\}}\ seq \ 1 \ 2:(R) + +The idea behind using the ``seq`` is to break the programs into +manageable chunks and deal with them separately. In our program, we have +an ``if`` condition in ``optimised`` that we can deal with and then work +with the ``while`` conditions. In this part of the proof, we know that +the code inside the conditions is not executed. Hence, we know that we +can pass the precondition itself as :math:`R`. With this we can knock +off the ``if`` from ``optimised`` using ``seq``. Then we use ``rcondf`` +to deal with the ``while`` loops since we know that they won’t be +executed. + +:: + + lemma optimisation_correct_a: + equiv [Compiler.unoptimised ~ Compiler.optimised: + ={x, y ,z} /\ (z{1}=y{1} \/ z{1} ={res} ]. + proof. + proc. + simplify. + + (* Dealing with the if on the right *) + seq 0 1: ( ={x, y ,z} /\ (z{1}=y{1} \/ z{1} ={res} ]. + proof. + proc. + (* Dealing with the if condition in optimised *) + seq 0 1: (={y,z} /\ y{1} ={res} ]. + proof. + + proc*. + + (* Branching on the boolean *) + case (y{1}

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 literal 0 HcmV?d00001 diff --git a/doc/tutorials/introduction-itp-program-logics/ambient-logic.ec b/doc/tutorials/introduction-itp-program-logics/ambient-logic.ec new file mode 100644 index 0000000000..e59a556c84 --- /dev/null +++ b/doc/tutorials/introduction-itp-program-logics/ambient-logic.ec @@ -0,0 +1,428 @@ +(* +As we saw earlier in the abstract-ind-ror.ec file, +we use Emacs, and ProofGeneral to work with EasyCrypt. +We will need various commands/keybindings to work with Emacs. +All the keybindings begin either with the CONTROL key, denoted by "C", +or the META or ALT key denoted by "M". +So if you see "C-c C-n" it simply means: CONTROL + c and then CONTROL + n. +Go ahead, try it. This will evaluate the current comment, highlight it +to indicate that it has been evaluated and will place a small black dot on the +left margin at the beginning of the next block to be evaluated. +*) + +(* +Most formal proofs are written interactively. +The proof-assistant, EC in our case, will keep track of the goals +(context, and conclusions) for us. +The front-end, Proof-General + Emacs in our case, will show us the +goals and messages from the assistant, in the "goals" pane, and "response" pane +on the right. +Our objective is to use different tactics to prove or "discharge" the goal. +Since we only have comments so far there are no goals for EC to work with. +We will change that in a short while. +*) + +(* +Here is a short list of keystrokes that will come in handy for this file: +1. C-c C-n : Evaluate next line or block of code +2. C-c C-u : Go back one line or block of code +3. C-c C-ENTER: Evaluate until the cursor position +4. C-c C-l: To reset the Proof-General layout +5. C-x C-s: Save file +6. C-x C-c: Exit Emacs (read the prompt at the bottom of the screen) +*) + +(* +EC has a typed expression language, so everything we declare +should either explicitly have a type or it should be inferable +from the operators that are used. +To begin with let us import the built-in Integer theory file. +*) + +require import Int. + +(* The pragma line simply tells EC to print all goals *) +pragma Goals: printall. + +(* +Now, let us start with something trivial to prove. +Let us start with the reflexivity of integers. +Reflexivity is simply the property that an integer is equal to itself. +Mathematically, we would write it like so: +For every integer x, x=x. +*) + +(* +Here is how we declare something like that in EC. +C-c C-n multiple times to get EC to evaluate the lemma. +Or alternatively, move the cursor to the line with the lemma, +and hit C-c C-ENTER. +*) + +lemma int_refl: forall (x: int), x = x. +(* +Notice how EC populates the goals pane on the right +with the context and the conclusion. +Keep stepping through the proof with C-c C-n. +*) +proof. + trivial. +qed. + +(* +We begin a formal proof with the tactic called "proof", +although it is optional to begin a proof with the "proof" keyword/tactic, +it is considered good style to use it. + +Then we use a set of tactics which transform the goal into zero or more subgoals. +In this case, we used the tactic "trivial", to prove our int_refl lemma. +Once there are no more goals, we can end the proof with "qed", +and EC saves the lemma for further use. +*) + +(* +"trivial" tries to solve the goal using a mixture of other tactics. +So it can be hard to understand when to apply it, but the good news +is that trivial never fails. It either solves the goals or leaves the goal +unchanged. So you can always try it without harm. +*) + +print int_refl. + +(* +The "print" command prints out the request in the response pane. +We can print types, modules, operations, lemmas etc using the print keyword. +Here are some examples: +*) + +print op (+). +print op min. +print axiom Int.fold0. + +(* +The keywords simply act as qualifiers and filters. +You can print even without those. +Like so: +*) +print (+). +print min. + +(* +Now EC knows the lemma int_refl, and allows us to use it to prove other lemmas. +Although the next lemma is trivial, it illustrates the idea of this applying +known results. +*) + +print Int. + +lemma forty_two_equal: 42 = 42. +proof. + apply int_refl. +qed. + +(* +"apply" tries to match the conclusion of what we are applying (the proof term), +with the goal's conclusion. If there is a match, it replaces the goal +with the subgoals of the proof term. +In our case, EC matches int_refl to the goal's conclusion, sees that it +matches, and replaces the goal with what needs to be proven for int_relf which is +nothing, and it concludes the proof. +*) + +(* +EC comes with a lot of predefined lemmas and axioms that we can use. +Let us now look at axioms about commutativity and associativity for integers. +They are by the names addzC, and addzA. Print them out as an exercise. +*) + + +(* Simplifying goals *) + +(* +In the proofs, sometimes tactics yield us something that can be simplified +We use the tactic "simplify", in order to carry out the simplification. + +The simplify tactic reduces the goal to a normal form using lambda calculus. +We don't need to worry about the specifics of how, but it is important to +understand that EC can simplify the goals given it knows how to. +It will leave the goal unchanged if the goal is already in the normal form. + +For instance, here is a contrived example that illustrates the idea. +We will get to more meaningful examples later, but going through these +simple examples will make writing complex proofs easier. +*) + +(* Commutativity *) +lemma x_plus_comm (x: int): x + 2*3 = 6 + x. +proof. + simplify. + (* EC does the mathematical computation for us and simplifies the goal *) + simplify. + (* simplify doesn't fail, and leaves the goal unchanged *) + trivial. + (* trivial doesn't fail either, and leaves the goal unchanged *) + apply addzC. +qed. + +(* ---- Exercise ---- *) +(* +"admit" is a tactic that closes the current goal by admitting it. +Replace admit in the following lemma and prove it using the earlier tactics. +*) +lemma x_minus_equal (x: int): x - 10 = x - 9 - 1. +proof. +admit. +qed. + +(* +The goal list in EC is an ordered one, and you have to prove them +in the same order as EC lists it. "admit" can be used to bypass a certain +goal and focus on something else in the goal list. +*) + +(* +Use the tactic "split" to split the disjunction into two +and apply the previous axioms to discharge the goals. +Experiment with admiting the first goal after splitting +*) +lemma int_assoc_comm (x y z: int): x + (y + z) = (x + y) + z /\ x + y = y + x. +proof. +admit. +qed. + +(* +To deal with disjunctions in EC, you can use the tactics "left" or "right" +to step into a proof of the left proof term, or the right proof term respectively. +*) + +(* Searching in EC *) + +(* +Since, there is a lot that is already done in EC, +we need a way to look for things. +We do that using the "search" command. It prints out all axioms and lemmas +involving the list of operators that give it. +*) + +search [-]. +(* [] - Square braces for unary operators *) + +search (+). + +(* +As you can see the list can be quite overwhelming and difficult to navigate. +So we can limit the results using a list of operators, or patterns. +*) + +search ( * ). +(* +() - Parentheses for binary operators. +Notice the extra space for the "*" operator. +We need that since (* *) also indicates comments. +*) + +search (+) (=) (=>). +(* List of operators "=>" is the implication symbol *) + +search min. +(* By just the name of the operators. *) + +(*---- Exercises ----*) + +(* Distributivity *) +(* Search for the appropriate axiom and apply it to discharge this goal. *) +lemma int_distr (x y z: int): (x + y) * z = x * z + y * z. +proof. + admit. +qed. + +(* +So far, we saw lemmas without any assumptions +except for that of the type of the variable in question. +More often than not we will have assumptions regarding variables. +We need to treat these assumptions as a given and introduce them into the context. +This is done by using "move => ..." followed by the name you want to give +the assumption. +*) + +lemma x_pos (x: int): 0 < x => 0 < x+1. +proof. + move => x_ge0. + simplify. + trivial. + (* Both of those tactics don't work. We need something else here *) + (* Let us see if EC has something that we can use. *) + search (<) (+) (0) (=>). + rewrite addz_gt0. + (* + "rewrite" simply rewrites the pattern provided, so in our case it + rewrites our goal here (0 < x + 1), with the pattern that we provided + which is addz_gt0, and then requires us to prove the assumptions of + the pattern which are 0 < x and 0 < 1. + *) + (* Goal 1: 0 < x *) + + (* + When we have a goal matches an assumption, we + can use the tactic assumption to discharge it. + *) + assumption. + + (* Goal 2: 0 < 1 *) + trivial. +qed. + +(* Let us see some variations *) + +lemma int_assoc_rev (x y z: int): x + y + z = x + (y + z). +proof. + print addzA. + (* + We might have a lemma or an axiom that we can apply to the goal, + but the LHS and RHS might be flipped, and EC will complain that + they don't match to apply them. + To rewrite a lemma or axiom in reverse, we simply add the "-" infront + of the lemma to switch the sides like so. + *) + rewrite -addzA. + trivial. +qed. + +(* +Note that here "apply addzA." or "apply -addzA" do not work +We encourage you to try them. +*) + +(* +Recap: +So far we have seen the following tactics: +trivial, simplify, apply, rewrite, +move, split, left, right, admit, and assumption. +We also saw how to print and search for patterns. +These are at the foundation of how we work with EC. +*) + +(* +Intro to smt and external provers: +An important point to understand, however, is that EC +was built to work with cryptographic properties and more complex things. +So although other mathematical theorems and claims can be proven in EC, +it will be quite painful to do so. We will employ powerful automated tools +to take care of some of these low-level tactics and logic. +EC offers this in the form of the "smt" tactic. +When we run smt, EC sends the conclusion and the context to external smt solvers. +If they are able to solve the goal, then EC completes the proof. +If not smt fails and the burden of the proof is still on us. +*) + +lemma x_pos_smt (x: int): 0 < x => 0 < x+1. +proof. +smt. +qed. + +(* +As you can see, smt can make our lives much easier. +Now, here are some properties about logarithms that are mentioned in +The Joy of Cryptography. We leave them to be completed as exercises, +without using the smt tactic. Most of them are straightforward and +serve the purpose of exercising the use of basic tactics. +*) + +require import AllCore. + + +(* print AllCore to see what it includes *) + +(* Logs and exponents: *) + +lemma exp_product (x: real) (a b: int): x^(a*b) = x ^ a ^ b. +proof. + search (^) (=). + by apply RField.exprM. +qed. + +lemma exp_product2 (x: real) (a b: int): x <> 0%r => x^a * x^b = x^(a + b). +proof. + move => x_pos. + search (^) (=). + print RField.exprD. + rewrite -RField.exprD. + assumption. + trivial. +qed. + +(* Logarithm exercises *) +require import RealExp. + +(* +Print and search for "ln" to see how it is defined and +the results we have available already +*) +lemma ln_product (x y: real) : 0%r < x => 0%r < y => ln (x*y) = ln x + ln y. +proof. + search (ln) (+). + move => H1 H2. + by apply lnM. +qed. + +print log. +(* +Notice how log is defined. It is defined as an operator that expects two inputs +Since most of ECs axioms are written for natural logs (ln), inorder to reason with +log and inorder to work with the next lemma, you will need to rewrite log. +To do so the syntax is + +rewrite /log. + +The "/" will rewrite the pattern that follows. +*) + +(* +This helper can come in handy in the next proof. +Sometimes it can be cumbersome to reason with a goal. +In cases like those, it is useful to reduce the complexity of the proof by using +helper lemmas like these. +*) + +lemma helper (x y z: real): (x + y) / z = x/z + y/z. +proof. +smt. +qed. + +lemma log_product (x y a : real): + 0%r < x => 0%r < y => log a (x*y) = log a x + log a y. +proof. + move => H1 H2. + rewrite /log. + rewrite lnM. + assumption. + assumption. + by apply helper. +qed. + +(* Or we can simply let smt do the heavy lifting for us *) +lemma log_product_smt (x y a : real): + 0%r < x => 0%r < y => log a (x*y) = log a x + log a y. +proof. + smt. +qed. + +(* +Modulo arithmatic exercises: +This is one of the properties that is mentioned in the + *) +require import IntDiv. + +lemma mod_add (x y z: int): (x %% z + y %% z) %% z = (x + y) %% z. +proof. + by apply modzDm. +qed. + +(* +A couple of more keystrokes that might be useful. + +1. C-c C-r: Begin evaluating from the start +2. C-c C-b: Evaluate until the end of the file. + +Go ahead and give these a try. +*) diff --git a/doc/tutorials/introduction-itp-program-logics/ambient-logic.png b/doc/tutorials/introduction-itp-program-logics/ambient-logic.png new file mode 100644 index 0000000000000000000000000000000000000000..97299e23041c1e19983b0848031a370818e6065c GIT binary patch literal 190271 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