val set_taint_cf_and_flags (ts: analysis_taints) (t: taint) : analysis_taints
let set_taint_cf_and_flags (ts:analysis_taints) (t:taint) : analysis_taints =
  let AnalysisTaints (LeakageTaints rs flags cf ovf) rts = ts in
  AnalysisTaints (LeakageTaints rs (merge_taint t flags) t ovf) rts
val set_taint_cf_and_flags (ts: analysis_taints) (t: taint) : analysis_taints
let set_taint_cf_and_flags (ts: analysis_taints) (t: taint) : analysis_taints =
let AnalysisTaints (LeakageTaints rs flags cf ovf) rts = ts in
AnalysisTaints (LeakageTaints rs (merge_taint t flags) t ovf) rts
Vale.X64.Leakage_Helpers.fst.checked
Vale.X64.Machine_Semantics_s.fst.checked Vale.X64.Machine_s.fst.checked Vale.X64.Leakage_s.fst.checked Vale.X64.Instruction_s.fsti.checked Vale.Lib.MapTree.fsti.checked prims.fst.checked FStar.Pervasives.Native.fst.checked FStar.Pervasives.fsti.checked FStar.Mul.fst.checked FStar.FunctionalExtensionality.fsti.checked
Vale.X64.Leakage_Helpers.fst
Vale.X64.Leakage_Helpers.analysis_taints Vale.Arch.HeapTypes_s.taint Vale.X64.Leakage_s.reg_taint Vale.X64.Leakage_Helpers.regmap Vale.X64.Leakage_Helpers.is_map_of Vale.X64.Leakage_s.__proj__LeakageTaints__item__regTaint Vale.X64.Leakage_s.LeakageTaints Vale.X64.Leakage_Helpers.AnalysisTaints Vale.X64.Leakage_Helpers.merge_taint
module Vale.X64.Leakage_Helpers
open FStar.Mul
open Vale.X64.Machine_Semantics_s
open Vale.X64.Machine_s
open Vale.X64.Leakage_s
open Vale.X64.Instruction_s
open Vale.Lib.MapTree

let regmap = map reg taint

let reg_le (r1 r2:reg) : bool =
  let Reg f1 n1 = r1 in
  let Reg f2 n2 = r2 in
  f1 < f2 || (f1 = f2 && n1 <= n2)

let map_to_regs (m:regmap) : reg_taint =
  FunctionalExtensionality.on reg (sel m)

let is_map_of (m:regmap) (rs:reg_taint) =
  FStar.FunctionalExtensionality.feq (map_to_regs m) rs

let rec regs_to_map_rec (rs:reg_taint) (f n:nat) : Pure regmap
  (requires (f == n_reg_files /\ n == 0) \/ (f < n_reg_files /\ n <= n_regs f))
  (ensures (fun m -> forall (r:reg).{:pattern sel m r}
    r.rf < f \/ (r.rf == f /\ r.r < n) ==> sel m r == rs r))
  (decreases %[f; n])
  =
  if n = 0 then
    if f = 0 then const reg taint reg_le Secret
    else regs_to_map_rec rs (f - 1) (n_regs (f - 1))
  else
    let m = regs_to_map_rec rs f (n - 1) in
    let r = Reg f (n - 1) in
    upd m r (rs r)

let regs_to_map (rs:reg_taint) : (m:regmap{is_map_of m rs}) =
  regs_to_map_rec rs n_reg_files 0

noeq type analysis_taints =
  | AnalysisTaints: lts:leakage_taints -> rts:regmap{is_map_of rts lts.regTaint} -> analysis_taints

let merge_taint (t1:taint) (t2:taint) :taint =
  if Secret? t1 || Secret? t2 then Secret
  else Public

// Also pass the taint of the instruction
let operand_taint (rf:reg_file_id) (o:operand_rf rf) (ts:analysis_taints) : taint =
  match o with
  | OConst _ -> Public
  | OReg r -> sel ts.rts (Reg rf r)
  | OMem (_, t) | OStack (_, t) -> t

[@instr_attr]
let operand_taint_explicit
  (i:instr_operand_explicit)
  (o:instr_operand_t i)
  (ts:analysis_taints)
  : taint =
  match i with
  | IOp64 -> operand_taint 0 (o <: operand64) ts
  | IOpXmm -> operand_taint 1 (o <: operand128) ts

[@instr_attr]
let operand_taint_implicit
  (i:instr_operand_implicit)
  (ts:analysis_taints)
  : taint =
  match i with
  | IOp64One o -> operand_taint 0 o ts
  | IOpXmmOne o -> operand_taint 1 o ts
  | IOpFlagsCf -> ts.lts.cfFlagsTaint
  | IOpFlagsOf -> ts.lts.ofFlagsTaint

[@instr_attr]
let rec args_taint
  (args:list instr_operand)
  (oprs:instr_operands_t_args args)
  (ts:analysis_taints)
  : taint =
  match args with
  | [] -> Public
  | i::args ->
    match i with
    | IOpEx i ->
      let oprs = coerce oprs in merge_taint
      (operand_taint_explicit i (fst oprs) ts)
      (args_taint args (snd oprs) ts)
    | IOpIm i ->
      merge_taint
      (operand_taint_implicit i ts)
      (args_taint args (coerce oprs) ts)

[@instr_attr]
let rec inouts_taint
  (inouts:list instr_out)
  (args:list instr_operand)
  (oprs:instr_operands_t inouts args)
  (ts:analysis_taints)
  : taint =
  match inouts with
  | [] -> args_taint args oprs ts
  | (Out, i)::inouts ->
    let oprs =
      match i with
      | IOpEx i -> snd #(instr_operand_t i) (coerce oprs)
      | IOpIm i -> coerce oprs
    in inouts_taint inouts args oprs ts
  | (InOut, i)::inouts ->
    let (v, oprs) =
      match i with
      | IOpEx i ->
        let oprs = coerce oprs in
        ((operand_taint_explicit i (fst oprs) ts), snd oprs)
      | IOpIm i -> (operand_taint_implicit i ts, coerce oprs)
    in merge_taint v (inouts_taint inouts args oprs ts)

let maddr_does_not_use_secrets (addr:maddr) (ts:analysis_taints) : bool =
  match addr with
  | MConst _ -> true
  | MReg r _ -> Public? (sel ts.rts r)
  | MIndex base _ index _ ->
      let baseTaint = sel ts.rts base in
      let indexTaint = sel ts.rts index in
      (Public? baseTaint) && (Public? indexTaint)

let operand_does_not_use_secrets (#tc #tr:eqtype) (o:operand tc tr) (ts:analysis_taints) : bool =
  match o with
  | OConst _ | OReg _ -> true
  | OMem (m, _) | OStack (m, _) -> maddr_does_not_use_secrets m ts

let operand_taint_allowed (#tc #tr:eqtype) (o:operand tc tr) (t_data:taint) : bool =
  match o with
  | OConst _ | OReg _ -> true
  | OMem (_, t_operand) | OStack (_, t_operand) -> t_operand = Secret || t_data = Public

let set_taint (rf:reg_file_id) (dst:operand_rf rf) (ts:analysis_taints) (t:taint) : analysis_taints =
  match dst with
  | OConst _ -> ts  // Shouldn't actually happen
  | OReg r ->
      let AnalysisTaints (LeakageTaints rs f c o) rts = ts in
      let rts = upd rts (Reg rf r) t in
      AnalysisTaints (LeakageTaints (map_to_regs rts) f c o) rts
  | OMem _ | OStack _ -> ts // Ensured by taint semantics
val set_taint_cf_and_flags (ts: analysis_taints) (t: taint) : analysis_taints
ts: Vale.X64.Leakage_Helpers.analysis_taints -> t: Vale.Arch.HeapTypes_s.taint
  -> Vale.X64.Leakage_Helpers.analysis_taints