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

inffast.c.len.lean

此页源文件快照 · 0b99873cf4c83566 · 对应提交的原文 ↗

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

1import ZlibF.Proof.«inffast.c.lp»
2
3namespace Zlib.Inffast.Proofs
4open C Zlib.Inffast Zlib.Inffast.Spec ZlibF.Spec
5
6variable {e : Env} {c : Ctx}
7
8/-- `dodist:` reached from the length block: look up the distance code and run the distance block. -/
9def dolenDist (c : Ctx) (l : L) : M L := do
10  let __do_lift ← Ptr.add c.dcode ↑(l.hold &&& c.dmask.toUInt64).toNat
11  let l : L := { l with here := __do_lift }
12  cdoWhile (dodist c) (fun l => pure (l.againD, l)) l
13
14theorem dolenDist_wp (hc : CtxOK e c) (A : Array UInt8) (msg : BPtr) (m : UInt32) (l : L) (i o : Nat)
15    (hts : DistTableSafe e.DCA e.od e.s0.distbits.toNat)
16    (hls : LS e l i o) (hA : e.o0 + e.sm0.avail_out.toNat ≤ A.size) (ho : o + 258 ≤ e.o0 + e.sm0.avail_out.toNat)
17    (hAb : A.size < 2 ^ 63) (hbroke : l.broke = false) (hlen : 3 ≤ l.len.toNat ∧ l.len.toNat ≤ 258)
18    (hb15 : 15 ≤ l.bits.toNat)
19    (hpull : i + 2 ≤ e.i0 + e.sm0.avail_in.toNat ∨ (i + 1 ≤ e.i0 + e.sm0.avail_in.toNat ∧ 20 ≤ l.bits.toNat)) :
20    Wp (dolenDist c l) (e.heap A msg m) (fun l' h' =>
21      ∃ E cb, cb ≤ 15 ∧ DistLook e l.hold.toNat (l.hold.toNat % 2 ^ e.s0.distbits.toNat) E cb ∧
22        DistEnd e A msg m ((Sg e l.hold.toNat l.bits.toNat i).drop cb) i o l.len.toNat E l' h') := by
23  unfold dolenDist
24  have hdc : c.dcode = .ref e.rd e.od := by rw [hc.dcode]; exact e.hdc
25  have hR : e.s0.distbits.toNat < 32 := by have := hts.1; omega
26  have hmask : c.dmask.toUInt64.toNat = 2 ^ e.s0.distbits.toNat - 1 := by
27    rw [hc.dmask, UInt32.toNat_toUInt64]; exact u32_shl1_sub1 hR
28  have hidx := u64_and_mask (x := l.hold) hmask
29  have hmod : l.hold.toNat % 2 ^ e.s0.distbits.toNat < 2 ^ e.s0.distbits.toNat :=
30    Nat.mod_lt _ (Nat.pow_pos (by omega))
31  refine Wp.bindO (x := Ptr.ref e.rd (e.od + l.hold.toNat % 2 ^ e.s0.distbits.toNat)) ?_ ?_
32  · rw [hdc, hidx]
33    exact Ptr.add_nat_ok (e.heap_cget_DCA A msg m) (by have := hts.2.1; omega)
34  · exact Wp.mono (dodistLoop_wp hc A msg m { l with here := Ptr.ref e.rd (e.od + l.hold.toNat % 2 ^ e.s0.distbits.toNat) }
35      i o _ hts hmod (LS.congr hls rfl rfl rfl rfl) hA ho hAb hbroke hlen rfl hb15 hpull) (fun _ _ h => h)
36
37
38/-- The refill before the distance lookup (`if (bits < 15) { two bytes }`) and the distance block. -/
39def dolenRefill (c : Ctx) (l : L) : M L :=
40  if l.bits < 15 then do
41    let __x ← pull l
42    let __x ← pull __x
43    dolenDist c __x
44  else dolenDist c l
45
46/-- What follows the refill: the stream, and the lookup and the end of the distance block. -/
47def RefillPost (e : Env) (A : Array UInt8) (msg : BPtr) (m : UInt32) (S : List Bool) (i o len : Nat)
48    (l' : L) (h' : Heap) : Prop :=
49  ∃ i3 H3 b3 E cb, i ≤ i3 ∧ i3 ≤ i + 2 ∧ Sg e H3 b3 i3 = S ∧ H3 < 2 ^ b3 ∧ 15 ≤ b3 ∧ b3 ≤ 30 ∧ cb ≤ 15 ∧
50    DistLook e H3 (H3 % 2 ^ e.s0.distbits.toNat) E cb ∧ DistEnd e A msg m (S.drop cb) i3 o len E l' h'
51
52theorem dolenRefill_wp (hc : CtxOK e c) (A : Array UInt8) (msg : BPtr) (m : UInt32) (l : L) (i o s : Nat)
53    (hts : DistTableSafe e.DCA e.od e.s0.distbits.toNat)
54    (hls : LS e l i o) (hA : e.o0 + e.sm0.avail_out.toNat ≤ A.size) (ho : o + 258 ≤ e.o0 + e.sm0.avail_out.toNat)
55    (hAb : A.size < 2 ^ 63) (hbroke : l.broke = false) (hlen : 3 ≤ l.len.toNat ∧ l.len.toNat ≤ 258)
56    (hs6 : s + 6 ≤ e.i0 + e.sm0.avail_in.toNat) (hT : i ≤ s + 3) (hT3 : i = s + 3 → 4 ≤ l.bits.toNat) :
57    Wp (dolenRefill c l) (e.heap A msg m) (fun l' h' =>
58      RefillPost e A msg m (Sg e l.hold.toNat l.bits.toNat i) i o l.len.toNat l' h') := by
59  unfold dolenRefill
60  by_cases h1 : l.bits < 15
61  · simp only [h1, ite_true]
62    have h1' : l.bits.toNat < 15 := by simpa using UInt32.lt_iff_toNat_lt.mp h1
63    have hiin : i < e.i0 + e.sm0.avail_in.toNat := by omega
64    refine Wp.bindO (pull_run e _ l i o hls (by omega) hiin (e.heap_bytes_in A msg m)) ?_
65    have hl3 := hls.pullL (by omega) hiin
66    have hs3 := Sg_pullL hls (by omega) hiin
67    have hb3 := pullL_bits l (e.IN.getD i 0) (.ref (BRef.blk e.ib) (i + 1)) hls.hb
68    have hi2 : i + 1 < e.i0 + e.sm0.avail_in.toNat := by omega
69    have hb3' : (pullL l (e.IN.getD i 0) (.ref (BRef.blk e.ib) (i + 1))).bits.toNat ≤ 22 := by
70      simp only [pullL] at hb3 ⊢; omega
71    refine Wp.bindO (pull_run e _ _ (i + 1) o hl3 hb3' hi2 (e.heap_bytes_in A msg m)) ?_
72    have hl4 := hl3.pullL hb3' hi2
73    have hs4 := Sg_pullL hl3 hb3' hi2
74    have hb4 := pullL_bits (pullL l (e.IN.getD i 0) (.ref (BRef.blk e.ib) (i + 1))) (e.IN.getD (i + 1) 0)
75      (.ref (BRef.blk e.ib) (i + 1 + 1)) hl3.hb
76    simp only [pullL] at hb3 hb4
77    refine Wp.mono (dolenDist_wp hc A msg m _ (i + 1 + 1) o hts hl4 hA ho hAb hbroke hlen (by simp only [pullL]; omega) ?_) ?_
78    · by_cases hc3 : i = s + 3
79      · right; have := hT3 hc3; simp only [pullL]; omega
80      · left; omega
81    · intro l' h' hq
82      obtain ⟨E, cb, hcb, hlk, hend⟩ := hq
83      refine ⟨i + 1 + 1, (pullL (pullL l (e.IN.getD i 0) (.ref (BRef.blk e.ib) (i + 1))) (e.IN.getD (i + 1) 0) (.ref (BRef.blk e.ib) (i + 1 + 1))).hold.toNat,
84        (pullL (pullL l (e.IN.getD i 0) (.ref (BRef.blk e.ib) (i + 1))) (e.IN.getD (i + 1) 0) (.ref (BRef.blk e.ib) (i + 1 + 1))).bits.toNat,
85        E, cb, by omega, by omega, ?_, ?_, ?_, ?_, hcb, hlk, ?_⟩
86      · exact hs4.trans hs3
87      · exact hl4.hH
88      · simp only [pullL]; omega
89      · exact hl4.hb
90      · rw [hs4, hs3] at hend; exact hend
91  · simp only [h1, ite_false]
92    have h1' : 15 ≤ l.bits.toNat := by
93      have : ¬ (l.bits.toNat < 15) := fun h => h1 (UInt32.lt_iff_toNat_lt.mpr (by simpa using h))
94      omega
95    refine Wp.mono (dolenDist_wp hc A msg m l i o hts hls hA ho hAb hbroke hlen h1' (Or.inl (by omega))) ?_
96    intro l' h' hq
97    obtain ⟨E, cb, hcb, hlk, hend⟩ := hq
98    exact ⟨i, l.hold.toNat, l.bits.toNat, E, cb, by omega, by omega, rfl, hls.hH, h1', hls.hb, hcb, hlk, hend⟩
99
100
101/-- The extra bits of a length are read and added to the base, then the refill and the distance block follow. -/
102def dolenExt (c : Ctx) (l : L) : M L := do
103  let m ← shl32 1 l.op
104  let l : L := { l with len := l.len + (l.hold.toUInt32 &&& m - 1) }
105  let __do_lift ← shr64 l.hold l.op.toUInt64
106  let l : L := { l with hold := __do_lift }
107  let l : L := { l with bits := l.bits - l.op }
108  dolenRefill c l
109
110theorem dolenExt_wp (hc : CtxOK e c) (A : Array UInt8) (msg : BPtr) (m : UInt32) (l : L) (i o s : Nat)
111    (hts : DistTableSafe e.DCA e.od e.s0.distbits.toNat)
112    (hls : LS e l i o) (hA : e.o0 + e.sm0.avail_out.toNat ≤ A.size) (ho : o + 258 ≤ e.o0 + e.sm0.avail_out.toNat)
113    (hAb : A.size < 2 ^ 63) (hbroke : l.broke = false) (hx : l.op.toNat ≤ 5) (hxb : l.op.toNat ≤ l.bits.toNat)
114    (hlen : 3 ≤ l.len.toNat ∧ l.len.toNat + 2 ^ l.op.toNat ≤ 259)
115    (hs6 : s + 6 ≤ e.i0 + e.sm0.avail_in.toNat) (hT : i ≤ s + 3)
116    (hT3 : i = s + 3 → 4 + l.op.toNat ≤ l.bits.toNat) :
117    Wp (dolenExt c l) (e.heap A msg m) (fun l' h' =>
118      ∃ lx S1, readBits l.op.toNat (Sg e l.hold.toNat l.bits.toNat i) = some (lx, S1) ∧
119        RefillPost e A msg m S1 i o (l.len.toNat + lx) l' h') := by
120  unfold dolenExt
121  have hxs : l.op.toNat < 32 := by omega
122  refine Wp.bindO (shl32_ok hxs) ?_
123  dsimp only
124  have hlow := hold_low32 (x := l.hold) (k := l.op) hxs
125  have hlowlt : l.hold.toNat % 2 ^ l.op.toNat < 2 ^ l.op.toNat := Nat.mod_lt _ (Nat.pow_pos (by omega))
126  have hpow : 0 < 2 ^ l.op.toNat := Nat.pow_pos (by omega)
127  have hlen' : (l.len + (l.hold.toUInt32 &&& (1 <<< l.op) - 1)).toNat = l.len.toNat + l.hold.toNat % 2 ^ l.op.toNat := by
128    rw [u32_toNat_add (by rw [hlow]; omega), hlow]
129  refine Wp.bindO (shr64_ok (x := l.hold) (n := l.op.toUInt64) (by rw [UInt32.toNat_toUInt64]; omega)) ?_
130  have hls1 : LS e (dropL l l.op) i o := hls.dropL l.op hxb (by omega)
131  have hbn := dropL_bits l l.op hxb
132  have hrb := readBits_bitsOfNat l.op.toNat l.bits.toNat l.hold.toNat (inBits e i) hxb
133  have hsg := Sg_dropL (e := e) l l.op i hxb (by omega)
134  refine Wp.mono (dolenRefill_wp hc A msg m
135    { in_ := l.in_, out := l.out, hold := l.hold >>> l.op.toUInt64, bits := l.bits - l.op, here := l.here, op := l.op,
136      len := l.len + (l.hold.toUInt32 &&& (1 <<< l.op) - 1), dist := l.dist, from_ := l.from_, broke := l.broke,
137      againL := l.againL, againD := l.againD } i o s hts (LS.congr hls1 rfl rfl rfl rfl) hA ho hAb hbroke
138    (by rw [hlen']; omega) hs6 hT (by intro h3; have := hT3 h3; show 4 ≤ (l.bits - l.op).toNat; simp only [dropL] at hbn; omega)) ?_
139  intro l' h' hq
140  refine ⟨l.hold.toNat % 2 ^ l.op.toNat, Sg e (dropL l l.op).hold.toNat (dropL l l.op).bits.toNat i, ?_, ?_⟩
141  · unfold Sg; rw [hrb, dropL_hold l l.op (by omega), dropL_bits l l.op hxb]
142  · simp only [hlen'] at hq
143    exact hq
144
145
146/-- After `op &= 15`: the extra bits of the length (read after at most one more byte), then `dolenExt`. -/
147def dolenLen (c : Ctx) (l : L) : M L :=
148  if l.op != 0 then
149    if l.bits < l.op then do
150      let __x ← pull l
151      dolenExt c __x
152    else dolenExt c l
153  else dolenRefill c l
154
155theorem dolenLen_wp (hc : CtxOK e c) (A : Array UInt8) (msg : BPtr) (m : UInt32) (l : L) (i o s : Nat)
156    (hts : DistTableSafe e.DCA e.od e.s0.distbits.toNat)
157    (hls : LS e l i o) (hA : e.o0 + e.sm0.avail_out.toNat ≤ A.size) (ho : o + 258 ≤ e.o0 + e.sm0.avail_out.toNat)
158    (hAb : A.size < 2 ^ 63) (hbroke : l.broke = false) (hx : l.op.toNat ≤ 5)
159    (hlen : 3 ≤ l.len.toNat ∧ l.len.toNat + 2 ^ l.op.toNat ≤ 259)
160    (hs6 : s + 6 ≤ e.i0 + e.sm0.avail_in.toNat) (hT : i ≤ s + 2) (hb2 : i = s + 2 → 1 ≤ l.bits.toNat) :
161    Wp (dolenLen c l) (e.heap A msg m) (fun l' h' =>
162      ∃ i2 lx S1, i ≤ i2 ∧ i2 ≤ i + 1 ∧ readBits l.op.toNat (Sg e l.hold.toNat l.bits.toNat i) = some (lx, S1) ∧
163        RefillPost e A msg m S1 i2 o (l.len.toNat + lx) l' h') := by
164  unfold dolenLen
165  by_cases h0 : l.op != 0
166  · simp only [h0, ite_true]
167    have h0' : l.op.toNat ≠ 0 := by
168      intro h; apply (by simpa using h0 : l.op ≠ 0); exact UInt32.toNat_inj.mp (by simpa using h)
169    by_cases h1 : l.bits < l.op
170    · simp only [h1, ite_true]
171      have h1' : l.bits.toNat < l.op.toNat := UInt32.lt_iff_toNat_lt.mp h1
172      have hiin : i < e.i0 + e.sm0.avail_in.toNat := by omega
173      refine Wp.bindO (pull_run e _ l i o hls (by omega) hiin (e.heap_bytes_in A msg m)) ?_
174      have hl3 := hls.pullL (by omega) hiin
175      have hs3 := Sg_pullL hls (by omega) hiin
176      have hb3 := pullL_bits l (e.IN.getD i 0) (.ref (BRef.blk e.ib) (i + 1)) hls.hb
177      refine Wp.mono (dolenExt_wp hc A msg m _ (i + 1) o s hts hl3 hA ho hAb hbroke (by simp only [pullL]; omega)
178        (by simp only [pullL] at hb3 ⊢; omega) (by simp only [pullL]; omega) hs6 (by omega)
179        (by intro h3; simp only [pullL] at hb3 ⊢; have := hb2 (by omega); omega)) ?_
180      intro l' h' hq
181      obtain ⟨lx, S1, hr, hrp⟩ := hq
182      refine ⟨i + 1, lx, S1, by omega, by omega, ?_, ?_⟩
183      · simp only [pullL] at hr hs3 ⊢; rw [hs3] at hr; exact hr
184      · simp only [pullL] at hrp ⊢; exact hrp
185    · simp only [h1, ite_false]
186      have h1' : l.op.toNat ≤ l.bits.toNat := by
187        have : ¬ (l.bits.toNat < l.op.toNat) := fun h => h1 (UInt32.lt_iff_toNat_lt.mpr h)
188        omega
189      refine Wp.mono (dolenExt_wp hc A msg m l i o s hts hls hA ho hAb hbroke hx h1' hlen hs6 (by omega)
190        (by intro h3; omega)) ?_
191      intro l' h' hq
192      obtain ⟨lx, S1, hr, hrp⟩ := hq
193      exact ⟨i, lx, S1, by omega, by omega, hr, hrp⟩
194  · simp only [h0, ite_false]
195    have h0' : l.op.toNat = 0 := by
196      have : l.op = 0 := by simpa using h0
197      rw [this]; rfl
198    refine Wp.mono (dolenRefill_wp hc A msg m l i o s hts hls hA ho hAb hbroke ⟨hlen.1, by
199      have : 0 < 2 ^ l.op.toNat := Nat.pow_pos (by omega)
200      omega⟩ hs6 (by omega) (by intro h3; omega)) ?_
201    intro l' h' hq
202    refine ⟨i, 0, Sg e l.hold.toNat l.bits.toNat i, by omega, by omega, ?_, ?_⟩
203    · rw [h0']; rfl
204    · simpa using hq
205
206end Zlib.Inffast.Proofs
ZLIB × LEAN

全局目录

当前位置inffast.c.len.lean