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