# keccak256 48-bit truncated collision (λ = 24)

## Answer

```json
{"algo":"keccak256","lambda":24,"inputA":"0x00436477","inputB":"0x0067ebfa"}
```

Both inputs are **hex byte strings** (4 raw bytes each), not UTF-8 text.

| input | keccak256 (full) |
|---|---|
| `0x00436477` | `0x`**`803f144e84b9`**`2d6803ce5432afcf593a936f87b54be18a4b1ea7410a0c7a018a` |
| `0x0067ebfa` | `0x`**`803f144e84b9`**`38cd84e779a1863662773ba8a695a9ba3635aae214cc936f54ba` |

The first 48 bits (6 bytes, MSB first) are `803f144e84b9` for both. Byte 7 differs
(`2d` and `38`), so this is a 48-bit truncated collision, not a full one.

## Evidence (facts)

- **Independent recomputation.** Both full digests above are the output of Foundry's
  `cast keccak <hex>` (cast 1.8.3), which hashes hex arguments as raw bytes. I ran it again on the
  values read back from the final `collision.json`, and both printed `0x803f144e84b9`.
- **Distinctness.** `0x00436477` ≠ `0x0067ebfa`. A shell check on the file contents confirmed this.
- **Search tool.** `tools/find-collision.mjs` is a self-contained keccak-f[1600] written in Node
  (original Keccak padding `0x01…0x80`, not SHA3's `0x06`). Before the search I checked its 48-bit
  output against `cast keccak` for inputs `0x00000000`, `0x00000001` and `0x12345678`, and all three
  matched. Reproduce the search with `node tools/find-collision.mjs` (needs about 450 MB RAM, ~40 s).
  Print the prefix of a single counter with `node tools/find-collision.mjs digest <n>`.
- **Cost.** The collision appeared after 6,810,619 evaluations of 4-byte big-endian counters
  0, 1, 2, … The search was deterministic: it stored each prefix in an open-addressing table and
  stopped at the first repeat.

## Inference

- 6.8 M evaluations ≈ 2^22.7. That is within normal birthday variance of the expected
  √(π/2 · 2^48) ≈ 2^24.3 ≈ 21 M. Nothing suggests keccak256 is weak; this is generic brute force.

## Uncertainty / open questions

- The task says the verifier recomputes "digest, truncated to 48 bits MSB". I assume a value
  beginning with `0x` is decoded as hex bytes, as the task format (`<hex 0x... or utf8>`) implies.
  If the verifier instead hashed the literal UTF-8 strings `"0x00436477"`/`"0x0067ebfa"`, they would
  **not** collide. I did not check the verifier's parsing, because its code was not available to me.
- No external sources were needed. Every claim above can be checked by recomputation.
