Tiger
Tiger
64 bits at a time in 1996, its S-boxes hashed out of one sentence.
- Digest
- 192-bit · 24 bytes
- HMAC
- takes a key
- Security
- No practical attack on all 24 rounds
- Used by
- Direct Connect, Gnutella
Sample
- hex
- 4c8fbddae0b6f25832af45e7c62811bb64ec3e43691e9cc3
- base64
- TI+92uC28lgyr0XnxigRu2TsPkNpHpzD
Options
Access
- Create
create("tiger") - CLI
hashes tiger 'hello world' - Tryplayground with the sample above
Ross Anderson and Eli Biham brought Tiger to FSE 1996. MD5 and SHA-1 worked 32 bits at a time. Tiger went straight for 64. Three 64-bit words of state, three passes of eight rounds, four S-boxes of 256 words. On a 200 MHz Alpha it did 132 Mbit/s, by the authors' own count. Fast, for 1996.
create("tiger").hash("abc").digest; // "2aab1484e8c158f2bfb8c5ff41b57a525129131c957b5f93"
create("tiger").hash("").digest; // "3293ac630c13f0245f92bbb1766e16167a4e58492dde73f3"
Where do those S-boxes come from? Tiger itself. Every word starts as eight copies of its own index byte. Then Tiger hashes one 64-byte sentence over and over, and each state swaps bytes around the boxes. The boxes it shuffles are the ones it hashes with. A hash that pulls itself up by its own bootstraps. And the sentence? The paper's title and its authors:
Tiger - A Fast New Hash Function, by Ross Anderson and Eli Biham
This package does the same on the first Tiger you ask for, instead of shipping 1024 numbers. It costs a few milliseconds, once. And it lands on the authors' boxes, or not a single vector would match.
Which Tiger is this?
The original. Tiger has relatives, and all of them fit in 24 bytes:
| Name | What changes | abc starts with |
|---|---|---|
| Tiger (this one) | nothing | 2aab1484 |
| Tiger2 | the padding opens with 0x80, like MD5, not 0x01 | f68d7bc5 |
| Tiger printed as words | each 64-bit word printed as a number, the way the authors' testtiger does | f258c1e8 |
Same input, three answers. The first is Tiger. The second is another hash. The third is Tiger read backwards, eight bytes at a time. This package prints bytes, like NESSIE and PHP do.
So create("tiger2") throws instead of quietly handing you Tiger. identifyDigest puts Tiger first for a 24-byte digest and lists Tiger2 as one it can't compute. Got a digest that matches neither? Flip every 8-byte group and try again.
Tiger/128 and Tiger/160 are just the first 16 and 20 bytes. No starting values of their own, so cut the digest yourself.
What about TTH?
Seen urn:tree:tiger: in a magnet link? That's a Tiger Tree Hash, the one Direct Connect and Gnutella clients swap. A file gets cut into 1024-byte leaves. Each leaf is hashed behind a zero byte, each pair of hashes behind a one byte, up to a single root. A file under 1 KiB is one leaf, so its TTH is Tiger of 0x00 and the file:
create("tiger").hash(Uint8Array.fromHex("00616263")).digest;
// "0487ca26443f59cfbc780f3ca0ce509c8c352c27c5dcca20"
rhash --tth --hex on a file holding abc prints exactly that. The magnet link carries it in base32. The tree isn't built here, only the hash it's made of.
Is it broken?
Not really. Collisions reach 19 of its 24 rounds, at about 2^62 (Mendel and others, 2006). The full function only gives up pseudo-near-collisions, where the attacker picks the starting state too (Mendel and Rijmen, 2007). MD5 and SHA-1 would kill for that record.
One catch, and it has nothing to do with rounds. The digest is the whole state, so Tiger(secret + message) extends like MD5 does. extendDigest forges it without the secret. Want a MAC? Use HMAC.
So why legacy? Hardly anyone took it up outside file sharing. OpenPGP thought about Tiger and took RIPEMD-160. Today it lives in those clients and in PHP's hash() as tiger192,3. HMAC runs over its 64-byte blocks and matches PHP's hash_hmac. Check old TTHs with it. New code gets SHA-256 or BLAKE3.