1 // Package multihash is the Go implementation of
2 // https://github.com/multiformats/multihash, or self-describing
13 b58 "github.com/mr-tron/base58/base58"
18 ErrUnknownCode = errors.New("unknown multihash code")
19 ErrTooShort = errors.New("multihash too short. must be >= 2 bytes")
20 ErrTooLong = errors.New("multihash too long. must be < 129 bytes")
21 ErrLenNotSupported = errors.New("multihash does not yet support digests longer than 127 bytes")
22 ErrInvalidMultihash = errors.New("input isn't valid multihash")
24 ErrVarintBufferShort = errors.New("uvarint: buffer too small")
25 ErrVarintTooLong = errors.New("uvarint: varint too big (max 64bit)")
28 // ErrInconsistentLen is returned when a decoded multihash has an inconsistent length
29 type ErrInconsistentLen struct {
33 func (e ErrInconsistentLen) Error() string {
34 return fmt.Sprintf("multihash length inconsistent: %v", e.dm)
69 // Add blake2b (64 codes)
70 for c := uint64(BLAKE2B_MIN); c <= BLAKE2B_MAX; c++ {
71 n := c - BLAKE2B_MIN + 1
72 name := fmt.Sprintf("blake2b-%d", n*8)
75 DefaultLengths[c] = int(n)
78 // Add blake2s (32 codes)
79 for c := uint64(BLAKE2S_MIN); c <= BLAKE2S_MAX; c++ {
80 n := c - BLAKE2S_MIN + 1
81 name := fmt.Sprintf("blake2s-%d", n*8)
84 DefaultLengths[c] = int(n)
88 // Names maps the name of a hash to the code
89 var Names = map[string]uint64{
99 "dbl-sha2-256": DBL_SHA2_256,
101 "keccak-224": KECCAK_224,
102 "keccak-256": KECCAK_256,
103 "keccak-384": KECCAK_384,
104 "keccak-512": KECCAK_512,
105 "shake-128": SHAKE_128,
106 "shake-256": SHAKE_256,
110 // Codes maps a hash code to it's name
111 var Codes = map[uint64]string{
114 SHA2_256: "sha2-256",
115 SHA2_512: "sha2-512",
116 SHA3_224: "sha3-224",
117 SHA3_256: "sha3-256",
118 SHA3_384: "sha3-384",
119 SHA3_512: "sha3-512",
120 DBL_SHA2_256: "dbl-sha2-256",
122 KECCAK_224: "keccak-224",
123 KECCAK_256: "keccak-256",
124 KECCAK_384: "keccak-384",
125 KECCAK_512: "keccak-512",
126 SHAKE_128: "shake-128",
127 SHAKE_256: "shake-256",
131 // DefaultLengths maps a hash code to it's default length
132 var DefaultLengths = map[uint64]int{
152 func uvarint(buf []byte) (uint64, []byte, error) {
153 n, c := binary.Uvarint(buf)
156 return n, buf, ErrVarintBufferShort
158 return n, buf[-c:], ErrVarintTooLong
160 return n, buf[c:], nil
164 // DecodedMultihash represents a parsed multihash and allows
165 // easy access to the different parts of a multihash.
166 type DecodedMultihash struct {
169 Length int // Length is just int as it is type of len() opearator
170 Digest []byte // Digest holds the raw multihash bytes
173 // Multihash is byte slice with the following form:
174 // <hash function code><digest size><hash function output>.
175 // See the spec for more information.
176 type Multihash []byte
178 // HexString returns the hex-encoded representation of a multihash.
179 func (m *Multihash) HexString() string {
180 return hex.EncodeToString([]byte(*m))
183 // String is an alias to HexString().
184 func (m *Multihash) String() string {
188 // FromHexString parses a hex-encoded multihash.
189 func FromHexString(s string) (Multihash, error) {
190 b, err := hex.DecodeString(s)
192 return Multihash{}, err
198 // B58String returns the B58-encoded representation of a multihash.
199 func (m Multihash) B58String() string {
200 return b58.Encode([]byte(m))
203 // FromB58String parses a B58-encoded multihash.
204 func FromB58String(s string) (m Multihash, err error) {
205 b, err := b58.Decode(s)
207 return Multihash{}, ErrInvalidMultihash
213 // Cast casts a buffer onto a multihash, and returns an error
214 // if it does not work.
215 func Cast(buf []byte) (Multihash, error) {
216 dm, err := Decode(buf)
218 return Multihash{}, err
221 if !ValidCode(dm.Code) {
222 return Multihash{}, ErrUnknownCode
225 return Multihash(buf), nil
228 // Decode parses multihash bytes into a DecodedMultihash.
229 func Decode(buf []byte) (*DecodedMultihash, error) {
232 return nil, ErrTooShort
236 var code, length uint64
238 code, buf, err = uvarint(buf)
243 length, buf, err = uvarint(buf)
248 if length > math.MaxInt32 {
249 return nil, errors.New("digest too long, supporting only <= 2^31-1")
252 dm := &DecodedMultihash{
259 if len(dm.Digest) != dm.Length {
260 return nil, ErrInconsistentLen{dm}
266 // Encode a hash digest along with the specified function code.
267 // Note: the length is derived from the length of the digest itself.
268 func Encode(buf []byte, code uint64) ([]byte, error) {
270 if !ValidCode(code) {
271 return nil, ErrUnknownCode
274 start := make([]byte, 2*binary.MaxVarintLen64, 2*binary.MaxVarintLen64+len(buf))
276 n := binary.PutUvarint(spot, code)
278 n += binary.PutUvarint(spot, uint64(len(buf)))
280 return append(start[:n], buf...), nil
283 // EncodeName is like Encode() but providing a string name
284 // instead of a numeric code. See Names for allowed values.
285 func EncodeName(buf []byte, name string) ([]byte, error) {
286 return Encode(buf, Names[name])
289 // ValidCode checks whether a multihash code is valid.
290 func ValidCode(code uint64) bool {