# Keccak-256 collision in the first 48 bits

The distinct four-byte inputs `0xa0c9eb00` and `0x8c465b01` have the same first 48 bits of their Keccak-256 digests: **`654b41768127`**. The required answer is [collision.json](../collision.json).

## Observed result

Here, `0x` denotes hexadecimal encoding of raw input bytes, not text to be hashed literally. The first 48 bits MSB are the first six digest bytes, or first twelve hexadecimal digits.

| Field | Input A | Input B |
| --- | --- | --- |
| Raw bytes (hex) | `a0c9eb00` | `8c465b01` |
| Full Keccak-256 digest | `654b4176812717d0cbff1dce8492b2daad8199b3b60fd2df84ae32f2e8a39f26` | `654b41768127009ad7e17b9170a66c8954393e43c6c7eba5c7e42b92930da12e` |
| First 48 bits | `654b41768127` | `654b41768127` |

These values were computed locally by [the JavaScript search](../src/search.js) and recomputed by [a separate Python implementation](../src/verify.py). The resulting evidence is saved in [search-result.json](search-result.json) and [verification.json](verification.json). Both implementations also passed the empty-message and `abc` known-answer checks. The Python verification checked the exact JSON field set, algorithm, integer lambda, distinct decoded inputs, and equality of the first six digest bytes. It returned `PASS`.

## Method and attribution

The search enumerated four-byte little-endian integers starting at zero, hashed each candidate, and stored 48-bit prefixes in a hash table. It found the pair after **22,759,053 candidate evaluations**, taking **405.321 seconds** in this run. The table preserves all six prefix bytes; the table-index hash is only used to locate entries. The full digests were recomputed after the match.

The permutation, rotation offsets, round constants, and sponge construction follow the primary-source [Keccak Team specifications summary](https://keccak.team/keccak_specs_summary.html), consulted on 2026-10-05. The implementations use Keccak-f[1600] with 24 rounds, a 1088-bit rate, 512-bit capacity, and original Keccak padding with delimited suffix `0x01`. The source describes how the suffix is computed from trailing domain bits and gives SHA3-256's different suffix, `0x06`. The requested lambda of 24 describes the collision task; the comparison length is 48 bits.

The JavaScript implementation represents lanes as pairs of 32-bit words; the Python implementation uses 64-bit integer lanes. Both are included as ordinary source files and require no downloaded packages or network access. Runtime versions used here were Node.js v24.21.0 and Python 3.12.3.

To reproduce the final check from the repository root:

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

## Conclusions and limits

The observed equality of the six-byte prefixes and inequality of the inputs establish the requested truncated collision under the implemented Keccak-256 byte convention. The full digests differ; this is not a full 256-bit collision.

The checks are local evidence from two implementations written during this assignment, not an independent review or SIMD certification. SIMD verification was not available or run here; its external verdict remains unanswered. No statistical assumption is needed to compare the reported prefixes.

The supplied previous-attempt failure was `runtime_error` with “Credit balance is too low.” No prior files or more detailed logs were supplied. This attempt completed its search and local verification without installing dependencies or using a paid external hashing service; it does not establish the cause of that earlier failure.
