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

crc32.c.lean

此页源文件快照 · 3bb6a8fc2eda401c · 对应提交的原文 ↗

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

1import ZlibF.Runtime.Alloc
2import ZlibF.Runtime.Address
3import ZlibF.Zlib.«crc32.h»
4
5/-!
6# crc32.c — faithful translation
7
8Source: `crc32.c` and `crc32.h`, default x86_64 Linux build. Preprocessor decisions: `DYNAMIC_CRC_TABLE`, `MAKECRCH`,
9`Z_TESTN`, `Z_TESTW`, `ARMCRC32` (`__aarch64__` only) and `HAVE_S390X_VX` are undefined, so the static tables of
10`crc32.h` are used and `make_crc_table`, `braid`, `write_table*` and `z_once` are dead. `N = 5`, `W = 8`
11(`__x86_64__`), `z_word_t` is `unsigned long`, `z_crc_t` is `unsigned`. The `#if N > 5` parts are dead.
12
13Decisions on the model:
14
15* **Tables.** `crc_table` and `x2n_table` are the `Statics` fields of the same name (read through `UPtr`;
16  `initStatics` sets them from `crc32.h.lean`). `crc_big_table`, `crc_braid_table`, `crc_braid_big_table` are only
17  indexed, so they are Lean constants, indexed with a bounds check.
18* **Alignment.** `((z_size_t)buf & (W - 1))` observes the low three address bits. Raw byte blocks retain the
19  aligned-origin convention, so their offsets supply these bits. Static and embedded byte arrays use arbitrary
20  stable origin residues from the heap. Proofs must hold for every residue, including nonzero field alignment.
21  This abstraction is only for the low-bit test; it does not supply a general ABI address or aliasing model.
22* **Words.** `words[i]` reads the byte buffer as `unsigned long`; the translation reads the 8 bytes in order and
23  assembles them little endian (`loadWord`). The formal strict-aliasing issue of this cast is not modelled; it is
24  inside the object either way.
25* **Endianness.** `*(unsigned char *)&endian` with `endian = 1` is the low byte of `endian` on the little-endian
26  target, so the big-endian branch is dead at run time; it is translated for completeness and is not reached
27  (the differential test cannot cover it).
28* `multmodp` loops forever when `a` has no bit set among bits 0..31 (`a != 0` is not enough); the C then never
29  ends, and here the loop runs out of fuel. `crc32_combine_op(crc1, crc2, op)` reaches it for `op` with zero low
30  32 bits.
31-/
32
33namespace Zlib.Crc32
34open C
35
36/-- `Z_BATCH` etc. are `ARMCRC32` only. `N` and `W`: -/
37def N : Int32 := 5
38def W : Int32 := 8
39
40/-- `#define POLY 0xedb88320` (an `unsigned int` constant). -/
41def POLY : UInt64 := 0xedb88320
42
43/-- The `Statics` with the contents that `crc32.c` fixes: `crc_table` and `x2n_table` (from `crc32.h`). -/
44def initStatics (s : Statics) : Statics :=
45  { s with crc_table := Zlib.Crc32H.crc_table, x2n_table := Zlib.Crc32H.x2n_table }
46
47/-- `x >> n` for `unsigned long`: undefined if `n >= 64`. -/
48def shr64 (x n : UInt64) : M UInt64 :=
49  if n < 64 then pure (x >>> n) else ub "shift count out of range"
50
51/-- `crc_table[i]` -/
52def crcTab (i : UInt64) : M UInt32 := Ptr.index (Ptr.ref URef.st_crc_table 0) i.toNat
53
54/-- `x2n_table[i]` -/
55def x2nTab (i : UInt32) : M UInt32 := Ptr.index (Ptr.ref URef.st_x2n_table 0) i.toNat
56
57/-- `t[k][i]` for a constant two-dimensional table. -/
58def idx2 {α : Type} (t : Array (Array α)) (k i : Nat) : M α :=
59  match t[k]? with
60  | some r => match r[i]? with
61    | some v => pure v
62    | none => ub "table index outside its array"
63  | none => ub "table index outside its array"
64
65/-- `t[i]` for a constant table. -/
66def idx1 {α : Type} (t : Array α) (i : Nat) : M α :=
67  match t[i]? with
68  | some v => pure v
69  | none => ub "table index outside its array"
70
71/-- `(z_size_t)buf`, represented up to the low bits observed by the CRC alignment test. -/
72def addrOf (p : BPtr) : M UInt64 :=
73  C.ByteAddress.address p
74
75/-- `words[i]` for `z_word_t const *words` over the byte buffer at `p` (little-endian target). -/
76def loadWord (p : BPtr) : M UInt64 := do
77  let mut w : UInt64 := 0
78  for i in [0:8] do
79    let b ← index8 p i
80    w := w ||| (b.toUInt64 <<< (8 * i).toUInt64)
81  pure w
82
83/-! ### Byte swaps and the word CRCs -/
84
85/-- `local z_word_t byte_swap(z_word_t word)` (`W == 8`) -/
86def byte_swap (word : UInt64) : UInt64 :=
87  (word &&& 0xff00000000000000) >>> 56 |||
88  (word &&& 0xff000000000000) >>> 40 |||
89  (word &&& 0xff0000000000) >>> 24 |||
90  (word &&& 0xff00000000) >>> 8 |||
91  (word &&& 0xff000000) <<< 8 |||
92  (word &&& 0xff0000) <<< 24 |||
93  (word &&& 0xff00) <<< 40 |||
94  (word &&& 0xff) <<< 56
95
96/-- `local z_crc_t crc_word(z_word_t data)` -/
97def crc_word (data : UInt64) : M UInt32 := do
98  -- for (k = 0; k < W; k++) data = (data >> 8) ^ crc_table[data & 0xff];
99  let (data, _) ← cwhile (fun (data, k) => pure (k < W, (data, k)))
100    (fun (data, k) => do
101      let t ← crcTab (data &&& 0xff)
102      pure ((data >>> 8) ^^^ t.toUInt64, k + 1)) (data, (0 : Int32))
103  -- return (z_crc_t)data;
104  pure data.toUInt32
105
106/-- `local z_word_t crc_word_big(z_word_t data)` -/
107def crc_word_big (data : UInt64) : M UInt64 := do
108  -- for (k = 0; k < W; k++) data = (data << 8) ^ crc_big_table[(data >> ((W - 1) << 3)) & 0xff];
109  let (data, _) ← cwhile (fun (data, k) => pure (k < W, (data, k)))
110    (fun (data, k) => do
111      let t ← idx1 Zlib.Crc32H.crc_big_table (((data >>> 56) &&& 0xff).toNat)
112      pure ((data <<< 8) ^^^ t, k + 1)) (data, (0 : Int32))
113  pure data
114
115/-! ### Polynomial arithmetic -/
116
117/-- `local uLong multmodp(uLong a, uLong b)` -/
118def multmodp (a b : UInt64) : M UInt64 := do
119  -- m = (uLong)1 << 31; p = 0;
120  -- for (;;) { if (a & m) { p ^= b; if ((a & (m - 1)) == 0) break; }
121  --            m >>= 1; b = b & 1 ? (b >> 1) ^ POLY : b >> 1; }
122  let (_, p, _, _) ← cwhile (fun (m, p, b, brk) => pure (!brk, (m, p, b, brk)))
123    (fun (m, p, b, brk) => do
124      let mut p := p
125      if a &&& m != 0 then
126        p := p ^^^ b
127        if a &&& (m - 1) == 0 then return (m, p, b, true)
128      let m := m >>> 1
129      let b := if b &&& 1 != 0 then (b >>> 1) ^^^ POLY else b >>> 1
130      pure (m, p, b, brk)) (((1 : UInt64) <<< 31, (0 : UInt64), b, false) : UInt64 × UInt64 × UInt64 × Bool)
131  pure p
132
133/-- `local uLong x2nmodp(z_off64_t n, unsigned k)` -/
134def x2nmodp (n : Int64) (k : UInt32) : M UInt64 := do
135  -- p = (uLong)1 << 31;             /* x^0 == 1 */
136  -- while (n) { if (n & 1) p = multmodp(x2n_table[k & 31], p); n >>= 1; k++; }
137  let (p, _, _) ← cwhile (fun (p, n, k) => pure (n != 0, (p, n, k)))
138    (fun (p, n, k) => do
139      let mut p := p
140      if n &&& 1 != 0 then
141        let t ← x2nTab (k &&& 31)
142        p ← multmodp t.toUInt64 p
143      pure (p, n >>> 1, k + 1)) (((1 : UInt64) <<< 31, n, k) : UInt64 × Int64 × UInt32)
144  pure p
145
146/-- `const z_crc_t FAR * ZEXPORT get_crc_table(void)` -/
147def get_crc_table : M UPtr :=
148  -- return (const z_crc_t FAR *)crc_table;
149  pure (Ptr.ref URef.st_crc_table 0)
150
151/-! ### `crc32_z` -/
152
153/-- The little-endian braids: `crc0 .. crc4` (`z_crc_t`), `words`, `blks`. -/
154structure BL where
155  crc0 : UInt32
156  crc1 : UInt32
157  crc2 : UInt32
158  crc3 : UInt32
159  crc4 : UInt32
160  words : BPtr
161  blks : UInt64
162
163/-- The big-endian braids: `crc0 .. crc4` (`z_word_t`). -/
164structure BB where
165  crc0 : UInt64
166  crc1 : UInt64
167  crc2 : UInt64
168  crc3 : UInt64
169  crc4 : UInt64
170  words : BPtr
171  blks : UInt64
172
173/-- `words[i]` for `i < N`. -/
174def wordAt (words : BPtr) (i : Nat) : M UInt64 := do
175  loadWord (← words.add (8 * i))
176
177/-- `crcK ^= crc_braid_table[k][(wordK >> (k << 3)) & 0xff];` -/
178def braidTab (k : Int32) (word : UInt64) : M UInt32 := do
179  let sh ← shr64 word (k <<< 3).toInt.toNat.toUInt64
180  idx2 Zlib.Crc32H.crc_braid_table k.toInt.toNat (sh &&& 0xff).toNat
181
182/-- `crcK ^= crc_braid_big_table[k][(wordK >> (k << 3)) & 0xff];` -/
183def braidBigTab (k : Int32) (word : UInt64) : M UInt64 := do
184  let sh ← shr64 word (k <<< 3).toInt.toNat.toUInt64
185  idx2 Zlib.Crc32H.crc_braid_big_table k.toInt.toNat (sh &&& 0xff).toNat
186
187/-- The body of `while (--blks)` in the little-endian branch. -/
188def blockLittle (s : BL) : M BL := do
189  -- word0 = crc0 ^ words[0]; ... word4 = crc4 ^ words[4];
190  let word0 := s.crc0.toUInt64 ^^^ (← wordAt s.words 0)
191  let word1 := s.crc1.toUInt64 ^^^ (← wordAt s.words 1)
192  let word2 := s.crc2.toUInt64 ^^^ (← wordAt s.words 2)
193  let word3 := s.crc3.toUInt64 ^^^ (← wordAt s.words 3)
194  let word4 := s.crc4.toUInt64 ^^^ (← wordAt s.words 4)
195  -- words += N;
196  let words ← s.words.add 40
197  -- crc0 = crc_braid_table[0][word0 & 0xff]; ... crc4 = ...
198  let crc0 ← braidTab 0 word0
199  let crc1 ← braidTab 0 word1
200  let crc2 ← braidTab 0 word2
201  let crc3 ← braidTab 0 word3
202  let crc4 ← braidTab 0 word4
203  -- for (k = 1; k < W; k++) { crc0 ^= ...; crc1 ^= ...; ... crc4 ^= ...; }
204  let (crc0, crc1, crc2, crc3, crc4, _) ← cwhile (fun (c0, c1, c2, c3, c4, k) => pure (k < W, (c0, c1, c2, c3, c4, k)))
205    (fun (c0, c1, c2, c3, c4, k) => do
206      let c0 := c0 ^^^ (← braidTab k word0)
207      let c1 := c1 ^^^ (← braidTab k word1)
208      let c2 := c2 ^^^ (← braidTab k word2)
209      let c3 := c3 ^^^ (← braidTab k word3)
210      let c4 := c4 ^^^ (← braidTab k word4)
211      pure (c0, c1, c2, c3, c4, k + 1)) (crc0, crc1, crc2, crc3, crc4, (1 : Int32))
212  pure { s with crc0, crc1, crc2, crc3, crc4, words }
213
214/-- The body of `while (--blks)` in the big-endian branch. -/
215def blockBig (s : BB) : M BB := do
216  let word0 := s.crc0 ^^^ (← wordAt s.words 0)
217  let word1 := s.crc1 ^^^ (← wordAt s.words 1)
218  let word2 := s.crc2 ^^^ (← wordAt s.words 2)
219  let word3 := s.crc3 ^^^ (← wordAt s.words 3)
220  let word4 := s.crc4 ^^^ (← wordAt s.words 4)
221  let words ← s.words.add 40
222  let crc0 ← (do let sh ← shr64 word0 0; idx2 Zlib.Crc32H.crc_braid_big_table 0 (sh &&& 0xff).toNat)
223  let crc1 ← (do let sh ← shr64 word1 0; idx2 Zlib.Crc32H.crc_braid_big_table 0 (sh &&& 0xff).toNat)
224  let crc2 ← (do let sh ← shr64 word2 0; idx2 Zlib.Crc32H.crc_braid_big_table 0 (sh &&& 0xff).toNat)
225  let crc3 ← (do let sh ← shr64 word3 0; idx2 Zlib.Crc32H.crc_braid_big_table 0 (sh &&& 0xff).toNat)
226  let crc4 ← (do let sh ← shr64 word4 0; idx2 Zlib.Crc32H.crc_braid_big_table 0 (sh &&& 0xff).toNat)
227  let (crc0, crc1, crc2, crc3, crc4, _) ← cwhile (fun (c0, c1, c2, c3, c4, k) => pure (k < W, (c0, c1, c2, c3, c4, k)))
228    (fun (c0, c1, c2, c3, c4, k) => do
229      let c0 := c0 ^^^ (← braidBigTab k word0)
230      let c1 := c1 ^^^ (← braidBigTab k word1)
231      let c2 := c2 ^^^ (← braidBigTab k word2)
232      let c3 := c3 ^^^ (← braidBigTab k word3)
233      let c4 := c4 ^^^ (← braidBigTab k word4)
234      pure (c0, c1, c2, c3, c4, k + 1)) (crc0, crc1, crc2, crc3, crc4, (1 : Int32))
235  pure { s with crc0, crc1, crc2, crc3, crc4, words }
236
237/-- `crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff];` -/
238def crcByte (crc : UInt64) (buf : BPtr) : M (UInt64 × BPtr) := do
239  let b ← load8 buf
240  let buf ← buf.add 1
241  let t ← crcTab ((crc ^^^ b.toUInt64) &&& 0xff)
242  pure ((crc >>> 8) ^^^ t.toUInt64, buf)
243
244/-- `uLong ZEXPORT crc32_z(uLong crc, const unsigned char FAR *buf, z_size_t len)` -/
245def crc32_z (crc : UInt64) (buf : BPtr) (len : UInt64) : M UInt64 := do
246  -- if (buf == Z_NULL) return 0;
247  if buf == .null then return 0
248  -- crc = (~crc) & 0xffffffff;
249  let mut crc := (~~~crc) &&& 0xffffffff
250  let mut buf := buf
251  let mut len := len
252  -- if (len >= N * W + W - 1) {
253  if len ≥ (N * W + W - 1).toInt.toNat.toUInt64 then
254    -- while (len && ((z_size_t)buf & (W - 1)) != 0) { len--; crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; }
255    let (c, b, l) ← cwhile
256      (fun (c, b, l) => do
257        if l == 0 then pure (false, (c, b, l))
258        else pure ((← addrOf b) &&& (W - 1).toInt.toNat.toUInt64 != 0, (c, b, l)))
259      (fun (c, b, l) => do
260        let l := l - 1
261        let (c, b) ← crcByte c b
262        pure (c, b, l)) (crc, buf, len)
263    crc := c; buf := b; len := l
264    -- blks = len / (N * W); len -= blks * N * W; words = (z_word_t const *)buf;
265    let nw : UInt64 := (N * W).toInt.toNat.toUInt64
266    let blks := len / nw
267    len := len - blks * nw
268    let words := buf
269    -- endian = 1;
270    let endian : UInt32 := 1
271    -- if (*(unsigned char *)&endian) {   /* Little endian. */
272    if endian.toUInt8 != 0 then
273      -- crc0 = (z_crc_t)crc; crc1 = 0; ... crc4 = 0;
274      let s : BL := { crc0 := crc.toUInt32, crc1 := 0, crc2 := 0, crc3 := 0, crc4 := 0, words, blks }
275      -- while (--blks) { ... }
276      let s ← cwhile (fun s => let blks := s.blks - 1; pure (blks != 0, { s with blks })) blockLittle s
277      -- crc = crc_word(crc0 ^ words[0]);
278      crc := (← crc_word (s.crc0.toUInt64 ^^^ (← wordAt s.words 0))).toUInt64
279      -- crc = crc_word(crc1 ^ words[1] ^ crc); ... crc4
280      crc := (← crc_word (s.crc1.toUInt64 ^^^ (← wordAt s.words 1) ^^^ crc)).toUInt64
281      crc := (← crc_word (s.crc2.toUInt64 ^^^ (← wordAt s.words 2) ^^^ crc)).toUInt64
282      crc := (← crc_word (s.crc3.toUInt64 ^^^ (← wordAt s.words 3) ^^^ crc)).toUInt64
283      crc := (← crc_word (s.crc4.toUInt64 ^^^ (← wordAt s.words 4) ^^^ crc)).toUInt64
284      -- words += N;
285      buf := ← s.words.add 40
286    else
287      -- /* Big endian. */ crc0 = byte_swap(crc); crc1 = 0; ... crc4 = 0;
288      let s : BB := { crc0 := byte_swap crc, crc1 := 0, crc2 := 0, crc3 := 0, crc4 := 0, words, blks }
289      let s ← cwhile (fun s => let blks := s.blks - 1; pure (blks != 0, { s with blks })) blockBig s
290      -- comb = crc_word_big(crc0 ^ words[0]); comb = crc_word_big(crc1 ^ words[1] ^ comb); ...
291      let comb ← crc_word_big (s.crc0 ^^^ (← wordAt s.words 0))
292      let comb ← crc_word_big (s.crc1 ^^^ (← wordAt s.words 1) ^^^ comb)
293      let comb ← crc_word_big (s.crc2 ^^^ (← wordAt s.words 2) ^^^ comb)
294      let comb ← crc_word_big (s.crc3 ^^^ (← wordAt s.words 3) ^^^ comb)
295      let comb ← crc_word_big (s.crc4 ^^^ (← wordAt s.words 4) ^^^ comb)
296      -- words += N; crc = byte_swap(comb);
297      let words ← s.words.add 40
298      crc := byte_swap comb
299      -- buf = (unsigned char const *)words;
300      buf := words
301    -- (little endian: buf = (unsigned char const *)words;  done above)
302  -- while (len >= 8) { len -= 8; eight times: crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; }
303  let (c, b, l) ← cwhile (fun (c, b, l) => pure (l ≥ 8, (c, b, l)))
304    (fun (c, b, l) => do
305      let l := l - 8
306      let (c, b) ← crcByte c b
307      let (c, b) ← crcByte c b
308      let (c, b) ← crcByte c b
309      let (c, b) ← crcByte c b
310      let (c, b) ← crcByte c b
311      let (c, b) ← crcByte c b
312      let (c, b) ← crcByte c b
313      let (c, b) ← crcByte c b
314      pure (c, b, l)) (crc, buf, len)
315  crc := c; buf := b; len := l
316  -- while (len) { len--; crc = (crc >> 8) ^ crc_table[(crc ^ *buf++) & 0xff]; }
317  let (c, _, _) ← cwhile (fun (c, b, l) => pure (l != 0, (c, b, l)))
318    (fun (c, b, l) => do
319      let l := l - 1
320      let (c, b) ← crcByte c b
321      pure (c, b, l)) (crc, buf, len)
322  -- return crc ^ 0xffffffff;
323  pure (c ^^^ 0xffffffff)
324
325/-- `uLong ZEXPORT crc32(uLong crc, const unsigned char FAR *buf, uInt len)` -/
326def crc32 (crc : UInt64) (buf : BPtr) (len : UInt32) : M UInt64 :=
327  -- return crc32_z(crc, buf, len);
328  crc32_z crc buf len.toUInt64
329
330/-- `uLong ZEXPORT crc32_combine_gen64(z_off64_t len2)` -/
331def crc32_combine_gen64 (len2 : Int64) : M UInt64 := do
332  -- if (len2 < 0) return 0;
333  if len2 < 0 then return 0
334  -- return x2nmodp(len2, 3);
335  x2nmodp len2 3
336
337/-- `uLong ZEXPORT crc32_combine_gen(z_off_t len2)` -/
338def crc32_combine_gen (len2 : Int64) : M UInt64 :=
339  -- return crc32_combine_gen64((z_off64_t)len2);
340  crc32_combine_gen64 len2
341
342/-- `uLong ZEXPORT crc32_combine_op(uLong crc1, uLong crc2, uLong op)` -/
343def crc32_combine_op (crc1 crc2 op : UInt64) : M UInt64 := do
344  -- if (op == 0) return 0;
345  if op == 0 then return 0
346  -- return multmodp(op, crc1 & 0xffffffff) ^ (crc2 & 0xffffffff);
347  let m ← multmodp op (crc1 &&& 0xffffffff)
348  pure (m ^^^ (crc2 &&& 0xffffffff))
349
350/-- `uLong ZEXPORT crc32_combine64(uLong crc1, uLong crc2, z_off64_t len2)` -/
351def crc32_combine64 (crc1 crc2 : UInt64) (len2 : Int64) : M UInt64 := do
352  -- return crc32_combine_op(crc1, crc2, crc32_combine_gen64(len2));
353  crc32_combine_op crc1 crc2 (← crc32_combine_gen64 len2)
354
355/-- `uLong ZEXPORT crc32_combine(uLong crc1, uLong crc2, z_off_t len2)` -/
356def crc32_combine (crc1 crc2 : UInt64) (len2 : Int64) : M UInt64 :=
357  -- return crc32_combine64(crc1, crc2, (z_off64_t)len2);
358  crc32_combine64 crc1 crc2 len2
359
360end Zlib.Crc32
ZLIB × LEAN

全局目录

当前位置crc32.c.lean