package multihash

  1. Overview
  2. Docs
Self-describing Hash Functions


Dune Dependency






Multihashes are self-describing hashes. That means that they encode both the hash digest of some value and also the digest length and the hash function identifier as per the multicodec.

# #require "multihash";;
# #require "digestif.ocaml";;
# #require "multihash-digestif";;


The following section explains how to use multihash and multihash-digestif.


The multihash library is implementation-agnostic. It provides a functor for creating a new module which can actually perform the digesting of values. This might be useful because OCaml has quite a few hashing libraries including:

# #show_module_type Multihash__Multihash_intf.Hasher;;
module type Hasher =
    val digest :
      Multicodec.multihash ->
      Cstruct.t -> (Cstruct.t, [ `Msg of string | `Unsupported ]) result
    val digest_string :
      Multicodec.multihash ->
      string -> (string, [ `Msg of string | `Unsupported ]) result
    val iter :
      Multicodec.multihash ->
      ((Cstruct.t -> unit) -> unit) ->
      (Cstruct.t, [ `Msg of string | `Unsupported ]) result
    val iter_string :
      Multicodec.multihash ->
      ((string -> unit) -> unit) ->
      (string, [ `Msg of string | `Unsupported ]) result
    val is_supported : Multicodec.multihash -> bool

An implementation must provide a means to digest a value and also a function detailing which hash functions are supported by the implementation.


multihash-digestif is a multihash library implemented with digestif. Note this library will force you to decide between the C and OCaml implementation of digestif just like any other library with a digestif dependency.

module Md = Multihash_digestif
let s = "Merkle–Damgård"

It might be nice to alias the library as we've done here to Md. Creating a new multihash from some string is as simple as.

# let v = Md.of_string `Sha2_256 s |> Result.get_ok;;
val v : string Md.t = <abstr>

Note that a multihash is also "tagged" with the internal representation of the digest. We expose two main representations, string and Cstruct.t. This is mainly to help with avoiding copying bytes when using this library with other libraries. So Md.of_string keeps the digest in the string representation. Note that there are copying conversion functions in Md.Conv.

Having now digested the data, it can be converted to the full sequence of bytes. We write the bytes out as the internal representation. Unfortunately the bytes aren't necessarily UTF-8 and that breaks MDX for some reason, so we'll convert them to Cstructs.

# let data = Md.write v |> Cstruct.of_string;;
val data : Cstruct.t = {Cstruct.buffer = <abstr>; off = 0; len = 34}
# let () = hexdump data;;
12 20 41 dd 7b 64 43 54  2e 75 70 1a a9 8a 0c 23
59 51 a2 8a 0d 85 1b 11  56 4d 20 02 2a b1 1d 25
89 a8

And of course the hash function used and the length are recoverable from the data by reading it back in.

# let v = Md.read_buff data |> Result.get_ok;;
val v : Cstruct.t Md.t = <abstr>
# let (ident, length, digest) = 
  let ident = Multicodec.multihash_to_string (Md.get_hash v) in
  (ident, Md.get_length v, Md.get_digest v);;
val ident : string = "sha2-256"
val length : int = 32
val digest : Cstruct.t = {Cstruct.buffer = <abstr>; off = 2; len = 32}
# let () = hexdump digest;;
41 dd 7b 64 43 54 2e 75  70 1a a9 8a 0c 23 59 51
a2 8a 0d 85 1b 11 56 4d  20 02 2a b1 1d 25 89 a8

Innovation. Community. Security.