Hash Fusing

Exploring Hash Fusing via Upper Triangular Matrix Multiplication.
Author
Published

January 12, 2026

Keywords

data, hash, sha256, matrix, fusing, merkle-tree

The basic question this article tries to answer is: Can fusing hashes together provide unique identifiers for arbitrary data? The answer is no. Specifically, we can not provide unique identifiers for sufficiently large repeated sequences of values. That is, sufficiently low entropy data is not representable by fusing hashes together. The good news is that low entropy data is compressible.

This is an article about fusing hashes together while having the key properties of associativity and non-commutativity. I describe the basic approach of using matrix multiplication of Upper Triangle Matricies and then show the results of two types experiments showing the quality and limits of this hash fusing approach.

Introduction

I have begun working on implementing distributed immutable data structures as a way to efficiently share structured data between multiple clients. One of the key challenges in this area is being able to efficiently reference ordered collections of data. The usual apprach is to use Merkle Trees but, since the immuable data structure for ordered collections is based on finger trees, I need references that are insensitive to tree shape. This means that I need to be able to fuse hashes together in a way that is associative but not commutative. As a starting point, I have been reading the HP paper describing hash fusing via matrix multiplication: https://www.labs.hpe.com/techreports/2017/HPE-2017-08.pdf

Hash Fusing via Upper Triangular Matrix Multiplication

The basic approach of fusing two hashes is to represent each hash as an upper triangular matrix. For example, if we have a hash that is 4 bytes long, we can represent it as a 4x4 upper triangular matrix like this:

true
(defn random-hex
  "Generate a random hex string representing length `n` bytes."
  [n]
  (let [hex-chars "0123456789abcdef"]
    (apply str (repeatedly (* 2 n) #(rand-nth hex-chars)))))
(defn hex->hash8
  "Convert a hex string to a byte vector."
  [s]
  (->> s
       (partition 2)
       (map #(-> (apply str %)
                 (Integer/parseInt 16)))
       (vec)))
(defn hash8->hex
  "Convert a byte vector to a hex string."
  [bytes]
  (->> bytes
       (map #(format "%02x" %))
       (apply str)))
(def zero-hex
  "Generate a zero hash of given byte length."
  (-> (repeat 32 0)
      hash8->hex))
(def h1
  (hex->hash8 "a1a2a3a4"))
1 6 1 1 6 2
1 6 3 1 6 4
(def m1
  [[1 (h1 0) (h1 1) (h1 2)]
   [0 1 (h1 3) 0]
   [0 0 1 0]
   [0 0 0 1]])
1 161 162 163
0 1 164 0
0 0 1 0
0 0 0 1

To fuse two hashes, we convert each hash to its corresponding upper triangular matrix and then multiply the two matrices together. The result is another upper triangular matrix which can be converted back to a hash by taking the elements above the main diagonal.

(defn hash8->utm8
  "Convert a vector of 32 bytes into a 9x9 upper triangular matrix."
  [[h00 h01 h02 h03 h04 h05 h06 h07
    h08 h09 h10 h11 h12 h13 h14 h15
    h16 h17 h18 h19 h20 h21 h22 h23
    h24 h25 h26 h27 h28 h29 h30 h31]]
  [[1 h00 h08 h15 h21 h26 h29 h31 h25]
   [0   1 h01 h09 h16 h22 h27 h30 h20]
   [0   0   1 h02 h10 h17 h23 h28 h14]
   [0   0   0   1 h03 h11 h18 h24 h07]
   [0   0   0   0   1 h04 h12 h19   0]
   [0   0   0   0   0   1 h05 h13   0]
   [0   0   0   0   0   0   1 h06   0]
   [0   0   0   0   0   0   0   1   0]
   [0   0   0   0   0   0   0   0   1]])
(defn hash16->utm16
  "Convert a vector of 16 2-byte words into a 7x7 upper triangular matrix."
  [[h00 h01 h02 h03 h04 h05 h06 h07
    h08 h09 h10 h11 h12 h13 h14 h15]]
  [[1 h00 h06 h10 h13 h15 h05]
   [0   1 h01 h07 h11 h14   0]
   [0   0   1 h02 h08 h12   0]
   [0   0   0   1 h03 h09   0]
   [0   0   0   0   1 h04   0]
   [0   0   0   0   0   1   0]
   [0   0   0   0   0   0   1]])
(defn hash32->utm32
  "Convert a vector of 8 4-byte words into a 5x5 upper triangular matrix."
  [[h00 h01 h02 h03 h04 h05 h06 h07]]
  [[1 h00 h04 h07 h06]
   [0   1 h01 h05 h03]
   [0   0   1 h02   0]
   [0   0   0   1   0]
   [0   0   0   0   1]])
(defn hash64->utm64
  "Convert a vector of 4 8-byte words into a 4x4 upper triangular matrix."
  [[h00 h01 h02 h03]]
  [[1 h00 h03 h02]
   [0   1 h01   0]
   [0   0   1   0]
   [0   0   0   1]])
(defn utm8->hash8
  "Convert a 9x9 upper triangular matrix back to a vector of 32 bytes."
  [[[_ h00 h08 h15 h21 h26 h29 h31 h25]
    [_   _ h01 h09 h16 h22 h27 h30 h20]
    [_   _   _ h02 h10 h17 h23 h28 h14]
    [_   _   _   _ h03 h11 h18 h24 h07]
    [_   _   _   _   _ h04 h12 h19   _]
    [_   _   _   _   _   _ h05 h13   _]
    [_   _   _   _   _   _   _ h06   _]
    [_   _   _   _   _   _   _   _   _]
    [_   _   _   _   _   _   _   _   _]]]
  (mapv #(bit-and % 0xFF)
        [h00 h01 h02 h03 h04 h05 h06 h07
         h08 h09 h10 h11 h12 h13 h14 h15
         h16 h17 h18 h19 h20 h21 h22 h23
         h24 h25 h26 h27 h28 h29 h30 h31]))
(defn utm16->hash16
  "Convert a 7x7 upper triangular matrix back to a vector of 16 2-byte words."
  [[[_ h00 h06 h10 h13 h15 h05]
    [_   _ h01 h07 h11 h14   _]
    [_   _   _ h02 h08 h12   _]
    [_   _   _   _ h03 h09   _]
    [_   _   _   _   _ h04   _]
    [_   _   _   _   _   _   _]
    [_   _   _   _   _   _   _]]]
  (mapv #(bit-and % 0xFFFF)
        [h00 h01 h02 h03 h04 h05 h06 h07
         h08 h09 h10 h11 h12 h13 h14 h15]))
(defn utm32->hash32
  "Convert a 5x5 upper triangular matrix back to a vector of 8 4-byte words."
  [[[_ h00 h04 h07 h06]
    [_   _ h01 h05 h03]
    [_   _   _ h02   _]
    [_   _   _   _   _]
    [_   _   _   _   _]]]
  (mapv #(bit-and % 0xFFFFFFFF)
        [h00 h01 h02 h03 h04 h05 h06 h07]))
(defn utm64->hash64
  "Convert a 4x4 upper triangular matrix back to a vector of 4 8-byte words."
  [[[_ h00 h03 h02]
    [_   _ h01   _]
    [_   _   _   _]
    [_   _   _   _]]]
  [h00 h01 h02 h03])
(defn utm-multiply
  "Multiply two upper triangular matrices `a` and `b`. Each cell value is
  constrained by `bit-size`"
  [a b]
  (let [dim (count a)
        bit-mask (-> Long/MAX_VALUE dec)]
    (vec (for [i (range dim)]
           (vec (for [j (range dim)]
                  (cond
                    (< j i) 0
                    (= j i) 1
                    :else
                    (reduce (fn [sum k]
                              (-> sum
                                  (+ (* (get-in a [i k])
                                        (get-in b [k j])))
                                  (bit-and bit-mask)))
                            0
                            (range i (inc j))))))))))
(defn hash8->hash16
  "Convert a vector of 32 bytes into a vector of 16 2-byte words."
  [hash8]
  (vec (map (fn [i]
              (+ (bit-shift-left (hash8 (* 2 i)) 8)
                 (hash8 (+ 1 (* 2 i)))))
            (range 16))))
(defn hash8->hash32
  "Convert a vector of 32 bytes into a vector of 8 4-byte words."
  [hash8]
  (vec (map (fn [i]
              (+ (bit-shift-left (hash8 (* 4 i)) 24)
                 (bit-shift-left (hash8 (+ 1 (* 4 i))) 16)
                 (bit-shift-left (hash8 (+ 2 (* 4 i))) 8)
                 (hash8 (+ 3 (* 4 i)))))
            (range 8))))
(defn hash8->hash64
  "Convert a vector of 32 bytes into a vector of 4 8-byte words."
  [hash8]
  (vec (map (fn [i]
              (+ (bit-shift-left (hash8 (* 8 i)) 56)
                 (bit-shift-left (hash8 (+ 1 (* 8 i))) 48)
                 (bit-shift-left (hash8 (+ 2 (* 8 i))) 40)
                 (bit-shift-left (hash8 (+ 3 (* 8 i))) 32)
                 (bit-shift-left (hash8 (+ 4 (* 8 i))) 24)
                 (bit-shift-left (hash8 (+ 5 (* 8 i))) 16)
                 (bit-shift-left (hash8 (+ 6 (* 8 i))) 8)
                 (hash8 (+ 7 (* 8 i)))))
            (range 4))))
(defn hash16->hash8
  "Convert a vector 2-byte words into a vector of bytes."
  [hash16]
  (vec (mapcat (fn [word]
                 [(bit-and (bit-shift-right word 8) 0xFF)
                  (bit-and word 0xFF)])
               hash16)))
(defn hash32->hash8
  "Convert a vector of 4-byte words into a vector of bytes."
  [hash32]
  (vec (mapcat (fn [word]
                 [(bit-and (bit-shift-right word 24) 0xFF)
                  (bit-and (bit-shift-right word 16) 0xFF)
                  (bit-and (bit-shift-right word 8) 0xFF)
                  (bit-and word 0xFF)])
               hash32)))
(defn hash64->hash8
  "Convert a vector of 8-byte words into a vector of bytes."
  [hash64]
  (vec (mapcat (fn [word]
                 [(bit-and (bit-shift-right word 56) 0xFF)
                  (bit-and (bit-shift-right word 48) 0xFF)
                  (bit-and (bit-shift-right word 40) 0xFF)
                  (bit-and (bit-shift-right word 32) 0xFF)
                  (bit-and (bit-shift-right word 24) 0xFF)
                  (bit-and (bit-shift-right word 16) 0xFF)
                  (bit-and (bit-shift-right word 8) 0xFF)
                  (bit-and word 0xFF)])
               hash64)))
(def hex->utm8
  "Convert a hex string to an upper triangular matrix with 8-bit cells."
  (comp hash8->utm8 hex->hash8))
(def hex->utm16
  "Convert a hex string to an upper triangular matrix with 16-bit cells."
  (comp hash16->utm16 hash8->hash16 hex->hash8))
(def hex->utm32
  "Convert a hex string to an upper triangular matrix with 32-bit cells."
  (comp hash32->utm32 hash8->hash32 hex->hash8))
(def hex->utm64
  "Convert a hex string to an upper triangular matrix with 32-bit cells."
  (comp hash64->utm64 hash8->hash64 hex->hash8))
(def utm8->hex
  "Convert an upper triangular matrix with 8-bit cells to a hex string."
  (comp hash8->hex utm8->hash8))
(def utm16->hex
  "Convert an upper triangular matrix with 16-bit cells to a hex string."
  (comp hash8->hex hash16->hash8 utm16->hash16))
(def utm32->hex
  "Convert an upper triangular matrix with 32-bit cells to a hex string."
  (comp hash8->hex hash32->hash8 utm32->hash32))
(def utm64->hex
  "Convert an upper triangular matrix with 64-bit cells to a hex string."
  (comp hash8->hex hash64->hash8 utm64->hash64))
(defn with-conversion
  "Use given converters and return a high order function that converts incoming
  parameters and return value."
  [to-fn from-fn]
  (fn
    [f & args]
    (->> args
         (map to-fn)
         (apply f)
         (from-fn))))
(def apply-hash8
  "Return a fn that takes `f` and applies it to 32-byte hashes, converting them
  and then applying `f` to them."
  (with-conversion hex->utm8 utm8->hex))
(def apply-hash16
  "Return a fn that takes 32-byte hashes, converts them into a utm of 2-byte
  words per cell and then applies `f` to them."
  (with-conversion hex->utm16 utm16->hex))
(def apply-hash32
  "Return a fn that takes 32-byte hashes, converts them into a utm of 4-byte
  words per cell and then applies `f` to them."
  (with-conversion hex->utm32 utm32->hex))
(def apply-hash64
  "Return a fn that takes 32-byte hashes, converts them into a utm of 8-byte
  words per cell and then applies `f` to them."
  (with-conversion hex->utm64 utm64->hex))

Example Multiplications

Here are some example multiplications of two random 32-byte hashes using different bit sizes for the cells of the upper triangular matrices.

(let [a (random-hex 32)
      b (random-hex 32)]
  (kind/table
   {:row-vectors
    {:a a
     :b b
     :b8 (apply-hash8 utm-multiply a b)
     :b16 (apply-hash16 utm-multiply a b)
     :b32 (apply-hash32 utm-multiply a b)
     :b64 (apply-hash64 utm-multiply a b)}}))
a 930222511c9b3c7e1d98fb779784653447cb7793628b4176549355cf67c9a200
b 7782742a0cc6743b28ec3b5eeab81e17d0916790658a53f294cbd176b89a9642
b8 0884967a2860b0b8ea6cc8a0287858f27c9af0ae0abad886ecbcd47c5646fca8
b16 0a84967a2960b0b8468436d48890d9f0ec12534a995ab84444b088f4cca45b26
b32 0a84967a2961b0b8468536d4823c834a480d7bcc842ed5ac12cdba8ab2fbb4ce
b64 0a84967b2961b0b8468536d6823c834a185cdf23c81595686921730c89fd6b94

Experiment 1: Random Fuses

This experiment is run with two different hashes which are fused onto an accumulator iteratively. For each iteration, one of the two hashes is randomly selected and is fused to the accumulator. This random fusing is repeated many times and the quality of the accumulator is measured both by keeping track of global uniqueness after each fuse and by the uniform distribution of bit values.

(defn random-fuses
  "Perform random fuses of two hashes onto an accumulator keeping track of all
  unique hashes produced and all duplicate hashes produced. Repeat this for all
  four utm sizes based on cell bit size."
  []
  (let [hashes {:a (random-hex 32)
                :b (random-hex 32)}
        ;; convert hashes to utms for each bit size and store in a map
        utms {8  (update-vals hashes hex->utm8)
              16 (update-vals hashes hex->utm16)
              32 (update-vals hashes hex->utm32)
              64 (update-vals hashes hex->utm64)}
        results {8  {:acc (hex->utm8 zero-hex)
                     :unique   #{}
                     :duplicates #{}}
                 16 {:acc (hex->utm16 zero-hex)
                     :unique   #{}
                     :duplicates #{}}
                 32 {:acc (hex->utm32 zero-hex)
                     :unique   #{}
                     :duplicates #{}}
                 64 {:acc (hex->utm64 zero-hex)
                     :unique   #{}
                     :duplicates #{}}}
        results (reduce
                 (fn [results _]
                   (reduce
                    (fn [results bit-size]
                      (let [curr-acc (get-in results [bit-size :acc])
                            ;; randomly select one of the two hashes
                            selected-hash (if (< (rand) 0.5)
                                            (get-in utms [bit-size :a])
                                            (get-in utms [bit-size :b]))
                            ;; fuse the selected hash onto the accumulator
                            new-acc (utm-multiply curr-acc selected-hash)]
                        ;; update results with new accumulator and uniqueness info
                        (if (contains? (get-in results [bit-size :unique]) new-acc)
                          (update-in results [bit-size :duplicates] conj new-acc)
                          (-> results
                              (assoc-in [bit-size :acc] new-acc)
                              (update-in [bit-size :unique] conj new-acc)))))
                    results
                    [8 16 32 64]))
                 results
                 (range 10000))]
    ;; convert final results to totals of unique and duplicate hashes
    (->> results
         (map (fn [[bit-size {:keys [unique duplicates]}]]
                {:bit-size   bit-size
                 :unique     (count unique)
                 :duplicates (count duplicates)}))
         (kind/table))))
(random-fuses)
bit-size unique duplicates
8 10000 0
16 10000 0
32 10000 0
64 10000 0

Experiment 2: Folded Fuses

This experiment is run with a hash fused together with itself (i.e. folding) and then the result in turn fused with itself and so on. This folding is repeated many times and the quality of the accumulator is measured both by keeping track of global uniqueness after each fuse and by the uniform distribution of bit values. Once the lower bits of the accumulator become all zero, the folding stops and the number of folds to reach this state is recorded.

(defn zero-in-low-bits?
  "Return true if the lower bits of the utm are all zero."
  [utm bit-size]
  (let [bit-mask (bit-shift-right Long/MAX_VALUE (- 64 bit-size))]
    (every?
     (fn [[i j]]
       (or (<= j i)
           (zero? (bit-and bit-mask (get-in utm [i j])))))
     (for [i (range (count utm))
           j (range (count utm))]
       [i j]))))
(defn repeat-fold
  [starting-utm low-bit-size]
  (loop [new-fold starting-utm
         folds []]
    (let [folds (conj folds new-fold)]
      (if (or (zero-in-low-bits? new-fold low-bit-size)
              (>= (count folds) 100))
        folds
        (recur (utm-multiply new-fold new-fold)
               folds)))))
(defn folded-fuses
  "Perform folded fuses starting with a given hash and keeping track of of when
  folding produces the zero hash. Continue folding until the zero hash is found
  or 1000 folds occur and report the number of folds performed. Repeat this for
  all four utm sizes based on cell bit size and for different lower bit sizes."
  []
  (let [hash (random-hex 32)
        starting-utms {8  (hex->utm8 hash)
                       16 (hex->utm16 hash)
                       32 (hex->utm32 hash)
                       64 (hex->utm64 hash)}
        utm->hex-fns {8  utm8->hex
                      16 utm16->hex
                      32 utm32->hex
                      64 utm64->hex}
        result
        (reduce
         (fn [result bit-size]
           (assoc result bit-size
                  (reduce
                   (fn [result lower-bit-divider]
                     (let [utm->hex (get utm->hex-fns bit-size)
                           low-bit-size (quot bit-size lower-bit-divider)]
                       (assoc result low-bit-size
                              (->> (repeat-fold (get starting-utms bit-size)
                                                low-bit-size)
                                   (map utm->hex)))))
                   {}
                   [1 2 3 4 8])))
         {}
         [8 16 32 64])]

    ;; return a result with values converted back to hex strings
    (->> (for [[bit-size folds-map] result
               [low-bit-size folds] folds-map]
           {:bit-size           bit-size
            :low-bit-size  low-bit-size
            :folds-to-zero (if (< (count folds) 100) (count folds) 'NA)
            :folds folds})
         (kind/table))))
(folded-fuses)
bit-size low-bit-size folds-to-zero folds
8 8 8
("79d203c6a4f10ad9386d02a310cc74510e10336165c862b337e0475f2411e5e1"
 "f0a4048c48e014b0b24e561c840272cc0e5036105444422c5484106a6ca6d648"
 "e048081890c02860242cdc980884a480dc401c0050043c88d84c1070985c2090"
 "c0901030208050c0489878b0100848a0b800f880407858d070a8e0d030f89020"
 "802020604000a0809030f060201090c07000f00000b030a0e090c06060f06040"
 "004040c0800040002060e0c040202080e000e00000606040c02080c0c0e0c080"
 "008080800000800040c0c08080404000c000c00000c0c0808040008080c08000"
 "0000000000000000808080000080800080008000008080000080000000800000")
8 4 4
("79d203c6a4f10ad9386d02a310cc74510e10336165c862b337e0475f2411e5e1"
 "f0a4048c48e014b0b24e561c840272cc0e5036105444422c5484106a6ca6d648"
 "e048081890c02860242cdc980884a480dc401c0050043c88d84c1070985c2090"
 "c0901030208050c0489878b0100848a0b800f880407858d070a8e0d030f89020")
8 2 2
("79d203c6a4f10ad9386d02a310cc74510e10336165c862b337e0475f2411e5e1"
 "f0a4048c48e014b0b24e561c840272cc0e5036105444422c5484106a6ca6d648")
8 1 1
("79d203c6a4f10ad9386d02a310cc74510e10336165c862b337e0475f2411e5e1")
16 16 16
("79d203c6a4f10ad9386d02a310cc74510e10336165c862b337e0475f2411e5e1"
 "f3a4078c49e015b070d80544d0044e0656687d24ff0e986c6ee06bda8346856c"
 "e7480f1893c02b60e1b00a8859b8228cd6d046c8d3746bd809005a248b046518"
 "ce901e30278056c0c36015109a305f1855a0bf90a448a3b07f006e082fe87eb0"
 "9d203c604f00ad8086c02a20cf6026304b4047207e107760b20043100750eb60"
 "3a4078c09e005b000d8054400ac0ec601680ae40d220aec034002220aca06ec0"
 "7480f1803c00b6001b00a880c58058c02d00dc80fc405d80a800b440d1403d80"
 "e900e30078006c00360051004b00b1805a00b9005880bb00500028808280fb00"
 "d200c600f000d8006c00a20096006300b400720031007600a00051008500f600"
 "a4008c00e000b000d80044002c00c6006800e4006200ec004000a2000a00ec00"
 "48001800c0006000b000880058008c00d000c800c400d800800044001400d800"
 "900030008000c00060001000b0001800a00090008800b000000088002800b000"
 "2000600000008000c00020006000300040002000100060000000100050006000"
 "4000c0000000000080004000c0006000800040002000c00000002000a000c000"
 "8000800000000000000080008000c00000008000400080000000400040008000"
 "0000000000000000000000000000800000000000800000000000800080000000")
16 8 8
("79d203c6a4f10ad9386d02a310cc74510e10336165c862b337e0475f2411e5e1"
 "f3a4078c49e015b070d80544d0044e0656687d24ff0e986c6ee06bda8346856c"
 "e7480f1893c02b60e1b00a8859b8228cd6d046c8d3746bd809005a248b046518"
 "ce901e30278056c0c36015109a305f1855a0bf90a448a3b07f006e082fe87eb0"
 "9d203c604f00ad8086c02a20cf6026304b4047207e107760b20043100750eb60"
 "3a4078c09e005b000d8054400ac0ec601680ae40d220aec034002220aca06ec0"
 "7480f1803c00b6001b00a880c58058c02d00dc80fc405d80a800b440d1403d80"
 "e900e30078006c00360051004b00b1805a00b9005880bb00500028808280fb00")
16 5 5
("79d203c6a4f10ad9386d02a310cc74510e10336165c862b337e0475f2411e5e1"
 "f3a4078c49e015b070d80544d0044e0656687d24ff0e986c6ee06bda8346856c"
 "e7480f1893c02b60e1b00a8859b8228cd6d046c8d3746bd809005a248b046518"
 "ce901e30278056c0c36015109a305f1855a0bf90a448a3b07f006e082fe87eb0"
 "9d203c604f00ad8086c02a20cf6026304b4047207e107760b20043100750eb60")
16 4 4
("79d203c6a4f10ad9386d02a310cc74510e10336165c862b337e0475f2411e5e1"
 "f3a4078c49e015b070d80544d0044e0656687d24ff0e986c6ee06bda8346856c"
 "e7480f1893c02b60e1b00a8859b8228cd6d046c8d3746bd809005a248b046518"
 "ce901e30278056c0c36015109a305f1855a0bf90a448a3b07f006e082fe87eb0")
16 2 2
("79d203c6a4f10ad9386d02a310cc74510e10336165c862b337e0475f2411e5e1"
 "f3a4078c49e015b070d80544d0044e0656687d24ff0e986c6ee06bda8346856c")
32 32 32
("79d203c6a4f10ad9386d02a310cc74510e10336165c862b337e0475f2411e5e1"
 "f3a4078c49e215b070da05442198e8a0f8b15596c9855f8e86b178621922b3f4"
 "e7480f1893c42b60e1b40a884331d1407c5e576c1564f1dc81de8844154d3568"
 "ce901e30278856c0c36815108663a28024ab5fd83432aeb8d5ab6e88c595a4d0"
 "9d203c604f10ad8086d02a200cc74500f91183b08e088970f31055106df851a0"
 "3a4078c09e215b000da05440198e8a00b10e1760b29dc2e005068a201e25c340"
 "7480f1803c42b6001b40a880331d14005dc86ec0bf6e45c085a49440fd280680"
 "e901e30078856c0036815100663a2800aa41dd80e7a78b80f9a72880be020d00"
 "d203c600f10ad8006d02a200cc7450000f47bb00727b1700acc651008ccc1a00"
 "a4078c00e215b000da05440098e8a000099f760071a62e003f6ca2006cb83400"
 "480f1800c42b6000b40a880031d14000bf7eec00160c5c0016594400a5f06800"
 "901e30008856c0006815100063a280002ffdd800f718b8008ab288007de0d000"
 "203c600010ad8000d02a2000c745000023fbb0001a3170008d651000c3c1a000"
 "4078c000215b0000a05440008e8a000057f76000e462e000faca2000a7834000"
 "80f1800042b6000040a880001d140000efeec00088c5c00075944000cf068000"
 "01e30000856c0000815100003a280000dfdd8000118b8000eb2880009e0d0000"
 "03c600000ad8000002a2000074500000bfbb000023170000d65100003c1a0000"
 "078c000015b0000005440000e8a000007f760000462e0000aca2000078340000"
 "0f1800002b6000000a880000d1400000feec00008c5c000059440000f0680000"
 "1e30000056c0000015100000a2800000fdd8000018b80000b2880000e0d00000"
 "3c600000ad8000002a20000045000000fbb000003170000065100000c1a00000"
 "78c000005b000000544000008a000000f760000062e00000ca20000083400000"
 "f1800000b6000000a880000014000000eec00000c5c000009440000006800000"
 "e30000006c0000005100000028000000dd8000008b800000288000000d000000"
 "c6000000d8000000a200000050000000bb00000017000000510000001a000000"
 "8c000000b000000044000000a0000000760000002e000000a200000034000000"
 "18000000600000008800000040000000ec0000005c0000004400000068000000"
 "30000000c00000001000000080000000d8000000b800000088000000d0000000"
 "60000000800000002000000000000000b00000007000000010000000a0000000"
 "c000000000000000400000000000000060000000e00000002000000040000000"
 "80000000000000008000000000000000c0000000c00000004000000080000000"
 "0000000000000000000000000000000080000000800000008000000000000000")
32 16 16
("79d203c6a4f10ad9386d02a310cc74510e10336165c862b337e0475f2411e5e1"
 "f3a4078c49e215b070da05442198e8a0f8b15596c9855f8e86b178621922b3f4"
 "e7480f1893c42b60e1b40a884331d1407c5e576c1564f1dc81de8844154d3568"
 "ce901e30278856c0c36815108663a28024ab5fd83432aeb8d5ab6e88c595a4d0"
 "9d203c604f10ad8086d02a200cc74500f91183b08e088970f31055106df851a0"
 "3a4078c09e215b000da05440198e8a00b10e1760b29dc2e005068a201e25c340"
 "7480f1803c42b6001b40a880331d14005dc86ec0bf6e45c085a49440fd280680"
 "e901e30078856c0036815100663a2800aa41dd80e7a78b80f9a72880be020d00"
 "d203c600f10ad8006d02a200cc7450000f47bb00727b1700acc651008ccc1a00"
 "a4078c00e215b000da05440098e8a000099f760071a62e003f6ca2006cb83400"
 "480f1800c42b6000b40a880031d14000bf7eec00160c5c0016594400a5f06800"
 "901e30008856c0006815100063a280002ffdd800f718b8008ab288007de0d000"
 "203c600010ad8000d02a2000c745000023fbb0001a3170008d651000c3c1a000"
 "4078c000215b0000a05440008e8a000057f76000e462e000faca2000a7834000"
 "80f1800042b6000040a880001d140000efeec00088c5c00075944000cf068000"
 "01e30000856c0000815100003a280000dfdd8000118b8000eb2880009e0d0000")
32 10 10
("79d203c6a4f10ad9386d02a310cc74510e10336165c862b337e0475f2411e5e1"
 "f3a4078c49e215b070da05442198e8a0f8b15596c9855f8e86b178621922b3f4"
 "e7480f1893c42b60e1b40a884331d1407c5e576c1564f1dc81de8844154d3568"
 "ce901e30278856c0c36815108663a28024ab5fd83432aeb8d5ab6e88c595a4d0"
 "9d203c604f10ad8086d02a200cc74500f91183b08e088970f31055106df851a0"
 "3a4078c09e215b000da05440198e8a00b10e1760b29dc2e005068a201e25c340"
 "7480f1803c42b6001b40a880331d14005dc86ec0bf6e45c085a49440fd280680"
 "e901e30078856c0036815100663a2800aa41dd80e7a78b80f9a72880be020d00"
 "d203c600f10ad8006d02a200cc7450000f47bb00727b1700acc651008ccc1a00"
 "a4078c00e215b000da05440098e8a000099f760071a62e003f6ca2006cb83400")
32 8 8
("79d203c6a4f10ad9386d02a310cc74510e10336165c862b337e0475f2411e5e1"
 "f3a4078c49e215b070da05442198e8a0f8b15596c9855f8e86b178621922b3f4"
 "e7480f1893c42b60e1b40a884331d1407c5e576c1564f1dc81de8844154d3568"
 "ce901e30278856c0c36815108663a28024ab5fd83432aeb8d5ab6e88c595a4d0"
 "9d203c604f10ad8086d02a200cc74500f91183b08e088970f31055106df851a0"
 "3a4078c09e215b000da05440198e8a00b10e1760b29dc2e005068a201e25c340"
 "7480f1803c42b6001b40a880331d14005dc86ec0bf6e45c085a49440fd280680"
 "e901e30078856c0036815100663a2800aa41dd80e7a78b80f9a72880be020d00")
32 4 4
("79d203c6a4f10ad9386d02a310cc74510e10336165c862b337e0475f2411e5e1"
 "f3a4078c49e215b070da05442198e8a0f8b15596c9855f8e86b178621922b3f4"
 "e7480f1893c42b60e1b40a884331d1407c5e576c1564f1dc81de8844154d3568"
 "ce901e30278856c0c36815108663a28024ab5fd83432aeb8d5ab6e88c595a4d0")
64 64 63
("79d203c6a4f10ad9386d02a310cc74510e10336165c862b337e0475f2411e5e1"
 "73a4078d49e215b070da05462198e8a01c2066c2cb90c5640f78de42e63e8e68"
 "67480f1a93c42b6061b40a8c4331d1403840cd8597218ac854d6e0f16df22ad0"
 "4e901e35278856c0436815188663a28070819b0b2e4315900142539161b88da0"
 "1d203c6a4f10ad8006d02a310cc74500610336165c862b2060d6eddcdac1fb40"
 "3a4078d49e215b000da05462198e8a0042066c2cb90c56403af6f6a212c77680"
 "7480f1a93c42b6001b40a8c4331d1400040cd8597218ac805b1258e59a9ced00"
 "6901e35278856c0036815188663a28000819b0b2e43159004ab660510971da00"
 "5203c6a4f10ad8006d02a310cc74500010336165c862b20067b37ab963c3b400"
 "24078d49e215b0005a05462198e8a0002066c2cb90c564001881ddd00b076800"
 "480f1a93c42b6000340a8c4331d1400040cd8597218ac800556f5d15240ed000"
 "101e35278856c0006815188663a28000019b0b2e431590003c8d3ffe801da000"
 "203c6a4f10ad8000502a310cc74500000336165c862b20003fd4974de03b4000"
 "4078d49e215b0000205462198e8a0000066c2cb90c5640001a918bdf40768000"
 "00f1a93c42b6000040a8c4331d1400000cd8597218ac800020c48ccc80ed0000"
 "01e35278856c0000015188663a28000019b0b2e431590000700eedd101da0000"
 "03c6a4f10ad8000002a310cc74500000336165c862b200001a352c8203b40000"
 "078d49e215b0000005462198e8a0000066c2cb90c56400001cc79c8407680000"
 "0f1a93c42b6000000a8c4331d14000004d8597218ac800005b0447080ed00000"
 "1e35278856c0000015188663a28000001b0b2e43159000003bdcc6101da00000"
 "3c6a4f10ad8000002a310cc74500000036165c862b2000000f0a6c203b400000"
 "78d49e215b0000005462198e8a0000006c2cb90c564000007b58584076800000"
 "71a93c42b600000028c4331d1400000058597218ac8000006bbeb080ed000000"
 "635278856c0000005188663a2800000030b2e431590000002bb56101da000000"
 "46a4f10ad80000002310cc74500000006165c862b2000000284ac203b4000000"
 "0d49e215b0000000462198e8a000000042cb90c5640000001415840768000000"
 "1a93c42b600000000c4331d1400000000597218ac8000000362b080ed0000000"
 "35278856c0000000188663a2800000000b2e4315900000002456101da0000000"
 "6a4f10ad80000000310cc74500000000165c862b2000000028ac203b40000000"
 "549e215b0000000062198e8a000000002cb90c56400000005158407680000000"
 "293c42b60000000044331d1400000000597218ac8000000022b080ed00000000"
 "5278856c0000000008663a280000000032e4315900000000456101da00000000"
 "24f10ad80000000010cc74500000000065c862b2000000000ac203b400000000"
 "49e215b0000000002198e8a0000000004b90c564000000001584076800000000"
 "13c42b60000000004331d1400000000017218ac8000000002b080ed000000000"
 "278856c0000000000663a280000000002e4315900000000056101da000000000"
 "4f10ad80000000000cc74500000000005c862b20000000002c203b4000000000"
 "1e215b0000000000198e8a0000000000390c5640000000005840768000000000"
 "3c42b60000000000331d1400000000007218ac80000000003080ed0000000000"
 "78856c0000000000663a28000000000064315900000000006101da0000000000"
 "710ad800000000004c745000000000004862b200000000004203b40000000000"
 "6215b0000000000018e8a0000000000010c56400000000000407680000000000"
 "442b60000000000031d1400000000000218ac80000000000080ed00000000000"
 "0856c0000000000063a28000000000004315900000000000101da00000000000"
 "10ad8000000000004745000000000000062b200000000000203b400000000000"
 "215b0000000000000e8a0000000000000c564000000000004076800000000000"
 "42b60000000000001d1400000000000018ac80000000000000ed000000000000"
 "056c0000000000003a28000000000000315900000000000001da000000000000"
 "0ad8000000000000745000000000000062b200000000000003b4000000000000"
 "15b000000000000068a000000000000045640000000000000768000000000000"
 "2b6000000000000051400000000000000ac80000000000000ed0000000000000"
 "56c0000000000000228000000000000015900000000000001da0000000000000"
 "2d8000000000000045000000000000002b200000000000003b40000000000000"
 "5b000000000000000a0000000000000056400000000000007680000000000000"
 "360000000000000014000000000000002c800000000000006d00000000000000"
 "6c00000000000000280000000000000059000000000000005a00000000000000"
 "5800000000000000500000000000000032000000000000003400000000000000"
 "3000000000000000200000000000000064000000000000006800000000000000"
 "6000000000000000400000000000000048000000000000005000000000000000"
 "4000000000000000000000000000000010000000000000002000000000000000"
 "0000000000000000000000000000000020000000000000004000000000000000"
 "0000000000000000000000000000000040000000000000000000000000000000"
 "0000000000000000000000000000000000000000000000000000000000000000")
64 32 31
("79d203c6a4f10ad9386d02a310cc74510e10336165c862b337e0475f2411e5e1"
 "73a4078d49e215b070da05462198e8a01c2066c2cb90c5640f78de42e63e8e68"
 "67480f1a93c42b6061b40a8c4331d1403840cd8597218ac854d6e0f16df22ad0"
 "4e901e35278856c0436815188663a28070819b0b2e4315900142539161b88da0"
 "1d203c6a4f10ad8006d02a310cc74500610336165c862b2060d6eddcdac1fb40"
 "3a4078d49e215b000da05462198e8a0042066c2cb90c56403af6f6a212c77680"
 "7480f1a93c42b6001b40a8c4331d1400040cd8597218ac805b1258e59a9ced00"
 "6901e35278856c0036815188663a28000819b0b2e43159004ab660510971da00"
 "5203c6a4f10ad8006d02a310cc74500010336165c862b20067b37ab963c3b400"
 "24078d49e215b0005a05462198e8a0002066c2cb90c564001881ddd00b076800"
 "480f1a93c42b6000340a8c4331d1400040cd8597218ac800556f5d15240ed000"
 "101e35278856c0006815188663a28000019b0b2e431590003c8d3ffe801da000"
 "203c6a4f10ad8000502a310cc74500000336165c862b20003fd4974de03b4000"
 "4078d49e215b0000205462198e8a0000066c2cb90c5640001a918bdf40768000"
 "00f1a93c42b6000040a8c4331d1400000cd8597218ac800020c48ccc80ed0000"
 "01e35278856c0000015188663a28000019b0b2e431590000700eedd101da0000"
 "03c6a4f10ad8000002a310cc74500000336165c862b200001a352c8203b40000"
 "078d49e215b0000005462198e8a0000066c2cb90c56400001cc79c8407680000"
 "0f1a93c42b6000000a8c4331d14000004d8597218ac800005b0447080ed00000"
 "1e35278856c0000015188663a28000001b0b2e43159000003bdcc6101da00000"
 "3c6a4f10ad8000002a310cc74500000036165c862b2000000f0a6c203b400000"
 "78d49e215b0000005462198e8a0000006c2cb90c564000007b58584076800000"
 "71a93c42b600000028c4331d1400000058597218ac8000006bbeb080ed000000"
 "635278856c0000005188663a2800000030b2e431590000002bb56101da000000"
 "46a4f10ad80000002310cc74500000006165c862b2000000284ac203b4000000"
 "0d49e215b0000000462198e8a000000042cb90c5640000001415840768000000"
 "1a93c42b600000000c4331d1400000000597218ac8000000362b080ed0000000"
 "35278856c0000000188663a2800000000b2e4315900000002456101da0000000"
 "6a4f10ad80000000310cc74500000000165c862b2000000028ac203b40000000"
 "549e215b0000000062198e8a000000002cb90c56400000005158407680000000"
 "293c42b60000000044331d1400000000597218ac8000000022b080ed00000000")
64 21 20
("79d203c6a4f10ad9386d02a310cc74510e10336165c862b337e0475f2411e5e1"
 "73a4078d49e215b070da05462198e8a01c2066c2cb90c5640f78de42e63e8e68"
 "67480f1a93c42b6061b40a8c4331d1403840cd8597218ac854d6e0f16df22ad0"
 "4e901e35278856c0436815188663a28070819b0b2e4315900142539161b88da0"
 "1d203c6a4f10ad8006d02a310cc74500610336165c862b2060d6eddcdac1fb40"
 "3a4078d49e215b000da05462198e8a0042066c2cb90c56403af6f6a212c77680"
 "7480f1a93c42b6001b40a8c4331d1400040cd8597218ac805b1258e59a9ced00"
 "6901e35278856c0036815188663a28000819b0b2e43159004ab660510971da00"
 "5203c6a4f10ad8006d02a310cc74500010336165c862b20067b37ab963c3b400"
 "24078d49e215b0005a05462198e8a0002066c2cb90c564001881ddd00b076800"
 "480f1a93c42b6000340a8c4331d1400040cd8597218ac800556f5d15240ed000"
 "101e35278856c0006815188663a28000019b0b2e431590003c8d3ffe801da000"
 "203c6a4f10ad8000502a310cc74500000336165c862b20003fd4974de03b4000"
 "4078d49e215b0000205462198e8a0000066c2cb90c5640001a918bdf40768000"
 "00f1a93c42b6000040a8c4331d1400000cd8597218ac800020c48ccc80ed0000"
 "01e35278856c0000015188663a28000019b0b2e431590000700eedd101da0000"
 "03c6a4f10ad8000002a310cc74500000336165c862b200001a352c8203b40000"
 "078d49e215b0000005462198e8a0000066c2cb90c56400001cc79c8407680000"
 "0f1a93c42b6000000a8c4331d14000004d8597218ac800005b0447080ed00000"
 "1e35278856c0000015188663a28000001b0b2e43159000003bdcc6101da00000")
64 16 15
("79d203c6a4f10ad9386d02a310cc74510e10336165c862b337e0475f2411e5e1"
 "73a4078d49e215b070da05462198e8a01c2066c2cb90c5640f78de42e63e8e68"
 "67480f1a93c42b6061b40a8c4331d1403840cd8597218ac854d6e0f16df22ad0"
 "4e901e35278856c0436815188663a28070819b0b2e4315900142539161b88da0"
 "1d203c6a4f10ad8006d02a310cc74500610336165c862b2060d6eddcdac1fb40"
 "3a4078d49e215b000da05462198e8a0042066c2cb90c56403af6f6a212c77680"
 "7480f1a93c42b6001b40a8c4331d1400040cd8597218ac805b1258e59a9ced00"
 "6901e35278856c0036815188663a28000819b0b2e43159004ab660510971da00"
 "5203c6a4f10ad8006d02a310cc74500010336165c862b20067b37ab963c3b400"
 "24078d49e215b0005a05462198e8a0002066c2cb90c564001881ddd00b076800"
 "480f1a93c42b6000340a8c4331d1400040cd8597218ac800556f5d15240ed000"
 "101e35278856c0006815188663a28000019b0b2e431590003c8d3ffe801da000"
 "203c6a4f10ad8000502a310cc74500000336165c862b20003fd4974de03b4000"
 "4078d49e215b0000205462198e8a0000066c2cb90c5640001a918bdf40768000"
 "00f1a93c42b6000040a8c4331d1400000cd8597218ac800020c48ccc80ed0000")
64 8 7
("79d203c6a4f10ad9386d02a310cc74510e10336165c862b337e0475f2411e5e1"
 "73a4078d49e215b070da05462198e8a01c2066c2cb90c5640f78de42e63e8e68"
 "67480f1a93c42b6061b40a8c4331d1403840cd8597218ac854d6e0f16df22ad0"
 "4e901e35278856c0436815188663a28070819b0b2e4315900142539161b88da0"
 "1d203c6a4f10ad8006d02a310cc74500610336165c862b2060d6eddcdac1fb40"
 "3a4078d49e215b000da05462198e8a0042066c2cb90c56403af6f6a212c77680"
 "7480f1a93c42b6001b40a8c4331d1400040cd8597218ac805b1258e59a9ced00")

Conclusion

This article has described a method for fusing hashes together using upper triangular matrix multiplication. The method is associative and non-commutative.

Final conclusion is to use 64 bit cells with 32 lower bits to tolerate many repeated values.

source: src/math/hashing/hashfusing.clj