~james/remy

feat(encoding): prove decoder progress and consumed byte bounds

commit
44cdd77b156b101cebd114088595dd4f1a0203fb browse tree
parent
e43395488ea9ada734e845de1d029e87990e690f
author
james <j@cpl0.zip>
signature
Verified ~james signed with a key registered by ~james
date
2026-10-15 11:00 UTC

1 files changed, +47 −0

src/Encoding.thy modified

@@ -176,6 +176,53 @@ theorem encode_injective:
176176 using decode_encode[of a "[]"] decode_encode[of b "[]"]
177177 by (metis append_Nil option.inject prod.inject)
178178
179+lemma push_nonempty [simp]: "pushcode r \<noteq> []"
180+ by (cases r) auto
181+
182+lemma pop_nonempty [simp]: "popcode r \<noteq> []"
183+ by (cases r) auto
184+
185+lemma arithmetic_nonempty [simp]: "arithmetic op \<noteq> []"
186+ by (cases op) auto
187+
188+lemma encode_nonempty [simp]: "encode op \<noteq> []"
189+ by (cases op) (auto simp: movecode_def)
190+
191+lemma fixed_decode:
192+ "List.find (\<lambda>op. take (length (encode op)) bs = encode op) fixed = Some op \<Longrightarrow>
193+ 0 < length (encode op) \<and> length (encode op) \<le> length bs \<and>
194+ list_all (\<lambda>b. b < 256) (take (length (encode op)) bs)"
195+ using encode_bytes[of op]
196+ by (auto simp: find_Some_iff list_all_iff dest: arg_cong[where f=length])
197+
198+theorem decode_progress:
199+ "decode bs = Some (op,rest) \<Longrightarrow> length rest < length bs"
200+ unfolding decode_def
201+ apply (auto simp: Let_def dest: fixed_decode split: if_splits option.splits)
202+ apply (drule fixed_decode)
203+ apply auto
204+ by (cases bs) auto
205+
206+theorem decode_consumed:
207+ "decode bs = Some (op,rest) \<Longrightarrow> list_all (\<lambda>b. b < 256) bs \<Longrightarrow>
208+ \<exists>prefix. bs = prefix @ rest \<and> prefix \<noteq> [] \<and> list_all (\<lambda>b. b < 256) prefix"
209+proof -
210+ assume decoded: "decode bs = Some (op,rest)"
211+ and input: "list_all (\<lambda>b. b < 256) bs"
212+ have drop: "rest = drop (length bs - length rest) bs"
213+ using decoded unfolding decode_def
214+ apply (auto simp: Let_def split: if_splits option.splits)
215+ apply (drule fixed_decode)
216+ by auto
217+ have bytes: "list_all (\<lambda>b. b < 256) (take (length bs - length rest) bs)"
218+ using input by (auto simp: list_all_iff dest: in_set_takeD)
219+ have decomposition: "bs = take (length bs - length rest) bs @ rest"
220+ using drop append_take_drop_id[of "length bs - length rest" bs] by metis
221+ show ?thesis
222+ using decomposition bytes decode_progress[OF decoded]
223+ by (intro exI[where x="take (length bs - length rest) bs"]) auto
224+qed
225+
179226 fun recover :: "nat \<Rightarrow> nat list \<Rightarrow> (opcode list \<times> nat list) option" where
180227 "recover 0 bs = Some ([],bs)"
181228 | "recover (Suc n) bs = Option.bind (decode bs) (\<lambda>(op,tail).