# Report: SHA-256 truncated to 48 bits — collision (λ=24)

## Answer
```json
{"algo":"sha256","lambda":24,"inputA":"imd-12192837","inputB":"imd-19093962"}
```
Inputs are UTF-8 strings with no trailing newline.

## Evidence (facts, checked locally on 2026-10-05)
| input | SHA-256 (full hex) |
|---|---|
| `imd-12192837` | `c94563ba4883`4c66186fe07f1f2233f777eed615e843ce03144ade7e659074d9 |
| `imd-19093962` | `c94563ba4883`0d17ce781584012f36b6502808166df0a05236829c7c1c062211 |

- The first 12 hex digits (48 bits) are `c94563ba4883` for both inputs. The next digit is different (`4` vs `0`), so the full digests are different.
- Two separate implementations produced the same digests: Python `hashlib.sha256` and GNU coreutils `sha256sum` (`printf %s <input> | sha256sum`).
- The inputs are different strings. `collision.json` contains exactly the keys `algo`, `inputA`, `inputB` and `lambda`.

## Method
`tools/find_collision.py` hashes `imd-0`, `imd-1`, … and saves each 6-byte digest prefix in a dict. It stops at the first repeated prefix. The repeat came after 19,093,963 evaluations, which is about 2^24.19. That is close to the birthday-bound expectation of √(π/2·2^48) ≈ 2^24.3. The run took about 48 s on 4 cores using one Python process.

## Inferences and uncertainty
- Inference: the verifier's "truncated to 48 bits MSB" means the first 6 bytes of the big-endian digest. That is the standard reading. Under it the collision holds.
- Uncertainty: how the verifier parses the inputs. The values have no `0x` prefix, so they should be treated as UTF-8. If a verifier decoded them some other way, the result would not hold. I did not test the SIMD verifier because I have no access to it.

## Unanswered / out of scope
- This collision is in the 48-bit truncation only. It does not affect the collision resistance of full SHA-256 (FIPS 180-4, https://csrc.nist.gov/pubs/fips/180-4/upd1/final), and it implies nothing about it.
- No external research sources were needed. Every claim above can be reproduced with the commands listed.
