Skip to content
REFERENCE / ZLIB × LEAN

Examples.lean

Source snapshot · 2871fdc98a611ea5 · Source at the matching commit ↗

Lean source with line numbers. Follow a line number to locate a statement, or an import to read its dependency.

1import ZlibF.Spec.Api.Goals
2import ZlibF.Spec.Format.Examples
3import ZlibF.Proof.Format.Api
4import ZlibF.Proof.Api.InflateCausality
5
6/-!
7# API model: examples and non-vacuity
8
9Computable definitions are checked by `decide`/`rfl` on small cases. Then a tiny deflate-then-inflate
10is run through the model itself: the specification of `deflate` and of `inflate` is satisfied by
11a concrete run (so neither is contradictory), and the output of the first is accepted by the
12second. The example stream is the zlib stream of "a" of `Format/Examples.lean`.
13-/
14
15namespace ZlibF.Spec.Api
16
17open ZlibF.Spec
18
19set_option maxRecDepth 100000
20
21local macro "dk" : term => `(by decide +kernel)
22
23/-! ## Parameters (computable) -/
24
25example : inflWbits 15 = some (.zlib, 15) := by decide
26example : inflWbits 0 = some (.zlib, 0) := by decide
27example : inflWbits 31 = some (.gzip, 15) := by decide
28example : inflWbits 16 = some (.gzip, 0) := by decide
29example : inflWbits 47 = some (.auto, 15) := by decide
30example : inflWbits (-15) = some (.raw, 15) := by decide
31example : inflWbits (-8) = some (.raw, 8) := by decide
32example : inflWbits 7 = none := by decide
33example : inflWbits 48 = none := by decide
34example : inflWbits (-7) = none := by decide
35example : inflWbits (-16) = none := by decide
36example : inflWbits 16 ≠ inflWbits 0 := by decide
37
38example : deflInit? (-1) 8 15 8 0 = some ⟨6, .zlib, 15, 8, 0⟩ := by decide
39example : deflInit? 9 8 31 9 4 = some ⟨9, .gzip, 15, 9, 4⟩ := by decide
40example : deflInit? 6 8 (-15) 8 0 = some ⟨6, .raw, 15, 8, 0⟩ := by decide
41example : deflInit? 6 8 8 8 0 = some ⟨6, .zlib, 9, 8, 0⟩ := by decide
42example : deflInit? 6 8 (-8) 8 0 = none := by decide     -- raw with 8 bits is refused
43example : deflInit? 6 8 24 8 0 = none := by decide        -- gzip with 8 bits is refused
44example : deflInit? 10 8 15 8 0 = none := by decide
45example : deflInit? 6 8 15 0 0 = none := by decide
46example : deflInit? 6 8 15 8 5 = none := by decide
47example : deflInit? 6 9 15 8 0 = none := by decide
48example : deflInit? 6 8 0 8 0 = none := by decide
49
50example : compressBound 0 = 13 := by decide
51example : compressBound 4096 = 4096 + 1 + 0 + 0 + 13 := by decide
52example : compressBound (2 ^ 64 - 1) = 2 ^ 64 - 1 := by decide
53
54/-- With the parameters of `compress2` the bound of `deflateBound` is the bound of `compressBound`
55(`compress.c`: "if the default memLevel or windowBits for deflateInit() is changed, then this
56function needs to be updated"). -/
57theorem bound_default (n : Nat) (h : n < 2 ^ 60) :
58    (DeflState.fresh ⟨6, .zlib, 15, 8, 0⟩).bound n = compressBound n := by
59  unfold DeflState.bound compressBound DeflState.fresh DeflState.dictEff
60  simp only [Option.getD_none]
61  have : ¬ (n + n / 2 ^ 12 + n / 2 ^ 14 + n / 2 ^ 25 + 13 ≥ 2 ^ 64) := by omega
62  simp [this]
63
64example : (DeflState.fresh ⟨6, .gzip, 15, 8, 0⟩).bound 0 = 13 + 12 := by decide
65example : (DeflState.fresh ⟨6, .raw, 15, 8, 0⟩).bound 0 = 7 := by decide
66example : (DeflState.fresh ⟨6, .zlib, 9, 8, 0⟩).bound 0 = 4 + 6 := by decide
67example : (DeflState.fresh ⟨6, .zlib, 15, 1, 0⟩).bound 100 = 100 + 3 + 0 + 0 + 7 + 6 := by decide
68
69example : syncSearch 0 [1, 0, 0, 255, 255, 7] = (4, 5) := by decide
70example : syncSearch 0 [0, 0, 255] = (3, 3) := by decide
71example : syncSearch 3 [255, 9] = (4, 1) := by decide
72example : syncSearch 0 [0, 0, 0, 255, 255] = (4, 5) := by decide
73example : (syncSearch 0 [1, 2, 3]).1 = 0 := by decide
74
75example : gzMode? "rb".toList = some (.read, -1, 0, 1) → False := by decide
76example : gzMode? "rb".toList = some (.read, -1, 0, 0) := by decide
77example : gzMode? "wb9".toList = some (.write, 9, 0, 0) := by decide
78example : gzMode? "ab6h".toList = some (.append, 6, 2, 0) := by decide
79example : gzMode? "wT".toList = some (.write, -1, 0, 1) := by decide
80example : gzMode? "rb+".toList = none := by decide
81example : gzMode? "b".toList = none := by decide
82example : gzMode? "rT".toList = none := by decide
83example : gzMode? "wG".toList = none := by decide
84
85example : syncStep 0 0 = 1 ∧ syncStep 2 255 = 3 ∧ syncStep 2 7 = 0 ∧ syncStep 3 0 = 1 := by decide
86
87/-! ## The example stream and a model run of inflate -/
88
89/-- zlib's stream for "a" (`Format/Examples.lean`). -/
90def zA : List UInt8 := [0x78, 0x9C, 0x4b, 0x04, 0x00, 0x00, 0x62, 0x00, 0x62]
91
92theorem zA_decodes : Zlib.Decodes [] zA [0x61] :=
93  ⟨0x78, 0x9C, [], _, rfl, dk, fun _ => ⟨rfl, _, .last rfl rfl (.fixed (.lit (s := 97) rfl dk (.eob rfl))), dk⟩,
94    fun h => absurd h dk⟩
95
96theorem zA_layer : Layer.Decodes .zlib 15 [] zA [0x61] :=
97  ⟨zA_decodes, Or.inr ⟨0x78, rfl, by decide⟩⟩
98
99theorem zA_not_needDict : ¬ HdrNeedsDict .zlib 15 zA := by
100  rintro ⟨_, cmf, flg, r, h, _, hb, _⟩
101  have h2 : flg = 0x9C := by simp [zA] at h; exact h.2.1.symm
102  subst h2
103  exact absurd hb dk
104
105theorem zA_not_detectable : ¬ Layer.Detectable .zlib 15 [] zA := by
106  rintro ⟨m, hm, hv⟩
107  have h1 : m ≤ 1 := by simp [detectLag, zA] at hm; omega
108  exact hv (Or.inl (by simp [hdrLag, List.length_take]; omega))
109
110/-- Everything inflate does with the whole stream in one call: one `Z_FINISH` call with room 10. -/
111def stDoneA : InflState :=
112  { (InflState.fresh .zlib 15) with
113    phase := .done, seen := zA, out := [0x61], totalIn := 9, totalOut := 1, adler := adler32 [0x61] }
114
115theorem infl_one_call :
116    InflStep (InflState.fresh .zlib 15) ⟨zA, 10, .finish, false⟩ ⟨9, [0x61], Z.streamEnd⟩ stDoneA := by
117  refine ⟨fun h => absurd h (by decide), fun _ => ?_⟩
118  show InflRun _ _ _ _
119  left
120  unfold InflRunOk
121  and_intros
122  all_goals first
123    | rfl
124    | decide
125    | (intro h; exact absurd h (by decide))
126    | (intro _ h; exact absurd h (by decide))
127    | (intro _ _; exact zA_layer)
128    | (intro _ _ _ _ _; rfl)
129    | (intro _ _ _ hD _; exact absurd hD (by simpa [InflState.dictEff, InflState.fresh] using zA_not_detectable))
130    | (intro _ _ _ hN; exact absurd hN (by simpa [InflState.fresh] using zA_not_needDict))
131    | (intro _ _ _; rfl)
132    | (intro req h; simp [InflState.fresh] at h)
133
134theorem not_zlib_short (d x o : List UInt8) (h : x.length < 2) : ¬ Zlib.Decodes d x o := by
135  rintro ⟨cmf, flg, pre, s, hs, _⟩
136  simp [hs] at h
137  omega
138
139theorem not_decodes_short (d x o : List UInt8) (b : Nat) (h : x.length < 2) :
140    ¬ Layer.Decodes .zlib b d x o := by
141  rintro ⟨⟨cmf, flg, pre, s, hs, _⟩, _⟩
142  simp [hs] at h
143  omega
144
145/-- Closes the side conditions of `InflRun` for the concrete steps below. -/
146local macro "close_infl" : tactic =>
147  `(tactic| (and_intros; all_goals first
148      | rfl
149      | decide
150      | (intro h; exact absurd h (by decide))
151      | (intro _ h; exact absurd h (by decide))
152      | (intro _ _; exact zA_layer)
153      | (intro _ _ _ _ _; rfl)
154      | (intro _ _ _ hD _; exact absurd hD zA_not_detectable)
155      | (intro _ _ _ hN; exact absurd hN zA_not_needDict)
156      | (intro _ _ h; exact absurd h (by decide))
157      | (intro _ _ _; rfl)
158      | (intro req h; cases h <;> fail)
159      | (intro _; exact ⟨Or.inl (by decide), by decide, rfl⟩)
160      | (intro _ _; exact Proofs.output_evidence_nil (Or.inl (by decide)) zA_layer _)
161      | (intro _ _ _ _ _ _ _ _; exact List.nil_prefix)
162      | (intro _ _ _ _ ⟨n, o', h1, h2, h3, _⟩; exact absurd h3 (not_decodes_short _ _ _ _ (Nat.lt_of_le_of_lt (List.length_take_le' _ _) (by simp [InflState.fresh]))))
163      | (intro _ _ _ ⟨m, hm, _⟩ _; exact absurd hm (by simp [detectLag, InflState.fresh] <;> omega))
164      | (intro _ _ h; rcases h with h | h; exact absurd rfl h; exact absurd h (by decide))))
165
166/-- Two calls with the same stream cut after the first byte: the first call only reads the byte of
167the header that it gets, with `Z_OK`. -/
168def stHalfA : InflState :=
169  { (InflState.fresh .zlib 15) with seen := [0x78], totalIn := 1 }
170
171theorem infl_step1 :
172    InflStep (InflState.fresh .zlib 15) ⟨[0x78], 10, .noFlush, false⟩ ⟨1, [], Z.ok⟩ stHalfA := by
173  refine ⟨fun h => absurd h (by decide), fun _ => ?_⟩
174  show InflRun _ _ _ _
175  left
176  unfold InflRunOk
177  close_infl
178
179theorem infl_step2 :
180    InflStep stHalfA ⟨zA.drop 1, 10, .finish, false⟩ ⟨8, [0x61], Z.streamEnd⟩ stDoneA := by
181  refine ⟨fun h => absurd h (by decide), fun _ => ?_⟩
182  show InflRun _ _ _ _
183  left
184  unfold InflRunOk
185  close_infl
186
187/-- A run of `inflate` over `zA` cut in two calls reaches the end of the stream with the
188decoded data. -/
189theorem infl_trace : InflTrace zA [] (InflStart .zlib 15 []) stDoneA :=
190  .step (c := ⟨[0x78], 10, .noFlush, false⟩) (r := { rc := Z.ok, out := ⟨1, [], Z.ok⟩ })
191    (by decide) ⟨infl_step1, rfl⟩
192    (.step (c := ⟨zA.drop 1, 10, .finish, false⟩) (r := { rc := Z.streamEnd, out := ⟨8, [0x61], Z.streamEnd⟩ })
193      (by decide) ⟨infl_step2, rfl⟩ .nil)
194
195/-! ## A model run of deflate -/
196
197/-- The parameters of `compress2` at level 6. -/
198def dP : DeflParams := ⟨6, .zlib, 15, 8, 0⟩
199
200theorem zA_valid : (DeflState.fresh dP).Valid zA [0x61] :=
201  ⟨zA_decodes, by decide, 0x78, 0x9C, _, rfl, by decide⟩
202
203/-- The state after one `Z_FINISH` call with the byte "a" and room 20 that delivers `zA`. -/
204def dDoneA : DeflState :=
205  { (DeflState.fresh dP) with
206    input := [0x61], produced := zA, totalIn := 1, totalOut := 9, adler := adler32 [0x61],
207    last := 4, finishing := true, done := true, started := true }
208
209theorem defl_one_call :
210    DeflStep (DeflState.fresh dP) ⟨[0x61], 20, .finish, false⟩ ⟨1, zA, Z.streamEnd⟩ dDoneA := by
211  refine ⟨fun h => absurd h (by decide), fun _ h => absurd h (by decide),
212    fun _ _ _ h => absurd h (by decide), fun _ _ _ _ => ?_⟩
213  unfold DeflRun DeflFrame
214  and_intros
215  all_goals first
216    | rfl
217    | decide
218    | (intro h; exact absurd h (by decide))
219    | (intro h; exact absurd h.2.1 (by decide))
220    | (intro _; refine ⟨rfl, fun v h => ?_⟩; exact (Option.some.inj h).symm)
221    | (intro _; exact ⟨rfl, rfl, rfl, rfl, rfl, rfl, fun _ => zA_valid, fun _ h => absurd h (by decide), fun _ => by decide⟩)
222    | (intro _ _ _ _ _ _; rfl)
223    | (intro _ _ h; exact absurd h (by decide))
224    | (intro _ _; exact absurd ‹_› (by decide))
225    | (intro _ _ _; exact absurd ‹_› (by decide))
226
227/-- Deflate then inflate, through the model: the data of the example goes through both. -/
228theorem roundtrip_example :
229    DeflTrace [0x61] (DeflState.fresh dP) dDoneA ∧ InflTrace zA [] (InflStart .zlib 15 []) stDoneA ∧
230    dDoneA.produced = zA ∧ stDoneA.out = [0x61] :=
231  ⟨.step (c := ⟨[0x61], 20, .finish, false⟩) (r := { rc := Z.streamEnd, out := ⟨1, zA, Z.streamEnd⟩ })
232      (by decide) ⟨defl_one_call, rfl⟩ .nil,
233    infl_trace, rfl, rfl⟩
234
235/-- Non-vacuity of `Goal.roundtrip`'s hypotheses: this deflate trace is one the goal talks
236about, and the inflate trace is one of its runs. -/
237example : DeflCfg dP ∧ Compatible dP .zlib 15 ∧ dDoneA.done = true ∧ dDoneA.precise = true ∧
238    dDoneA.input = [0x61] ∧ dDoneA.dictEff = [] :=
239  ⟨⟨6, 8, 15, 8, 0, by decide⟩, ⟨⟨15, by decide⟩, rfl, Or.inr (Or.inl ⟨rfl, Or.inl rfl⟩)⟩, rfl, rfl, rfl, rfl⟩
240
241/-- The hypotheses of `Goal.inflate_decodes` and `Goal.inflate_completes` are satisfiable. -/
242example : InflCfg .zlib 15 ∧ Layer.Decodes .zlib 15 [] zA [0x61] ∧ FullWindow .zlib 15 zA ∧
243    ¬ HdrNeedsDict .zlib 15 zA ∧ InflTrace zA [] (InflStart .zlib 15 []) stHalfA :=
244  ⟨⟨15, by decide⟩, zA_layer, Or.inl rfl, zA_not_needDict,
245    .step (c := ⟨[0x78], 10, .noFlush, false⟩) (r := { rc := Z.ok, out := ⟨1, [], Z.ok⟩ })
246      (by decide) ⟨infl_step1, rfl⟩ .nil⟩
247
248/-- Two states of the `Goal.inflate_completes` shape: from `stHalfA` the call with the rest ends the
249stream (this is `infl_step2`, seen as the conclusion of the goal). -/
250example : (⟨zA.drop 1, 10, .finish, false⟩ : InflCall).inp = zA.drop stHalfA.seen.length ∧
251    zA_layer = zA_layer ∧ [0x61].length ≤ stHalfA.out.length + 10 := ⟨rfl, rfl, by decide⟩
252
253/-! ## `compress2` and `uncompress2` -/
254
255example : compressParams 6 = some dP := by decide
256example : compressParams (-1) = some dP := by decide
257example : compressParams 10 = none := by decide
258
259theorem compress2_example : Compress2 true 6 [0x61] 100 Z.ok zA :=
260  Or.inr (Or.inl ⟨rfl, zA_valid, by decide, by decide⟩)
261
262/-- A level outside -1 to 9: nothing is written. -/
263example : Compress2 true 10 [0x61] 100 Z.streamError [] := ⟨rfl, rfl⟩
264/-- A null argument. -/
265example : Compress2 false 6 [0x61] 100 Z.streamError [] := ⟨rfl, rfl⟩
266/-- A destination of `compressBound` bytes is enough: the same call with the room at the bound
267still succeeds. -/
268example : Compress2 true 6 [0x61] (compressBound 1) Z.ok zA :=
269  Or.inr (Or.inl ⟨rfl, zA_valid, by decide, by decide⟩)
270
271/-- The room is one byte: only the first byte of a stream fits. -/
272example : Compress2 true 6 [0x61] 1 Z.bufError [0x78] :=
273  Or.inr (Or.inr ⟨rfl, rfl, by decide, zA, zA_valid, by decide⟩)
274
275/-- `uncompress2` on an empty source: `Z_DATA_ERROR` and nothing is written. -/
276example : Uncompress2 true [] 10 Z.dataError [] 0 := by
277  refine ⟨by decide, by decide, Or.inr (Or.inr (Or.inl rfl)),
278    fun h => absurd h (by decide), fun h => absurd h (by decide), ?_, ?_, ?_⟩
279  · intro stream decoded _ _
280    exact List.nil_prefix
281  · exact Proofs.output_evidence_nil (allowed := fun dictionary => dictionary = []) rfl zA_layer []
282  · intro n o _ h
283    exact absurd h (not_zlib_short _ _ _ (by simp))
284
285/-- Null arguments to `uncompress2`. -/
286example : Uncompress2 false zA 10 Z.streamError [] 0 := ⟨rfl, rfl, rfl⟩
287
288/-! ## gz files -/
289
290/-- A file of two bytes is read as it is. -/
291theorem gz_direct_file : GzDecoded false [0x61, 0x62] [0x61, 0x62] Z.ok :=
292  Or.inl ⟨rfl, fun h => absurd h.1 (by decide), rfl, rfl⟩
293
294/-- Opening it for reading. -/
295def gzR : GzHandle :=
296  { mode := .read, level := -1, strategy := 0, direct := 0, raw := [0x61, 0x62], dec := [0x61, 0x62],
297    dstat := Z.ok, rpos := 0, pushed := [], past := false, err := Z.ok, written := [], out := [],
298    base := [], want := gzBufDefault, sized := false, failed := false }
299
300example : GzOpen "r".toList (some [0x61, 0x62]) (some gzR) :=
301  Or.inr ⟨[0x61, 0x62], [0x61, 0x62], Z.ok, fun _ => ⟨rfl, gz_direct_file⟩, rfl⟩
302
303example : GzOpen "r".toList none none := Or.inl rfl
304example : GzOpen "q".toList (some []) none := rfl
305example : GzOpen "r+".toList (some []) none := rfl
306
307/-- Reading one byte, then asking for more than is left: the second read comes up short and sets
308the end indicator. -/
309example : GzReadFn gzR 1 [0x61] 1 { gzR with rpos := 1, sized := true } := by
310  unfold GzReadFn GzHandle.avail
311  refine ⟨fun h => absurd rfl h, fun _ => ?_⟩
312  decide
313example : GzReadFn { gzR with rpos := 1 } 5 [0x62] 1 { gzR with rpos := 2, sized := true, past := true } := by
314  unfold GzReadFn GzHandle.avail
315  refine ⟨fun h => absurd rfl h, fun _ => ?_⟩
316  decide
317example : GzReadFn { gzR with rpos := 2 } 5 [] 0 { gzR with rpos := 2, sized := true, past := true } := by
318  unfold GzReadFn GzHandle.avail
319  refine ⟨fun h => absurd rfl h, fun _ => ?_⟩
320  decide
321
322example : GzEof { gzR with past := true } 1 := by unfold GzEof; decide
323example : GzEof gzR 0 := by unfold GzEof; decide
324example : GzTell { gzR with rpos := 1 } 1 := by unfold GzTell GzHandle.tell; decide
325example : GzDirect gzR 1 { gzR with sized := true } :=
326  ⟨Or.inl ⟨rfl, rfl, fun h => absurd h.1 (by decide), by decide⟩, rfl⟩
327
328/-- zlib's gzip member for "a" (`Format/Examples.lean`). -/
329def gzA : List UInt8 := [31, 139, 8, 0, 0, 0, 0, 0, 2, 19, 75, 4, 0, 67, 190, 183, 232, 1, 0, 0, 0]
330
331theorem gzA_decodes : Gzip.Decodes gzA [0x61] :=
332  ⟨0, [0, 0, 0, 0], 2, 19, [], [], [], [75, 4, 0, 67, 190, 183, 232, 1, 0, 0, 0], dk, dk, dk, dk, dk, dk,
333    _, .last rfl rfl (.fixed (.lit (s := 97) rfl dk (.eob rfl))), dk⟩
334
335theorem gzip_empty (o : List UInt8) : ¬ Gzip.Decodes [] o := by
336  rintro ⟨flg, mtime, xfl, os, extra, name, comment, s, _, _, _, _, _, hm, _⟩
337  simp [Gzip.header] at hm
338
339/-- The file that a writer produces for "a" reads back as "a" (`C7`): the member is the whole
340file, there is nothing after it. -/
341theorem gzA_file : GzDecoded false gzA [0x61] Z.ok :=
342  Or.inr (Or.inr ⟨Or.inl ⟨by decide, by decide, by decide, by decide, by decide⟩,
343    [(gzA, [0x61])], [], by simpa using gzA_decodes, rfl,
344    fun ⟨m, o, t, h, hd⟩ => by
345      have hm : m = [] := (List.append_eq_nil_iff.mp h.symm).1
346      subst hm
347      exact gzip_empty _ hd,
348    Or.inl ⟨rfl, by simp, rfl, rfl⟩⟩)
349
350/-- A writer that wrote "a" and closes: the file is the member. -/
351def gzW : GzHandle :=
352  { gzR with mode := .write, raw := [], dec := [], written := [0x61], out := gzA }
353
354example : GzClose gzW Z.ok gzA := by
355  refine ⟨Or.inl rfl, fun h => absurd h (by decide), fun _ _ => Or.inr rfl, fun _ _ _ => ⟨fun h => absurd h (by decide), fun _ => ?_⟩⟩
356  exact ⟨gzA, by simp [gzW, gzR], List.prefix_refl _, gzA_decodes⟩
357
358/-! ## Witnesses for the repaired parts of the specification
359
360A `Z_FINISH` call that returns `Z_BUF_ERROR` (nothing is consumed, nothing is finished, `done` stays
361false), a completed `Z_FULL_FLUSH` (it sets `fullAt`), and an `inflate` call that returns
362`Z_MEM_ERROR` after reading input and writing output (the totals stay). The lemmas say that the
363clauses of the model are the ones that exclude the earlier errors. -/
364
365theorem defl_done_iff {st : DeflState} {c : DeflCall} {o : DeflOut} {st' : DeflState}
366    (h : DeflRun st c o st') : st'.done = true ↔ (st.done = true ∨ o.rc = Z.streamEnd) := by
367  obtain ⟨_, _, _, _, _, _, _, _, _, _, _, _, _, _, hd, -⟩ := h
368  exact hd
369
370/-- `done` is not set by a `Z_BUF_ERROR` (the first error of the review). -/
371theorem defl_no_done_on_buf_error {st : DeflState} {c : DeflCall} {o : DeflOut} {st' : DeflState}
372    (h : DeflRun st c o st') (hr : o.rc = Z.bufError) (hd : st.done = false) : st'.done = false := by
373  have := (defl_done_iff h).1
374  cases hd' : st'.done
375  · rfl
376  · rcases this hd' with h1 | h1
377    · simp [hd] at h1
378    · rw [hr] at h1; exact absurd h1 (by decide)
379
380/-- `fullAt` is kept by every call that does not complete a full flush. -/
381theorem defl_fullAt_kept {st : DeflState} {c : DeflCall} {o : DeflOut} {st' : DeflState}
382    (h : DeflRun st c o st')
383    (hn : ¬ (o.rc = Z.ok ∧ o.produced.length < c.availOut ∧ c.flush = .fullFlush)) :
384    st'.fullAt = st.fullAt := by
385  obtain ⟨_, _, _, _, _, _, _, _, _, _, _, _, _, hk, -⟩ := h
386  exact hk hn
387
388/-- A stream whose `Z_FINISH` was accepted but not finished: the output bytes `78` are out, three are pending. -/
389def dBusy : DeflState :=
390  { (DeflState.fresh dP) with
391    input := [0x61], produced := [0x78], totalIn := 1, totalOut := 1, adler := adler32 [0x61],
392    pend := 3, last := 4, finishing := true, started := true }
393
394/-- More input after `Z_FINISH`: `Z_BUF_ERROR`, nothing consumed, the stream is not finished. -/
395theorem defl_finish_buf_error :
396    DeflStep dBusy ⟨[0x62], 5, .finish, false⟩ ⟨0, [], Z.bufError⟩ dBusy := by
397  refine ⟨fun h => absurd h (by decide), fun _ h => absurd h (by decide),
398    fun _ _ _ h => absurd h (by decide), fun _ _ _ _ => ?_⟩
399  unfold DeflRun DeflFrame
400  and_intros
401  all_goals first
402    | rfl
403    | decide
404    | (intro h; exact absurd h (by decide))
405    | (intro h; exact absurd h.1 (by decide))
406    | (intro _ h; exact absurd h (by decide))
407    | (intro _ _; exact Or.inl rfl)
408    | (intro _ _; exact ⟨rfl, Or.inl rfl⟩)
409    | (intro _ _; exact absurd ‹_› (by decide))
410    | (intro _ _ h; exact absurd h (by decide))
411    | (intro _ _ _; exact absurd ‹_› (by decide))
412    | (intro h _; exact absurd h (by decide))
413    | (intro _ _ _ _ _ h; exact absurd h (by decide))
414
415/-- The stream state of that witness is not finished, and the `done` flag stays false, whatever
416the call: the repaired clause. -/
417example : dBusy.done = false := rfl
418
419/-- Raw deflate of "a" with a completed full flush: `4a 04 00` then the empty stored block `00 00 ff ff`
420(what zlib writes). Followed by `03 00` it is a valid stream of "a". -/
421def fullA : List UInt8 := [0x4a, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff]
422
423theorem fullA_flushed : Deflate.Decodes [] (fullA ++ [3, 0]) [0x61] :=
424  ⟨_, .more rfl rfl (.fixed (.lit (s := 97) rfl dk (.eob rfl)))
425    (.more rfl rfl (.stored rfl rfl rfl rfl) (.last rfl rfl (.fixed (.eob rfl)))), dk⟩
426
427def dPraw : DeflParams := ⟨6, .raw, 15, 8, 0⟩
428
429def dFullA : DeflState :=
430  { (DeflState.fresh dPraw) with
431    input := [0x61], produced := fullA, totalIn := 1, totalOut := 7, last := 3, started := true,
432    clean := false, fullAt := some (7, 1) }
433
434/-- A completed full flush with `fullAt = none` before: the call has an allowed outcome and sets `fullAt`. -/
435theorem defl_full_flush :
436    DeflStep (DeflState.fresh dPraw) ⟨[0x61], 20, .fullFlush, false⟩ ⟨1, fullA, Z.ok⟩ dFullA := by
437  refine ⟨fun h => absurd h (by decide), fun _ h => absurd h (by decide),
438    fun _ _ _ h => absurd h (by decide), fun _ _ _ _ => ?_⟩
439  unfold DeflRun DeflFrame
440  and_intros
441  all_goals first
442    | rfl
443    | decide
444    | (intro h; exact absurd h (by decide))
445    | (intro h; exact absurd h.1 (by decide))
446    | (intro _ h; exact absurd h (by decide))
447    | (intro _; exact ⟨rfl, fun v h => by cases h⟩)
448    | (intro _ _ _; exact ⟨by decide, by decide, rfl⟩)
449    | (intro _ _ _; exact ⟨rfl, rfl⟩)
450    | (intro _ _ _; refine ⟨rfl, fun _ => ?_⟩; exact fullA_flushed)
451    | (intro _ _ _; rfl)
452    | (intro _ _ _ _ _ _; exact absurd ‹_› (by decide))
453    | (intro _ h; exact absurd h (by decide))
454    | (intro h; exact absurd ⟨rfl, by decide, rfl⟩ h)
455
456/-- The completed flush is not the old, contradictory outcome (`fullAt` kept `none`). -/
457example : dFullA.fullAt ≠ (DeflState.fresh dPraw).fullAt := by decide
458
459/-- An inflate call that reads the whole raw stream of "a" and writes the byte, then fails to allocate the
460window: `Z_MEM_ERROR`, consumed 3, produced 1, `total_in` and `total_out` still 0, state `mem`. -/
461def rawA : List UInt8 := [0x4b, 0x04, 0x00]
462
463def stMemA : InflState :=
464  { (InflState.fresh .raw 15) with phase := .mem, seen := rawA, out := [0x61] }
465
466theorem rawA_decodes : Layer.Decodes .raw 15 [] rawA [0x61] :=
467  ⟨_, .last rfl rfl (.fixed (.lit (s := 97) rfl dk (.eob rfl))), dk⟩
468
469theorem infl_mem_error :
470    InflStep (InflState.fresh .raw 15) ⟨rawA, 10, .noFlush, false⟩ ⟨3, [0x61], Z.memError⟩ stMemA := by
471  refine ⟨fun h => absurd h (by decide), fun _ => ?_⟩
472  show InflRun _ _ _ _
473  right
474  unfold InflRunMem
475  and_intros
476  all_goals first
477    | rfl
478    | decide
479    | (intro _; exact Proofs.output_evidence_of_decodes (Or.inr rfl)
480        (fun d hd => by simpa [InflState.PermitsDictionary, InflState.fresh] using hd) rawA_decodes)
481    | (intro _ dictionary _
482       change Layer.Determined .raw 15 dictionary rawA [0x61]
483       have ha : Layer.Decodes .raw 15 dictionary rawA [0x61] :=
484         ⟨_, .last rfl rfl (.fixed (.lit (s := 97) rfl dk (.eob rfl))), dk⟩
485       intro stream decoded comparable hd
486       rcases comparable with ⟨tail, heq⟩ | ⟨tail, heq⟩
487       · have hx := Proofs.Layer.ext ha (by simpa only [← heq] using hd)
488         simpa only [← hx.2] using (List.prefix_refl [0x61])
489       · have hx := Proofs.Layer.ext hd (by simpa only [← heq] using ha)
490         simpa only [hx.2] using (List.prefix_refl [0x61]))
491    | (intro req h; cases h)
492
493example : stMemA.totalIn = 0 ∧ stMemA.totalOut = 0 ∧ (3 : Nat) > 0 ∧ stMemA.out = [0x61] := ⟨rfl, rfl, by decide, rfl⟩
494
495/-- In the `mem` state every call returns `Z_MEM_ERROR` and changes nothing. -/
496example : InflStep stMemA ⟨[0], 10, .noFlush, false⟩ ⟨0, [], Z.memError⟩ stMemA :=
497  ⟨fun h => absurd h (by decide), fun _ => ⟨rfl, rfl, rfl, rfl⟩⟩
498
499/-! ## `gzseek` after the end of the data -/
500
501/-- A gzip file of "a", read to its end (`past`). -/
502def gzP : GzHandle :=
503  { gzR with raw := gzA, dec := [0x61], rpos := 1, past := true, sized := true }
504
505theorem gzA_looks : GzLooksGzip gzA := by unfold GzLooksGzip gzA; decide
506
507/-- `gzseek(f, 5, SEEK_CUR)` returns 6 but `gztell` stays 1 and `gzeof` stays 1: what the real library
508does (a quirk). The model allows exactly this. -/
509theorem gz_seek_quirk :
510    GzSeek gzP 5 1 6 { gzP with rpos := 6 } ∧ ({ gzP with rpos := 6 } : GzHandle).tell = 1 ∧
511      GzEof { gzP with rpos := 6 } 1 := by
512  refine ⟨?_, by unfold GzHandle.tell; decide, by unfold GzEof; decide⟩
513  unfold GzSeek
514  refine ⟨fun h => absurd h (by decide), fun _ => Or.inr ⟨by decide, fun h => absurd h (by decide), ?_⟩⟩
515  intro _
516  refine ⟨rfl, rfl, ?_, ?_⟩
517  · intro h
518    rcases h with hc | hc
519    · exact absurd gzA_looks hc.2.2.1
520    · exact absurd hc (by decide)
521  · intro _ _
522    exact ⟨rfl, rfl, by decide, by decide⟩
523
524/-- In a transparent file the same seek clears `past`, and `gztell` is the position. -/
525def gzC : GzHandle :=
526  { gzR with rpos := 2, past := true, sized := true }
527
528theorem gz_seek_copy :
529    GzSeek gzC 5 1 7 { gzC with rpos := 7, past := false } ∧
530      ({ gzC with rpos := 7, past := false } : GzHandle).tell = 7 := by
531  refine ⟨?_, by unfold GzHandle.tell; decide⟩
532  unfold GzSeek
533  have hc : gzC.CopyMode := ⟨rfl, by decide, fun h => absurd h.1 (by decide), by decide⟩
534  refine ⟨fun h => absurd h (by decide), fun _ => Or.inr ⟨by decide, fun h => absurd h (by decide), ?_⟩⟩
535  intro _
536  refine ⟨rfl, rfl, fun _ => ⟨by decide, rfl, rfl, by decide⟩, fun h => absurd hc h⟩
537
538end ZlibF.Spec.Api
ZLIB × LEAN

Global contents

READING NOWExamples.lean