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

## Question
Find two distinct inputs A ≠ B such that the first 48 bits (6 bytes, MSB-first) of
RIPEMD-160(A) and RIPEMD-160(B) are equal.

## Answer
`collision.json` (repo root; copy in `artifacts/collision.json`):

```json
{"algo":"ripemd160","lambda":24,"inputA":"0x69646d642d3133343538303031","inputB":"0x69646d642d3231373737323238"}
```

| | bytes (hex) | ASCII | RIPEMD-160 (full) |
|---|---|---|---|
| A | `69646d642d3133343538303031` | `idmd-13458001` | `9ff5cb7e7844`b4e20774f357c3ce88d721e7832f |
| B | `69646d642d3231373737323238` | `idmd-21777228` | `9ff5cb7e7844`b94fb8896a518dd50687714b3a45 |

Shared 48-bit prefix: **`9ff5cb7e7844`**. The digests differ from the 7th byte onward. That's
what a truncated collision should look like. It is not a full collision.

## Evidence (facts: observed locally on 2026-10-05)
1. **Implementation sanity check.** Python `hashlib.new('ripemd160', b'abc')` returned
   `8eb208f7e05d987a9b044a8e98c6b087f15a0bfc`. This matches the "abc" test vector published by
   the RIPEMD-160 authors (Dobbertin, Bosselaers, Preneel, *RIPEMD-160: A Strengthened Version
   of RIPEMD*, FSE 1996; test vectors at https://homes.esat.kuleuven.be/~bosselae/ripemd160.html).
2. **Search.** `artifacts/search.py` hashes `b"idmd-%d" % i` for i = 0, 1, 2, … and stores each
   6-byte prefix in a dict until two prefixes match. A match came up at i = 21,777,228 against
   i = 13,458,001. That took 21,777,229 evaluations (about 2^24.4) and 75 s of wall time on one
   core.
3. **Independent recomputation.** The OpenSSL CLI (`openssl dgst -ripemd160`) produced the same
   full digests for both inputs as Python's hashlib.
4. **Format check.** A script loaded `collision.json`, confirmed it has exactly these keys:
   `algo, lambda, inputA, inputB`. It decoded both hex inputs, then asserted that A ≠ B and that
   the 6-byte prefixes are equal. The check passed.

## Inferences
- The birthday bound for a 48-bit target is about √(π/2 · 2^48) ≈ 1.25 · 2^24 ≈ 2.1 · 10^7 expected
  evaluations. The observed 2.18 · 10^7 is consistent with that. Nothing suggests a structural
  weakness in RIPEMD-160 was involved. This is a generic attack on a truncated output, and it says
  nothing about the security of full 160-bit RIPEMD-160.
- I gave the inputs in `0x` hex form, so their bytes are unambiguous. As UTF-8 strings they would
  be the same bytes, because they are plain ASCII.

## Uncertainty / unanswered
- I am assuming the verifier reads "first 48 bits MSB" as the first 6 bytes of the standard
  big-endian hex digest. Under that reading the collision holds. Any other bit ordering would
  need a separate check.
- I did not run the SIMD verifier itself. It is not available here, so its behaviour is not
  independently confirmed.
