参考文档 / ZLIB × LEAN
deflate.c.base.lean
此页源文件快照 ·
a3ee5f0d1fd13b4f · 对应提交的原文 ↗本页保留 Lean 源码及行号。点击行号可定位语句,点击 import 中的模块名可查看依赖。
1import ZlibF.Zlib.«deflate.c»
2import ZlibF.Proof.«zutil.c»
3import ZlibF.Proof.«trees.c.bits»
4
5/-!
6# deflate.c: the stream invariant and the lemmas the stream functions share
7
8The statements of `docs/spec/api/deflate-stream.md`. The definitions of namespace `Zlib.Deflate.Spec` are part of
9what a theorem means; the lemmas of `Zlib.Deflate.Proofs` are not.
10
11* `Uniq`: a block number holds an object of at most one table.
12* `DBlocks`: the four buffers of a deflate state (window, prev, head, pending_buf) are live blocks of the right size.
13* `DStInv`: the representation invariant of a deflate state record (array sizes, hash and window relations, the
14 ranges of level, strategy and wrapper, the pointers into the blocks, the symbol buffer and the bit buffer).
15* `DLive`: the stream is one that `deflateStateCheck` accepts, and its state is the record `d` at block `ds`.
16* `DGood`: `DLive`, `DStInv`, `Uniq`, `Fresh` and the trees invariant together.
17
18The proofs of the engine (`deflate`, `fill_window`, the strategies) import this module: a function that keeps
19`DGood` keeps the bounds the next function needs.
20
21**The trees invariant.** `DGood` includes `TreesInv h ds` of `trees.c.inv`: the invariant the functions of `trees.c` need
22(descriptors, static tables, the byte block that holds `pending_buf` and `sym_buf`). Several of its facts are also stated
23in `DStInv` (`bits`, `sym`), so that a proof about the lifecycle functions can read them without unpacking it.
24-/
25
26namespace Zlib.Deflate.Spec
27open C
28
29/-- 1 if the table entry holds an object, else 0. -/
30def cnt {α : Type} (o : Option α) : Nat := if o.isSome then 1 else 0
31
32@[simp] theorem cnt_none {α : Type} : cnt (none : Option α) = 0 := rfl
33@[simp] theorem cnt_some {α : Type} (a : α) : cnt (some a) = 1 := rfl
34
35/-- A block number holds an object of at most one table. -/
36def Uniq (h : Heap) : Prop := ∀ b,
37 cnt (h.bytes b) + cnt (h.words b) + cnt (h.streams b) + cnt (h.gzheaders b) + cnt (h.dstates b) + cnt (h.istates b) +
38 cnt (h.gzstates b) ≤ 1
39
40/-- The heap with the deflate state record `ds` replaced. -/
41def setD (h : Heap) (ds : Nat) (d : DeflateState) : Heap := { h with dstates := upd h.dstates ds (some d) }
42
43/-- The status values `deflateStateCheck` accepts: the zlib header, the gzip header, extra, name, comment, header CRC,
44busy and finish. -/
45def GoodStatus (s : Int32) : Prop :=
46 s = INIT_STATE ∨ s = GZIP_STATE ∨ s = EXTRA_STATE ∨ s = NAME_STATE ∨ s = COMMENT_STATE ∨ s = HCRC_STATE ∨
47 s = BUSY_STATE ∨ s = FINISH_STATE
48
49/-- The user's gzip header pointer: `NULL`, or a live `gz_header` record. -/
50def GzOk (h : Heap) (g : Option GzHeaderRef) : Prop :=
51 g = none ∨ ∃ i, g = some (.tab i) ∧ (h.gzheaders i).isSome
52
53/-- The four buffers of the deflate state record `d`: `window` is the writable byte block `w` of `2 * w_size` bytes,
54`pending_buf` the writable byte block `b` of `4 * lit_bufsize` bytes, `prev` and `head` are blocks of 16-bit words that
55hold `w_size` and `hash_size` entries. The four blocks are different. `pending_out` lies in `pending_buf`
56and `pending_out + pending` does not leave it. -/
57structure DBlocks (h : Heap) (d : DeflateState) (w p q b : Nat) : Prop where
58 win : d.window = .ref (.blk w) 0
59 prev : d.prev = .ref (.blk p) 0
60 head : d.head = .ref (.blk q) 0
61 pbuf : d.pending_buf = .ref (.blk b) 0
62 wa : ∃ a, h.bytes w = some a ∧ a.size = 2 * d.w_size.toNat
63 wro : h.ro w = false
64 pa : ∃ a, h.words p = some a ∧ a.size = d.w_size.toNat
65 qa : ∃ a, h.words q = some a ∧ a.size = d.hash_size.toNat
66 ba : ∃ a, h.bytes b = some a ∧ a.size = 4 * d.lit_bufsize.toNat
67 bro : h.ro b = false
68 psize : d.pending_buf_size.toNat = 4 * d.lit_bufsize.toNat
69 wb : w ≠ b
70 pq : p ≠ q
71 pout : ∃ off, d.pending_out = .ref (.blk b) off ∧ off + d.pending.toNat ≤ d.pending_buf_size.toNat
72
73/-- The representation invariant of a deflate state record `d` at block `ds`, as far as the stream functions and the
74engine need it (`deflateInit2_` establishes it).
75
76* sizes: `w_bits` is 9 to 15, `w_size = 2^w_bits`, `w_mask = w_size - 1`, `window_size = 2 * w_size`; `hash_bits` is 8 to
77 16 (`memLevel + 7`), `hash_size = 2^hash_bits`, `hash_mask = hash_size - 1`, `hash_shift = (hash_bits + 2) / 3`,
78 `lit_bufsize = hash_size / 2 = 2^(memLevel + 6)`;
79* ranges: `level` 0 to 9, `strategy` 0 to 4, `method = Z_DEFLATED`, `wrap` from `-2` to `2` (negative after the trailer);
80* `high_water <= window_size`;
81* the symbol buffer overlays `pending_buf` at `lit_bufsize`, `sym_end = 3 (lit_bufsize - 1)`, `sym_next <= sym_end`
82 and a multiple of 3;
83* the bit buffer holds `bi_valid` bits (0 to 16) and no bit above them. -/
84structure DStInv (h : Heap) (ds : Nat) (d : DeflateState) : Prop where
85 wf : d.WellFormed
86 wbits_lo : 9 ≤ d.w_bits.toNat
87 wbits_hi : d.w_bits.toNat ≤ 15
88 wsize : d.w_size.toNat = 2 ^ d.w_bits.toNat
89 wmask : d.w_mask.toNat = d.w_size.toNat - 1
90 wsz : d.window_size.toNat = 2 * d.w_size.toNat
91 hbits_lo : 8 ≤ d.hash_bits.toNat
92 hbits_hi : d.hash_bits.toNat ≤ 16
93 hsize : d.hash_size.toNat = 2 ^ d.hash_bits.toNat
94 hmask : d.hash_mask.toNat = d.hash_size.toNat - 1
95 hshift : d.hash_shift.toNat = (d.hash_bits.toNat + 2) / 3
96 lit : 2 * d.lit_bufsize.toNat = d.hash_size.toNat
97 level_lo : 0 ≤ d.level.toInt
98 level_hi : d.level.toInt ≤ 9
99 strat_lo : 0 ≤ d.strategy.toInt
100 strat_hi : d.strategy.toInt ≤ 4
101 method : d.method = 8
102 wrap_lo : -2 ≤ d.wrap.toInt
103 wrap_hi : d.wrap.toInt ≤ 2
104 hw : d.high_water.toNat ≤ d.window_size.toNat
105 blocks : ∃ w p q b, DBlocks h d w p q b
106 sym : (∃ b, d.pending_buf = .ref (.blk b) 0 ∧ d.sym_buf = .ref (.blk b) d.lit_bufsize.toNat) ∧
107 d.sym_end.toNat = 3 * (d.lit_bufsize.toNat - 1) ∧ d.sym_next.toNat ≤ d.sym_end.toNat ∧ d.sym_next.toNat % 3 = 0
108 bits : 0 ≤ d.bi_valid.toInt ∧ d.bi_valid.toInt ≤ 16 ∧ d.bi_buf.toNat < 2 ^ d.bi_valid.toInt.toNat
109 gz : GzOk h d.gzhead
110
111/-- The stream `r` is the record `z`; its state is the record `d` at block `ds`, which points back to the stream; the
112status is one `deflateStateCheck` accepts; the allocator functions are not `NULL`. -/
113structure DLive (h : Heap) (r : ZStreamRef) (ds : Nat) (z : ZStream) (d : DeflateState) : Prop where
114 hz : r.get h = some z
115 hs : h.dstates ds = some d
116 zst : z.state = some (.deflate ds)
117 back : d.strm = some r
118 status : GoodStatus d.status
119 zalloc : z.zalloc ≠ .null
120 zfree : z.zfree ≠ .null
121
122/-- The stream functions can allocate and free: the allocator functions are the default ones (the only ones the model
123has; any other makes the translation fault). -/
124def DefAlloc (z : ZStream) : Prop := z.zalloc = .fn "zcalloc" ∧ z.zfree = .fn "zcfree"
125
126/-- Everything the stream functions assume of the heap around a live deflate stream. -/
127structure DGood (h : Heap) (r : ZStreamRef) (ds : Nat) (z : ZStream) (d : DeflateState) : Prop where
128 live : DLive h r ds z d
129 inv : DStInv h ds d
130 uniq : Uniq h
131 fresh : Fresh h
132 trees : Zlib.Trees.Proofs.Out.TreesInv h ds
133
134/-- The blocks a stream owns: its state record and the four buffers. -/
135def DOwned (d : DeflateState) (ds : Nat) (x : Nat) : Prop :=
136 x = ds ∨ (∃ w, d.window = .ref (.blk w) 0 ∧ x = w) ∨ (∃ p, d.prev = .ref (.blk p) 0 ∧ x = p) ∨
137 (∃ q, d.head = .ref (.blk q) 0 ∧ x = q) ∨ (∃ b, d.pending_buf = .ref (.blk b) 0 ∧ x = b)
138
139/-- The streams `deflateStateCheck` handles: `NULL`, or a live stream record that has a `NULL` allocator function, or
140no state, or a state that is a live deflate state record. (A state that is an inflate state, a freed state or a freed
141stream is undefined behaviour in C and a fault here.) -/
142def StreamDom (h : Heap) (strm : ZStreamPtr) : Prop :=
143 strm = none ∨ ∃ r z, strm = some r ∧ r.get h = some z ∧
144 (z.zalloc = .null ∨ z.zfree = .null ∨ z.state = none ∨ ∃ ds d, z.state = some (.deflate ds) ∧ h.dstates ds = some d)
145
146/-- The stream is one `deflateStateCheck` accepts. -/
147def DInitialised (h : Heap) (strm : ZStreamPtr) : Prop := ∃ r ds z d, strm = some r ∧ DLive h r ds z d
148
149end Zlib.Deflate.Spec
150
151namespace Zlib.Deflate.Proofs
152open C Zlib.Deflate Zlib.Deflate.Spec
153
154/-! ### Updating the heap -/
155
156@[simp] theorem setD_dstates_same (h : Heap) (ds : Nat) (d : DeflateState) : (setD h ds d).dstates ds = some d := by
157 simp [setD]
158@[simp] theorem setD_dstates_ne (h : Heap) (ds x : Nat) (d : DeflateState) (hx : x ≠ ds) :
159 (setD h ds d).dstates x = h.dstates x := by simp [setD, upd_ne _ _ _ _ hx]
160@[simp] theorem setD_bytes (h : Heap) (ds : Nat) (d : DeflateState) : (setD h ds d).bytes = h.bytes := rfl
161@[simp] theorem setD_words (h : Heap) (ds : Nat) (d : DeflateState) : (setD h ds d).words = h.words := rfl
162@[simp] theorem setD_streams (h : Heap) (ds : Nat) (d : DeflateState) : (setD h ds d).streams = h.streams := rfl
163@[simp] theorem setD_gzstates (h : Heap) (ds : Nat) (d : DeflateState) : (setD h ds d).gzstates = h.gzstates := rfl
164@[simp] theorem setD_gzheaders (h : Heap) (ds : Nat) (d : DeflateState) : (setD h ds d).gzheaders = h.gzheaders := rfl
165@[simp] theorem setD_istates (h : Heap) (ds : Nat) (d : DeflateState) : (setD h ds d).istates = h.istates := rfl
166@[simp] theorem setD_ro (h : Heap) (ds : Nat) (d : DeflateState) : (setD h ds d).ro = h.ro := rfl
167@[simp] theorem setD_static (h : Heap) (ds : Nat) (d : DeflateState) : (setD h ds d).static = h.static := rfl
168@[simp] theorem setD_nextBlk (h : Heap) (ds : Nat) (d : DeflateState) : (setD h ds d).nextBlk = h.nextBlk := rfl
169@[simp] theorem setD_nalloc (h : Heap) (ds : Nat) (d : DeflateState) : (setD h ds d).nalloc = h.nalloc := rfl
170@[simp] theorem setD_allocOk (h : Heap) (ds : Nat) (d : DeflateState) : (setD h ds d).allocOk = h.allocOk := rfl
171@[simp] theorem setD_garbage (h : Heap) (ds : Nat) (d : DeflateState) : (setD h ds d).garbage = h.garbage := rfl
172@[simp] theorem setD_setD (h : Heap) (ds : Nat) (d d' : DeflateState) : setD (setD h ds d) ds d' = setD h ds d' := by
173 simp [setD, upd_upd]
174theorem setD_self {h : Heap} {ds : Nat} {d : DeflateState} (hd : h.dstates ds = some d) : setD h ds d = h := by
175 simp [setD, upd_self _ _ _ hd]
176
177theorem ZStreamRef.get_put_same {h : Heap} {r : ZStreamRef} {z : ZStream} (e : r.get h = some z) (v : ZStream) :
178 r.get (r.put h v) = some v := by
179 cases r with
180 | tab i => simp [ZStreamRef.get] at e; simp [ZStreamRef.put, ZStreamRef.get, e]
181 | in_gzstate_strm i =>
182 simp [ZStreamRef.get] at e
183 obtain ⟨g, hg, -⟩ := e
184 simp [ZStreamRef.put, ZStreamRef.get, hg]
185
186@[simp] theorem ZStreamRef.get_setD (h : Heap) (r : ZStreamRef) (ds : Nat) (d : DeflateState) :
187 r.get (setD h ds d) = r.get h := by
188 cases r <;> rfl
189
190@[simp] theorem ZStreamRef.put_dstates (h : Heap) (r : ZStreamRef) (v : ZStream) : (r.put h v).dstates = h.dstates := by
191 cases r with
192 | tab i => simp only [ZStreamRef.put]; split <;> rfl
193 | in_gzstate_strm i => simp only [ZStreamRef.put]; split <;> rfl
194
195@[simp] theorem ZStreamRef.put_bytes (h : Heap) (r : ZStreamRef) (v : ZStream) : (r.put h v).bytes = h.bytes := by
196 cases r with
197 | tab i => simp only [ZStreamRef.put]; split <;> rfl
198 | in_gzstate_strm i => simp only [ZStreamRef.put]; split <;> rfl
199
200@[simp] theorem ZStreamRef.put_ro (h : Heap) (r : ZStreamRef) (v : ZStream) : (r.put h v).ro = h.ro := by
201 cases r with
202 | tab i => simp only [ZStreamRef.put]; split <;> rfl
203 | in_gzstate_strm i => simp only [ZStreamRef.put]; split <;> rfl
204
205@[simp] theorem ZStreamRef.put_words (h : Heap) (r : ZStreamRef) (v : ZStream) : (r.put h v).words = h.words := by
206 cases r with
207 | tab i => simp only [ZStreamRef.put]; split <;> rfl
208 | in_gzstate_strm i => simp only [ZStreamRef.put]; split <;> rfl
209
210@[simp] theorem ZStreamRef.put_istates (h : Heap) (r : ZStreamRef) (v : ZStream) : (r.put h v).istates = h.istates := by
211 cases r with
212 | tab i => simp only [ZStreamRef.put]; split <;> rfl
213 | in_gzstate_strm i => simp only [ZStreamRef.put]; split <;> rfl
214
215@[simp] theorem ZStreamRef.put_gzheaders (h : Heap) (r : ZStreamRef) (v : ZStream) :
216 (r.put h v).gzheaders = h.gzheaders := by
217 cases r with
218 | tab i => simp only [ZStreamRef.put]; split <;> rfl
219 | in_gzstate_strm i => simp only [ZStreamRef.put]; split <;> rfl
220
221@[simp] theorem ZStreamRef.put_nextBlk (h : Heap) (r : ZStreamRef) (v : ZStream) : (r.put h v).nextBlk = h.nextBlk := by
222 cases r with
223 | tab i => simp only [ZStreamRef.put]; split <;> rfl
224 | in_gzstate_strm i => simp only [ZStreamRef.put]; split <;> rfl
225
226@[simp] theorem ZStreamRef.put_nalloc (h : Heap) (r : ZStreamRef) (v : ZStream) : (r.put h v).nalloc = h.nalloc := by
227 cases r with
228 | tab i => simp only [ZStreamRef.put]; split <;> rfl
229 | in_gzstate_strm i => simp only [ZStreamRef.put]; split <;> rfl
230
231@[simp] theorem ZStreamRef.put_allocOk (h : Heap) (r : ZStreamRef) (v : ZStream) : (r.put h v).allocOk = h.allocOk := by
232 cases r with
233 | tab i => simp only [ZStreamRef.put]; split <;> rfl
234 | in_gzstate_strm i => simp only [ZStreamRef.put]; split <;> rfl
235
236@[simp] theorem ZStreamRef.put_garbage (h : Heap) (r : ZStreamRef) (v : ZStream) : (r.put h v).garbage = h.garbage := by
237 cases r with
238 | tab i => simp only [ZStreamRef.put]; split <;> rfl
239 | in_gzstate_strm i => simp only [ZStreamRef.put]; split <;> rfl
240
241@[simp] theorem ZStreamRef.put_static (h : Heap) (r : ZStreamRef) (v : ZStream) : (r.put h v).static = h.static := by
242 cases r with
243 | tab i => simp only [ZStreamRef.put]; split <;> rfl
244 | in_gzstate_strm i => simp only [ZStreamRef.put]; split <;> rfl
245
246@[simp] theorem ZStreamRef.get_put (h : Heap) (r : ZStreamRef) (v : ZStream) :
247 r.get (r.put h v) = (r.get h).map (fun _ => v) := by
248 cases r with
249 | tab i =>
250 simp only [ZStreamRef.put, ZStreamRef.get]
251 cases hh : h.streams i <;> simp [hh]
252 | in_gzstate_strm i =>
253 simp only [ZStreamRef.put, ZStreamRef.get]
254 cases hh : h.gzstates i <;> simp [hh]
255
256@[simp] theorem ZStreamRef.put_put (h : Heap) (r : ZStreamRef) (v v' : ZStream) : r.put (r.put h v) v' = r.put h v' := by
257 cases r with
258 | tab i =>
259 simp only [ZStreamRef.put]
260 cases hh : h.streams i <;> simp [hh, upd_upd]
261 | in_gzstate_strm i =>
262 simp only [ZStreamRef.put]
263 cases hh : h.gzstates i <;> simp [hh, upd_upd]
264
265@[simp] theorem ZStreamRef.put_setD (h : Heap) (r : ZStreamRef) (ds : Nat) (d : DeflateState) (v : ZStream) :
266 r.put (setD h ds d) v = setD (r.put h v) ds d := by
267 cases r with
268 | tab i => simp only [ZStreamRef.put, setD]; cases hh : h.streams i <;> simp
269 | in_gzstate_strm i => simp only [ZStreamRef.put, setD]; cases hh : h.gzstates i <;> simp
270
271/-! ### Reading and writing the stream and the state -/
272
273theorem castD {h : Heap} {ds : Nat} : castDeflateState (some (.deflate ds)) h = .ok (some (.tab ds), h) := rfl
274
275theorem ldD_eq (h : Heap) (i : Nat) : ldDeflateState (some (.tab i)) h =
276 match h.dstates i with
277 | some v => .ok (v, h)
278 | none => .error (.ub "access through a dangling pointer (deflate_state)") := rfl
279
280theorem ldZ_eq (h : Heap) (r : ZStreamRef) : ldZStream (some r) h =
281 match r.get h with
282 | some v => .ok (v, h)
283 | none => .error (.ub "access through a dangling pointer (z_stream)") := rfl
284
285theorem rdD_eq {α : Type} (h : Heap) (i : Nat) (f : DeflateState → α) : rd (some (.tab i)) f h =
286 match h.dstates i with
287 | some v => .ok (f v, h)
288 | none => .error (.ub "access through a dangling pointer (deflate_state)") := by
289 simp only [rd, bind_app, ldD_eq]; cases h.dstates i <;> rfl
290
291theorem zrd_eq {α : Type} (h : Heap) (r : ZStreamRef) (f : ZStream → α) : zrd (some r) f h =
292 match r.get h with
293 | some v => .ok (f v, h)
294 | none => .error (.ub "access through a dangling pointer (z_stream)") := by
295 simp only [zrd, bind_app, ldZ_eq]; cases r.get h <;> rfl
296
297theorem stD_eq (h : Heap) (i : Nat) (v : DeflateState) : stDeflateState (some (.tab i)) v h =
298 match h.dstates i with
299 | some _ => .ok ((), setD h i v)
300 | none => .error (.ub "access through a dangling pointer (deflate_state)") := by
301 cases hh : h.dstates i with
302 | none => simp [stDeflateState, DeflateStateRef.get, hh]
303 | some w => simp [stDeflateState_tab hh, setD, hh]
304
305theorem wrD_eq (h : Heap) (i : Nat) (f : DeflateState → DeflateState) : wr (some (.tab i)) f h =
306 match h.dstates i with
307 | some v => .ok ((), setD h i (f v))
308 | none => .error (.ub "access through a dangling pointer (deflate_state)") := by
309 cases hh : h.dstates i with
310 | none => simp [wr, bind_app, ldD_eq, hh]
311 | some v => simp [wr, bind_app, ldD_eq, hh, stD_eq]
312
313theorem stZ_eq (h : Heap) (r : ZStreamRef) (v : ZStream) : stZStream (some r) v h =
314 match r.get h with
315 | some _ => .ok ((), r.put h v)
316 | none => .error (.ub "access through a dangling pointer (z_stream)") := by
317 have hro : r.isRo = false := by cases r <;> rfl
318 cases hh : r.get h with
319 | none => simp [stZStream, hh]
320 | some w => simp [stZStream_ok hh hro, hh]
321
322theorem zwr_eq (h : Heap) (r : ZStreamRef) (f : ZStream → ZStream) : zwr (some r) f h =
323 match r.get h with
324 | some v => .ok ((), r.put h (f v))
325 | none => .error (.ub "access through a dangling pointer (z_stream)") := by
326 cases hh : r.get h with
327 | none => simp [zwr, bind_app, ldZ_eq, hh]
328 | some v => simp [zwr, bind_app, ldZ_eq, hh, stZ_eq]
329
330/-- Evaluate a straight-line sequence of accesses to a stream and its deflate state. -/
331macro "dsimp'" "[" ts:Lean.Parser.Tactic.simpLemma,* "]" : tactic =>
332 `(tactic| simp [bind_app, pure_app, ldD_eq, ldZ_eq, rdD_eq, zrd_eq, wrD_eq, zwr_eq, stD_eq, stZ_eq, castD, $ts,*])
333
334/-! ### The stream check -/
335
336theorem hdec {a b : UInt32} : a ≤ b ∨ b < a := by
337 rcases Nat.lt_or_ge b.toNat a.toNat with h | h
338 · exact Or.inr (UInt32.lt_iff_toNat_lt.mpr h)
339 · exact Or.inl (UInt32.le_iff_toNat_le.mpr h)
340
341theorem stateCheck_live {h : Heap} {r : ZStreamRef} {ds : Nat} {z : ZStream} {d : DeflateState}
342 (hL : DLive h r ds z d) : deflateStateCheck (some r) h = .ok (0, h) := by
343 obtain ⟨hz, hs, zst, back, st, za, zf⟩ := hL
344 have e1 : ldZStream (some r) h = .ok (z, h) := ldZStream_ok hz
345 unfold deflateStateCheck
346 rcases st with hh | hh | hh | hh | hh | hh | hh | hh <;>
347 simp [bind_app, e1, za, zf, zst, castDeflateState_ok, ldDeflateState_tab hs, back, hh]
348
349
350theorem ZStreamRef.put_self {h : Heap} {r : ZStreamRef} {z : ZStream} (e : r.get h = some z) : r.put h z = h := by
351 cases r with
352 | tab i =>
353 simp only [ZStreamRef.get] at e
354 simp [ZStreamRef.put, e, upd_self _ _ _ e]
355 | in_gzstate_strm i =>
356 simp only [ZStreamRef.get] at e
357 obtain ⟨g, hg, rfl⟩ := Option.map_eq_some_iff.mp e
358 simp [ZStreamRef.put, hg, upd_self _ _ _ hg]
359
360/-! ### Which objects exist: the shape of a heap -/
361
362/-- The two heaps hold an object in the same tables at the same block numbers (the objects may differ). -/
363def Shape (h h' : Heap) : Prop := ∀ b, (h'.bytes b).isSome = (h.bytes b).isSome ∧ (h'.words b).isSome = (h.words b).isSome ∧
364 (h'.streams b).isSome = (h.streams b).isSome ∧ (h'.gzheaders b).isSome = (h.gzheaders b).isSome ∧
365 (h'.dstates b).isSome = (h.dstates b).isSome ∧ (h'.istates b).isSome = (h.istates b).isSome ∧
366 (h'.gzstates b).isSome = (h.gzstates b).isSome
367
368theorem _root_.Zlib.Deflate.Proofs.Shape.refl (h : Heap) : Shape h h := fun _ => ⟨rfl, rfl, rfl, rfl, rfl, rfl, rfl⟩
369
370theorem _root_.Zlib.Deflate.Proofs.Shape.trans {h1 h2 h3 : Heap} (a : Shape h1 h2) (b : Shape h2 h3) : Shape h1 h3 := by
371 intro x
372 obtain ⟨a1, a2, a3, a4, a5, a6, a7⟩ := a x
373 obtain ⟨b1, b2, b3, b4, b5, b6, b7⟩ := b x
374 exact ⟨b1.trans a1, b2.trans a2, b3.trans a3, b4.trans a4, b5.trans a5, b6.trans a6, b7.trans a7⟩
375
376theorem _root_.Zlib.Deflate.Proofs.Shape.uniq {h h' : Heap} (hS : Shape h h') (hU : Uniq h) : Uniq h' := by
377 intro b
378 obtain ⟨e1, e2, e3, e4, e5, e6, e7⟩ := hS b
379 have := hU b
380 simp only [cnt, e1, e2, e3, e4, e5, e6, e7] at this ⊢
381 exact this
382
383theorem _root_.Zlib.Deflate.Proofs.Shape.live {h h' : Heap} (hS : Shape h h') (b : Nat) : h'.live b ↔ h.live b := by
384 obtain ⟨e1, e2, e3, e4, e5, e6, e7⟩ := hS b
385 simp only [Heap.live, ← Option.isSome_iff_ne_none, e1, e2, e3, e4, e5, e6, e7]
386
387theorem _root_.Zlib.Deflate.Proofs.Shape.fresh {h h' : Heap} (hS : Shape h h') (hn : h'.nextBlk = h.nextBlk) (hF : Fresh h) : Fresh h' := by
388 intro b hb hl
389 exact hF b (by omega) ((hS.live b).1 hl)
390
391theorem _root_.Zlib.Deflate.Proofs.Shape.owns {h h' : Heap} (hS : Shape h h') {S : Nat → Prop} (hO : h.Owns S) : h'.Owns S :=
392 fun b => (hS.live b).trans (hO b)
393
394theorem shape_setD {h : Heap} {ds : Nat} {d0 : DeflateState} (e : h.dstates ds = some d0) (d : DeflateState) :
395 Shape h (setD h ds d) := by
396 intro b
397 by_cases hb : b = ds
398 · subst hb; simp [setD, e]
399 · simp [setD, upd_ne _ _ _ _ hb]
400
401theorem shape_put {h : Heap} {r : ZStreamRef} {z0 : ZStream} (e : r.get h = some z0) (v : ZStream) :
402 Shape h (r.put h v) := by
403 cases r with
404 | tab i =>
405 simp only [ZStreamRef.get] at e
406 intro b
407 by_cases hb : b = i
408 · subst hb; simp [ZStreamRef.put, e]
409 · simp [ZStreamRef.put, e, upd_ne _ _ _ _ hb]
410 | in_gzstate_strm i =>
411 simp only [ZStreamRef.get] at e
412 obtain ⟨g, hg, -⟩ := Option.map_eq_some_iff.mp e
413 intro b
414 by_cases hb : b = i
415 · subst hb; simp [ZStreamRef.put, hg]
416 · simp [ZStreamRef.put, hg, upd_ne _ _ _ _ hb]
417
418theorem shape_setB {h : Heap} {w : Nat} {a0 : Array UInt8} (e : h.bytes w = some a0) (a : Array UInt8) :
419 Shape h { h with bytes := upd h.bytes w (some a) } := by
420 intro b
421 by_cases hb : b = w
422 · subst hb; simp [e]
423 · simp [upd_ne _ _ _ _ hb]
424
425theorem shape_setW {h : Heap} {w : Nat} {a0 : Array UInt16} (e : h.words w = some a0) (a : Array UInt16) :
426 Shape h { h with words := upd h.words w (some a) } := by
427 intro b
428 by_cases hb : b = w
429 · subst hb; simp [e]
430 · simp [upd_ne _ _ _ _ hb]
431
432/-! ### Uniqueness -/
433
434theorem _root_.Zlib.Deflate.Spec.Uniq.bytes_only {h : Heap} (hU : Uniq h) {b : Nat} {a : Array UInt8} (hb : h.bytes b = some a) :
435 h.words b = none ∧ h.streams b = none ∧ h.gzheaders b = none ∧ h.dstates b = none ∧ h.istates b = none ∧
436 h.gzstates b = none := by
437 have := hU b
438 simp only [hb, cnt_some] at this
439 refine ⟨?_, ?_, ?_, ?_, ?_, ?_⟩
440 · cases hx : h.words b with
441 | none => rfl
442 | some _ => simp only [hx, cnt_some] at this <;> omega
443 · cases hx : h.streams b with
444 | none => rfl
445 | some _ => simp only [hx, cnt_some] at this <;> omega
446 · cases hx : h.gzheaders b with
447 | none => rfl
448 | some _ => simp only [hx, cnt_some] at this <;> omega
449 · cases hx : h.dstates b with
450 | none => rfl
451 | some _ => simp only [hx, cnt_some] at this <;> omega
452 · cases hx : h.istates b with
453 | none => rfl
454 | some _ => simp only [hx, cnt_some] at this <;> omega
455 · cases hx : h.gzstates b with
456 | none => rfl
457 | some _ => simp only [hx, cnt_some] at this <;> omega
458
459theorem _root_.Zlib.Deflate.Spec.Uniq.words_only {h : Heap} (hU : Uniq h) {b : Nat} {a : Array UInt16} (hb : h.words b = some a) :
460 h.bytes b = none ∧ h.streams b = none ∧ h.gzheaders b = none ∧ h.dstates b = none ∧ h.istates b = none ∧
461 h.gzstates b = none := by
462 have := hU b
463 simp only [hb, cnt_some] at this
464 refine ⟨?_, ?_, ?_, ?_, ?_, ?_⟩
465 · cases hx : h.bytes b with
466 | none => rfl
467 | some _ => simp only [hx, cnt_some] at this <;> omega
468 · cases hx : h.streams b with
469 | none => rfl
470 | some _ => simp only [hx, cnt_some] at this <;> omega
471 · cases hx : h.gzheaders b with
472 | none => rfl
473 | some _ => simp only [hx, cnt_some] at this <;> omega
474 · cases hx : h.dstates b with
475 | none => rfl
476 | some _ => simp only [hx, cnt_some] at this <;> omega
477 · cases hx : h.istates b with
478 | none => rfl
479 | some _ => simp only [hx, cnt_some] at this <;> omega
480 · cases hx : h.gzstates b with
481 | none => rfl
482 | some _ => simp only [hx, cnt_some] at this <;> omega
483
484theorem _root_.Zlib.Deflate.Spec.Uniq.dstates_only {h : Heap} (hU : Uniq h) {b : Nat} {a : DeflateState} (hb : h.dstates b = some a) :
485 h.bytes b = none ∧ h.words b = none ∧ h.streams b = none ∧ h.gzheaders b = none ∧ h.istates b = none ∧
486 h.gzstates b = none := by
487 have := hU b
488 simp only [hb, cnt_some] at this
489 refine ⟨?_, ?_, ?_, ?_, ?_, ?_⟩
490 · cases hx : h.bytes b with
491 | none => rfl
492 | some _ => simp only [hx, cnt_some] at this <;> omega
493 · cases hx : h.words b with
494 | none => rfl
495 | some _ => simp only [hx, cnt_some] at this <;> omega
496 · cases hx : h.streams b with
497 | none => rfl
498 | some _ => simp only [hx, cnt_some] at this <;> omega
499 · cases hx : h.gzheaders b with
500 | none => rfl
501 | some _ => simp only [hx, cnt_some] at this <;> omega
502 · cases hx : h.istates b with
503 | none => rfl
504 | some _ => simp only [hx, cnt_some] at this <;> omega
505 · cases hx : h.gzstates b with
506 | none => rfl
507 | some _ => simp only [hx, cnt_some] at this <;> omega
508
509/-! ### Preserving the invariants -/
510
511theorem _root_.Zlib.Deflate.Spec.DBlocks.congr {h h' : Heap} {d : DeflateState} {w p q b : Nat} (hb : h'.bytes = h.bytes)
512 (hw : h'.words = h.words) (hr : h'.ro = h.ro) (hB : DBlocks h d w p q b) : DBlocks h' d w p q b := by
513 obtain ⟨a1, a2, a3, a4, ⟨x1, y1, z1⟩, r1, ⟨x2, y2, z2⟩, ⟨x3, y3, z3⟩, ⟨x4, y4, z4⟩, r4, ps, wb, pq, po⟩ := hB
514 exact ⟨a1, a2, a3, a4, ⟨x1, by rw [hb]; exact y1, z1⟩, by rw [hr]; exact r1, ⟨x2, by rw [hw]; exact y2, z2⟩,
515 ⟨x3, by rw [hw]; exact y3, z3⟩, ⟨x4, by rw [hb]; exact y4, z4⟩, by rw [hr]; exact r4, ps, wb, pq, po⟩
516
517theorem _root_.Zlib.Deflate.Spec.DStInv.congr {h h' : Heap} {ds : Nat} {d : DeflateState} (hb : h'.bytes = h.bytes) (hw : h'.words = h.words)
518 (hr : h'.ro = h.ro) (hg : h'.gzheaders = h.gzheaders) (hI : DStInv h ds d) : DStInv h' ds d := by
519 obtain ⟨wf, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, ⟨w, p, q, b, hB⟩, sy, bi, gz⟩ := hI
520 refine ⟨wf, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19,
521 ⟨w, p, q, b, hB.congr hb hw hr⟩, sy, bi, ?_⟩
522 rcases gz with g | ⟨i, g, e⟩
523 · exact Or.inl g
524 · exact Or.inr ⟨i, g, by rw [hg]; exact e⟩
525
526theorem _root_.Zlib.Deflate.Spec.DBlocks.keys {h : Heap} {d d' : DeflateState} {w p q b : Nat}
527 (hB : DBlocks h d w p q b) (e1 : d'.window = d.window) (e2 : d'.prev = d.prev) (e3 : d'.head = d.head)
528 (e4 : d'.pending_buf = d.pending_buf) (e5 : d'.w_size = d.w_size) (e6 : d'.hash_size = d.hash_size)
529 (e7 : d'.lit_bufsize = d.lit_bufsize) (e8 : d'.pending_buf_size = d.pending_buf_size)
530 (e9 : d'.pending_out = d.pending_out) (e10 : d'.pending = d.pending) : DBlocks h d' w p q b := by
531 obtain ⟨a1, a2, a3, a4, ⟨x1, y1, z1⟩, r1, ⟨x2, y2, z2⟩, ⟨x3, y3, z3⟩, ⟨x4, y4, z4⟩, r4, ps, wb, pq, ⟨off, po, pl⟩⟩ := hB
532 refine ⟨by rw [e1]; exact a1, by rw [e2]; exact a2, by rw [e3]; exact a3, by rw [e4]; exact a4,
533 ⟨x1, y1, by rw [e5]; exact z1⟩, r1, ⟨x2, y2, by rw [e5]; exact z2⟩, ⟨x3, y3, by rw [e6]; exact z3⟩,
534 ⟨x4, y4, by rw [e7]; exact z4⟩, r4, by rw [e8, e7]; exact ps, wb, pq, ⟨off, by rw [e9]; exact po, by rw [e10, e8]; exact pl⟩⟩
535
536/-- The blocks of the state stay the same when the record changes only in fields other than the ten `DBlocks` reads
537(each equality is `rfl` for a record update that leaves them alone). -/
538theorem _root_.Zlib.Deflate.Spec.DStInv.blocks_keys {h : Heap} {ds : Nat} {d d' : DeflateState} (hI : DStInv h ds d)
539 (e1 : d'.window = d.window) (e2 : d'.prev = d.prev) (e3 : d'.head = d.head)
540 (e4 : d'.pending_buf = d.pending_buf) (e5 : d'.w_size = d.w_size) (e6 : d'.hash_size = d.hash_size)
541 (e7 : d'.lit_bufsize = d.lit_bufsize) (e8 : d'.pending_buf_size = d.pending_buf_size)
542 (e9 : d'.pending_out = d.pending_out) (e10 : d'.pending = d.pending) : ∃ w p q b, DBlocks h d' w p q b := by
543 obtain ⟨w, p, q, b, hB⟩ := hI.blocks
544 exact ⟨w, p, q, b, hB.keys e1 e2 e3 e4 e5 e6 e7 e8 e9 e10⟩
545
546/-- The fields of a state record that `trees.c` relies on are unchanged: the buffers and the symbol buffer, the three tree
547descriptors, the bit buffer and the symbol count. -/
548def TrKeep (d d' : DeflateState) : Prop :=
549 d'.pending_buf = d.pending_buf ∧ d'.pending_buf_size = d.pending_buf_size ∧ d'.sym_buf = d.sym_buf ∧
550 d'.lit_bufsize = d.lit_bufsize ∧ d'.sym_end = d.sym_end ∧ d'.l_desc = d.l_desc ∧ d'.d_desc = d.d_desc ∧
551 d'.bl_desc = d.bl_desc ∧ d'.bi_valid = d.bi_valid ∧ d'.bi_buf = d.bi_buf ∧ d'.sym_next = d.sym_next
552
553/-- Prove `TrKeep d d'` when `d'` is a record update of `d` that leaves those fields alone. -/
554macro "trkeep" : tactic => `(tactic| exact ⟨rfl, rfl, rfl, rfl, rfl, rfl, rfl, rfl, rfl, rfl, rfl⟩)
555
556/-- The invariant of `trees.c` survives a change of the state record that keeps the fields of `TrKeep` (and the sizes of
557its arrays), on a heap with the same byte blocks, read-only flags and static tables. -/
558theorem TreesInv.keep {h h' : Heap} {id : Nat} {d d' : DeflateState} (hT : Zlib.Trees.Proofs.Out.TreesInv h id)
559 (hd : h.dstates id = some d) (hb : h'.bytes = h.bytes) (hr : h'.ro = h.ro) (hs : h'.static = h.static)
560 (hd' : h'.dstates id = some d') (hw : d'.WellFormed) (hk : TrKeep d d')
561 (hp : d'.pending.toNat ≤ d'.pending_buf_size.toNat) : Zlib.Trees.Proofs.Out.TreesInv h' id := by
562 obtain ⟨d0, b, buf, hB, hR⟩ := hT
563 have e : d0 = d := Option.some.inj (hB.dstate.symm.trans hd)
564 subst e
565 obtain ⟨k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, k11⟩ := hk
566 refine ⟨d', b, buf, ⟨hd', hw, ?_, ?_, ?_, ?_, ?_, ?_, ?_, ?_, ?_, ?_, hp⟩, ?_⟩
567 · rw [hs]; exact hB.static
568 · rw [k1]; exact hB.pbuf
569 · rw [hb]; exact hB.bytes
570 · rw [hr]; exact hB.rw
571 · rw [k4]; exact hB.size
572 · rw [k2]; exact hB.psize
573 · rw [k3, k4]; exact hB.sym
574 · rw [k4]; exact hB.lit_lo
575 · rw [k4]; exact hB.lit_hi
576 · rw [k5, k4]; exact hB.sym_end
577 · refine ⟨by rw [k6]; exact hR.ldyn, by rw [k6]; exact hR.lstat, by rw [k7]; exact hR.ddyn, by rw [k7]; exact hR.dstat,
578 by rw [k8]; exact hR.bldyn, by rw [k8]; exact hR.blstat, by rw [k9]; exact hR.bi_lo, by rw [k9]; exact hR.bi_hi,
579 by rw [k10, k9]; exact hR.bi_buf, by rw [k11, k5]; exact hR.sym_next_le, by rw [k11]; exact hR.sym_next_mod⟩
580
581/-- Replacing a block of words keeps the invariant of `trees.c` (it mentions only byte blocks). -/
582theorem TreesInv.words_set {h : Heap} {id : Nat} (hT : Zlib.Trees.Proofs.Out.TreesInv h id) (x : Nat) (a : Array UInt16) :
583 Zlib.Trees.Proofs.Out.TreesInv { h with words := upd h.words x (some a) } id := by
584 obtain ⟨d, b, buf, hB, hR⟩ := hT
585 exact ⟨d, b, buf, ⟨hB.dstate, hB.wf, hB.static, hB.pbuf, hB.bytes, hB.rw, hB.size, hB.psize, hB.sym, hB.lit_lo,
586 hB.lit_hi, hB.sym_end, hB.pending_le⟩, hR⟩
587
588/-- Replacing a byte block by an array of the same size keeps the invariant of `trees.c`: if it is the block of
589`pending_buf` the content changes, which the invariant allows. -/
590theorem TreesInv.bytes_set {h : Heap} {id : Nat} (hT : Zlib.Trees.Proofs.Out.TreesInv h id) (x : Nat) (a a0 : Array UInt8)
591 (hx : h.bytes x = some a0) (hsz : a.size = a0.size) :
592 Zlib.Trees.Proofs.Out.TreesInv { h with bytes := upd h.bytes x (some a) } id := by
593 obtain ⟨d, b, buf, hB, hR⟩ := hT
594 by_cases hxb : x = b
595 · subst hxb
596 have : buf = a0 := Option.some.inj (hB.bytes.symm.trans hx)
597 subst this
598 exact ⟨d, x, a, ⟨hB.dstate, hB.wf, hB.static, hB.pbuf, by simp, hB.rw, by rw [hsz]; exact hB.size,
599 by rw [hsz]; exact hB.psize, hB.sym, hB.lit_lo, hB.lit_hi, hB.sym_end, hB.pending_le⟩, hR⟩
600 · exact ⟨d, b, buf, ⟨hB.dstate, hB.wf, hB.static, hB.pbuf, by simp [upd_apply, Ne.symm hxb, hB.bytes], hB.rw, hB.size,
601 hB.psize, hB.sym, hB.lit_lo, hB.lit_hi, hB.sym_end, hB.pending_le⟩, hR⟩
602
603theorem _root_.Zlib.Deflate.Spec.DStInv.pending_le {h : Heap} {ds : Nat} {d : DeflateState} (hI : DStInv h ds d) :
604 d.pending.toNat ≤ d.pending_buf_size.toNat := by
605 obtain ⟨w, p, q, b, hB⟩ := hI.blocks
606 obtain ⟨off, -, hpl⟩ := hB.pout
607 omega
608
609/-- Rewrite the stream record and the state record of a live stream, keeping the state pointer, the back pointer and
610the status; the new state record satisfies the invariant and keeps the fields `trees.c` relies on (`TrKeep`). -/
611theorem _root_.Zlib.Deflate.Spec.DGood.setZD {h : Heap} {r : ZStreamRef} {ds : Nat} {z : ZStream} {d : DeflateState}
612 (hG : DGood h r ds z d) {z' : ZStream} {d' : DeflateState}
613 (hz : z'.state = z.state) (hza : z'.zalloc ≠ .null) (hzf : z'.zfree ≠ .null) (hback : d'.strm = d.strm)
614 (hst : GoodStatus d'.status) (hI : DStInv h ds d') (hk : TrKeep d d') :
615 DGood (setD (r.put h z') ds d') r ds z' d' := by
616 have hS : Shape h (setD (r.put h z') ds d') :=
617 (shape_put hG.live.hz z').trans (shape_setD (by simpa using hG.live.hs) d')
618 have hT : Zlib.Trees.Proofs.Out.TreesInv (setD (r.put h z') ds d') ds :=
619 TreesInv.keep (d := d) (d' := d') (h := h) hG.trees hG.live.hs (by simp) (by simp) (by simp) (by simp) hI.wf hk
620 hI.pending_le
621 refine ⟨⟨?_, by simp, hz.trans hG.live.zst, hback.trans hG.live.back, hst, hza, hzf⟩,
622 DStInv.congr (h := h) (h' := setD (r.put h z') ds d') (by simp) (by simp) (by simp) (by simp) hI,
623 hS.uniq hG.uniq, hS.fresh (by simp) hG.fresh, hT⟩
624 simp [ZStreamRef.get_put, hG.live.hz]
625
626/-- The same for a change of the state record only. -/
627theorem _root_.Zlib.Deflate.Spec.DGood.setD' {h : Heap} {r : ZStreamRef} {ds : Nat} {z : ZStream} {d : DeflateState}
628 (hG : DGood h r ds z d) {d' : DeflateState} (hback : d'.strm = d.strm) (hst : GoodStatus d'.status)
629 (hI : DStInv h ds d') (hk : TrKeep d d') : DGood (setD h ds d') r ds z d' := by
630 have e : r.put h z = h := ZStreamRef.put_self hG.live.hz
631 have := hG.setZD (z' := z) (d' := d') rfl hG.live.zalloc hG.live.zfree hback hst hI hk
632 rw [e] at this
633 exact this
634
635/-- Replacing a block of words by an array of the same size keeps the four buffers. -/
636theorem _root_.Zlib.Deflate.Spec.DBlocks.words_set {h : Heap} {d : DeflateState} {w p q b : Nat}
637 (hB : DBlocks h d w p q b) (x : Nat) (a : Array UInt16) (a0 : Array UInt16) (hx : h.words x = some a0)
638 (hsz : a.size = a0.size) : DBlocks { h with words := upd h.words x (some a) } d w p q b := by
639 obtain ⟨a1, a2, a3, a4, wa, r1, ⟨pa, hpa, pz⟩, ⟨qa, hqa, qz⟩, ba, r4, ps, wb, pq, po⟩ := hB
640 refine ⟨a1, a2, a3, a4, wa, r1, ?_, ?_, ba, r4, ps, wb, pq, po⟩
641 · by_cases hxp : x = p
642 · subst hxp
643 have : pa = a0 := Option.some.inj (hpa.symm.trans hx)
644 subst this
645 exact ⟨a, by simp, by omega⟩
646 · exact ⟨pa, by simp [upd_apply, Ne.symm hxp, hpa], pz⟩
647 · by_cases hxq : x = q
648 · subst hxq
649 have : qa = a0 := Option.some.inj (hqa.symm.trans hx)
650 subst this
651 exact ⟨a, by simp, by omega⟩
652 · exact ⟨qa, by simp [upd_apply, Ne.symm hxq, hqa], qz⟩
653
654/-- Replacing a byte block by an array of the same size keeps the four buffers. -/
655theorem _root_.Zlib.Deflate.Spec.DBlocks.bytes_set {h : Heap} {d : DeflateState} {w p q b : Nat}
656 (hB : DBlocks h d w p q b) (x : Nat) (a : Array UInt8) (a0 : Array UInt8) (hx : h.bytes x = some a0)
657 (hsz : a.size = a0.size) : DBlocks { h with bytes := upd h.bytes x (some a) } d w p q b := by
658 obtain ⟨a1, a2, a3, a4, ⟨wa, hwa, wz⟩, r1, pa, qa, ⟨ba, hba, bz⟩, r4, ps, wb, pq, po⟩ := hB
659 refine ⟨a1, a2, a3, a4, ?_, r1, pa, qa, ?_, r4, ps, wb, pq, po⟩
660 · by_cases hxw : x = w
661 · subst hxw
662 have : wa = a0 := Option.some.inj (hwa.symm.trans hx)
663 subst this
664 exact ⟨a, by simp, by omega⟩
665 · exact ⟨wa, by simp [upd_apply, Ne.symm hxw, hwa], wz⟩
666 · by_cases hxb : x = b
667 · subst hxb
668 have : ba = a0 := Option.some.inj (hba.symm.trans hx)
669 subst this
670 exact ⟨a, by simp, by omega⟩
671 · exact ⟨ba, by simp [upd_apply, Ne.symm hxb, hba], bz⟩
672
673theorem _root_.Zlib.Deflate.Spec.DStInv.words_set {h : Heap} {ds : Nat} {d : DeflateState} (hI : DStInv h ds d)
674 (x : Nat) (a a0 : Array UInt16) (hx : h.words x = some a0) (hsz : a.size = a0.size) :
675 DStInv { h with words := upd h.words x (some a) } ds d := by
676 obtain ⟨w, p, q, b, hB⟩ := hI.blocks
677 exact { hI with blocks := ⟨w, p, q, b, hB.words_set x a a0 hx hsz⟩ }
678
679theorem _root_.Zlib.Deflate.Spec.DStInv.bytes_set {h : Heap} {ds : Nat} {d : DeflateState} (hI : DStInv h ds d)
680 (x : Nat) (a a0 : Array UInt8) (hx : h.bytes x = some a0) (hsz : a.size = a0.size)
681 (hro : ∀ y, y = x → h.ro y = h.ro y) :
682 DStInv { h with bytes := upd h.bytes x (some a) } ds d := by
683 obtain ⟨w, p, q, b, hB⟩ := hI.blocks
684 exact { hI with blocks := ⟨w, p, q, b, hB.bytes_set x a a0 hx hsz⟩ }
685
686/-- Replacing a block of words of a good heap by an array of the same size keeps it good. -/
687theorem _root_.Zlib.Deflate.Spec.DGood.words_set {h : Heap} {r : ZStreamRef} {ds : Nat} {z : ZStream} {d : DeflateState}
688 (hG : DGood h r ds z d) (x : Nat) (a a0 : Array UInt16) (hx : h.words x = some a0) (hsz : a.size = a0.size) :
689 DGood { h with words := upd h.words x (some a) } r ds z d := by
690 have hS := shape_setW hx a
691 refine ⟨⟨?_, ?_, hG.live.zst, hG.live.back, hG.live.status, hG.live.zalloc, hG.live.zfree⟩, hG.inv.words_set x a a0 hx hsz,
692 hS.uniq hG.uniq, hS.fresh rfl hG.fresh, TreesInv.words_set hG.trees x a⟩
693 · cases r <;> simpa [ZStreamRef.get] using hG.live.hz
694 · exact hG.live.hs
695
696/-- Replacing a byte block of a good heap by an array of the same size keeps it good. -/
697theorem _root_.Zlib.Deflate.Spec.DGood.bytes_set {h : Heap} {r : ZStreamRef} {ds : Nat} {z : ZStream} {d : DeflateState}
698 (hG : DGood h r ds z d) (x : Nat) (a a0 : Array UInt8) (hx : h.bytes x = some a0) (hsz : a.size = a0.size) :
699 DGood { h with bytes := upd h.bytes x (some a) } r ds z d := by
700 have hS := shape_setB hx a
701 refine ⟨⟨?_, ?_, hG.live.zst, hG.live.back, hG.live.status, hG.live.zalloc, hG.live.zfree⟩,
702 hG.inv.bytes_set x a a0 hx hsz (fun _ _ => rfl), hS.uniq hG.uniq, hS.fresh rfl hG.fresh, TreesInv.bytes_set hG.trees x a a0 hx hsz⟩
703 · cases r <;> simpa [ZStreamRef.get] using hG.live.hz
704 · exact hG.live.hs
705
706/-- The owned blocks are live. -/
707theorem _root_.Zlib.Deflate.Spec.DOwned.live {h : Heap} {r : ZStreamRef} {ds : Nat} {z : ZStream} {d : DeflateState}
708 (hG : DGood h r ds z d) {x : Nat} (hx : DOwned d ds x) : h.live x := by
709 obtain ⟨w, p, q, b, hB⟩ := hG.inv.blocks
710 rcases hx with rfl | ⟨w', hw, rfl⟩ | ⟨p', hp, rfl⟩ | ⟨q', hq, rfl⟩ | ⟨b', hb, rfl⟩
711 · exact Or.inr (Or.inr (Or.inr (Or.inr (Or.inl (by simp [hG.live.hs])))))
712 · rw [hB.win] at hw; cases hw
713 obtain ⟨a, ha, -⟩ := hB.wa
714 exact Or.inl (by simp [ha])
715 · rw [hB.prev] at hp; cases hp
716 obtain ⟨a, ha, -⟩ := hB.pa
717 exact Or.inr (Or.inl (by simp [ha]))
718 · rw [hB.head] at hq; cases hq
719 obtain ⟨a, ha, -⟩ := hB.qa
720 exact Or.inr (Or.inl (by simp [ha]))
721 · rw [hB.pbuf] at hb; cases hb
722 obtain ⟨a, ha, -⟩ := hB.ba
723 exact Or.inl (by simp [ha])
724
725
726/-- **deflateStateCheck, safety and specification.** On every stream of the domain `StreamDom` (`NULL`, or a live stream
727whose state pointer is `NULL`, a deflate state, or irrelevant because an allocator function is `NULL`) the check
728returns without a fault and without changing the heap; it returns 0 exactly for an initialised stream (the stream and
729its state point to each other, the allocator functions are not `NULL`, and the status is one of the eight values)
730and 1 otherwise. -/
731theorem deflateStateCheck_total {h : Heap} {strm : ZStreamPtr} (hD : StreamDom h strm) :
732 ∃ v, deflateStateCheck strm h = .ok (v, h) ∧ (v = 0 ∧ DInitialised h strm ∨ v = 1 ∧ ¬ DInitialised h strm) := by
733 rcases hD with rfl | ⟨r, z, rfl, hr, hcase⟩
734 · refine ⟨1, by simp [deflateStateCheck], Or.inr ⟨rfl, ?_⟩⟩
735 rintro ⟨r, ds, z, d, hh, -⟩; cases hh
736 · have e1 : ldZStream (some r) h = .ok (z, h) := ldZStream_ok hr
737 by_cases hza : z.zalloc = .null
738 · refine ⟨1, by simp [deflateStateCheck, e1, hza], Or.inr ⟨rfl, ?_⟩⟩
739 rintro ⟨r', ds, z', d, hh, hL⟩
740 cases hh; exact hL.zalloc (by rw [hL.hz] at hr; cases hr; exact hza)
741 by_cases hzf : z.zfree = .null
742 · refine ⟨1, by simp [deflateStateCheck, e1, hza, hzf], Or.inr ⟨rfl, ?_⟩⟩
743 rintro ⟨r', ds, z', d, hh, hL⟩
744 cases hh; exact hL.zfree (by rw [hL.hz] at hr; cases hr; exact hzf)
745 rcases hcase with h1 | h1 | h1 | ⟨ds, d, hzs, hst⟩
746 · exact absurd h1 hza
747 · exact absurd h1 hzf
748 · refine ⟨1, by simp [deflateStateCheck, e1, hza, hzf, h1, castDeflateState], Or.inr ⟨rfl, ?_⟩⟩
749 rintro ⟨r', ds, z', d, hh, hL⟩
750 cases hh; rw [hL.hz] at hr; cases hr; rw [hL.zst] at h1; cases h1
751 · by_cases c1 : d.strm = some r
752 · by_cases c2 : GoodStatus d.status
753 · have hL : DLive h r ds z d := ⟨hr, hst, hzs, c1, c2, hza, hzf⟩
754 exact ⟨0, stateCheck_live hL, Or.inl ⟨rfl, r, ds, z, d, rfl, hL⟩⟩
755 · refine ⟨1, ?_, Or.inr ⟨rfl, ?_⟩⟩
756 · simp only [GoodStatus, not_or] at c2
757 simp [deflateStateCheck, bind_app, e1, castD, ldD_eq, hza, hzf, hzs, hst, c1, c2]
758 · rintro ⟨r', ds', z', d', hh, hL⟩
759 cases hh
760 rw [hL.hz] at hr; cases hr
761 rw [hL.zst] at hzs; cases hzs
762 rw [hL.hs] at hst; cases hst
763 exact c2 hL.status
764 · refine ⟨1, ?_, Or.inr ⟨rfl, ?_⟩⟩
765 · simp [deflateStateCheck, bind_app, e1, castD, ldD_eq, hza, hzf, hzs, hst, c1]
766 · rintro ⟨r', ds', z', d', hh, hL⟩
767 cases hh
768 rw [hL.hz] at hr; cases hr
769 rw [hL.zst] at hzs; cases hzs
770 rw [hL.hs] at hst; cases hst
771 exact c1 hL.back
772
773/-- The state check fails: a function that starts with it returns `Z_STREAM_ERROR` and changes nothing. -/
774theorem notInit_check {h : Heap} {strm : ZStreamPtr} (hD : StreamDom h strm) (hN : ¬ DInitialised h strm) :
775 deflateStateCheck strm h = .ok (1, h) := by
776 obtain ⟨v, hv, hc⟩ := deflateStateCheck_total hD
777 rcases hc with ⟨rfl, hI⟩ | ⟨rfl, -⟩
778 · exact absurd hI hN
779 · exact hv
780
781/-! ### The stream check refuses -/
782
783/-- A function of the shape `if deflateStateCheck strm ≠ 0 then return X; rest` returns `X` and changes nothing when
784the check refuses the stream. -/
785theorem check_refuse {α : Type} {h : Heap} {strm : ZStreamPtr} (hD : StreamDom h strm) (hN : ¬ DInitialised h strm)
786 (X : α) (rest : M α) :
787 (do if (← deflateStateCheck strm) != 0 then return X
788 rest : M α) h = .ok (X, h) := by
789 simp [bind_app, notInit_check hD hN]
790
791end Zlib.Deflate.Proofs