gxhash 3.5.0: the shortest every-seed flooding family (18 bytes), and any-chunk replacement

1. 18 bytes, and why nothing shorter works

For 17..32 bytes, compress_all = aesenclast(hv, P2(v0)) with hv = get_partial(first e bytes, e), e = len - 16, and P2(v) = aesenc(aesenc(v, K0), K1), all public; the seed enters only afterwards, through a keyed permutation of the 128-bit state. So for a target T and each e-byte prefix, v0 = P2^-1(T ^ SR(SB(hv))) gives a member: 256^e members at 16 + e bytes, all with state T. The program builds 256 members of 17 bytes plus 65,536 of 18 bytes (65,792 in total) and checks them.

Minimality among families that share one compressed state: up to 16 bytes a block has at most two preimages (the 16-byte one and at most one shorter one), and at most 2 + 256 messages of length <= 17 share a block, so 18 bytes is the shortest maximum length for a 2^16-member family. (Messages with different states would need the keyed 128-bit permutation to collide for most seeds.)

Examples (memory order): 17 B 0048979328eaf4cfde08239c51a5b2e507; 18 B 3930e82fb3d3a38495c68625264b99bcdd2f.

program result log
gx_mc.c on M2 (armv8 AES, cross-checked against a table AES; SMHasher3 verification 64A77B47 / 48F84240) 65,792 members, 0 state mismatches; all in one 128-bit class for 4096/4096 seeds; published 15/16-byte pair 4096/4096; lengths <= 8: no shared state logs/gx_mc_m2_2p12.txt
cc -O2 -std=c11 -march=armv8-a+crypto gx_mc.c -o gx_mc && ./gx_mc 12     # x86-64: -maes

2. Long inputs: any 128-byte chunk can be replaced

compress_all never sees the seed. Per 128-byte chunk the lanes are a = aesenc(aesenc(aesenc(v0, v2), v4), v6) and b likewise from v1, v3, v5, v7; for any new v2..v7, solving v0 (and v1) by inverting the three rounds keeps (a, b) unchanged, so any chunk can be replaced by any of 2^768 others. This is the mechanism of O. Peters, gxhash issue #83 (2024); these programs only verify it.

length 64-bit and 128-bit collisions
256 B, 1000 B, 1 KiB, 64 KiB, 64 KiB + 13 65,536/65,536 seeds each (x86-64)
1 MiB, 1 MiB + 7 256/256
2^16 family at 1000 B all members equal for 1024/1024 seeds
M2 rerun, 192 B .. 1 MiB + 7 and the 1000 B family 256/256 seeds each
cc -O2 -std=c11 -maes gx_long.c -o gx_long && ./gx_long 16      # arm64: -march=armv8-a+crypto

Logs: logs/gx_long_xeon.txt, logs/gx_long_m2_2p8.txt.