theory Bounds imports Branches begin fun guarded_run :: "nat \ opcode list \ machine \ bool" where "guarded_run limit [] s = (length (stack s) \ limit)" | "guarded_run limit (op # code) s = (length (stack s) \ limit \ (case transition op s of None \ False | Some q \ guarded_run limit code q))" fun guarded_flow :: "nat \ flow \ machine \ bool" where "guarded_flow limit (Basic code) s = guarded_run limit code s" | "guarded_flow limit (Sequence a b) s = (guarded_flow limit a s \ (case flowrun a s of None \ False | Some q \ guarded_flow limit b q))" | "guarded_flow limit (Choice a b) s = guarded_flow limit (if registers s Rax = 0 then b else a) s" lemma effect_shift: "effect op n = Some m \ effect op (n + base) = Some (m + base)" by (cases op; cases n; auto split: if_splits; arith) lemma effect_frame: "effect op n = Some m \ transition op s = Some q \ drop m (stack q) = drop n (stack s)" by (cases op; cases n; cases "stack s") (auto simp: effect.simps transition.simps split: if_splits) lemma audit_limit: "n \ 512 \ audit code n = Some m \ m \ 512" by (induction code arbitrary: n) (auto split: if_splits bind_splits) lemma flowaudit_limit: "n \ 512 \ flowaudit code n = Some m \ m \ 512" proof (induction code arbitrary: n m) case (Basic code) then show ?case by (auto dest: audit_limit) next case (Sequence a b) obtain k where a: "flowaudit a n = Some k" and b: "flowaudit b k = Some m" using Sequence.prems(2) by (auto split: bind_splits) have "k \ 512" using Sequence.IH(1)[OF Sequence.prems(1) a] . then show ?case using Sequence.IH(2)[OF _ b] by blast next case (Choice a b) have "flowaudit a n = Some m" using Choice.prems(2) by (auto split: option.splits if_splits) then show ?case using Choice.IH(1)[OF Choice.prems(1)] by blast qed theorem audit_window: assumes "length (stack s) = base + n" "n \ 512" "audit code n = Some m" shows "\q. run code s = Some q \ length (stack q) = base + m \ drop m (stack q) = drop n (stack s) \ guarded_run (base + 512) code s" using assms proof (induction code arbitrary: s n m) case Nil then show ?case by auto next case (Cons op code) obtain k where effect: "effect op n = Some k" and bound: "k \ 512" and tail: "audit code k = Some m" using Cons.prems(3) by (auto split: if_splits bind_splits) have shifted: "effect op (length (stack s)) = Some (base + k)" using effect_shift[OF effect, of base] Cons.prems(1) by (simp add: add.commute) obtain p where p: "transition op s = Some p" "length (stack p) = base + k" using effect_sound[OF shifted] by blast obtain q where q: "run code p = Some q" "length (stack q) = base + m" "drop m (stack q) = drop k (stack p)" "guarded_run (base + 512) code p" using Cons.IH[OF p(2) bound tail] by blast have frame: "drop k (stack p) = drop n (stack s)" using effect_frame[OF effect p(1)] . have "length (stack s) \ base + 512" using Cons.prems(1,2) by arith then show ?case using p q frame by auto qed theorem flow_window: assumes "length (stack s) = base + n" "n \ 512" "flowaudit code n = Some m" shows "\q. flowrun code s = Some q \ length (stack q) = base + m \ drop m (stack q) = drop n (stack s) \ inputs q = inputs s \ guarded_flow (base + 512) code s" using assms proof (induction code arbitrary: s n m) case (Basic code) have audit: "audit code n = Some m" using Basic.prems by simp obtain q where q: "run code s = Some q" "length (stack q) = base + m" "drop m (stack q) = drop n (stack s)" "guarded_run (base + 512) code s" using audit_window[OF Basic.prems(1,2) audit] by blast show ?case using q audit_inputs[OF audit q(1)] by auto next case (Sequence a b) obtain k where a: "flowaudit a n = Some k" and b: "flowaudit b k = Some m" using Sequence.prems(3) by (auto split: bind_splits) obtain p where p: "flowrun a s = Some p" "length (stack p) = base + k" "drop k (stack p) = drop n (stack s)" "inputs p = inputs s" "guarded_flow (base + 512) a s" using Sequence.IH(1)[OF Sequence.prems(1,2) a] by blast have bound: "k \ 512" using flowaudit_limit[OF Sequence.prems(2) a] . obtain q where q: "flowrun b p = Some q" "length (stack q) = base + m" "drop m (stack q) = drop k (stack p)" "inputs q = inputs p" "guarded_flow (base + 512) b p" using Sequence.IH(2)[OF p(2) bound b] by blast show ?case using p q by auto next case (Choice a b) have a: "flowaudit a n = Some m" and b: "flowaudit b n = Some m" using Choice.prems(3) by (auto split: option.splits if_splits) show ?case using Choice.IH(1)[OF Choice.prems(1,2) a] Choice.IH(2)[OF Choice.prems(1,2) b] by (cases "registers s Rax = 0") auto qed corollary checked_frame: "flowaudit code 0 = Some 0 \ \q. flowrun code s = Some q \ stack q = stack s \ inputs q = inputs s \ guarded_flow (length (stack s) + 512) code s" using flow_window[where s=s and base="length (stack s)" and n=0 and m=0 and code=code] by auto end