Humanhash: Human-readable representations of digests
github.com
github.com
I agree with various commenters' would-be-nice features (larger word list for more bits represented per word, better phonetic distance between items in the word list), and have one of my own (an implementation in C with no library dependencies would be nice).
Solid effort overall.
With that in mind, the code could be much simpler: Each possible pair of hex digits gets assigned to one of 256 words, and the humanhash is the words for the first n pair of the digest.
Or am I missing something big?
The humanhash is not intended to guarantee any level of collision protection, it's simply supposed to be a human-memorable representation of a much longer underlying digest. When computers exchange representations, they should certainly use the full digest.
However, even with only four bytes, you're looking at a 1 in 4.3 billion chance of collision. So for user interfaces, where a user merely has to distinguish between different values, or even a situation where two people want to check that they're talking about (probably) the same thing, it remains useful.
It doesn't appear that you've made any attempt to secure this humanhash against a malicious third-party.
If the input to humanhash really is the result of a cryptographically-strong hash function, then at first glance it looks like the "XOR everything into an n-byte buffer" is no stronger (and potentially actually weaker) than the naive "just use the first n bytes". (Disclaimer: not my field, although I did take a couple of formal crypto classes once.)
If the input to humanhash is arbitrary, and you aren't protecting against a malicious third party, then why not use a much-better understood CRC rather than "XOR everything into an n-byte buffer"?
EDIT: On reflection, the input to humanhash has to be short (because the compression function needs to know the length of the input and so can't operate on a stream) and of known length (because you're just xor'ing, and it's trivial to get two inputs to "compress" to the same thing by padding one with NUL bytes.)
I hadn't seen the PGP word list; thanks a lot for that. I would integrate that list this very second if I could, but I'm concerned that PGP owns the copyright to the list.
> So for user interfaces, where a user merely has to distinguish between different values, or even a situation where two people want to check that they're talking about (probably) the same thing, it remains useful.
Yes, absolutely, as I also wrote. I just wanted (and maybe you do too) to warn that it's not appropriate for sensitive stuff, while the relative complexity of the implementation could suggest that's the case.
This has the nice property that a given set of words uniquely translates back to a specific hash, and that the user can use their favorite wordlist as long as it's large enough. If you were to use it for recognition rather than memorization (and wanted fewer words to remember) you would have to manually decide where to truncate the hash before converting it. If you wanted to pick a specific wordlist, you could do that.
I originally came up with this as a system for helping to memorize IPv6 addresses; it also works as a system for passphrase generation (first generate a random number with the desired number of bits of entropy, then convert to words.)
It would be better if we had a much larger dictionary, since we could map more bytes to a single word -- with a list of 65,536 words we would need only 8 words per 16 byte hash, which I think is a lot more manageable.
Note that I never intended this to have all the uniqueness of the original digest. It's merely supposed to be 'good enough' for UI purposes.
/usr/share/dict/words is likely to be pretty big, over 200k words, but it's still human readable. You could prune it by removing proper words (i.e. anything capitalized).
https://en.wikipedia.org/wiki/English_phonology#Phonotactics
I think this is getting a little beyond my linguistics skills...
Edit: I suppose which syllables are easily corruptable depends on the medium: written hashes would require a different set of graphemes than spoken hashes would phonemes, for example, while memorised hashes would likely be different again. I wonder if there's been any research or anything into this.