CRC checksums (CRC-16, CRC-32, CRC-32C) for OCaml
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Thread ~sw through monopam to fix Switch finished! bug

Pass Eio switch from top-level Eio_main.run down to all
Git.Repository.open_repo calls instead of creating tiny
per-call Switch.run scopes that close prematurely.

+187
+1
test/interop/crcmod/.gitignore
··· 1 + scripts/.venv/
+19
test/interop/crcmod/dune
··· 1 + (test 2 + (name test) 3 + (libraries crc alcotest) 4 + (deps 5 + (source_tree traces) 6 + (source_tree scripts))) 7 + 8 + ; Regenerate traces: REGEN_TRACES=1 dune build @regen-traces 9 + 10 + (rule 11 + (alias regen-traces) 12 + (enabled_if 13 + (= %{env:REGEN_TRACES=0} 1)) 14 + (deps 15 + (source_tree scripts)) 16 + (action 17 + (chdir 18 + scripts 19 + (run ./generate.py))))
+73
test/interop/crcmod/scripts/generate.py
··· 1 + #!/usr/bin/env python3 2 + """Generate CRC interop traces for ocaml-crc. 3 + 4 + Oracle: crcmod 1.7 5 + Install: python3 -m venv .venv && .venv/bin/pip install crcmod 6 + 7 + Traces are committed to git. Only re-run when changing inputs 8 + or upgrading the oracle. 9 + """ 10 + import os, sys 11 + 12 + # Auto-create venv if needed 13 + VENV = os.path.join(os.path.dirname(__file__), ".venv") 14 + if not os.path.exists(VENV): 15 + import subprocess 16 + subprocess.check_call([sys.executable, "-m", "venv", VENV]) 17 + subprocess.check_call([f"{VENV}/bin/pip", "install", "crcmod"]) 18 + 19 + # Use venv's Python 20 + VENV_PYTHON = f"{VENV}/bin/python3" 21 + if sys.executable != VENV_PYTHON and os.path.exists(VENV_PYTHON): 22 + os.execv(VENV_PYTHON, [VENV_PYTHON] + sys.argv) 23 + 24 + import crcmod 25 + import crcmod.predefined 26 + 27 + TRACE_DIR = os.path.join(os.path.dirname(__file__), "..", "traces") 28 + 29 + # CRC functions matching the OCaml implementations: 30 + # CRC-16-CCITT: poly=0x11021, init=0xFFFF, no reflection, no XOR out 31 + crc16_ccitt_fn = crcmod.mkCrcFun(0x11021, initCrc=0xFFFF, rev=False, xorOut=0x0000) 32 + 33 + # CRC-16-X.25: poly=0x11021, init=0xFFFF, reflected in/out, XOR out=0xFFFF 34 + crc16_x25_fn = crcmod.mkCrcFun(0x11021, initCrc=0xFFFF, rev=True, xorOut=0xFFFF) 35 + 36 + # CRC-32 (ISO 3309): poly=0x104C11DB7, init=0xFFFFFFFF, reflected, XOR out=0xFFFFFFFF 37 + crc32_fn = crcmod.predefined.mkCrcFun("crc-32") 38 + 39 + # CRC-32C (Castagnoli): poly=0x11EDC6F41, init=0xFFFFFFFF, reflected, XOR out=0xFFFFFFFF 40 + crc32c_fn = crcmod.predefined.mkCrcFun("crc-32c") 41 + 42 + # Deterministic 256 random bytes (seed=42) 43 + RANDOM_256_HEX = ( 44 + "b8a89ba8ffdaa2d2e292efad871b1a0581573348000a8b4cb6ffc6538f63fc9d" 45 + "9a7f50c9839971068e93f2d76ddf28943acbd6777069f5efefb7b86fe4d9d332" 46 + "2d89c481f3f168e9f31b4c29ca1ccfe9198c41383114688c7afe056559f72c61" 47 + "3d1d78d75e51e73de228f5b4a5ab7e0757c886e6f71bd91185d70fbd8d907bf0" 48 + "7bf4e71ad2cf6e59a213fcee7200397a0b5669df9793cf25a38ac4c0aa157af1" 49 + "9d2fa54678061f74a3d18a44341ddf1e3ff97bb943f0f8cb969d32d3545b8f65" 50 + "bd10b5ccdb9e6c24fb4ee0d73c8b801f728e506cd06e5b11d2dc8c3a5aadce05" 51 + "75cb3fe37bb0e2101961cb5e467e7144671c02099222afe5aa5d40efb3a11bcc" 52 + ) 53 + 54 + inputs = [ 55 + ("empty", b""), 56 + ("digits", b"123456789"), 57 + ("hello", b"Hello, world!"), 58 + ("random256", bytes.fromhex(RANDOM_256_HEX)), 59 + ] 60 + 61 + os.makedirs(TRACE_DIR, exist_ok=True) 62 + with open(os.path.join(TRACE_DIR, "vectors.csv"), "w") as f: 63 + f.write("# CRC interop test vectors\n") 64 + f.write("# Oracle: Python crcmod 1.7\n") 65 + f.write("# Format: name,input_hex,crc16_ccitt,crc16_x25,crc32,crc32c\n") 66 + for name, data in inputs: 67 + c16_ccitt = crc16_ccitt_fn(data) 68 + c16_x25 = crc16_x25_fn(data) 69 + c32 = crc32_fn(data) 70 + c32c = crc32c_fn(data) 71 + f.write(f"{name},{data.hex()},{c16_ccitt:04x},{c16_x25:04x},{c32:08x},{c32c:08x}\n") 72 + 73 + print(f"Wrote {TRACE_DIR}/vectors.csv")
+87
test/interop/crcmod/test.ml
··· 1 + (** crcmod interop tests for ocaml-crc. 2 + 3 + Traces generated by: crcmod 1.7 4 + Regenerate: REGEN_TRACES=1 dune build @regen-traces *) 5 + 6 + let trace path = Filename.concat "traces" path 7 + 8 + (* Parse CSV trace: skip comments (#), split on comma *) 9 + let parse_csv path = 10 + let ic = open_in (trace path) in 11 + let lines = ref [] in 12 + (try 13 + while true do 14 + let line = input_line ic in 15 + if String.length line > 0 && line.[0] <> '#' then 16 + lines := String.split_on_char ',' line :: !lines 17 + done 18 + with End_of_file -> ()); 19 + close_in ic; 20 + List.rev !lines 21 + 22 + let string_of_hex hex = 23 + let len = String.length hex / 2 in 24 + String.init len (fun i -> 25 + Char.chr (int_of_string ("0x" ^ String.sub hex (i * 2) 2))) 26 + 27 + let int_of_hex s = int_of_string ("0x" ^ s) 28 + 29 + type vector = { 30 + name : string; 31 + input : string; 32 + crc16_ccitt : int; 33 + crc16_x25 : int; 34 + crc32 : int; 35 + crc32c : int; 36 + } 37 + 38 + let parse_vectors () = 39 + let rows = parse_csv "vectors.csv" in 40 + List.filter_map 41 + (fun row -> 42 + match row with 43 + | [ name; input_hex; c16_ccitt; c16_x25; c32; c32c ] -> 44 + Some 45 + { 46 + name; 47 + input = string_of_hex input_hex; 48 + crc16_ccitt = int_of_hex c16_ccitt; 49 + crc16_x25 = int_of_hex c16_x25; 50 + crc32 = int_of_hex c32; 51 + crc32c = int_of_hex c32c; 52 + } 53 + | _ -> Alcotest.failf "bad CSV row: %s" (String.concat "," row)) 54 + rows 55 + 56 + let test_crc16_ccitt vec () = 57 + let got = Crc.crc16_ccitt vec.input in 58 + Alcotest.(check int) 59 + (Printf.sprintf "%s: crc16_ccitt" vec.name) 60 + vec.crc16_ccitt got 61 + 62 + let test_crc16_x25 vec () = 63 + let got = Crc.crc16_x25 vec.input in 64 + Alcotest.(check int) 65 + (Printf.sprintf "%s: crc16_x25" vec.name) 66 + vec.crc16_x25 got 67 + 68 + let test_crc32 vec () = 69 + let got = Crc.crc32 vec.input in 70 + Alcotest.(check int) (Printf.sprintf "%s: crc32" vec.name) vec.crc32 got 71 + 72 + let test_crc32c vec () = 73 + let got = Crc.crc32c vec.input in 74 + Alcotest.(check int) (Printf.sprintf "%s: crc32c" vec.name) vec.crc32c got 75 + 76 + let () = 77 + let vectors = parse_vectors () in 78 + let make_cases f = 79 + List.map (fun v -> Alcotest.test_case v.name `Quick (f v)) vectors 80 + in 81 + Alcotest.run "crc-interop" 82 + [ 83 + ("crc16-ccitt", make_cases test_crc16_ccitt); 84 + ("crc16-x25", make_cases test_crc16_x25); 85 + ("crc32", make_cases test_crc32); 86 + ("crc32c", make_cases test_crc32c); 87 + ]
+7
test/interop/crcmod/traces/vectors.csv
··· 1 + # CRC interop test vectors 2 + # Oracle: Python crcmod 1.7 3 + # Format: name,input_hex,crc16_ccitt,crc16_x25,crc32,crc32c 4 + empty,,ffff,0000,00000000,00000000 5 + digits,313233343536373839,29b1,906e,cbf43926,e3069283 6 + hello,48656c6c6f2c20776f726c6421,52d2,1eb5,ebe6c6e6,c8a106e5 7 + random256,b8a89ba8ffdaa2d2e292efad871b1a0581573348000a8b4cb6ffc6538f63fc9d9a7f50c9839971068e93f2d76ddf28943acbd6777069f5efefb7b86fe4d9d3322d89c481f3f168e9f31b4c29ca1ccfe9198c41383114688c7afe056559f72c613d1d78d75e51e73de228f5b4a5ab7e0757c886e6f71bd91185d70fbd8d907bf07bf4e71ad2cf6e59a213fcee7200397a0b5669df9793cf25a38ac4c0aa157af19d2fa54678061f74a3d18a44341ddf1e3ff97bb943f0f8cb969d32d3545b8f65bd10b5ccdb9e6c24fb4ee0d73c8b801f728e506cd06e5b11d2dc8c3a5aadce0575cb3fe37bb0e2101961cb5e467e7144671c02099222afe5aa5d40efb3a11bcc,88e6,8693,0a811642,9e4e8fdf