Theory MLWE

theory MLWE

imports Lemmas_for_spmf
        "Game_Based_Crypto.CryptHOL_Tutorial"

begin

section ‹Module Learning-with-Errors Problem (module-LWE)›

text ‹‹Berlekamp_Zassenhaus› loads the vector type ‹'a vec› from ‹Jordan_Normal_Form.Matrix›. 
This doubles the symbols ‹\$› and ‹χ› for ‹vec_nth› and ‹vec_lambda›. Thus we delete the
‹vec_index› for type ‹'a vec›. Still some type ambiguities remain.›

unbundle %invisible lifting_syntax
no_adhoc_overloading %invisible Monad_Syntax.bind ⇌ bind_pmf
declare %invisible [[names_short]]


text ‹Here the actual theory starts.›

text ‹We introduce a locale ‹module_lwe› that represents the module-Learning-with-Errors 
(module-LWE) problem in the setting of Kyber. 
The locale takes as input:
\begin{itemize}
\item ‹type_a› the type of the quotient ring of Kyber. (This is a side effect of the Harrison 
    trick in the Kyber locale.)
\item ‹type_k› the finite type for indexing vectors in Kyber. The cardinality is exactely $k$.
   (This is a side effect of the Harrison trick in the Kyber locale.)
\item ‹idx› an indexing function from ‹'k› to ‹{0..<k}›
\item ‹eta› the specification value for the centered binomial distribution $\beta_\eta$
\end{itemize}›

locale module_lwe = 
fixes type_a :: "('a :: qr_spec) itself" 
  and type_k :: "('k ::finite) itself"
  and k :: nat
  and idx :: "'k::finite ⇒ nat"
  and eta :: nat
assumes "k = CARD('k)"
  and bij_idx: "bij_betw idx (UNIV::'k set) {0..<k}"
 
begin

text ‹The adversary in the module-LWE takes a matrix ‹A::(('b, 'n) vec, 'm) vec› and a vector
  ‹t::('b, 'm) vec› and returns a probability distribution on ‹bool› 
  guessing whether the given input was randomly generated or a valid module-LWE instance.›
type_synonym ('b, 'n, 'm) adversary = 
  "(('b, 'n) vec, 'm) vec ⇒ ('b, 'm) vec ⇒  bool spmf"

text ‹Next, we want to define the centered binomial distributions $\beta_\eta$.
‹bit_set› returns the set of all bit lists of length ‹eta›.
‹beta› is the centered binomial distribution $\beta_\eta$ as a ‹pmf› on the quotient ring $R_q$.
‹beta_vec› is then centered binomial distribution $\beta_\eta ^k$ on vectors in $R_q^k$.›

definition bit_set :: "int list set" where
"bit_set = {xs:: int list. set xs ⊆ {0,1} ∧ length xs = eta}"

lemma finite_bit_set:
"finite bit_set"
unfolding bit_set_def 
by (simp add: finite_lists_length_eq)

lemma bit_set_nonempty:
"bit_set ≠ {}"
proof -
  have "replicate eta 0 ∈ bit_set" unfolding bit_set_def by auto
  then show ?thesis by auto
qed

adhoc_overloading %invisible Monad_Syntax.bind ⇌ bind_pmf 
definition beta :: "'a qr pmf" where
"beta = do {
    as ← pmf_of_set (bit_set);
    bs ← pmf_of_set (bit_set);
    return_pmf (to_module (∑i<eta. as ! i - bs! i))
  } "

definition beta_vec :: "('a qr , 'k) vec pmf" where
"beta_vec = do {
    (xs :: 'a qr list) ← replicate_pmf (k) (beta);
    return_pmf (χ i.  xs ! (idx i))
  }"

text ‹Since we work over ‹spmf›, we need to show that ‹beta_vec› is lossless.›

lemma lossless_beta_vec[simp]:
  "lossless_spmf (spmf_of_pmf beta_vec)"
by (simp)

text ‹We define the game versions of module-LWE.
Given an adversary ‹𝒜›, we have two games: 
in ‹game›, the instance given to the adversary is a module-LWE instance, 
whereas in ‹game_random›, the instance is chosen randomly.›

definition game :: "('a qr,'k,'k) adversary ⇒ bool spmf" where
  "game 𝒜  = do {
    A ← spmf_of_set (UNIV:: (('a qr, 'k) vec, 'k) vec set);
    s ← beta_vec;
    e ← beta_vec;
    b' ← 𝒜 A (A *v s + e);
    return_spmf (b')
  }"

definition game_random :: "('a qr,'k,'k) adversary ⇒ bool spmf" where
  "game_random 𝒜  = do {
    A ← spmf_of_set (UNIV:: (('a qr, 'k) vec, 'k) vec set);
    b ← spmf_of_set (UNIV:: ('a qr, 'k) vec set);
    b' ← 𝒜 A b;
    return_spmf (b')
  }"

text ‹The advantage of an adversary ‹𝒜› returns a value how good the adversary is at guessing 
whether the instance is generated by the module-LWE or uniformly at random.›

definition advantage :: "('a qr,'k,'k) adversary ⇒ real" where 
"advantage 𝒜 = ¦spmf (game 𝒜) True - spmf (game_random 𝒜) True ¦"


text ‹Since the reduction proof of Kyber uses the module-LWE problem for two different dimensions
(ie.\ $A\in R_q^{(k+1)\times k}$ and $A\in R_q^{k\times k}$), we need a second definition of
the index function, the centered binomial distribution, the game and random game, and the advantage.
Here the problem is that the dimension $k$ of the vectors is hard-coded in the type ‹'k›. 
That makes it hard to ``simply add'' another dimension. A trick how this can be formalised 
nevertheless is to use the option type on ‹'k› to encode a type with $k+1$ elements.
With the option type, we can embed a vector of dimension $k$ indexed by the type ‹'k› into
a vector of dimension $k+1$ by adding a value for the index ‹None› (an element ‹a :: 'k› 
is mapped to ‹Some a›).
Note also that the additional index appears only in one dimension of $A$, resulting in 
a non-quadratic matrix.›

text ‹Index function of the option type ‹'k option›.›

fun idx' :: "'k option ⇒ nat" where
  "idx' None = 0" |
  "idx' (Some x) = idx x + 1"

lemma idx': "((x # xs) ! idx' i) = 
  ( if i = None then x else xs ! idx (the i))" 
  if "length xs = k" for xs and i::"'k option"
proof (cases i)
  case None
  then show ?thesis using nth_append_length[of xs x "[]"] that by (simp add: if_distrib)
next
  case (Some a)
  have "idx a < k" using bij_idx 
  by (meson UNIV_I atLeastLessThan_iff bij_betwE) 
  then show ?thesis using Some that by (simp add: if_distrib nth_append)
qed


lemma idx'_lambda:
  "(χ i. (x # xs) ! idx' i) = 
   (χ i. if i = None then x else xs ! idx (the i))" 
   if "length xs = k" for xs using idx'[OF that]
 by presburger

text ‹Definition of the centered binomial distribution $\beta_\eta^{k+1}$ and lossless property.›

definition beta_vec' :: "('a qr , 'k option) vec spmf" where
"beta_vec' = do {
    (xs :: 'a qr list) ← replicate_spmf (k+1) (beta);
    return_spmf (χ i.  xs ! (idx' i))
  }"

lemma lossless_beta_vec'[simp]:
  "lossless_spmf beta_vec'"
unfolding beta_vec'_def beta_def
by (simp add: replicate_spmf_def)

text ‹Some lemmas on replicate.›

lemma replicate_pmf_same_length:
assumes "⋀ xs. length xs = m ⟹ f xs = g xs"
shows "bind_pmf (replicate_pmf m p) f = bind_pmf (replicate_pmf m p) g"
by (metis (mono_tags, lifting) assms bind_pmf_cong mem_Collect_eq set_replicate_pmf)

lemma replicate_spmf_same_length:
assumes "⋀ xs. length xs = m ⟹ f xs = g xs"
shows "(replicate_spmf m p ⤜ f) = (replicate_spmf m p ⤜ g)"
unfolding replicate_spmf_def bind_spmf_of_pmf 
by (simp add: replicate_pmf_same_length[OF assms])

text ‹Lemma to split the ‹replicate (k+1)› function in ‹beta_vec'› into two parts: 
‹replicate k› and a separate value. Note, that the ‹xs› in the ‹do› notation below are 
always of length $k$. ›

no_adhoc_overloading Monad_Syntax.bind ⇌ bind_pmf

lemma beta_vec':
  "beta_vec' = do {
    (xs :: 'a qr list) ← replicate_spmf (k) (beta);
    (x :: 'a qr) ← spmf_of_pmf beta;
    return_spmf (χ i.  if i = None then x else xs ! (idx (the i)))
  }"                                                    
unfolding beta_vec'_def idx'_lambda[symmetric] replicate_spmf_Suc_cons 
  bind_spmf_assoc return_bind_spmf
by (subst replicate_spmf_same_length[where 
  f = "(λy. spmf_of_pmf beta ⤜ (λya. return_spmf (vec_lambda (λi. (ya # y) ! idx' i))))" and
  g = "(λxs. spmf_of_pmf beta ⤜ (λx. return_spmf (vec_lambda (λi. if i = None then x else 
        xs ! idx (the i)))))"])
   (simp_all add: idx'_lambda)

adhoc_overloading Monad_Syntax.bind ⇌ bind_pmf

text ‹Definition of the two games for the option type.›

definition game' :: "('a qr,'k,'k option) adversary ⇒ bool spmf" where
  "game' 𝒜  = do {
    A ← spmf_of_set (UNIV:: (('a qr, 'k) vec, 'k option) vec set);
    s ← beta_vec;
    e ← beta_vec';
    b' ← 𝒜 A (A *v s + e);
    return_spmf (b')
  }"

definition game_random' :: "('a qr,'k,'k option) adversary ⇒ bool spmf" where
  "game_random' 𝒜  = do {
    A ← spmf_of_set (UNIV:: (('a qr, 'k) vec, 'k option) vec set);
    b ← spmf_of_set (UNIV:: ('a qr, 'k option) vec set);
    b' ← 𝒜 A b;
    return_spmf (b')
  }"

text ‹Definition of the advantage for the option type.›

definition advantage' :: "('a qr,'k,'k option) adversary ⇒ real" where 
"advantage' 𝒜 = ¦spmf (game' 𝒜) True - spmf (game_random' 𝒜) True ¦"

text ‹Game and random game for finite type with one element only›

definition beta1 :: "('a qr , 1) vec pmf" where
"beta1 = bind_pmf beta (λx. return_pmf (χ i. x))"

definition game1 :: "('a qr, 1, 1) adversary ⇒ bool spmf" where
  "game1 𝒜  = do {
    A ← spmf_of_set (UNIV:: (('a qr, 1) vec, 1) vec set);
    s ← spmf_of_pmf beta1;
    e ← spmf_of_pmf beta1;
    b' ← 𝒜 A (A *v s + e);
    return_spmf (b')
  }"

definition game_random1 :: "('a qr,1,1) adversary ⇒ bool spmf" where
  "game_random1 𝒜  = do {
    A ← spmf_of_set (UNIV:: (('a qr, 1) vec, 1) vec set);
    b ← spmf_of_set (UNIV:: ('a qr, 1) vec set);
    b' ← 𝒜 A b;
    return_spmf (b')
  }"

text ‹The advantage of an adversary ‹𝒜› returns a value how good the adversary is at guessing 
whether the instance is generated by the module-LWE or uniformly at random.›

definition advantage1 :: "('a qr,1,1) adversary ⇒ real" where 
"advantage1 𝒜 = ¦spmf (game1 𝒜) True - spmf (game_random1 𝒜) True ¦"

end
end