Hashes designed for binary trees and other directed acyclic graphs. Used properly, identical graphs will hash to the same value, even if some parts of the graph are known only by their hash.
Currently this consists of C, Haskell, and Javascript implementations of blake2s1, BLAKE2s specialized to take a single input block, which is two of it's outputs.
Differentiation of node types is typically done with the salt, which can also be used to incorporate small amounts of data.
The C implementation may be found in blake2s1.c and blake2s1.h.
The prototype are straight-forward:
-
void blake2s1(const uint32_t m[16], const uint32_t salt[4], uint32_t out[8]);Hash 16 32-bit words in
mand 4 words of salt/personalization, into 8 words of hash inout. It is safe foroutto overlap withm. -
void blake2s1_hex(const uint32_t hash[8], char out[64]);Render 8 words of hash as hexadecimal in
out.
The Haskell implementation may be found in Blake2s1.hs.
Hashis the type of a Hashzerois the empty hashSaltis a 4-tuple ofWord32shash :: Hash -> Hash -> Salt -> Hashhashes toHashes and aSaltinto a newHashtoHex :: Hash -> Stringmakes a hex stringfromHex :: String -> Maybe Hashreads a hex stringtoList :: Hash -> [Word32]breaks out theWord32s of aHashinto a listfromList :: [Word32] -> Maybe Hashreads sufficientWord32s into aHash
An example to hash the structure of two trees.
data Tree t = Branch (Tree t) (Tree t) | Leaf t
structuralHash :: Tree t -> Hash
structuralHash (Leaf _) = hash zero zero (0,0,0,1)
structuralHash (Branch left right) = hash (structuralHash left) (structuralHash right) (0,0,0,0)A javascript implementation may be found in blake2s1.js.
-
hash = blake2s1.hash(data, salt, hash)Hash 16 32-bit words of
dataand 4 words of salt/personalization into 8 words inhash, return hash. -
words = blake2s1.fromBytes(bytes)Pack an array of bytes into an array of 32-bit words that blake2s1 can process.
-
bytes = blake2s1.toBytes(words)Unpack 32-bit words into an array of bytes.
-
hexstring = blake2s1.toHex(words)Render a hexadecimal string suitable for displaying a hash.
For example, the outline of a function to hash a tree:
function hashtree(tree){
var salt = nodeDataTo4Words(tree);
if(isleaf(tree)){
return blake2s1.hash(blake2s1.zero, salt, []);
} else {
return blake2s1.hash(hashtree(tree.left).concat(hashtree(tree.right)), salt, []);
}
}
var hex = blake2s1.toHex(hashtree(theTree));The Idris implementation may be found in Blake2s1.idr.
Much like the Haskell implementation:
Hashis the type of a Hashzerois the empty hashSaltisSfollowed by 4Bits32shash :: Hash -> Hash -> Salt -> Hashhashes toHashes and aSaltinto a newHashtoHex :: Hash -> Stringmakes a hex stringfromHex :: String -> Maybe Hashreads a hex stringtoVect :: Hash -> Vect 8 Bits32breaks out theBits32s of aHashinto a vectorfromVect :: Vect 8 Bits32 -> Hashconverts a vector ofBits32s into aHash
As you can see below, the Idris performance is abysmal.
Performance may be tested with make perf or by loading perf/index.html.
| Processor | Environment | Lang | Hash | MH/s | MB/s |
|---|---|---|---|---|---|
| i5-3337U 1.8GHz | clang v3.9.1 | C | blake2s1 | 5.00 | 320 |
| i5-3337U 1.8GHz | node v6.9.5 | js | blake2s1 | 3.51 | 225 |
| E5-2603 1.6GHz | clang v3.7.1 | C | blake2s1 | 3.45 | 220 |
| i5-3337U 1.8GHz | Chromium 61 | js | blake2s1 | 3.05 | 196 |
| E5-2603 1.6GHz | node v4.6.0 | js | blake2s1 | 2.37 | 152 |
| Core 2 1.0GHz | gcc 7.2.0 | C | blake2s1 | 2.08 | 132 |
| i5-3337U 1.8GHz | GHC v8.0.2 | Haskell | blake2s1 | 2.03 | 130 |
| E5-2603 1.6GHz | GHC v8.0.1 | Haskell | blake2s1 | 1.25 | 80 |
| Core 2 1.0GHz | GHC v8.0.2 | Haskell | blake2s1 | 0.99 | 63 |
| Core 2 1.0GHz | node v8.11.2 | js | blake2s1 | 0.53 | 34 |
| i5-3337U 1.8GHz | 1.0 gcc 6.4 | Idris | blake2s1 | 0.01 | 0.9 |
Tests may be run with make test or by loading test/index.html.
- blake2s1 salt is untested due to lack of support in the
b2sumutility.
Public Domain / Unlicence