Initial project import
This commit is contained in:
commit
23f2d29e32
11957 files changed
+1754577
No files matched your search
@@ -0,0 +1,86 @@
|
||||
# CRC64 Interoperability Fixture
|
||||
|
||||
This directory contains interoperability tests for the V `hash.crc64` module, cross-validating
|
||||
against reference implementations in C and Python.
|
||||
|
||||
## Overview
|
||||
|
||||
The fixture verifies that `hash.crc64` produces identical CRC-64-ECMA-182 checksums when:
|
||||
- Computing the same data in V, C, and Python
|
||||
- Operating on various input patterns (empty, binary, text, large payloads)
|
||||
|
||||
This helps catch:
|
||||
- Bit-ordering errors
|
||||
- Polynomial table generation bugs
|
||||
- Byte-order issues
|
||||
- Implementation divergences
|
||||
|
||||
## Files
|
||||
|
||||
- `crc64_interop.vsh` - Main V interop checker script
|
||||
- `crc64_ref.c` - C reference implementation (auto-compiled)
|
||||
- `crc64_ref.py` - Python reference implementation
|
||||
|
||||
## Running the fixture
|
||||
|
||||
From the V repository root:
|
||||
|
||||
```bash
|
||||
v run vlib/hash/crc64/interop/crc64_interop.vsh
|
||||
```
|
||||
|
||||
## Test vectors
|
||||
|
||||
The fixture tests 10 vector categories:
|
||||
|
||||
1. **empty** - Zero-length input
|
||||
2. **single_a** - Single character 'a'
|
||||
3. **single_null** - Single null byte
|
||||
4. **text_123456789** - Standard test vector
|
||||
5. **text_hello_world** - Common greeting
|
||||
6. **all_zeros_16** - 16 zero bytes
|
||||
7. **all_ones_16** - 16 0xFF bytes
|
||||
8. **repeating_pattern** - 150 bytes of "abc" repeated
|
||||
9. **all_bytes** - All 256 byte values in sequence
|
||||
10. **large_payload** - 10000 bytes of "test data " repeated
|
||||
|
||||
Each vector is checksummed by:
|
||||
- V: `hash.crc64.sum(data)`
|
||||
- C: compiled from `crc64_ref.c`
|
||||
- Python: `crc64_ref.py`
|
||||
|
||||
## Polynomial
|
||||
|
||||
All implementations use CRC-64-ECMA-182:
|
||||
- Polynomial: `0x42F0E1EBA9EA3693`
|
||||
- Initial value: `0x0000000000000000`
|
||||
- Final XOR: `0x0000000000000000`
|
||||
- Check value for `"123456789"`: `0x6c40df5f0b497347`
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- V compiler (tested with current repo version)
|
||||
- GCC (to compile C reference)
|
||||
- Python 3 (for Python reference)
|
||||
|
||||
## Expected output
|
||||
|
||||
```
|
||||
Compiling C reference helper...
|
||||
Running cross-validation tests...
|
||||
OK: empty => 0x0000000000000000
|
||||
OK: single_a => 0x926a79e87a919f5d
|
||||
OK: single_null => 0xbd4a6ec89c7eaafb
|
||||
...
|
||||
=== Results ===
|
||||
Passed: 10
|
||||
Failed: 0
|
||||
Total: 10
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If the fixture fails:
|
||||
1. Ensure `gcc` and `python3` are in PATH
|
||||
2. Check that `hash.crc64` module can be imported (`v -silent test vlib/hash/crc64/`)
|
||||
3. Manual check: `python3 crc64_ref.py checksum 313233343536373839` (should match C)
|
||||
@@ -0,0 +1,129 @@
|
||||
#!/usr/bin/env -S ./vnew run
|
||||
|
||||
import os
|
||||
import hash.crc64
|
||||
|
||||
struct TestVector {
|
||||
name string
|
||||
data []u8
|
||||
}
|
||||
|
||||
const ecma_check_123456789 = u64(0x6c40df5f0b497347)
|
||||
|
||||
fn compile_c_helper(dir string) string {
|
||||
ref_c := os.join_path(dir, 'crc64_ref.c')
|
||||
ref_bin := os.join_path(dir, 'crc64_ref')
|
||||
|
||||
// Compile: gcc -std=c99 crc64_ref.c -o crc64_ref
|
||||
cmd := 'gcc -std=c99 "${ref_c}" -o "${ref_bin}"'
|
||||
result := os.execute(cmd)
|
||||
if result.exit_code != 0 {
|
||||
eprintln('Failed to compile C helper:')
|
||||
eprintln(result.output)
|
||||
exit(1)
|
||||
}
|
||||
|
||||
return ref_bin
|
||||
}
|
||||
|
||||
fn run_c_checksum(ref_bin string, data []u8) !u64 {
|
||||
hex_str := data.hex()
|
||||
cmd := '${ref_bin} checksum ${hex_str}'
|
||||
result := os.execute(cmd)
|
||||
if result.exit_code != 0 {
|
||||
return error('C helper failed: ${result.output}')
|
||||
}
|
||||
|
||||
result_str := result.output.trim_space()
|
||||
return u64(result_str.parse_uint(16, 64)!)
|
||||
}
|
||||
|
||||
fn run_python_checksum(dir string, data []u8) !u64 {
|
||||
ref_py := os.join_path(dir, 'crc64_ref.py')
|
||||
hex_str := data.hex()
|
||||
cmd := 'python3 "${ref_py}" checksum ${hex_str}'
|
||||
result := os.execute(cmd)
|
||||
if result.exit_code != 0 {
|
||||
return error('Python helper failed: ${result.output}')
|
||||
}
|
||||
|
||||
result_str := result.output.trim_space()
|
||||
return u64(result_str.parse_uint(16, 64)!)
|
||||
}
|
||||
|
||||
fn test_vector(name string, data []u8, ref_bin string, dir string) ! {
|
||||
// V checksum
|
||||
v_sum := crc64.sum(data)
|
||||
|
||||
// C checksum
|
||||
c_sum := run_c_checksum(ref_bin, data)!
|
||||
|
||||
// Python checksum
|
||||
py_sum := run_python_checksum(dir, data)!
|
||||
|
||||
// All must match
|
||||
if v_sum != c_sum || v_sum != py_sum {
|
||||
eprintln('FAIL: ${name}')
|
||||
eprintln(' V: 0x${v_sum:016x}')
|
||||
eprintln(' C: 0x${c_sum:016x}')
|
||||
eprintln(' Python: 0x${py_sum:016x}')
|
||||
return error('checksum mismatch')
|
||||
}
|
||||
|
||||
if name == 'text_123456789' && v_sum != ecma_check_123456789 {
|
||||
eprintln('FAIL: ${name}')
|
||||
eprintln(' V: 0x${v_sum:016x}')
|
||||
eprintln(' Expected: 0x${ecma_check_123456789:016x}')
|
||||
return error('unexpected CRC-64-ECMA-182 check value')
|
||||
}
|
||||
|
||||
println('OK: ${name} => 0x${v_sum:016x}')
|
||||
}
|
||||
|
||||
fn main() {
|
||||
dir := os.dir(@FILE)
|
||||
|
||||
println('Compiling C reference helper...')
|
||||
ref_bin := compile_c_helper(dir)
|
||||
defer { os.rm(ref_bin) or {} }
|
||||
|
||||
println('Running cross-validation tests...')
|
||||
mut passed := 0
|
||||
mut failed := 0
|
||||
|
||||
mut vectors := []TestVector{}
|
||||
vectors << TestVector{'empty', []u8{}}
|
||||
vectors << TestVector{'single_a', 'a'.bytes()}
|
||||
vectors << TestVector{'single_null', [u8(0)]}
|
||||
vectors << TestVector{'text_123456789', '123456789'.bytes()}
|
||||
vectors << TestVector{'text_hello_world', 'Hello, World!'.bytes()}
|
||||
vectors << TestVector{'all_zeros_16', []u8{len: 16}}
|
||||
vectors << TestVector{'all_ones_16', []u8{len: 16, init: 0xFF}}
|
||||
vectors << TestVector{'repeating_pattern', ('abc'.repeat(50)).bytes()}
|
||||
|
||||
mut all_bytes := []u8{len: 256}
|
||||
for i in 0 .. 256 {
|
||||
all_bytes[i] = u8(i)
|
||||
}
|
||||
vectors << TestVector{'all_bytes', all_bytes}
|
||||
vectors << TestVector{'large_payload', ('test data '.repeat(1000)).bytes()}
|
||||
|
||||
for vec in vectors {
|
||||
test_vector(vec.name, vec.data, ref_bin, dir) or {
|
||||
eprintln(' Error: ${err}')
|
||||
failed++
|
||||
continue
|
||||
}
|
||||
passed++
|
||||
}
|
||||
|
||||
println('')
|
||||
println('=== Results ===')
|
||||
println('Passed: ${passed}')
|
||||
println('Failed: ${failed}')
|
||||
println('Total: ${passed + failed}')
|
||||
|
||||
if failed > 0 {
|
||||
exit(1)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
// Standard CRC64-ECMA reference implementation in C
|
||||
// Compiles with: gcc -std=c99 crc64_ref.c -o crc64_ref
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define CRC64_ECMA 0x42F0E1EBA9EA3693ULL
|
||||
|
||||
static uint64_t crc64_table[256];
|
||||
|
||||
void crc64_init_table(void) {
|
||||
for (int i = 0; i < 256; i++) {
|
||||
uint64_t crc = (uint64_t)i << 56;
|
||||
for (int j = 0; j < 8; j++) {
|
||||
if (crc & 0x8000000000000000ULL) {
|
||||
crc = (crc << 1) ^ CRC64_ECMA;
|
||||
} else {
|
||||
crc <<= 1;
|
||||
}
|
||||
}
|
||||
crc64_table[i] = crc;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t crc64_checksum(const uint8_t *data, size_t len) {
|
||||
uint64_t crc = 0ULL;
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
uint8_t byte = data[i];
|
||||
crc = crc64_table[(uint8_t)((crc >> 56) ^ byte)] ^ (crc << 8);
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
crc64_init_table();
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "Usage: %s <action> [data...]\n", argv[0]);
|
||||
fprintf(stderr, " checksum <hexstring> - compute CRC64 of hex data\n");
|
||||
fprintf(stderr, " table - print first 16 table entries\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *action = argv[1];
|
||||
|
||||
if (strcmp(action, "table") == 0) {
|
||||
printf("CRC64_ECMA table (first 16):\n");
|
||||
for (int i = 0; i < 16; i++) {
|
||||
printf(" [%d] = 0x%016llx\n", i, (unsigned long long)crc64_table[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp(action, "checksum") == 0) {
|
||||
const char *hexstr = (argc > 2) ? argv[2] : "";
|
||||
size_t hexlen = strlen(hexstr);
|
||||
|
||||
if (hexlen == 0) {
|
||||
// Empty input
|
||||
uint64_t crc = crc64_checksum(NULL, 0);
|
||||
printf("%016llx\n", (unsigned long long)crc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (hexlen % 2 != 0) {
|
||||
fprintf(stderr, "Error: hex string must have even length\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t datalen = hexlen / 2;
|
||||
uint8_t *data = malloc(datalen);
|
||||
if (!data) {
|
||||
fprintf(stderr, "Error: memory allocation failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < datalen; i++) {
|
||||
unsigned int byte;
|
||||
if (sscanf(&hexstr[i * 2], "%2x", &byte) != 1) {
|
||||
fprintf(stderr, "Error: invalid hex character\n");
|
||||
free(data);
|
||||
return 1;
|
||||
}
|
||||
data[i] = (uint8_t)byte;
|
||||
}
|
||||
|
||||
uint64_t crc = crc64_checksum(data, datalen);
|
||||
printf("%016llx\n", (unsigned long long)crc);
|
||||
free(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Error: unknown action '%s'\n", action);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env python3
|
||||
"""CRC64-ECMA reference implementation in Python."""
|
||||
|
||||
import sys
|
||||
import binascii
|
||||
|
||||
CRC64_ECMA = 0x42F0E1EBA9EA3693
|
||||
|
||||
class CRC64:
|
||||
def __init__(self):
|
||||
self.table = self._make_table(CRC64_ECMA)
|
||||
|
||||
@staticmethod
|
||||
def _make_table(poly):
|
||||
table = []
|
||||
for i in range(256):
|
||||
crc = i << 56
|
||||
for _ in range(8):
|
||||
if crc & 0x8000000000000000:
|
||||
crc = (crc << 1) ^ poly
|
||||
else:
|
||||
crc <<= 1
|
||||
table.append(crc & 0xFFFFFFFFFFFFFFFF)
|
||||
return table
|
||||
|
||||
def checksum(self, data):
|
||||
"""Compute CRC64 checksum of data."""
|
||||
crc = 0
|
||||
for byte in data:
|
||||
crc = self.table[((crc >> 56) ^ byte) & 0xFF] ^ ((crc << 8) & 0xFFFFFFFFFFFFFFFF)
|
||||
return crc & 0xFFFFFFFFFFFFFFFF
|
||||
|
||||
|
||||
def main():
|
||||
crc = CRC64()
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: crc64_ref.py <action> [data...]", file=sys.stderr)
|
||||
print(" checksum <hexstring> - compute CRC64 of hex data", file=sys.stderr)
|
||||
print(" table - print first 16 table entries", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
action = sys.argv[1]
|
||||
|
||||
if action == "table":
|
||||
print("CRC64_ECMA table (first 16):")
|
||||
for i in range(16):
|
||||
print(f" [{i:2d}] = 0x{crc.table[i]:016x}")
|
||||
return 0
|
||||
|
||||
if action == "checksum":
|
||||
hexstr = sys.argv[2] if len(sys.argv) > 2 else ""
|
||||
try:
|
||||
data = binascii.unhexlify(hexstr) if hexstr else b""
|
||||
result = crc.checksum(data)
|
||||
print(f"{result:016x}")
|
||||
return 0
|
||||
except (binascii.Error, ValueError) as e:
|
||||
print(f"Error: invalid hex input: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
print(f"Error: unknown action '{action}'", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
Reference in new issue
Block a user