Theory SUF_CMA

(* Title: SUF_CMA.thy
  Author: Andreas Lochbihler, ETH Zurich *)

theory SUF_CMA imports
  CryptHOL.Computational_Model
  CryptHOL.Negligible
  CryptHOL.Environment_Functor
begin

subsection ‹Strongly existentially unforgeable signature scheme›

locale sig_scheme =
  fixes key_gen :: "security ⇒ ('vkey × 'sigkey) spmf"
  and sign :: "security ⇒ 'sigkey ⇒ 'message ⇒ 'signature spmf"
  and verify :: "security ⇒ 'vkey ⇒ 'message ⇒ 'signature ⇒ bool" ― ‹verification is deterministic›
  and valid_message :: "security ⇒ 'message ⇒ bool"

locale suf_cma = sig_scheme +
  constrains key_gen :: "security ⇒ ('vkey × 'sigkey) spmf"
  and sign :: "security ⇒ 'sigkey ⇒ 'message ⇒ 'signature spmf"
  and verify :: "security ⇒ 'vkey ⇒ 'message ⇒ 'signature ⇒ bool"
  and valid_message :: "security ⇒ 'message ⇒ bool"
begin

type_synonym ('vkey', 'sigkey', 'message', 'signature') state_oracle 
  = "('vkey' × 'sigkey' × ('message' × 'signature') list) option"

fun vkey_oracle :: "security ⇒ (('vkey, 'sigkey, 'message, 'signature) state_oracle, unit, 'vkey) oracle'"
where
  "vkey_oracle η None _ = do {
     (vkey, sigkey) ← key_gen η;
     return_spmf (vkey, Some (vkey, sigkey, []))
   }"
| "⋀log. vkey_oracle η (Some (vkey, sigkey, log)) _ = return_spmf (vkey, Some (vkey, sigkey, log))"

context notes bind_spmf_cong[fundef_cong] begin
function sign_oracle
  :: "security ⇒ (('vkey, 'sigkey, 'message, 'signature) state_oracle, 'message, 'signature) oracle'"
where
  "sign_oracle η None m = do { (_, σ) ← vkey_oracle η None (); sign_oracle η σ m }"
| "⋀log. sign_oracle η (Some (vkey, skey, log)) m =
  (if valid_message η m then do {
    sig ← sign η skey m;
    return_spmf (sig, Some (vkey, skey, (m, sig) # log)) 
  } else return_pmf None)"
by pat_completeness auto
termination by(relation "Wellfounded.measure (λ(η, σ, m). case σ of None ⇒ 1 | _ ⇒ 0)") auto
end

lemma lossless_vkey_oracle [simp]:
  "lossless_spmf (vkey_oracle η σ x) ⟷ (σ = None ⟶ lossless_spmf (key_gen η))"
by(cases "(η, σ, x)" rule: vkey_oracle.cases) auto

lemma lossless_sign_oracle [simp]:
  "⟦ σ = None ⟹ lossless_spmf (key_gen η);
    ⋀skey m. valid_message η m ⟹ lossless_spmf (sign η skey m) ⟧
  ⟹ lossless_spmf (sign_oracle η σ m) ⟷ valid_message η m"
apply(cases "(η, σ, m)" rule: sign_oracle.cases)
apply(auto simp add: split_beta dest: lossless_spmfD_set_spmf_nonempty)
done

lemma lossless_sign_oracle_Some: fixes log shows
  "lossless_spmf (sign_oracle η (Some (vkey, skey, log)) m) ⟷ lossless_spmf (sign η skey m) ∧ valid_message η m"
by(simp)

subsubsection ‹Single-user setting›

type_synonym 'message' call1 = "unit + 'message'"
type_synonym ('vkey', 'signature') ret1 = "'vkey' + 'signature'"

definition oracle1 :: "security
  ⇒ (('vkey, 'sigkey, 'message, 'signature) state_oracle, 'message call1, ('vkey, 'signature) ret1) oracle'"
where "oracle1 η = vkey_oracle η ⊕O sign_oracle η"

lemma oracle1_simps [simp]:
  "oracle1 η s (Inl x) = map_spmf (apfst Inl) (vkey_oracle η s x)"
  "oracle1 η s (Inr y) = map_spmf (apfst Inr) (sign_oracle η s y)"
by(simp_all add: oracle1_def)

type_synonym ('vkey', 'message', 'signature') adversary1' = 
  "(('message' × 'signature'), 'message' call1, ('vkey', 'signature') ret1) gpv"
type_synonym ('vkey', 'message', 'signature') adversary1 =
  "security ⇒ ('vkey', 'message', 'signature') adversary1'"

definition suf_cma1 :: "('vkey, 'message, 'signature) adversary1 ⇒ security ⇒ bool spmf"
where
  "⋀log. suf_cma1 𝒜 η = do {
    ((m, sig), σ) ← exec_gpv (oracle1 η) (𝒜 η) None;
    return_spmf (
      case σ of None ⇒ False
      | Some (vkey, skey, log) ⇒ verify η vkey m sig ∧ (m, sig) ∉ set log)
  }"

definition advantage1 :: "('vkey, 'message, 'signature) adversary1 ⇒ advantage"
where "advantage1 𝒜 η = spmf (suf_cma1 𝒜 η) True"

lemma advantage1_nonneg: "advantage1 𝒜 η ≥ 0" by(simp add: advantage1_def pmf_nonneg)

abbreviation secure_for1 :: "('vkey, 'message, 'signature) adversary1 ⇒ bool"
where "secure_for1 𝒜 ≡ negligible (advantage1 𝒜)"

definition ibounded_by1' :: "('vkey, 'message, 'signature) adversary1' ⇒ nat ⇒ bool"
where "ibounded_by1' 𝒜 q = (interaction_any_bounded_by 𝒜 q)"

abbreviation ibounded_by1 :: "('vkey, 'message, 'signature) adversary1 ⇒ (security ⇒ nat) ⇒ bool"
where "ibounded_by1 ≡ rel_envir ibounded_by1'"

definition lossless1' :: "('vkey, 'message, 'signature) adversary1' ⇒ bool"
where "lossless1' 𝒜 = (lossless_gpv ℐ_full 𝒜)"

abbreviation lossless1 :: "('vkey, 'message, 'signature) adversary1 ⇒ bool"
where "lossless1 ≡ pred_envir lossless1'"

subsubsection ‹Multi-user setting›

definition oraclen :: "security
  ⇒ ('i ⇒ ('vkey, 'sigkey, 'message, 'signature) state_oracle, 'i × 'message call1, ('vkey, 'signature) ret1) oracle'"
where "oraclen η = family_oracle (λ_. oracle1 η)"

lemma oraclen_apply [simp]:
  "oraclen η s (i, x) = map_spmf (apsnd (fun_upd s i)) (oracle1 η (s i) x)"
by(simp add: oraclen_def)

type_synonym ('i, 'vkey', 'message', 'signature') adversaryn' = 
  "(('i × 'message' × 'signature'), 'i × 'message' call1, ('vkey', 'signature') ret1) gpv"
type_synonym ('i, 'vkey', 'message', 'signature') adversaryn =
  "security ⇒ ('i, 'vkey', 'message', 'signature') adversaryn'"

definition suf_cman :: "('i, 'vkey, 'message, 'signature) adversaryn ⇒ security ⇒ bool spmf"
where
  "⋀log. suf_cman 𝒜 η = do {
    ((i, m, sig), σ) ← exec_gpv (oraclen η) (𝒜 η) (λ_. None);
    return_spmf (
      case σ i of None ⇒ False
      | Some (vkey, skey, log) ⇒ verify η vkey m sig ∧ (m, sig) ∉ set log)
  }"

definition advantagen :: "('i, 'vkey, 'message, 'signature) adversaryn ⇒ advantage"
where "advantagen 𝒜 η = spmf (suf_cman 𝒜 η) True"

lemma advantagen_nonneg: "advantagen 𝒜 η ≥ 0" by(simp add: advantagen_def pmf_nonneg)

abbreviation secure_forn :: "('i, 'vkey, 'message, 'signature) adversaryn ⇒ bool"
where "secure_forn 𝒜 ≡ negligible (advantagen 𝒜)"

definition ibounded_byn' :: "('i, 'vkey, 'message, 'signature) adversaryn' ⇒ nat ⇒ bool"
where "ibounded_byn' 𝒜 q = (interaction_any_bounded_by 𝒜 q)"

abbreviation ibounded_byn :: "('i, 'vkey, 'message, 'signature) adversaryn ⇒ (security ⇒ nat) ⇒ bool"
where "ibounded_byn ≡ rel_envir ibounded_byn'"

definition losslessn' :: "('i, 'vkey, 'message, 'signature) adversaryn' ⇒ bool"
where "losslessn' 𝒜 = (lossless_gpv ℐ_full 𝒜)"

abbreviation losslessn :: "('i, 'vkey, 'message, 'signature) adversaryn ⇒ bool"
where "losslessn ≡ pred_envir losslessn'"

end

end