Skip to content
REFERENCE / ZLIB × LEAN

public-adler-combine.lean

Source snapshot · f57a18c8d03b3ea8 · 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.«adler32.c»
2import ZlibF.Spec.Public.Checksums
3
4/-! Bridging the bytewise format checksum to the component-sum proof. -/
5
6namespace Zlib.Adler32.Proofs
7open C Zlib.Adler32 Zlib.Adler32.Spec
8
9private theorem adler_step_components (lo hi : Nat) (b : UInt8)
10    (hl : lo < 65521) (hh : hi < 65521) :
11    ZlibF.Spec.adlerStep (UInt32.ofNat (lo + 65536 * hi)) b =
12      UInt32.ofNat ((step (lo, hi) b).1 + 65536 * (step (lo, hi) b).2) := by
13  have hpack : (UInt32.ofNat (lo + 65536 * hi)).toNat = lo + 65536 * hi := by
14    rw [UInt32.toNat_ofNat', Nat.mod_eq_of_lt (by omega)]
15  have hlow : (lo + 65536 * hi) % 65536 = lo := by omega
16  have hhigh : (lo + 65536 * hi) / 65536 = hi := by omega
17  unfold ZlibF.Spec.adlerStep
18  rw [hpack, hlow, hhigh]
19  simp only [step, Zlib.Adler32.Spec.BASE]
20  congr 1
21  omega
22
23/-- The format Adler recurrence agrees with the component-sum model on canonical states. -/
24theorem adler_fold_components (bs : List UInt8) (lo hi : Nat)
25    (hl : lo < 65521) (hh : hi < 65521) :
26    ZlibF.Spec.adler32Update (UInt32.ofNat (lo + 65536 * hi)) bs =
27      UInt32.ofNat ((sums lo hi bs).1 + 65536 * (sums lo hi bs).2) := by
28  induction bs generalizing lo hi with
29  | nil => rfl
30  | cons b rest ih =>
31    have hs := step_lt (lo, hi) b
32    simp only [ZlibF.Spec.adler32Update, List.foldl_cons, sums, step] at *
33    rw [adler_step_components lo hi b hl hh]
34    exact ih _ _ hs.1 hs.2
35
36/-- The two independent definitions of Adler-32 agree on every byte sequence. -/
37theorem adler32_format_eq (bs : List UInt8) :
38    ZlibF.Spec.adler32 bs = UInt32.ofNat (Zlib.Adler32.Spec.adler32 1 bs) := by
39  have h := adler_fold_components bs 1 0 (by decide) (by decide)
40  simpa [ZlibF.Spec.adler32, Zlib.Adler32.Spec.adler32, Zlib.Adler32.Spec.BASE] using h
41
42private theorem format_halves (a : UInt64) (bs : List UInt8)
43    (ha : a.toUInt32 = ZlibF.Spec.adler32 bs) :
44    (a &&& 65535).toNat = (sums 1 0 bs).1 ∧
45    (a >>> 16 &&& 65535).toNat = (sums 1 0 bs).2 := by
46  have hb := sums_lt 1 0 bs (by decide) (by decide)
47  change (sums 1 0 bs).1 < 65521 ∧ (sums 1 0 bs).2 < 65521 at hb
48  have heq := congrArg UInt32.toNat ha
49  rw [adler32_format_eq] at heq
50  have hp : Zlib.Adler32.Spec.adler32 1 bs =
51      (sums 1 0 bs).1 + 65536 * (sums 1 0 bs).2 := by
52    simp [Zlib.Adler32.Spec.adler32, Zlib.Adler32.Spec.BASE]
53  rw [hp, UInt32.toNat_ofNat', Nat.mod_eq_of_lt (by omega), UInt64.toNat_toUInt32] at heq
54  rw [low16, high16]
55  omega
56
57/-- Both Adler combine entries terminate for all values, reject negative lengths,
58and combine genuine format checksums, even if the arguments carry upper bits. -/
59theorem adler32_combine_public (h : Heap) (a1 a2 : UInt64) (len : Int64) :
60    ∃ result, C.run (adler32_combine a1 a2 len) h = .ok (result, h) ∧
61      (len.toInt < 0 → result = 0xffffffff) ∧
62      (∀ xs ys : List UInt8,
63        a1.toUInt32 = ZlibF.Spec.adler32 xs → a2.toUInt32 = ZlibF.Spec.adler32 ys →
64        len.toInt = (ys.length : Int) → result = (ZlibF.Spec.adler32 (xs ++ ys)).toUInt64) := by
65  obtain ⟨result, hr⟩ := adler32_combine_c_safe (h := h) a1 a2 len
66  change C.run (adler32_combine a1 a2 len) h = .ok (result, h) at hr
67  refine ⟨result, hr, ?_, ?_⟩
68  · intro hn
69    have hneg : len < 0 := Int64.lt_iff_toInt_lt.mpr (by simpa using hn)
70    have hresult : C.run (adler32_combine a1 a2 len) h = .ok (0xffffffff, h) := by
71      simp [C.run, adler32_combine, adler32_combine_, hneg]
72    rw [hresult] at hr
73    cases hr
74    rfl
75  · intro xs ys hxs hys hlen
76    have hx := format_halves a1 xs hxs
77    have hy := format_halves a2 ys hys
78    have bx := sums_lt 1 0 xs (by decide) (by decide)
79    have bys := sums_lt 1 0 ys (by decide) (by decide)
80    change (sums 1 0 xs).1 < 65521 ∧ (sums 1 0 xs).2 < 65521 at bx
81    change (sums 1 0 ys).1 < 65521 ∧ (sums 1 0 ys).2 < 65521 at bys
82    have hpos : 0 ≤ len := Int64.le_iff_toInt_le.mpr (by simp [hlen])
83    obtain ⟨out, hrun, hout⟩ := combine_value (h := h) a1 a2 len hpos
84      (by simpa [hx.1] using bx.1) (by simpa [hx.2] using bx.2)
85      (by simpa [hy.1] using bys.1) (by simpa [hy.2] using bys.2)
86    have heq : out = result := by
87      change C.run (adler32_combine a1 a2 len) h = .ok (out, h) at hrun
88      rw [hr] at hrun
89      cases hrun
90      rfl
91    subst out
92    apply UInt64.toNat_inj.mp
93    rw [hout, hx.1, hx.2, hy.1, hy.2, hlen, Int.toNat_natCast, adler32_format_eq,
94      UInt32.toNat_toUInt64, UInt32.toNat_ofNat']
95    have hab := sums_lt 1 0 (xs ++ ys) (by decide) (by decide)
96    change (sums 1 0 (xs ++ ys)).1 < 65521 ∧ (sums 1 0 (xs ++ ys)).2 < 65521 at hab
97    have e3 : Zlib.Adler32.Spec.adler32 1 (xs ++ ys) =
98        (sums 1 0 (xs ++ ys)).1 + 65536 * (sums 1 0 (xs ++ ys)).2 := rfl
99    have hb32 : (sums 1 0 (xs ++ ys)).1 + 65536 * (sums 1 0 (xs ++ ys)).2 < 2 ^ 32 := by omega
100    rw [e3, Nat.mod_eq_of_lt hb32, sums_combine]
101    rfl
102
103
104/-- The 64-bit length entry has the same LP64 contract. -/
105theorem adler32_combine64_public (h : Heap) (a1 a2 : UInt64) (len : Int64) :
106    ∃ result, C.run (adler32_combine64 a1 a2 len) h = .ok (result, h) ∧
107      (len.toInt < 0 → result = 0xffffffff) ∧
108      (∀ xs ys : List UInt8,
109        a1.toUInt32 = ZlibF.Spec.adler32 xs → a2.toUInt32 = ZlibF.Spec.adler32 ys →
110        len.toInt = (ys.length : Int) → result = (ZlibF.Spec.adler32 (xs ++ ys)).toUInt64) :=
111  adler32_combine_public h a1 a2 len
112
113end Zlib.Adler32.Proofs
114
115namespace ZlibF.Spec.Public.AdlerCombineProof
116
117/-- `uLong adler32_combine(uLong adler1, uLong adler2, z_off_t len2)` combines checksums. -/
118theorem combine_public : Goal.adler32_combine := Zlib.Adler32.Proofs.adler32_combine_public
119
120/-- `uLong adler32_combine64(uLong adler1, uLong adler2, z_off64_t len2)` combines checksums. -/
121theorem combine64_public : Goal.adler32_combine64 := Zlib.Adler32.Proofs.adler32_combine64_public
122
123#print axioms combine_public
124#print axioms combine64_public
125end ZlibF.Spec.Public.AdlerCombineProof
ZLIB × LEAN

Global contents

READING NOWpublic-adler-combine.lean