# Keccak-256 collision at 48 bits (lambda = 24)

## Result: locally verified

The distinct eight-byte inputs in [collision.json](../collision.json) have identical first six digest bytes, `0x8851a59bbb9d`. Each `0x` string is decoded as hexadecimal bytes, not hashed as literal text.

| Field | Value |
|---|---|
| inputA | `0x8375360100000000` |
| inputB | `0x7131040200000000` |
| Keccak-256(inputA) | `8851a59bbb9d6231d46ab9566296d3aed4afb5cd4212a1f68a094142b0366868` |
| Keccak-256(inputB) | `8851a59bbb9d27a12c8340ba34a0ac8820e6315e00542945f74d66f4ef53a9b1` |
| First 48 bits, MSB | `0x8851a59bbb9d` |

The full digests differ; the claimed collision is specifically for the requested 48-bit truncation.

## Method and attributable evidence

The local [C search](../src/search.c) enumerated eight-byte little-endian integers starting at zero, storing 48-bit digest prefixes in an open-addressed table. The two counters were 20,346,243 and 33,829,233. It found the pair after 33,829,234 evaluations; [search.log](search.log) records progress and the final count. The search used all 24 rounds of Keccak-f[1600], rate 1088, capacity 512, and the original Keccak suffix `0x01`.

The [Keccak team's specification summary](https://keccak.team/keccak_specs_summary.html) describes the permutation, sponge construction, and suffix encoding. Its formula gives `0x01` when no domain-separation bits are appended; SHA3-256 uses `0x06`. The first six serialized digest bytes are the most significant 48 bits of the displayed hexadecimal digest.

The offline [verifier](../src/verify.py) recomputed both full digests with two implementations: a local direct Python model and the [XKCP compact Python reference by Gilles Van Assche](https://github.com/XKCP/XKCP/blob/master/Standalone/CompactFIPS202/Python/CompactFIPS202.py). The latter is vendored unchanged with its CC0 notice; [provenance and file checksum](../src/vendor/README.md) identify the downloaded bytes. The reference is called as `Keccak(1088, 512, input_bytes, 0x01, 32)`.

Observed checks:

- Both implementations matched known-answer vectors for empty input and `abc`.
- The implementations agreed on 12 message lengths, including 135, 136, 137, 271, and 272 bytes.
- The delivered JSON has exactly the four required fields, the requested algorithm and integer lambda, and distinct decoded inputs.
- Both implementations agreed on each full candidate digest and its matching six-byte prefix.

[verification.json](verification.json) contains the recorded output. Reproduce the decisive checks without network or package installation:

```sh
python3 -B src/verify.py
```

## Conclusions and limits

The observed digest equality establishes the requested truncated collision under the two local implementations. No estimate of birthday probability is used as evidence that this particular pair works. These are local self-checks, not independent review or a SIMD verifier verdict. The external SIMD outcome remains unobserved; no acceptance is claimed. The prior attempt's stated failure was model capacity/runtime availability, and no files or results from it were reused.
