github.com/etsc3259/etsc@v0.0.0-20190109113336-a9c2c10f9c95/swarm/multihash/multihash.go (about) 1 // Copyright 2018 The go-etsc Authors 2 // This file is part of the go-etsc library. 3 // 4 // The go-etsc 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-etsc 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-etsc 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 }