# RIPEMD-160 truncated-48-bit collision (λ=24)

## Answer
`collision.json`:
```json
{"algo":"ripemd160","lambda":24,"inputA":"863122ce045e","inputB":"149b597971fc"}
```
Both inputs are UTF-8 strings (12 ASCII characters each, no `0x` prefix, so they are not hex-decoded).

| input (UTF-8) | full RIPEMD-160 digest | first 48 bits |
|---|---|---|
| `863122ce045e` | `fde5c3e418b6a945d046b3021004ba57cf553cbc` | `fde5c3e418b6` |
| `149b597971fc` | `fde5c3e418b6c5cf2810a4822db263fb78128f02` | `fde5c3e418b6` |

## Evidence (facts)
- Found with `artifacts/rho_search.py`: Floyd cycle-finding over
  f(x) = first 12 hex characters of RIPEMD-160(x), with x a 12-char hex string and seed `identitymd00`.
  The two predecessors of the cycle entry are distinct and map to the same value. Run time: about 45 s, single-threaded CPython.
- Checked separately with OpenSSL (`printf %s <input> | openssl dgst -ripemd160`). The output is the digest table above, and the first 48 bits match.
- I confirmed the Python `hashlib` RIPEMD-160 backend against the standard test vector RIPEMD-160("abc") = `8eb208f7e05d987a9b044a8e98c6b087f15a0bfc`.
  Source for the vector: Bosselaers' RIPEMD-160 page, https://homes.esat.kuleuven.be/~bosselae/ripemd160.html (cited from memory, not re-fetched in this session).

## Inferences
- The cost fits the generic birthday bound for a 48-bit output, about 2^24 evaluations. Rho needs a small constant multiple of that.
  Nothing here relies on any structural weakness in RIPEMD-160.

## Uncertainty / open questions
- I assume the verifier reads strings without a `0x` prefix as UTF-8, as the task format says. If it read them as hex instead, the inputs would be different byte strings and this collision would not hold.
- I did not run the SIMD verifier myself. Its result is not reproduced here.
