github.com/oskarth/go-ethereum@v1.6.8-0.20191013093314-dac24a9d3494/swarm/multihash/multihash.go (about)

     1  // Copyright 2018 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package multihash
    18  
    19  import (
    20  	"bytes"
    21  	"encoding/binary"
    22  	"errors"
    23  	"fmt"
    24  )
    25  
    26  const (
    27  	defaultMultihashLength   = 32
    28  	defaultMultihashTypeCode = 0x1b
    29  )
    30  
    31  var (
    32  	multihashTypeCode uint8
    33  	MultihashLength   = defaultMultihashLength
    34  )
    35  
    36  func init() {
    37  	multihashTypeCode = defaultMultihashTypeCode
    38  	MultihashLength = defaultMultihashLength
    39  }
    40  
    41  // check if valid swarm multihash
    42  func isSwarmMultihashType(code uint8) bool {
    43  	return code == multihashTypeCode
    44  }
    45  
    46  // GetMultihashLength returns the digest length of the provided multihash
    47  // It will fail if the multihash is not a valid swarm mulithash
    48  func GetMultihashLength(data []byte) (int, int, error) {
    49  	cursor := 0
    50  	typ, c := binary.Uvarint(data)
    51  	if c <= 0 {
    52  		return 0, 0, errors.New("unreadable hashtype field")
    53  	}
    54  	if !isSwarmMultihashType(uint8(typ)) {
    55  		return 0, 0, fmt.Errorf("hash code %x is not a swarm hashtype", typ)
    56  	}
    57  	cursor += c
    58  	hashlength, c := binary.Uvarint(data[cursor:])
    59  	if c <= 0 {
    60  		return 0, 0, errors.New("unreadable length field")
    61  	}
    62  	cursor += c
    63  
    64  	// we cheekily assume hashlength < maxint
    65  	inthashlength := int(hashlength)
    66  	if len(data[c:]) < inthashlength {
    67  		return 0, 0, errors.New("length mismatch")
    68  	}
    69  	return inthashlength, cursor, nil
    70  }
    71  
    72  // FromMulithash returns the digest portion of the multihash
    73  // It will fail if the multihash is not a valid swarm multihash
    74  func FromMultihash(data []byte) ([]byte, error) {
    75  	hashLength, _, err := GetMultihashLength(data)
    76  	if err != nil {
    77  		return nil, err
    78  	}
    79  	return data[len(data)-hashLength:], nil
    80  }
    81  
    82  // ToMulithash wraps the provided digest data with a swarm mulithash header
    83  func ToMultihash(hashData []byte) []byte {
    84  	buf := bytes.NewBuffer(nil)
    85  	b := make([]byte, 8)
    86  	c := binary.PutUvarint(b, uint64(multihashTypeCode))
    87  	buf.Write(b[:c])
    88  	c = binary.PutUvarint(b, uint64(len(hashData)))
    89  	buf.Write(b[:c])
    90  	buf.Write(hashData)
    91  	return buf.Bytes()
    92  }