Skip to content
REFERENCE / ZLIB × LEAN

inffast.c.final.lean

Source snapshot · de807517c52c2c3b · 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.Proof.«inffast.c.loop»
2
3/-!
4# inffast.c: normalization and final writeback
5
6The proof adapts the earlier split into normalization, pointer-derived
7remaining counts, and stream/state stores to the current record heap.
8-/
9
10namespace Zlib.Inffast.Proofs
11open C Zlib.Inffast Zlib.Inffast.Spec
12variable {e : Env} {c : Ctx}
13
14theorem bits_whole (b : UInt32) : (b >>> 3).toNat = b.toNat / 8 := by
15  rw [UInt32.toNat_shiftRight]
16  simp [Nat.shiftRight_eq_div_pow]
17
18theorem bits_whole_shift (b : UInt32) (hb : b.toNat ≤ 30) :
19    ((b >>> 3) <<< 3).toNat = b.toNat / 8 * 8 := by
20  rw [UInt32.toNat_shiftLeft, bits_whole, Nat.shiftLeft_eq]
21  change (b.toNat / 8 * 8) % 4294967296 = b.toNat / 8 * 8
22  exact Nat.mod_eq_of_lt (by omega)
23
24theorem bits_residual (b : UInt32) (hb : b.toNat ≤ 30) :
25    (b - ((b >>> 3) <<< 3)).toNat = b.toNat % 8 := by
26  rw [u32_toNat_sub (by rw [bits_whole_shift b hb]; omega), bits_whole_shift b hb]
27  omega
28
29theorem LS.buffered_le {l : L} {i o : Nat} (hl : LS e l i o) :
30    l.bits.toNat / 8 ≤ i - e.i0 := by
31  have hacc := hl.hacc
32  have hb0 := e.hbits
33  omega
34
35theorem normalized_hold_lt (H : UInt64) (b : UInt32) (hb : b.toNat < 32) :
36    (H &&& (((1 : UInt32) <<< b) - 1).toUInt64).toNat < 2 ^ b.toNat := by
37  have hm : ((((1 : UInt32) <<< b) - 1).toUInt64).toNat = 2 ^ b.toNat - 1 := by
38    rw [UInt32.toNat_toUInt64]
39    exact u32_shl1_sub1 hb
40  rw [u64_and_mask hm]
41  exact Nat.mod_lt _ (Nat.pow_pos (by omega))
42
43/-- The C conditional arithmetic computes the exact nonnegative remaining
44count, in both pointer-order branches. -/
45theorem ptr_avail_run {h : Heap} {r : BRef} {A : Array UInt8} {p q k : Nat}
46    (hg : Space.get h r = some A) (hp : p ≤ A.size) (hq : q ≤ A.size)
47    (hsz : A.size < 2 ^ 63) (hle : p ≤ q + k) (hk : k < 2 ^ 31)
48    (hr : q + k - p < 2 ^ 32) :
49    (do
50      if ← Ptr.lt (.ref r p) (.ref r q) then do
51        let d ← Ptr.diff (.ref r q) (.ref r p)
52        chk64 ((k : Int) + d.toInt)
53      else do
54        let d ← Ptr.diff (.ref r p) (.ref r q)
55        chk64 ((k : Int) - d.toInt)) h =
56    .ok (Int64.ofInt ((q + k - p : Nat) : Int), h) := by
57  rw [bind_ok (Ptr.lt_ok hg hp hq)]
58  by_cases hc : p < q
59  · simp only [hc, decide_true, ite_true]
60    have hd := Ptr.diff_ok hg hq hp (by omega)
61    have hdiff : (q : Int) - (p : Int) = ((q - p : Nat) : Int) := by omega
62    rw [hdiff] at hd
63    rw [bind_ok hd, i64_toInt (q - p) (by omega)]
64    have hv : (k : Int) + (q - p : Nat) = ((q + k - p : Nat) : Int) := by omega
65    rw [hv, chk64_eq (by omega) (by omega)]
66    rfl
67  · simp only [hc, decide_false, Bool.false_eq_true, ite_false]
68    have hd := Ptr.diff_ok hg hp hq (by omega)
69    have hdiff : (p : Int) - (q : Int) = ((p - q : Nat) : Int) := by omega
70    rw [hdiff] at hd
71    rw [bind_ok hd, i64_toInt (p - q) (by omega)]
72    have hv : (k : Int) - (p - q : Nat) = ((q + k - p : Nat) : Int) := by omega
73    rw [hv, chk64_eq (by omega) (by omega)]
74    rfl
75
76/-- The C conditional arithmetic computes the exact nonnegative remaining
77count, in both pointer-order branches. -/
78theorem ptr_avail_cont {α : Type} {h : Heap} {r : BRef} {A : Array UInt8} {p q k : Nat}
79    (hg : Space.get h r = some A) (hp : p ≤ A.size) (hq : q ≤ A.size)
80    (hsz : A.size < 2 ^ 63) (hle : p ≤ q + k) (hk : k < 2 ^ 31)
81    (hr : q + k - p < 2 ^ 32) (K : Int64 → M α) :
82    (do
83      if ← Ptr.lt (.ref r p) (.ref r q) then do
84        let d ← Ptr.diff (.ref r q) (.ref r p)
85        let v ← chk64 ((k : Int) + d.toInt)
86        K v
87      else do
88        let d ← Ptr.diff (.ref r p) (.ref r q)
89        let v ← chk64 ((k : Int) - d.toInt)
90        K v) h =
91    K (Int64.ofInt ((q + k - p : Nat) : Int)) h := by
92  rw [bind_ok (Ptr.lt_ok hg hp hq)]
93  by_cases hc : p < q
94  · simp only [hc, decide_true, ite_true]
95    have hd := Ptr.diff_ok hg hq hp (by omega)
96    have hdiff : (q : Int) - (p : Int) = ((q - p : Nat) : Int) := by omega
97    rw [hdiff] at hd
98    rw [bind_ok hd, i64_toInt (q - p) (by omega)]
99    have hv : (k : Int) + (q - p : Nat) = ((q + k - p : Nat) : Int) := by omega
100    rw [hv, chk64_eq (by omega) (by omega)]
101    rfl
102  · simp only [hc, decide_false, Bool.false_eq_true, ite_false]
103    have hd := Ptr.diff_ok hg hp hq (by omega)
104    have hdiff : (p : Int) - (q : Int) = ((p - q : Nat) : Int) := by omega
105    rw [hdiff] at hd
106    rw [bind_ok hd, i64_toInt (p - q) (by omega)]
107    have hv : (k : Int) - (p - q : Nat) = ((q + k - p : Nat) : Int) := by omega
108    rw [hv, chk64_eq (by omega) (by omega)]
109    rfl
110
111theorem ptr_avail_wp {α : Type} {h : Heap} {r : BRef} {A : Array UInt8} {p q k : Nat}
112    (hg : Space.get h r = some A) (hp : p ≤ A.size) (hq : q ≤ A.size)
113    (hsz : A.size < 2 ^ 63) (hle : p ≤ q + k) (hk : k < 2 ^ 31)
114    (hr : q + k - p < 2 ^ 32) {K : Int64 → M α} {Q : α → Heap → Prop}
115    (hK : Wp (K (Int64.ofInt ((q + k - p : Nat) : Int))) h Q) :
116    Wp (do
117      if ← Ptr.lt (.ref r p) (.ref r q) then do
118        let d ← Ptr.diff (.ref r q) (.ref r p)
119        let v ← chk64 ((k : Int) + d.toInt)
120        K v
121      else do
122        let d ← Ptr.diff (.ref r p) (.ref r q)
123        let v ← chk64 ((k : Int) - d.toInt)
124        K v) h Q := by
125  obtain ⟨v, h', hrK, hpost⟩ := hK
126  exact ⟨v, h', (ptr_avail_cont hg hp hq hsz hle hk hr K).trans hrK, hpost⟩
127
128theorem i64_to_u32_eq (n : Nat) (hn : n < 2 ^ 32) :
129    (Int64.ofInt (n : Int)).toUInt64.toUInt32 = UInt32.ofNat n := by
130  apply UInt32.toNat_inj.mp
131  rw [i64_toU32 n hn, UInt32.toNat_ofNat']
132  exact (Nat.mod_eq_of_lt hn).symm
133
134theorem Env.stream_get_frame (e : Env) (bytes : Tbl (Option (Array UInt8)))
135    (states : Tbl (Option InflateState)) :
136    e.r.get { e.h0 with bytes, istates := states } = some e.sm0 := by
137  have hh := e.hsm
138  cases hr : e.r <;> (rw [hr] at hh; simpa [ZStreamRef.get] using hh)
139
140/-- Exact stream/state stores in the translated epilogue. -/
141theorem fast_stores_run (e : Env) (A : Array UInt8) (msg : BPtr) (mode : UInt32)
142    (input output : BPtr) (ai ao : UInt32) (hold : UInt64) (bits : UInt32) :
143    (do
144      let sm ← ldZStream e.strm
145      stZStream e.strm { sm with next_in := input, next_out := output, avail_in := ai, avail_out := ao }
146      let st ← ldInflateState (some (.tab e.stid))
147      stInflateState (some (.tab e.stid)) { st with hold, bits }) (e.heap A msg mode) =
148    .ok ((), e.r.put
149      { e.h0 with bytes := upd e.h0.bytes e.ob (some A), istates := upd e.h0.istates e.stid (some { e.s0 with mode, hold, bits }) }
150      { e.sm0 with next_in := input, next_out := output, avail_in := ai, avail_out := ao, msg }) := by
151  rw [e.hstrm, bind_ok (ldZStream_ok (e.heap_rget A msg mode)),
152    bind_ok (stZStream_ok (e.heap_rget A msg mode) e.hrw)]
153  let H := e.r.put (e.heap A msg mode)
154    { e.sm0 with next_in := input, next_out := output, avail_in := ai, avail_out := ao, msg }
155  have hg : H.istates e.stid = some { e.s0 with mode } := by
156    dsimp only [H]
157    rw [put_istates, e.heap_istates]
158    exact upd_same _ _ _
159  rw [bind_ok (ldInflateState_tab hg), stInflateState_tab hg]
160  dsimp only [H]
161  unfold Env.heap
162  rw [put_istates_comm, put_istates_comm]
163  simp only [put_istates, upd_upd]
164  rw [put_put _ _ e.sm0 _ _ (e.stream_get_frame _ _)]
165
166/-- The actual normalization and writeback fragment establishes FastPost
167from the proved loop facts. No callee behavior is an assumption. -/
168theorem fast_finish_wp (e : Env) (A : Array UInt8) (msg : BPtr) (mode : UInt32)
169    (l : L) (i o : Nat) (hl : LS e l i o) (hAsz : A.size = e.A0.size)
170    (ho : o ≤ e.o0 + e.sm0.avail_out.toNat)
171    (hf : ∀ j, (j < e.o0 ∨ o ≤ j) → A[j]? = e.A0[j]?)
172    (hclass : (mode = e.s0.mode ∧ msg = e.sm0.msg) ∨ (mode = TYPE ∧ msg = e.sm0.msg) ∨ mode = BAD)
173    (hstop : mode ≠ TYPE → mode ≠ BAD → i + 6 > e.i0 + e.sm0.avail_in.toNat ∨
174      o + 258 > e.o0 + e.sm0.avail_out.toNat) :
175    Wp (do
176      let len := l.bits >>> 3
177      let input ← subn l.in_ len
178      let bits := l.bits - (len <<< 3)
179      let hold := l.hold &&& ((← shl32 1 bits) - 1).toUInt64
180      let ai : Int64 ←
181        if ← Ptr.lt input (.ref (BRef.blk e.ib) (e.i0 + e.sm0.avail_in.toNat - 5)) then do
182          let d ← Ptr.diff (.ref (BRef.blk e.ib) (e.i0 + e.sm0.avail_in.toNat - 5)) input
183          chk64 (5 + d.toInt)
184        else do
185          let d ← Ptr.diff input (.ref (BRef.blk e.ib) (e.i0 + e.sm0.avail_in.toNat - 5))
186          chk64 (5 - d.toInt)
187      let ao : Int64 ←
188        if ← Ptr.lt l.out (.ref (BRef.blk e.ob) (e.o0 + e.sm0.avail_out.toNat - 257)) then do
189          let d ← Ptr.diff (.ref (BRef.blk e.ob) (e.o0 + e.sm0.avail_out.toNat - 257)) l.out
190          chk64 (257 + d.toInt)
191        else do
192          let d ← Ptr.diff l.out (.ref (BRef.blk e.ob) (e.o0 + e.sm0.avail_out.toNat - 257))
193          chk64 (257 - d.toInt)
194      let sm ← ldZStream e.strm
195      stZStream e.strm { sm with next_in := input, next_out := l.out, avail_in := ai.toUInt64.toUInt32, avail_out := ao.toUInt64.toUInt32 }
196      let st ← ldInflateState (some (.tab e.stid))
197      stInflateState (some (.tab e.stid)) { st with hold, bits })
198      (e.heap A msg mode) (fun _ after => FastPost e after) := by
199  let buf := l.bits.toNat / 8
200  let used := i - e.i0 - buf
201  let produced := o - e.o0
202  let bits := l.bits - ((l.bits >>> 3) <<< 3)
203  let hold := l.hold &&& (((1 : UInt32) <<< bits) - 1).toUInt64
204  have hbuf : buf ≤ i - e.i0 := hl.buffered_le
205  have hsmall : buf ≤ 3 := by dsimp only [buf]; have := hl.hb; omega
206  have hused : used + buf = i - e.i0 := by dsimp only [used]; omega
207  have hui : used + buf ≤ e.sm0.avail_in.toNat := by have := hl.hi0; have := hl.hi1; omega
208  have hup : produced ≤ e.sm0.avail_out.toNat := by dsimp only [produced]; have := hl.ho0; omega
209  have hio : i - (l.bits >>> 3).toNat = e.i0 + used := by
210    rw [bits_whole]
211    change i - buf = e.i0 + used
212    have := hl.hi0
213    omega
214  have hout : o = e.o0 + produced := by dsimp only [produced]; have := hl.ho0; omega
215  have hbits : bits.toNat < 8 := by dsimp only [bits]; rw [bits_residual _ hl.hb]; omega
216  have hinbuf : OkOn (e.heap A msg mode) (subn l.in_ (l.bits >>> 3))
217      (.ref (BRef.blk e.ib) (e.i0 + used)) := by
218    rw [hl.hin]
219    have hr := subn_ok (h := e.heap A msg mode) (r := BRef.blk e.ib) (a := e.IN) (e.heap_bytes_in A msg mode)
220      (n := l.bits >>> 3) (off := i) (by rw [bits_whole]; have := hl.hi0; omega)
221      (by have := hl.hi1; have := e.hINsz; omega)
222    simpa only [hio] using hr
223  refine Wp.bindO hinbuf ?_
224  refine Wp.bindO (shl32_ok (x := 1) (n := bits) (by omega)) ?_
225  have hu32 : e.sm0.avail_in.toNat - used < 2 ^ 32 := by have := UInt32.toNat_lt e.sm0.avail_in; omega
226  have ho32 : e.sm0.avail_out.toNat - produced < 2 ^ 32 := by have := UInt32.toNat_lt e.sm0.avail_out; omega
227  have hei : e.i0 + e.sm0.avail_in.toNat - 5 + 5 - (e.i0 + used) = e.sm0.avail_in.toNat - used := by
228    have := e.hai; omega
229  refine ptr_avail_wp (h := e.heap A msg mode) (r := BRef.blk e.ib) (A := e.IN)
230    (p := e.i0 + used) (q := e.i0 + e.sm0.avail_in.toNat - 5) (k := 5)
231    (e.heap_bytes_in A msg mode) (by have := e.hINsz; omega) (by have := e.hINsz; omega)
232    e.hINbig (by have := e.hai; omega) (by decide) (by rw [hei]; exact hu32) ?_
233  rw [hei]
234  rw [hl.hout]
235  have heo : e.o0 + e.sm0.avail_out.toNat - 257 + 257 - o = e.sm0.avail_out.toNat - produced := by
236    have := e.hao; omega
237  refine ptr_avail_wp (h := e.heap A msg mode) (r := BRef.blk e.ob) (A := A)
238    (p := o) (q := e.o0 + e.sm0.avail_out.toNat - 257) (k := 257)
239    (e.heap_bytes_ob A msg mode) (by rw [hAsz]; have := e.hAsz; omega) (by rw [hAsz]; have := e.hAsz; omega)
240    (by rw [hAsz]; exact e.hAbig) (by have := e.hao; omega) (by decide) (by rw [heo]; exact ho32) ?_
241  rw [heo]
242  rw [i64_to_u32_eq _ hu32, i64_to_u32_eq _ ho32]
243  refine Wp.of_eq (fast_stores_run e A msg mode (.ref (BRef.blk e.ib) (e.i0 + used)) (.ref (BRef.blk e.ob) o)
244    (UInt32.ofNat (e.sm0.avail_in.toNat - used)) (UInt32.ofNat (e.sm0.avail_out.toNat - produced)) hold bits) ?_
245  refine ⟨used, produced, buf, A, msg, mode, bits, hold, hui, hsmall, hup, hAsz, hbits,
246    normalized_hold_lt l.hold bits (by omega), ?_, ?_, hclass, ?_⟩
247  · rw [← hout]
248  · intro j hj
249    exact hf j (by rw [← hout] at hj; exact hj)
250  · intro hnt hnb
251    rcases hstop hnt hnb with hi | ho
252    · exact Or.inl (by have := hl.hi0; omega)
253    · exact Or.inr (by omega)
254
255/-- The complete actual fast decoder satisfies the unchanged reviewed
256safety, termination, frame, normalization and writeback goal. -/
257theorem inflate_fast_safe : Goal.fast_safe := by
258  intro e
259  have hw : Wp (inflate_fast e.strm e.start) e.h0 (fun _ after => FastPost e after) := by
260    let c0 : Ctx := {
261      strm := e.strm, state := some (.tab e.stid),
262      last := .ref (BRef.blk e.ib) (e.i0 + e.sm0.avail_in.toNat - 5),
263      beg := .ref (BRef.blk e.ob) e.bg,
264      end_ := .ref (BRef.blk e.ob) (e.o0 + e.sm0.avail_out.toNat - 257),
265      wsize := e.s0.wsize, whave := e.s0.whave, wnext := e.s0.wnext, window := e.s0.window,
266      lcode := e.s0.lencode, dcode := e.s0.distcode,
267      lmask := ((1 : UInt32) <<< e.s0.lenbits) - 1, dmask := ((1 : UInt32) <<< e.s0.distbits) - 1 }
268    let l0 : L := {
269      in_ := .ref (BRef.blk e.ib) e.i0, out := .ref (BRef.blk e.ob) e.o0,
270      hold := e.s0.hold, bits := e.s0.bits, here := default, op := 0, len := 0, dist := 0,
271      from_ := default, broke := false, againL := false, againD := false }
272    have hc0 : CtxOK e c0 := ⟨rfl, rfl, rfl, rfl, rfl, rfl, rfl, rfl, rfl, rfl, rfl, rfl, rfl⟩
273    have hl0 : LS e l0 e.i0 e.o0 := by
274      dsimp only [l0]
275      refine ⟨rfl, rfl, by omega, ?_, by omega, ?_, e.hhold, ?_⟩
276      · have := e.hai; omega
277      · change e.s0.bits.toNat ≤ 30
278        have := e.hbits; omega
279      · change e.s0.bits.toNat + 8 * e.i0 ≤ e.s0.bits.toNat + 8 * e.i0
280        exact Nat.le_refl _
281    have hlast : OkOn e.h0 (Ptr.add e.sm0.next_in (e.sm0.avail_in - 5).toNat)
282        (.ref (BRef.blk e.ib) (e.i0 + e.sm0.avail_in.toNat - 5)) := by
283      rw [e.hnin, u32_toNat_sub (by change 5 ≤ e.sm0.avail_in.toNat; have := e.hai; omega)]
284      have hr := Ptr.add_nat_ok (h := e.h0) (r := BRef.blk e.ib) (a := e.IN)
285        (off := e.i0) (n := e.sm0.avail_in.toNat - 5) e.hIN (by have := e.hINsz; omega)
286      have hoff : e.i0 + (e.sm0.avail_in.toNat - 5) = e.i0 + e.sm0.avail_in.toNat - 5 := by have := e.hai; omega
287      simpa [hoff] using hr
288    have hbeg : OkOn e.h0 (subn e.sm0.next_out (e.start - e.sm0.avail_out))
289        (.ref (BRef.blk e.ob) e.bg) := by
290      rw [e.hnout]
291      have hn : (e.start - e.sm0.avail_out).toNat = e.start.toNat - e.sm0.avail_out.toNat :=
292        u32_toNat_sub e.hstart
293      have hr := subn_ok (h := e.h0) (r := BRef.blk e.ob) (a := e.A0)
294        (off := e.o0) (n := e.start - e.sm0.avail_out) e.hA0 (by rw [hn]; exact e.hbeg)
295        (by have := e.hAsz; omega)
296      simpa only [hn, Env.bg] using hr
297    have hend : OkOn e.h0 (Ptr.add e.sm0.next_out (e.sm0.avail_out - 257).toNat)
298        (.ref (BRef.blk e.ob) (e.o0 + e.sm0.avail_out.toNat - 257)) := by
299      rw [e.hnout, u32_toNat_sub (by change 257 ≤ e.sm0.avail_out.toNat; have := e.hao; omega)]
300      have hr := Ptr.add_nat_ok (h := e.h0) (r := BRef.blk e.ob) (a := e.A0)
301        (off := e.o0) (n := e.sm0.avail_out.toNat - 257) e.hA0 (by have := e.hAsz; omega)
302      have hoff : e.o0 + (e.sm0.avail_out.toNat - 257) = e.o0 + e.sm0.avail_out.toNat - 257 := by have := e.hao; omega
303      simpa [hoff] using hr
304    unfold inflate_fast
305    refine Wp.bindO (x := e.sm0) (by rw [e.hstrm]; exact ldZStream_ok e.hsm) ?_
306    refine Wp.bindO (x := some (InflateStateRef.tab e.stid)) (by rw [e.hstate]; exact castInflateState_ok) ?_
307    refine Wp.bindO hlast ?_
308    refine Wp.bindO hbeg ?_
309    refine Wp.bindO hend ?_
310    refine Wp.bindO (ldInflateState_tab e.hs0) ?_
311    refine Wp.bindO (shl32_ok (x := 1) (n := e.s0.lenbits) (by have := e.hlt.1; omega)) ?_
312    refine Wp.bindO (shl32_ok (x := 1) (n := e.s0.distbits) (by have := e.hdt.1; omega)) ?_
313    rw [e.hnin, e.hnout]
314    obtain ⟨l, h, hr, hpost⟩ := fast_loop_wp hc0 l0 e.i0 e.o0 e.A0 hl0 rfl rfl
315      (by have := e.hai; omega) (by have := e.hao; omega) (by intro _ _; rfl)
316    rw [e.heap_initial] at hr
317    refine Wp.bindE hr ?_
318    obtain ⟨i, o, A, msg, mode, hl, ho, hA, hh, hf, hclass, hstop⟩ := hpost
319    rw [hh]
320    exact fast_finish_wp e A msg mode l i o hl hA ho hf hclass hstop
321  obtain ⟨⟨⟩, after, hr, hp⟩ := hw
322  exact ⟨after, hr, hp⟩
323
324end Zlib.Inffast.Proofs
ZLIB × LEAN

Global contents

READING NOWinffast.c.final.lean