--- /dev/null
+// Package multihash is the Go implementation of
+// https://github.com/multiformats/multihash, or self-describing
+// hashes.
+package multihash
+
+import (
+ "encoding/binary"
+ "encoding/hex"
+ "errors"
+ "fmt"
+ "math"
+
+ b58 "github.com/mr-tron/base58/base58"
+)
+
+// errors
+var (
+ ErrUnknownCode = errors.New("unknown multihash code")
+ ErrTooShort = errors.New("multihash too short. must be >= 2 bytes")
+ ErrTooLong = errors.New("multihash too long. must be < 129 bytes")
+ ErrLenNotSupported = errors.New("multihash does not yet support digests longer than 127 bytes")
+ ErrInvalidMultihash = errors.New("input isn't valid multihash")
+
+ ErrVarintBufferShort = errors.New("uvarint: buffer too small")
+ ErrVarintTooLong = errors.New("uvarint: varint too big (max 64bit)")
+)
+
+// ErrInconsistentLen is returned when a decoded multihash has an inconsistent length
+type ErrInconsistentLen struct {
+ dm *DecodedMultihash
+}
+
+func (e ErrInconsistentLen) Error() string {
+ return fmt.Sprintf("multihash length inconsistent: %v", e.dm)
+}
+
+// constants
+const (
+ ID = 0x00
+ SHA1 = 0x11
+ SHA2_256 = 0x12
+ SHA2_512 = 0x13
+ SHA3_224 = 0x17
+ SHA3_256 = 0x16
+ SHA3_384 = 0x15
+ SHA3_512 = 0x14
+ SHA3 = SHA3_512
+ KECCAK_224 = 0x1A
+ KECCAK_256 = 0x1B
+ KECCAK_384 = 0x1C
+ KECCAK_512 = 0x1D
+
+ SHAKE_128 = 0x18
+ SHAKE_256 = 0x19
+
+ BLAKE2B_MIN = 0xb201
+ BLAKE2B_MAX = 0xb240
+ BLAKE2S_MIN = 0xb241
+ BLAKE2S_MAX = 0xb260
+
+ DBL_SHA2_256 = 0x56
+
+ MURMUR3 = 0x22
+
+ X11 = 0x1100
+)
+
+func init() {
+ // Add blake2b (64 codes)
+ for c := uint64(BLAKE2B_MIN); c <= BLAKE2B_MAX; c++ {
+ n := c - BLAKE2B_MIN + 1
+ name := fmt.Sprintf("blake2b-%d", n*8)
+ Names[name] = c
+ Codes[c] = name
+ DefaultLengths[c] = int(n)
+ }
+
+ // Add blake2s (32 codes)
+ for c := uint64(BLAKE2S_MIN); c <= BLAKE2S_MAX; c++ {
+ n := c - BLAKE2S_MIN + 1
+ name := fmt.Sprintf("blake2s-%d", n*8)
+ Names[name] = c
+ Codes[c] = name
+ DefaultLengths[c] = int(n)
+ }
+}
+
+// Names maps the name of a hash to the code
+var Names = map[string]uint64{
+ "id": ID,
+ "sha1": SHA1,
+ "sha2-256": SHA2_256,
+ "sha2-512": SHA2_512,
+ "sha3": SHA3_512,
+ "sha3-224": SHA3_224,
+ "sha3-256": SHA3_256,
+ "sha3-384": SHA3_384,
+ "sha3-512": SHA3_512,
+ "dbl-sha2-256": DBL_SHA2_256,
+ "murmur3": MURMUR3,
+ "keccak-224": KECCAK_224,
+ "keccak-256": KECCAK_256,
+ "keccak-384": KECCAK_384,
+ "keccak-512": KECCAK_512,
+ "shake-128": SHAKE_128,
+ "shake-256": SHAKE_256,
+ "x11": X11,
+}
+
+// Codes maps a hash code to it's name
+var Codes = map[uint64]string{
+ ID: "id",
+ SHA1: "sha1",
+ SHA2_256: "sha2-256",
+ SHA2_512: "sha2-512",
+ SHA3_224: "sha3-224",
+ SHA3_256: "sha3-256",
+ SHA3_384: "sha3-384",
+ SHA3_512: "sha3-512",
+ DBL_SHA2_256: "dbl-sha2-256",
+ MURMUR3: "murmur3",
+ KECCAK_224: "keccak-224",
+ KECCAK_256: "keccak-256",
+ KECCAK_384: "keccak-384",
+ KECCAK_512: "keccak-512",
+ SHAKE_128: "shake-128",
+ SHAKE_256: "shake-256",
+ X11: "x11",
+}
+
+// DefaultLengths maps a hash code to it's default length
+var DefaultLengths = map[uint64]int{
+ ID: -1,
+ SHA1: 20,
+ SHA2_256: 32,
+ SHA2_512: 64,
+ SHA3_224: 28,
+ SHA3_256: 32,
+ SHA3_384: 48,
+ SHA3_512: 64,
+ DBL_SHA2_256: 32,
+ KECCAK_224: 28,
+ KECCAK_256: 32,
+ MURMUR3: 4,
+ KECCAK_384: 48,
+ KECCAK_512: 64,
+ SHAKE_128: 32,
+ SHAKE_256: 64,
+ X11: 64,
+}
+
+func uvarint(buf []byte) (uint64, []byte, error) {
+ n, c := binary.Uvarint(buf)
+
+ if c == 0 {
+ return n, buf, ErrVarintBufferShort
+ } else if c < 0 {
+ return n, buf[-c:], ErrVarintTooLong
+ } else {
+ return n, buf[c:], nil
+ }
+}
+
+// DecodedMultihash represents a parsed multihash and allows
+// easy access to the different parts of a multihash.
+type DecodedMultihash struct {
+ Code uint64
+ Name string
+ Length int // Length is just int as it is type of len() opearator
+ Digest []byte // Digest holds the raw multihash bytes
+}
+
+// Multihash is byte slice with the following form:
+// <hash function code><digest size><hash function output>.
+// See the spec for more information.
+type Multihash []byte
+
+// HexString returns the hex-encoded representation of a multihash.
+func (m *Multihash) HexString() string {
+ return hex.EncodeToString([]byte(*m))
+}
+
+// String is an alias to HexString().
+func (m *Multihash) String() string {
+ return m.HexString()
+}
+
+// FromHexString parses a hex-encoded multihash.
+func FromHexString(s string) (Multihash, error) {
+ b, err := hex.DecodeString(s)
+ if err != nil {
+ return Multihash{}, err
+ }
+
+ return Cast(b)
+}
+
+// B58String returns the B58-encoded representation of a multihash.
+func (m Multihash) B58String() string {
+ return b58.Encode([]byte(m))
+}
+
+// FromB58String parses a B58-encoded multihash.
+func FromB58String(s string) (m Multihash, err error) {
+ b, err := b58.Decode(s)
+ if err != nil {
+ return Multihash{}, ErrInvalidMultihash
+ }
+
+ return Cast(b)
+}
+
+// Cast casts a buffer onto a multihash, and returns an error
+// if it does not work.
+func Cast(buf []byte) (Multihash, error) {
+ dm, err := Decode(buf)
+ if err != nil {
+ return Multihash{}, err
+ }
+
+ if !ValidCode(dm.Code) {
+ return Multihash{}, ErrUnknownCode
+ }
+
+ return Multihash(buf), nil
+}
+
+// Decode parses multihash bytes into a DecodedMultihash.
+func Decode(buf []byte) (*DecodedMultihash, error) {
+
+ if len(buf) < 2 {
+ return nil, ErrTooShort
+ }
+
+ var err error
+ var code, length uint64
+
+ code, buf, err = uvarint(buf)
+ if err != nil {
+ return nil, err
+ }
+
+ length, buf, err = uvarint(buf)
+ if err != nil {
+ return nil, err
+ }
+
+ if length > math.MaxInt32 {
+ return nil, errors.New("digest too long, supporting only <= 2^31-1")
+ }
+
+ dm := &DecodedMultihash{
+ Code: code,
+ Name: Codes[code],
+ Length: int(length),
+ Digest: buf,
+ }
+
+ if len(dm.Digest) != dm.Length {
+ return nil, ErrInconsistentLen{dm}
+ }
+
+ return dm, nil
+}
+
+// Encode a hash digest along with the specified function code.
+// Note: the length is derived from the length of the digest itself.
+func Encode(buf []byte, code uint64) ([]byte, error) {
+
+ if !ValidCode(code) {
+ return nil, ErrUnknownCode
+ }
+
+ start := make([]byte, 2*binary.MaxVarintLen64, 2*binary.MaxVarintLen64+len(buf))
+ spot := start
+ n := binary.PutUvarint(spot, code)
+ spot = start[n:]
+ n += binary.PutUvarint(spot, uint64(len(buf)))
+
+ return append(start[:n], buf...), nil
+}
+
+// EncodeName is like Encode() but providing a string name
+// instead of a numeric code. See Names for allowed values.
+func EncodeName(buf []byte, name string) ([]byte, error) {
+ return Encode(buf, Names[name])
+}
+
+// ValidCode checks whether a multihash code is valid.
+func ValidCode(code uint64) bool {
+ _, ok := Codes[code]
+ return ok
+}