跳到正文
参考文档 / ZLIB × LEAN

inflate.c.window.lean

此页源文件快照 · 5b9e4d8ca5d1355f · 对应提交的原文 ↗

本页保留 Lean 源码及行号。点击行号可定位语句,点击 import 中的模块名可查看依赖。

1import ZlibF.Proof.«inflate.c.misc2»
2import ZlibF.Proof.«pointer-arithmetic»
3
4/-!
5# inflate.c: the ring buffer of `updatewindow`
6
7The copy lemmas establish the two ring-buffer branches for `wbits ≤ 15`.
8Pointer arithmetic uses the checked rules in `ZlibF.Proof.PointerArithmetic`.
9-/
10
11namespace Zlib.Inflate.Proofs.W
12open C ZlibF.Proof
13
14
15/-- `if (state->wsize == 0) { wsize = 1U << wbits; wnext = 0; whave = 0; }` -/
16def initWin (st : InflateState) : InflateState :=
17  if st.wsize == 0 then { st with wsize := (1 : UInt32) <<< st.wbits, wnext := 0, whave := 0 } else st
18
19/-- `if (copy >= wsize)`: copy the last `wsize` bytes before `end` into the whole window. -/
20def uw_big (ist : InflateStatePtr) (st : InflateState) (e : BPtr) : M UInt32 := do
21  let src ← PointerArithmetic.subNat e st.wsize.toNat
22  memcpyB st.window src st.wsize.toNat
23  stInflateState ist { st with wnext := 0, whave := st.wsize }
24  return 0
25
26/-- `else`: copy `copy` bytes into the ring buffer, in at most two pieces. -/
27def uw_small (ist : InflateStatePtr) (st : InflateState) (e : BPtr) (copy : UInt32) : M UInt32 := do
28  let dist : UInt32 := if st.wsize - st.wnext > copy then copy else st.wsize - st.wnext
29  let dst ← PointerArithmetic.addNat st.window st.wnext.toNat
30  let src ← PointerArithmetic.subNat e copy.toNat
31  memcpyB dst src dist.toNat
32  let copy' : UInt32 := copy - dist
33  if copy' != 0 then
34    let src2 ← PointerArithmetic.subNat e copy'.toNat
35    memcpyB st.window src2 copy'.toNat
36    stInflateState ist { st with wnext := copy', whave := st.wsize }
37    return 0
38  else
39    let wn : UInt32 := st.wnext + dist
40    let wn : UInt32 := if wn == st.wsize then 0 else wn
41    let wh : UInt32 := if st.whave < st.wsize then st.whave + dist else st.whave
42    stInflateState ist { st with wnext := wn, whave := wh }
43    return 0
44
45/-- The part of `updatewindow(strm, end, copy)` after the window has been allocated. -/
46def update2 (sr : Nat) (e : BPtr) (copy : UInt32) : M UInt32 := do
47  let z ← ldZStream (some (.tab sr))
48  let ist ← castInflateState z.state
49  let st0 ← ldInflateState ist
50  let st := initWin st0
51  if copy ≥ st.wsize then uw_big ist st e else uw_small ist st e copy
52
53/-- The window invariant W of `docs/proof/inflate.md`: the window is a writable byte block of `2^wbits` bytes. -/
54structure WInv (h : Heap) (st : InflateState) : Prop where
55  k : st.wbits.toNat ≤ 15
56  win : ∃ w a, st.window = .ref (.blk w) 0 ∧ h.bytes w = some a ∧ h.ro w = false ∧ a.size = 2 ^ st.wbits.toNat
57  ws : st.wsize.toNat = 0 ∨ st.wsize.toNat = 2 ^ st.wbits.toNat
58  hv : st.whave.toNat ≤ st.wsize.toNat
59  wn : st.wnext.toNat < st.wsize.toNat ∨ (st.wsize.toNat = 0 ∧ st.wnext.toNat = 0)
60  eq : st.whave.toNat < st.wsize.toNat → st.wnext.toNat = st.whave.toNat
61
62theorem shl_toNat (b : UInt32) (hb : b.toNat ≤ 15) : ((1 : UInt32) <<< b).toNat = 2 ^ b.toNat := by
63  have h15 : 2 ^ b.toNat ≤ 2 ^ 15 := Nat.pow_le_pow_right (by decide) hb
64  have e32 : b.toNat % 32 = b.toNat := Nat.mod_eq_of_lt (by omega)
65  rw [UInt32.toNat_shiftLeft, e32]
66  simp [Nat.shiftLeft_eq]
67  omega
68
69/-- After `initWin` the window is in use and the invariant still holds. -/
70theorem initWin_inv {h : Heap} {st : InflateState} (hW : WInv h st) :
71    WInv h (initWin st) ∧ 0 < (initWin st).wsize.toNat ∧ (initWin st).window = st.window ∧
72    (initWin st).wbits = st.wbits := by
73  obtain ⟨hk2, ⟨w, a, hw, ha, hro, hasz⟩, hws, hv, hwn, heq⟩ := hW
74  have hpow : ((1 : UInt32) <<< st.wbits).toNat = 2 ^ st.wbits.toNat := shl_toNat _ hk2
75  have hp : 0 < 2 ^ st.wbits.toNat := Nat.two_pow_pos _
76  unfold initWin
77  by_cases h0 : st.wsize == 0
78  · have h0' : st.wsize = 0 := by simpa using h0
79    have h00 : st.wsize.toNat = 0 := by rw [h0']; rfl
80    simp only [h0, ite_true]
81    refine ⟨⟨hk2, ⟨w, a, hw, ha, hro, hasz⟩, ?_, ?_, ?_, ?_⟩, ?_, ?_, ?_⟩ <;> simp [hpow, hp]
82  · have h0' : ¬ st.wsize = 0 := by simpa using h0
83    have h00 : st.wsize.toNat ≠ 0 := fun h => h0' (UInt32.toNat_inj.mp (by simpa using h))
84    have h0'' : (st.wsize == 0) = false := by simpa using h0
85    simp only [h0'', Bool.false_eq_true, ite_false]
86    refine ⟨⟨hk2, ⟨w, a, hw, ha, hro, hasz⟩, hws, hv, hwn, heq⟩, by omega, ?_⟩
87    simp
88
89/-- `zmemcpy(w + d, e - n, m)` on a window block `w` and a different block `eb`, then the rest `k`: the heap with the
90window block replaced by a block of the same size. -/
91theorem cpy_step {h : Heap} {w eb : Nat} {a ebytes : Array UInt8} {eo n m d : Nat}
92    (ha : h.bytes w = some a) (hro : h.ro w = false) (heb : h.bytes eb = some ebytes) (hne : w ≠ eb)
93    (hn : n ≤ eo) (hm : m ≤ n) (hoff : eo ≤ ebytes.size) (hd : d + m ≤ a.size) :
94    ∃ A, (∀ {α : Type} (k : Unit → M α),
95        (PointerArithmetic.subNat (.ref (.blk eb) eo) n >>= fun src => (memcpyB (.ref (.blk w) d) src m >>= k)) h =
96          k () { h with bytes := upd h.bytes w (some A) }) ∧ A.size = a.size := by
97  refine ⟨copyRange a ebytes d (eo - n) m, ?_, size_copyRange ..⟩
98  intro α k
99  have h2 : eo - n + m ≤ ebytes.size := by omega
100  simp only [bind_app, PointerArithmetic.subNat_ok (r := BRef.blk eb) (by simpa using heb) hn hoff]
101  simp only [bind_app, memcpyB_blk_ok ha heb hro hne hd h2]
102
103/-- `zmemcpy(w + d, e - n, m)` where `w + d` is computed first (the first copy of `uw_small`). -/
104theorem cpy_step_off {h : Heap} {w eb : Nat} {a ebytes : Array UInt8} {eo n m d : Nat}
105    (ha : h.bytes w = some a) (hro : h.ro w = false) (heb : h.bytes eb = some ebytes) (hne : w ≠ eb)
106    (hn : n ≤ eo) (hm : m ≤ n) (hoff : eo ≤ ebytes.size) (hd : d + m ≤ a.size) (hda : d ≤ a.size) :
107    ∃ A, (∀ {α : Type} (k : Unit → M α),
108        (PointerArithmetic.addNat (.ref (.blk w) 0) d >>= fun dst => (PointerArithmetic.subNat (.ref (.blk eb) eo) n >>= fun src =>
109          (memcpyB dst src m >>= k))) h = k () { h with bytes := upd h.bytes w (some A) }) ∧ A.size = a.size := by
110  obtain ⟨A, hA, hs⟩ := cpy_step (d := 0 + d) ha hro heb hne hn hm hoff (by omega)
111  refine ⟨A, fun {α} k => ?_, hs⟩
112  rw [bind_ok (PointerArithmetic.addNat_ok (r := BRef.blk w) (a := a) (off := 0) (n := d) (by simpa using ha) (by omega))]
113  exact hA k
114
115/-- The tables other than `bytes` and `istates` are unchanged, and so are the read-only flags and the block counter. -/
116def Same (h h' : Heap) : Prop :=
117  h'.words = h.words ∧ h'.dstates = h.dstates ∧ h'.gzheaders = h.gzheaders ∧ h'.gzstates = h.gzstates ∧
118    h'.streams = h.streams ∧ h'.ro = h.ro ∧ h'.nextBlk = h.nextBlk
119
120/-- What the two branches of `updatewindow` establish. -/
121def UwPost (h h' : Heap) (zs w : Nat) (st' : InflateState) : Prop :=
122  h'.istates zs = some st' ∧ WInv h' st' ∧ (∀ r, r ≠ zs → h'.istates r = h.istates r) ∧
123    Same h h' ∧ (∀ b, b ≠ w → h'.bytes b = h.bytes b) ∧ st'.window = .ref (.blk w) 0
124
125/-- The branch `copy ≥ wsize` of `updatewindow` never faults and establishes the window invariant. -/
126theorem uw_big_ok {h : Heap} {zs w eb eo : Nat} {st : InflateState} {ebytes : Array UInt8}
127    (hW : WInv h st) (hw : st.window = .ref (.blk w) 0) (hpos : 0 < st.wsize.toNat)
128    (hex : ∃ s, h.istates zs = some s) (heb : h.bytes eb = some ebytes) (hne : w ≠ eb)
129    (hc : st.wsize.toNat ≤ eo) (hoff : eo ≤ ebytes.size) :
130    ∃ h' st', uw_big (some (.tab zs)) st (.ref (.blk eb) eo) h = .ok (0, h') ∧ UwPost h h' zs w st' := by
131  obtain ⟨hk2, ⟨w', a, hw', ha, hro, hasz⟩, hws, hv, hwn, heq⟩ := hW
132  have hww : w' = w := by rw [hw] at hw'; exact (Ptr.ref.inj hw').1 |> BRef.blk.inj |>.symm
133  subst hww
134  have hsz : st.wsize.toNat = 2 ^ st.wbits.toNat := by omega
135  obtain ⟨A, hstep, hAsz⟩ :=
136    cpy_step (h := h) (w := w') (eb := eb) (a := a) (ebytes := ebytes) (eo := eo) (n := st.wsize.toNat)
137      (m := st.wsize.toNat) (d := 0) ha hro heb hne hc (Nat.le_refl _) hoff (by omega)
138  obtain ⟨s0, hs0⟩ := hex
139  have hs0' : ({ h with bytes := upd h.bytes w' (some A) } : Heap).istates zs = some s0 := hs0
140  refine ⟨{ { h with bytes := upd h.bytes w' (some A) } with
141      istates := upd h.istates zs (some { st with wnext := 0, whave := st.wsize }) },
142    { st with wnext := 0, whave := st.wsize }, ?_, ?_⟩
143  · simp only [uw_big, hw, hstep, bind_app, stInflateState_tab hs0', pure_app]
144  · refine ⟨by simp, ⟨hk2, ⟨w', A, hw, by simp, by simpa using hro, hAsz.trans hasz⟩, hws, ?_, ?_, ?_⟩,
145      fun r hr => by simp [upd_ne _ _ _ _ hr], ⟨rfl, rfl, rfl, rfl, rfl, rfl, rfl⟩,
146      fun b hb => by simp [upd_ne _ _ _ _ hb], hw⟩
147    · show st.wsize.toNat ≤ st.wsize.toNat
148      exact Nat.le_refl _
149    · exact Or.inl (by show 0 < st.wsize.toNat; exact hpos)
150    · intro hh; exact absurd hh (Nat.lt_irrefl _)
151
152theorem uadd (a b : UInt32) (h : a.toNat + b.toNat < 2 ^ 32) : (a + b).toNat = a.toNat + b.toNat := by
153  rw [UInt32.toNat_add]; exact Nat.mod_eq_of_lt h
154
155/-- The branch `copy < wsize` of `updatewindow` (one or two pieces) never faults and keeps the window invariant. -/
156theorem uw_small_ok {h : Heap} {zs w eb eo : Nat} {st : InflateState} {copy : UInt32} {ebytes : Array UInt8}
157    (hW : WInv h st) (hw : st.window = .ref (.blk w) 0) (hpos : 0 < st.wsize.toNat)
158    (hex : ∃ s, h.istates zs = some s) (heb : h.bytes eb = some ebytes) (hne : w ≠ eb)
159    (hc : copy.toNat ≤ eo) (hlt : copy.toNat < st.wsize.toNat) (hoff : eo ≤ ebytes.size) :
160    ∃ h' st', uw_small (some (.tab zs)) st (.ref (.blk eb) eo) copy h = .ok (0, h') ∧ UwPost h h' zs w st' := by
161  obtain ⟨hk2, ⟨w', a, hw', ha, hro, hasz⟩, hws, hv, hwn, heq⟩ := hW
162  have hww : w' = w := by rw [hw] at hw'; exact (BRef.blk.inj (Ptr.ref.inj hw').1).symm
163  subst hww
164  have hsz : st.wsize.toNat = 2 ^ st.wbits.toNat := by omega
165  have hwn' : st.wnext.toNat < st.wsize.toNat := by omega
166  have h15 : 2 ^ st.wbits.toNat ≤ 2 ^ 15 := Nat.pow_le_pow_right (by decide) hk2
167  obtain ⟨dist, hdist⟩ : ∃ d : UInt32, d = (if st.wsize - st.wnext > copy then copy else st.wsize - st.wnext) := ⟨_, rfl⟩
168  have hsub : (st.wsize - st.wnext).toNat = st.wsize.toNat - st.wnext.toNat :=
169    UInt32.toNat_sub_of_le _ _ (by rw [UInt32.le_iff_toNat_le]; omega)
170  have hdn : (dist.toNat = copy.toNat ∧ copy.toNat < st.wsize.toNat - st.wnext.toNat) ∨
171      (dist.toNat = st.wsize.toNat - st.wnext.toNat ∧ ¬ copy.toNat < st.wsize.toNat - st.wnext.toNat) := by
172    rw [hdist]
173    by_cases hc' : st.wsize - st.wnext > copy
174    · left; rw [ite_eq_left hc']; have := UInt32.lt_iff_toNat_lt.mp hc'; omega
175    · right; rw [ite_eq_right hc']; refine ⟨hsub, fun hh => hc' (UInt32.lt_iff_toNat_lt.mpr (by omega))⟩
176  have hd1 : dist.toNat ≤ copy.toNat := by omega
177  have hd2 : dist.toNat ≤ st.wsize.toNat - st.wnext.toNat := by omega
178  obtain ⟨A1, hstep1, hA1sz⟩ :=
179    cpy_step_off (h := h) (w := w') (eb := eb) (a := a) (ebytes := ebytes) (eo := eo) (n := copy.toNat) (m := dist.toNat)
180      (d := st.wnext.toNat) ha hro heb hne hc hd1 hoff (by omega) (by omega)
181  obtain ⟨s0, hs0⟩ := hex
182  have hcsub : (copy - dist).toNat = copy.toNat - dist.toNat := UInt32.toNat_sub_of_le _ _ (by rw [UInt32.le_iff_toNat_le]; omega)
183  by_cases hcp : (copy - dist != 0) = true
184  · -- the window wraps: a second piece goes to the start
185    have hcn : 0 < (copy - dist).toNat := by
186      have : copy - dist ≠ 0 := by simpa using hcp
187      have h0 : (copy - dist).toNat ≠ 0 := fun hh => this (UInt32.toNat_inj.mp (by simpa using hh))
188      omega
189    obtain ⟨A2, hstep2, hA2sz⟩ :=
190      cpy_step (h := { h with bytes := upd h.bytes w' (some A1) }) (w := w') (eb := eb) (a := A1) (ebytes := ebytes)
191        (eo := eo) (n := (copy - dist).toNat) (m := (copy - dist).toNat) (d := 0) (by simp) (by simpa using hro)
192        (by simp [upd_ne _ _ _ _ hne.symm, heb]) hne (by omega) (Nat.le_refl _) hoff (by omega)
193    have hs0' : ({ { h with bytes := upd h.bytes w' (some A1) } with
194        bytes := upd (upd h.bytes w' (some A1)) w' (some A2) } : Heap).istates zs = some s0 := hs0
195    refine ⟨{ { { h with bytes := upd h.bytes w' (some A1) } with
196        bytes := upd (upd h.bytes w' (some A1)) w' (some A2) } with
197        istates := upd h.istates zs (some { st with wnext := copy - dist, whave := st.wsize }) },
198      { st with wnext := copy - dist, whave := st.wsize }, ?_, ?_⟩
199    · simp only [uw_small, hw, ← hdist, hstep1, hcp, ite_true, hstep2]
200      simp only [bind_app, stInflateState_tab hs0', pure_app]
201    · refine ⟨by simp, ⟨hk2, ⟨w', A2, hw, by simp, by simpa using hro, by show A2.size = 2 ^ st.wbits.toNat; omega⟩,
202          hws, ?_, ?_, ?_⟩,
203        fun r hr => by simp [upd_ne _ _ _ _ hr], ⟨rfl, rfl, rfl, rfl, rfl, rfl, rfl⟩,
204        fun b hb => by simp [upd_ne _ _ _ _ hb], hw⟩
205      · show st.wsize.toNat ≤ st.wsize.toNat
206        exact Nat.le_refl _
207      · exact Or.inl (by show (copy - dist).toNat < st.wsize.toNat; omega)
208      · intro hh; exact absurd hh (Nat.lt_irrefl _)
209  · -- everything fits before the end of the window
210    have hcp' : (copy - dist != 0) = false := by simpa using hcp
211    have hc0 : copy.toNat = dist.toNat := by
212      have : copy - dist = 0 := by simpa using hcp'
213      have : (copy - dist).toNat = 0 := by rw [this]; rfl
214      omega
215    have hwd : st.wnext.toNat + dist.toNat ≤ st.wsize.toNat := by omega
216    have hadd : (st.wnext + dist).toNat = st.wnext.toNat + dist.toNat := uadd _ _ (by omega)
217    obtain ⟨wn, hwn_def⟩ : ∃ x : UInt32, x = (if st.wnext + dist == st.wsize then 0 else st.wnext + dist) := ⟨_, rfl⟩
218    obtain ⟨wh, hwh_def⟩ : ∃ x : UInt32, x = (if st.whave < st.wsize then st.whave + dist else st.whave) := ⟨_, rfl⟩
219    have hwn_nat : (wn.toNat = 0 ∧ st.wnext.toNat + dist.toNat = st.wsize.toNat) ∨
220        (wn.toNat = st.wnext.toNat + dist.toNat ∧ st.wnext.toNat + dist.toNat < st.wsize.toNat) := by
221      rw [hwn_def]
222      by_cases hq : st.wnext + dist == st.wsize
223      · left; rw [ite_eq_left hq]
224        have := UInt32.toNat_inj.mpr (beq_iff_eq.mp hq)
225        refine ⟨rfl, by omega⟩
226      · right; rw [ite_eq_right hq]
227        have hne' : ¬ (st.wnext + dist = st.wsize) := fun hh => hq (beq_iff_eq.mpr hh)
228        have : st.wnext.toNat + dist.toNat ≠ st.wsize.toNat := fun hh =>
229          hne' (UInt32.toNat_inj.mp (by omega))
230        exact ⟨hadd, by omega⟩
231    have hwh_nat : (st.whave.toNat < st.wsize.toNat ∧ wh.toNat = st.whave.toNat + dist.toNat) ∨
232        (¬ st.whave.toNat < st.wsize.toNat ∧ wh.toNat = st.whave.toNat) := by
233      rw [hwh_def]
234      by_cases hl : st.whave < st.wsize
235      · left; rw [ite_eq_left hl]
236        have hl' := UInt32.lt_iff_toNat_lt.mp hl
237        have := heq hl'
238        exact ⟨hl', uadd _ _ (by omega)⟩
239      · right; rw [ite_eq_right hl]; exact ⟨fun hh => hl (UInt32.lt_iff_toNat_lt.mpr hh), rfl⟩
240    have hs0' : ({ h with bytes := upd h.bytes w' (some A1) } : Heap).istates zs = some s0 := hs0
241    refine ⟨{ { h with bytes := upd h.bytes w' (some A1) } with
242        istates := upd h.istates zs (some { st with wnext := wn, whave := wh }) },
243      { st with wnext := wn, whave := wh }, ?_, ?_⟩
244    · simp only [uw_small, hw, ← hdist, hstep1, hcp', Bool.false_eq_true, ite_false, ← hwn_def, ← hwh_def]
245      simp only [bind_app, stInflateState_tab hs0', pure_app]
246    · refine ⟨by simp, ⟨hk2, ⟨w', A1, hw, by simp, by simpa using hro, by show A1.size = 2 ^ st.wbits.toNat; omega⟩,
247          hws, ?_, ?_, ?_⟩,
248        fun r hr => by simp [upd_ne _ _ _ _ hr], ⟨rfl, rfl, rfl, rfl, rfl, rfl, rfl⟩,
249        fun b hb => by simp [upd_ne _ _ _ _ hb], hw⟩
250      · show wh.toNat ≤ st.wsize.toNat
251        omega
252      · show wn.toNat < st.wsize.toNat ∨ (st.wsize.toNat = 0 ∧ wn.toNat = 0)
253        omega
254      · show wh.toNat < st.wsize.toNat → wn.toNat = wh.toNat
255        omega
256
257
258end Zlib.Inflate.Proofs.W
ZLIB × LEAN

全局目录

当前位置inflate.c.window.lean