参考文档 / ZLIB × LEAN
trees.c.inv.lean
此页源文件快照 ·
85e95ff42714325e · 对应提交的原文 ↗本页保留 Lean 源码及行号。点击行号可定位语句,点击 import 中的模块名可查看依赖。
1import ZlibF.Zlib.«trees.c»
2
3/-!
4# trees.c: the invariant `TreesInv` and the calculus the proofs of `trees.c` use
5
6* `Wp`, a weakest-precondition calculus for `M` (loops with a measure, `if`, `bind`).
7* `setD`, the heap after replacing a deflate record; run lemmas for the helpers of `trees.c.lean`
8 (`rd`, `md`, `getFc`, `setFc`, ...) in terms of it.
9* `TreesInv h id`: the deflate state of block `id` is well formed for the code of `trees.c` (array sizes,
10 descriptors, bit buffer, the byte block that holds `pending_buf` and `sym_buf`, the static tables).
11 `TreesBase` is the part `deflateInit2_` establishes before `_tr_init` runs; `_tr_init_safe` extends it to
12 `TreesInv`.
13* The bit stream of the output (`outBits`): the bits of the pending bytes followed by the bits of `bi_buf`.
14-/
15
16namespace Zlib.Trees.Proofs.Out
17open C Zlib.Trees
18
19/-! ## A weakest-precondition calculus for `M` -/
20
21/-- `m` runs on `h` without a fault and its result satisfies `Q`. -/
22def Wp {α : Type} (m : M α) (h : Heap) (Q : α → Heap → Prop) : Prop :=
23 ∃ a h', m h = .ok (a, h') ∧ Q a h'
24
25theorem Wp.pure' {α : Type} {a : α} {h : Heap} {Q : α → Heap → Prop} (hq : Q a h) :
26 Wp (Pure.pure a : M α) h Q := ⟨a, h, rfl, hq⟩
27
28theorem Wp.bind' {α β : Type} {m : M α} {f : α → M β} {h : Heap} {Q : α → Heap → Prop} {R : β → Heap → Prop}
29 (hm : Wp m h Q) (hf : ∀ a h', Q a h' → Wp (f a) h' R) : Wp (m >>= f) h R := by
30 obtain ⟨a, h1, e, hq⟩ := hm
31 obtain ⟨b, h2, e2, hr⟩ := hf a h1 hq
32 exact ⟨b, h2, by rw [bind_app, e]; exact e2, hr⟩
33
34theorem Wp.mono {α : Type} {m : M α} {h : Heap} {Q R : α → Heap → Prop} (hm : Wp m h Q)
35 (hr : ∀ a h', Q a h' → R a h') : Wp m h R := by
36 obtain ⟨a, h1, e, hq⟩ := hm
37 exact ⟨a, h1, e, hr a h1 hq⟩
38
39theorem Wp.ite {α : Type} {c : Prop} [Decidable c] {m1 m2 : M α} {h : Heap} {Q : α → Heap → Prop}
40 (h1 : c → Wp m1 h Q) (h2 : ¬ c → Wp m2 h Q) : Wp (if c then m1 else m2) h Q := by
41 by_cases hc : c
42 · simp only [hc, ite_true]; exact h1 hc
43 · simp only [hc, ite_false]; exact h2 hc
44
45theorem Wp.of_eq {α : Type} {m : M α} {h h' : Heap} {a : α} (e : m h = .ok (a, h')) {Q : α → Heap → Prop}
46 (hq : Q a h') : Wp m h Q := ⟨a, h', e, hq⟩
47
48theorem Wp.bind_eq {α β : Type} {m : M α} {f : α → M β} {h h1 : Heap} {a : α} {R : β → Heap → Prop}
49 (e : m h = .ok (a, h1)) (hf : Wp (f a) h1 R) : Wp (m >>= f) h R := by
50 obtain ⟨b, h2, e2, hr⟩ := hf
51 exact ⟨b, h2, by rw [bind_app, e]; exact e2, hr⟩
52
53/-- Loop with a measure: `Inv` is kept, the measure decreases at each iteration, and `Q` holds when the
54condition fails. -/
55theorem Wp.cwhile {σ : Type} {cond : σ → M (Bool × σ)} {body : σ → M σ} (Inv : σ → Heap → Prop) (μ : σ → Nat)
56 (Q : σ → Heap → Prop)
57 (hstep : ∀ s h, Inv s h →
58 (∃ s1 h1, cond s h = .ok ((false, s1), h1) ∧ Q s1 h1) ∨
59 (∃ s1 h1 s2 h2, cond s h = .ok ((true, s1), h1) ∧ body s1 h1 = .ok (s2, h2) ∧ Inv s2 h2 ∧ μ s2 < μ s))
60 {s : σ} {h : Heap} (hI : Inv s h) (hfuel : μ s < fuel) :
61 Wp (cwhile cond body s) h Q := by
62 have key : ∀ k n s h, Inv s h → μ s ≤ k → k < n → ∃ s' h', cwhile.go cond body n s h = .ok (s', h') ∧ Q s' h' := by
63 intro k
64 induction k using Nat.strongRecOn with
65 | _ k ih =>
66 intro n s h hI hμ hn
67 obtain ⟨n, rfl⟩ : ∃ m, n = m + 1 := ⟨n - 1, by omega⟩
68 rcases hstep s h hI with ⟨s1, h1, hc, hq⟩ | ⟨s1, h1, s2, h2, hc, hb, hI2, hlt⟩
69 · exact ⟨s1, h1, by simp [cwhile.go, hc], hq⟩
70 · obtain ⟨s', h', hgo, hq⟩ := ih (μ s2) (by omega) n s2 h2 hI2 (Nat.le_refl _) (by omega)
71 exact ⟨s', h', by simp [cwhile.go, hc, hb, hgo], hq⟩
72 obtain ⟨s', h', e, hq⟩ := key (μ s) fuel s h hI (Nat.le_refl _) hfuel
73 exact ⟨s', h', e, hq⟩
74
75/-- `do ... while` with a measure: `Inv` holds before each body; the measure decreases. -/
76theorem Wp.cdoWhile {σ : Type} {cond : σ → M (Bool × σ)} {body : σ → M σ} (Inv : σ → Heap → Prop) (μ : σ → Nat)
77 (Q : σ → Heap → Prop)
78 (hstep : ∀ s h, Inv s h → ∃ s1 h1, body s h = .ok (s1, h1) ∧
79 ((∃ s2 h2, cond s1 h1 = .ok ((false, s2), h2) ∧ Q s2 h2) ∨
80 (∃ s2 h2, cond s1 h1 = .ok ((true, s2), h2) ∧ Inv s2 h2 ∧ μ s2 < μ s)))
81 {s : σ} {h : Heap} (hI : Inv s h) (hfuel : μ s < fuel) :
82 Wp (cdoWhile body cond s) h Q := by
83 have key : ∀ k n s h, Inv s h → μ s ≤ k → k < n → ∃ s' h', cdoWhile.go body cond n s h = .ok (s', h') ∧ Q s' h' := by
84 intro k
85 induction k using Nat.strongRecOn with
86 | _ k ih =>
87 intro n s h hI hμ hn
88 obtain ⟨n, rfl⟩ : ∃ m, n = m + 1 := ⟨n - 1, by omega⟩
89 obtain ⟨s1, h1, hb, hc⟩ := hstep s h hI
90 rcases hc with ⟨s2, h2, hc, hq⟩ | ⟨s2, h2, hc, hI2, hlt⟩
91 · exact ⟨s2, h2, by simp [cdoWhile.go, hb, hc], hq⟩
92 · obtain ⟨s', h', hgo, hq⟩ := ih (μ s2) (by omega) n s2 h2 hI2 (Nat.le_refl _) (by omega)
93 exact ⟨s', h', by simp [cdoWhile.go, hb, hc, hgo], hq⟩
94 obtain ⟨s', h', e, hq⟩ := key (μ s) fuel s h hI (Nat.le_refl _) hfuel
95 exact ⟨s', h', e, hq⟩
96
97/-! ## Machine integers -/
98
99theorem i32_ofInt_toInt {v : Int} (h1 : -2147483648 ≤ v) (h2 : v ≤ 2147483647) : (Int32.ofInt v).toInt = v := by
100 rw [Int32.toInt_ofInt]
101 simp only [Int32.size, Int.bmod]
102 omega
103
104theorem ck_eq {x : Int} (h1 : -2147483648 ≤ x) (h2 : x ≤ 2147483647) : ck x = pure (Int32.ofInt x) := by
105 funext h; simp [ck, h1, h2]
106
107theorem iadd_eq {a b : Int32} (h1 : -2147483648 ≤ a.toInt + b.toInt) (h2 : a.toInt + b.toInt ≤ 2147483647) :
108 iadd a b = pure (Int32.ofInt (a.toInt + b.toInt)) := ck_eq h1 h2
109
110theorem isub_eq {a b : Int32} (h1 : -2147483648 ≤ a.toInt - b.toInt) (h2 : a.toInt - b.toInt ≤ 2147483647) :
111 isub a b = pure (Int32.ofInt (a.toInt - b.toInt)) := ck_eq h1 h2
112
113/-! ## The deflate record and its helpers -/
114
115/-- The heap after replacing the deflate record `id`. -/
116def setD (h : Heap) (id : Nat) (d : DeflateState) : Heap := { h with dstates := upd h.dstates id (some d) }
117
118@[simp] theorem setD_dstates_same (h : Heap) (id : Nat) (d : DeflateState) : (setD h id d).dstates id = some d := by
119 simp [setD]
120theorem setD_dstates_ne (h : Heap) (id k : Nat) (d : DeflateState) (hne : k ≠ id) :
121 (setD h id d).dstates k = h.dstates k := by simp [setD, hne]
122@[simp] theorem setD_bytes (h : Heap) (id : Nat) (d : DeflateState) : (setD h id d).bytes = h.bytes := rfl
123@[simp] theorem setD_words (h : Heap) (id : Nat) (d : DeflateState) : (setD h id d).words = h.words := rfl
124@[simp] theorem setD_ro (h : Heap) (id : Nat) (d : DeflateState) : (setD h id d).ro = h.ro := rfl
125@[simp] theorem setD_static (h : Heap) (id : Nat) (d : DeflateState) : (setD h id d).static = h.static := rfl
126@[simp] theorem setD_streams (h : Heap) (id : Nat) (d : DeflateState) : (setD h id d).streams = h.streams := rfl
127@[simp] theorem setD_setD (h : Heap) (id : Nat) (d d' : DeflateState) : setD (setD h id d) id d' = setD h id d' := by
128 simp [setD, upd_upd]
129
130/-- The heap after replacing the byte block `b`. -/
131def setB (h : Heap) (b : Nat) (a : Array UInt8) : Heap := { h with bytes := upd h.bytes b (some a) }
132
133@[simp] theorem setB_bytes_same (h : Heap) (b : Nat) (a : Array UInt8) : (setB h b a).bytes b = some a := by
134 simp [setB]
135theorem setB_bytes_ne (h : Heap) (b k : Nat) (a : Array UInt8) (hne : k ≠ b) : (setB h b a).bytes k = h.bytes k := by
136 simp [setB, hne]
137@[simp] theorem setB_dstates (h : Heap) (b : Nat) (a : Array UInt8) : (setB h b a).dstates = h.dstates := rfl
138@[simp] theorem setB_ro (h : Heap) (b : Nat) (a : Array UInt8) : (setB h b a).ro = h.ro := rfl
139@[simp] theorem setB_static (h : Heap) (b : Nat) (a : Array UInt8) : (setB h b a).static = h.static := rfl
140@[simp] theorem setB_words (h : Heap) (b : Nat) (a : Array UInt8) : (setB h b a).words = h.words := rfl
141@[simp] theorem setD_setB (h : Heap) (id b : Nat) (a : Array UInt8) (d : DeflateState) :
142 setD (setB h b a) id d = setB (setD h id d) b a := rfl
143
144theorem rd_run {h : Heap} {id : Nat} {d : DeflateState} (e : h.dstates id = some d) :
145 rd (some (.tab id)) h = .ok (d, h) := ldDeflateState_tab e
146
147theorem md_run {h : Heap} {id : Nat} {d : DeflateState} (e : h.dstates id = some d) (f : DeflateState → DeflateState) :
148 md (some (.tab id)) f h = .ok ((), setD h id (f d)) := by
149 simp [md, ldDeflateState_tab e, stDeflateState_tab e, setD]
150 try rfl
151
152theorem sid_run {h : Heap} {id : Nat} {d : DeflateState} (e : h.dstates id = some d) :
153 sid (some (.tab id)) h = .ok (id, h) := by
154 simp [sid, ldDeflateState_tab e]; try rfl
155
156/-- The deflate record `id` of `h` (the default record if it is not live). -/
157def rdD (h : Heap) (id : Nat) : DeflateState := (h.dstates id).getD default
158
159theorem rd_run' {h : Heap} {id : Nat} (e : h.dstates id ≠ none) :
160 rd (some (.tab id)) h = .ok (rdD h id, h) := by
161 cases hd : h.dstates id with
162 | none => exact absurd hd e
163 | some d => simp [rdD, hd, rd_run hd]
164
165theorem md_run' {h : Heap} {id : Nat} (e : h.dstates id ≠ none) (f : DeflateState → DeflateState) :
166 md (some (.tab id)) f h = .ok ((), setD h id (f (rdD h id))) := by
167 cases hd : h.dstates id with
168 | none => exact absurd hd e
169 | some d => simp [rdD, hd, md_run hd]
170
171@[simp] theorem rdD_setD_same (h : Heap) (id : Nat) (d : DeflateState) : rdD (setD h id d) id = d := by
172 simp [rdD]
173@[simp] theorem rdD_setB (h : Heap) (id b : Nat) (a : Array UInt8) : rdD (setB h b a) id = rdD h id := rfl
174theorem setD_ne_none (h : Heap) (id : Nat) (d : DeflateState) : (setD h id d).dstates id ≠ none := by simp
175
176theorem pLtree_run {h : Heap} {id : Nat} {d : DeflateState} (e : h.dstates id = some d) :
177 pLtree (some (.tab id)) h = .ok (.ref (.dstate_dyn_ltree id) 0, h) := by
178 simp [pLtree, sid_run e]; try rfl
179theorem pDtree_run {h : Heap} {id : Nat} {d : DeflateState} (e : h.dstates id = some d) :
180 pDtree (some (.tab id)) h = .ok (.ref (.dstate_dyn_dtree id) 0, h) := by
181 simp [pDtree, sid_run e]; try rfl
182theorem pBltree_run {h : Heap} {id : Nat} {d : DeflateState} (e : h.dstates id = some d) :
183 pBltree (some (.tab id)) h = .ok (.ref (.dstate_bl_tree id) 0, h) := by
184 simp [pBltree, sid_run e]; try rfl
185theorem pHeap_run {h : Heap} {id : Nat} {d : DeflateState} (e : h.dstates id = some d) :
186 pHeap (some (.tab id)) h = .ok (.ref (.dstate_heap id) 0, h) := by
187 simp [pHeap, sid_run e]; try rfl
188theorem pDepth_run {h : Heap} {id : Nat} {d : DeflateState} (e : h.dstates id = some d) :
189 pDepth (some (.tab id)) h = .ok (.ref (.dstate_depth id) 0, h) := by
190 simp [pDepth, sid_run e]; try rfl
191theorem pBlCount_run {h : Heap} {id : Nat} {d : DeflateState} (e : h.dstates id = some d) :
192 pBlCount (some (.tab id)) h = .ok (.ref (.dstate_bl_count id) 0, h) := by
193 simp [pBlCount, sid_run e]; try rfl
194
195
196/-! ## The static data of `trees.c` -/
197
198/-- The static tables and descriptors of `trees.c` are installed: `install_trees` (`trees.c.lean`) provides this on
199any heap, and no function of `trees.c` changes `h.static`. -/
200def TreesStatic (st : Statics) : Prop := trees_statics st = st
201
202theorem install_trees_static (h : Heap) : TreesStatic (install_trees h).static := by
203 simp [TreesStatic, install_trees, trees_statics]
204
205theorem TreesStatic.dist_code {st : Statics} (hs : TreesStatic st) : st.dist_code = dist_code_tab := by
206 have := congrArg Statics.dist_code hs; simpa [trees_statics] using this.symm
207theorem TreesStatic.length_code {st : Statics} (hs : TreesStatic st) : st.length_code = length_code_tab := by
208 have := congrArg Statics.length_code hs; simpa [trees_statics] using this.symm
209theorem TreesStatic.base_dist {st : Statics} (hs : TreesStatic st) : st.base_dist = base_dist_tab := by
210 have := congrArg Statics.base_dist hs; simpa [trees_statics] using this.symm
211theorem TreesStatic.base_length {st : Statics} (hs : TreesStatic st) : st.base_length = base_length_tab := by
212 have := congrArg Statics.base_length hs; simpa [trees_statics] using this.symm
213theorem TreesStatic.static_ltree {st : Statics} (hs : TreesStatic st) : st.static_ltree = static_ltree_tab := by
214 have := congrArg Statics.static_ltree hs; simpa [trees_statics] using this.symm
215theorem TreesStatic.static_dtree {st : Statics} (hs : TreesStatic st) : st.static_dtree = static_dtree_tab := by
216 have := congrArg Statics.static_dtree hs; simpa [trees_statics] using this.symm
217theorem TreesStatic.extra_lbits {st : Statics} (hs : TreesStatic st) : st.extra_lbits = extra_lbits_tab := by
218 have := congrArg Statics.extra_lbits hs; simpa [trees_statics] using this.symm
219theorem TreesStatic.extra_dbits {st : Statics} (hs : TreesStatic st) : st.extra_dbits = extra_dbits_tab := by
220 have := congrArg Statics.extra_dbits hs; simpa [trees_statics] using this.symm
221theorem TreesStatic.extra_blbits {st : Statics} (hs : TreesStatic st) : st.extra_blbits = extra_blbits_tab := by
222 have := congrArg Statics.extra_blbits hs; simpa [trees_statics] using this.symm
223
224theorem dist_code_tab_size : dist_code_tab.size = 512 := by decide +kernel
225theorem length_code_tab_size : length_code_tab.size = 256 := by decide +kernel
226theorem static_ltree_tab_size : static_ltree_tab.size = 288 := by decide +kernel
227theorem static_dtree_tab_size : static_dtree_tab.size = 30 := by decide +kernel
228
229/-! ## The invariant -/
230
231/-- **What `deflateInit2_` establishes before `_tr_init` runs.** The deflate record `d` of block `id` is live and
232well formed (`dyn_ltree`, `heap`, `depth` have `HEAP_SIZE` = 573 entries, `dyn_dtree` 61, `bl_tree` 39, `bl_count`
23316); the static tables of `trees.c` are installed; `pending_buf` is the start of the writable byte block `b`, whose
234content is `buf` and whose size is `4 * lit_bufsize` (`ZALLOC(strm, lit_bufsize, LIT_BUFS)`, with
235`pending_buf_size = 4 * lit_bufsize`); `sym_buf = pending_buf + lit_bufsize` is in the same block
236(`deflate.c` L519: the overlay of the symbols on the output); `sym_end = (lit_bufsize - 1) * 3`;
237`lit_bufsize = 1 << (memLevel + 6)` lies in `128 .. 32768`; and `pending <= pending_buf_size` (zero after
238`deflateResetKeep`). -/
239structure TreesBase (h : Heap) (id : Nat) (d : DeflateState) (b : Nat) (buf : Array UInt8) : Prop where
240 dstate : h.dstates id = some d
241 wf : d.WellFormed
242 static : TreesStatic h.static
243 pbuf : d.pending_buf = .ref (.blk b) 0
244 bytes : h.bytes b = some buf
245 rw : h.ro b = false
246 size : buf.size = 4 * d.lit_bufsize.toNat
247 psize : d.pending_buf_size.toNat = buf.size
248 sym : d.sym_buf = .ref (.blk b) d.lit_bufsize.toNat
249 lit_lo : 128 ≤ d.lit_bufsize.toNat
250 lit_hi : d.lit_bufsize.toNat ≤ 32768
251 sym_end : d.sym_end.toNat = 3 * (d.lit_bufsize.toNat - 1)
252 pending_le : d.pending.toNat ≤ d.pending_buf_size.toNat
253
254/-- **What `_tr_init` adds.** The three tree descriptors point at the arrays of the record and at the static
255descriptors; the bit buffer holds `bi_valid <= 16 = Buf_size` bits (fact F9 of `docs/proof/trees.md`: `send_bits`
256shifts by at most 16) and no bit above them; the symbol count is a multiple of 3 and at most `sym_end`
257(`_tr_tally` is always followed by a flush when `sym_next == sym_end`). -/
258structure TreesRun (id : Nat) (d : DeflateState) : Prop where
259 ldyn : d.l_desc.dyn_tree = .ref (.dstate_dyn_ltree id) 0
260 lstat : d.l_desc.stat_desc = some .st_static_l_desc
261 ddyn : d.d_desc.dyn_tree = .ref (.dstate_dyn_dtree id) 0
262 dstat : d.d_desc.stat_desc = some .st_static_d_desc
263 bldyn : d.bl_desc.dyn_tree = .ref (.dstate_bl_tree id) 0
264 blstat : d.bl_desc.stat_desc = some .st_static_bl_desc
265 bi_lo : 0 ≤ d.bi_valid.toInt
266 bi_hi : d.bi_valid.toInt ≤ 16
267 bi_buf : d.bi_buf.toNat < 2 ^ d.bi_valid.toInt.toNat
268 sym_next_le : d.sym_next.toNat ≤ d.sym_end.toNat
269 sym_next_mod : d.sym_next.toNat % 3 = 0
270
271/-- The part of `TreesRun` that does not mention the symbol buffer: descriptors and bit buffer. -/
272structure TreesRun0 (id : Nat) (d : DeflateState) : Prop where
273 ldyn : d.l_desc.dyn_tree = .ref (.dstate_dyn_ltree id) 0
274 lstat : d.l_desc.stat_desc = some .st_static_l_desc
275 ddyn : d.d_desc.dyn_tree = .ref (.dstate_dyn_dtree id) 0
276 dstat : d.d_desc.stat_desc = some .st_static_d_desc
277 bldyn : d.bl_desc.dyn_tree = .ref (.dstate_bl_tree id) 0
278 blstat : d.bl_desc.stat_desc = some .st_static_bl_desc
279 bi_lo : 0 ≤ d.bi_valid.toInt
280 bi_hi : d.bi_valid.toInt ≤ 16
281 bi_buf : d.bi_buf.toNat < 2 ^ d.bi_valid.toInt.toNat
282
283theorem TreesRun.to0 {id : Nat} {d : DeflateState} (hr : TreesRun id d) : TreesRun0 id d :=
284 ⟨hr.ldyn, hr.lstat, hr.ddyn, hr.dstat, hr.bldyn, hr.blstat, hr.bi_lo, hr.bi_hi, hr.bi_buf⟩
285
286theorem TreesRun0.withSym {id : Nat} {d : DeflateState} (hr : TreesRun0 id d) (h1 : d.sym_next.toNat ≤ d.sym_end.toNat)
287 (h2 : d.sym_next.toNat % 3 = 0) : TreesRun id d :=
288 ⟨hr.ldyn, hr.lstat, hr.ddyn, hr.dstat, hr.bldyn, hr.blstat, hr.bi_lo, hr.bi_hi, hr.bi_buf, h1, h2⟩
289
290/-- **The deflate state is well formed for the code of `trees.c`**, with the byte block `b` (content `buf`) that
291holds `pending_buf` and `sym_buf`. -/
292structure TreesInvAt (h : Heap) (id : Nat) (d : DeflateState) (b : Nat) (buf : Array UInt8) : Prop where
293 base : TreesBase h id d b buf
294 run : TreesRun id d
295
296/-- `TreesInv h id`: the deflate state of block `id` is well formed for the code of `trees.c` (see `TreesInvAt`). -/
297def TreesInv (h : Heap) (id : Nat) : Prop := ∃ d b buf, TreesInvAt h id d b buf
298
299/-- Everything of the heap except the byte block `b` and the deflate record `id` is the same. -/
300structure HFrame (h h' : Heap) (b id : Nat) : Prop where
301 bytes : ∀ k, k ≠ b → h'.bytes k = h.bytes k
302 dstates : ∀ k, k ≠ id → h'.dstates k = h.dstates k
303 words : ∀ k, h'.words k = h.words k
304 ro : ∀ k, h'.ro k = h.ro k
305 streams : ∀ k, h'.streams k = h.streams k
306 gzheaders : ∀ k, h'.gzheaders k = h.gzheaders k
307 istates : ∀ k, h'.istates k = h.istates k
308 gzstates : ∀ k, h'.gzstates k = h.gzstates k
309 static : h'.static = h.static
310 nextBlk : h'.nextBlk = h.nextBlk
311 nalloc : h'.nalloc = h.nalloc
312 allocOk : h'.allocOk = h.allocOk
313 garbage : h'.garbage = h.garbage
314
315theorem HFrame.refl (h : Heap) (b id : Nat) : HFrame h h b id :=
316 ⟨fun _ _ => rfl, fun _ _ => rfl, fun _ => rfl, fun _ => rfl, fun _ => rfl, fun _ => rfl, fun _ => rfl,
317 fun _ => rfl, rfl, rfl, rfl, rfl, rfl⟩
318
319theorem HFrame.trans {h1 h2 h3 : Heap} {b id : Nat} (a : HFrame h1 h2 b id) (c : HFrame h2 h3 b id) :
320 HFrame h1 h3 b id :=
321 ⟨fun k hk => (c.bytes k hk).trans (a.bytes k hk), fun k hk => (c.dstates k hk).trans (a.dstates k hk),
322 fun k => (c.words k).trans (a.words k), fun k => (c.ro k).trans (a.ro k),
323 fun k => (c.streams k).trans (a.streams k), fun k => (c.gzheaders k).trans (a.gzheaders k),
324 fun k => (c.istates k).trans (a.istates k), fun k => (c.gzstates k).trans (a.gzstates k),
325 c.static.trans a.static, c.nextBlk.trans a.nextBlk, c.nalloc.trans a.nalloc, c.allocOk.trans a.allocOk,
326 c.garbage.trans a.garbage⟩
327
328theorem HFrame.setD (h : Heap) (b id : Nat) (d : DeflateState) : HFrame h (setD h id d) b id :=
329 ⟨fun _ _ => rfl, fun k hk => setD_dstates_ne h id k d hk, fun _ => rfl, fun _ => rfl, fun _ => rfl,
330 fun _ => rfl, fun _ => rfl, fun _ => rfl, rfl, rfl, rfl, rfl, rfl⟩
331
332theorem HFrame.setB (h : Heap) (b id : Nat) (a : Array UInt8) : HFrame h (setB h b a) b id :=
333 ⟨fun k hk => setB_bytes_ne h b k a hk, fun _ _ => rfl, fun _ => rfl, fun _ => rfl, fun _ => rfl,
334 fun _ => rfl, fun _ => rfl, fun _ => rfl, rfl, rfl, rfl, rfl, rfl⟩
335
336
337/-! ## The bit stream of the output -/
338
339/-- The low `n` bits of `v`, least significant first. -/
340def natBits (v n : Nat) : List Bool := (List.range n).map (fun i => v.testBit i)
341
342/-- The bits of the first `n` bytes of `a`, each byte least significant bit first. -/
343def bytesBits (a : Array UInt8) (n : Nat) : List Bool := (List.range n).flatMap (fun i => natBits (a.getD i 0).toNat 8)
344
345/-- **The output so far**, as a bit stream: the bits of the pending bytes `pending_buf[0 .. pending)` (each byte least
346significant bit first, as DEFLATE packs them), followed by the `bi_valid` low bits of `bi_buf` (least significant
347first). `buf` is the content of the byte block of `pending_buf`. Every bit writer of `trees.c` appends to this
348stream, and `flush_pending` moves complete bytes out of it. -/
349def outBits (buf : Array UInt8) (d : DeflateState) : List Bool :=
350 bytesBits buf d.pending.toNat ++ natBits d.bi_buf.toNat d.bi_valid.toInt.toNat
351
352@[simp] theorem natBits_length (v n : Nat) : (natBits v n).length = n := by simp [natBits]
353
354theorem natBits_add (v m n : Nat) : natBits v (m + n) = natBits v m ++ natBits (v >>> m) n := by
355 unfold natBits
356 rw [List.range_add, List.map_append, List.map_map]
357 congr 1
358 apply List.map_congr_left
359 intro i _
360 simp [Nat.testBit_shiftRight]
361
362theorem natBits_congr {v w : Nat} (n : Nat) (h : v % 2 ^ n = w % 2 ^ n) : natBits v n = natBits w n := by
363 unfold natBits
364 apply List.map_congr_left
365 intro i hi
366 have hi : i < n := List.mem_range.mp hi
367 have h1 := Nat.testBit_mod_two_pow v n i
368 rw [h] at h1
369 simp [hi] at h1
370 exact h1.symm
371
372theorem natBits_zero (n : Nat) : natBits 0 n = List.replicate n false := by
373 unfold natBits
374 apply List.ext_getElem <;> simp
375
376@[simp] theorem bytesBits_zero (a : Array UInt8) : bytesBits a 0 = [] := by simp [bytesBits]
377
378theorem bytesBits_succ (a : Array UInt8) (n : Nat) :
379 bytesBits a (n + 1) = bytesBits a n ++ natBits (a.getD n 0).toNat 8 := by
380 simp [bytesBits, List.range_succ]
381
382@[simp] theorem bytesBits_length (a : Array UInt8) (n : Nat) : (bytesBits a n).length = 8 * n := by
383 induction n with
384 | zero => simp
385 | succ n ih => rw [bytesBits_succ]; simp [ih]; omega
386
387theorem bytesBits_congr {a a' : Array UInt8} (n : Nat) (h : ∀ i, i < n → a.getD i 0 = a'.getD i 0) :
388 bytesBits a n = bytesBits a' n := by
389 induction n with
390 | zero => simp
391 | succ n ih =>
392 rw [bytesBits_succ, bytesBits_succ, ih (fun i hi => h i (by omega)), h n (by omega)]
393
394theorem bytesBits_set {a : Array UInt8} {j n : Nat} (v : UInt8) (hj : n ≤ j) :
395 bytesBits (a.set! j v) n = bytesBits a n := by
396 apply bytesBits_congr
397 intro i hi
398 rw [Array.set!_eq_setIfInBounds, Array.getD_eq_getD_getElem?, Array.getD_eq_getD_getElem?,
399 Array.getElem?_setIfInBounds]
400 have : j ≠ i := by omega
401 simp [this]
402
403end Zlib.Trees.Proofs.Out