github.com/avahowell/sia@v0.5.1-beta.0.20160524050156-83dcc3d37c94/crypto/hash.go (about) 1 package crypto 2 3 // hash.go supplies a few geneeral hashing functions, using the hashing 4 // algorithm blake2b. Because changing the hashing algorithm for Sia has much 5 // stronger implications than changing any of the other algorithms, blake2b is 6 // the only supported algorithm. Sia is not really flexible enough to support 7 // multiple. 8 9 import ( 10 "bytes" 11 "encoding/hex" 12 "encoding/json" 13 "errors" 14 "hash" 15 16 "github.com/NebulousLabs/Sia/encoding" 17 18 "github.com/dchest/blake2b" 19 ) 20 21 const ( 22 HashSize = 32 23 ) 24 25 type ( 26 Hash [HashSize]byte 27 28 // HashSlice is used for sorting 29 HashSlice []Hash 30 ) 31 32 var ( 33 ErrHashWrongLen = errors.New("encoded value has the wrong length to be a hash") 34 ) 35 36 // NewHash returns a blake2b 256bit hasher. 37 func NewHash() hash.Hash { 38 return blake2b.New256() 39 } 40 41 // HashAll takes a set of objects as input, encodes them all using the encoding 42 // package, and then hashes the result. 43 func HashAll(objs ...interface{}) Hash { 44 // Ideally we would just write HashBytes(encoding.MarshalAll(objs)). 45 // Unfortunately, you can't pass 'objs' to MarshalAll without losing its 46 // type information; MarshalAll would just see interface{}s. 47 var b []byte 48 for _, obj := range objs { 49 b = append(b, encoding.Marshal(obj)...) 50 } 51 return HashBytes(b) 52 } 53 54 // HashBytes takes a byte slice and returns the result. 55 func HashBytes(data []byte) Hash { 56 return Hash(blake2b.Sum256(data)) 57 } 58 59 // HashObject takes an object as input, encodes it using the encoding package, 60 // and then hashes the result. 61 func HashObject(obj interface{}) Hash { 62 return HashBytes(encoding.Marshal(obj)) 63 } 64 65 // These functions implement sort.Interface, allowing hashes to be sorted. 66 func (hs HashSlice) Len() int { return len(hs) } 67 func (hs HashSlice) Less(i, j int) bool { return bytes.Compare(hs[i][:], hs[j][:]) < 0 } 68 func (hs HashSlice) Swap(i, j int) { hs[i], hs[j] = hs[j], hs[i] } 69 70 // MarshalJSON marshales a hash as a hex string. 71 func (h Hash) MarshalJSON() ([]byte, error) { 72 return json.Marshal(h.String()) 73 } 74 75 // String prints the hash in hex. 76 func (h Hash) String() string { 77 return hex.EncodeToString(h[:]) 78 } 79 80 // UnmarshalJSON decodes the json hex string of the hash. 81 func (h *Hash) UnmarshalJSON(b []byte) error { 82 // *2 because there are 2 hex characters per byte. 83 // +2 because the encoded JSON string has a `"` added at the beginning and end. 84 if len(b) != HashSize*2+2 { 85 return ErrHashWrongLen 86 } 87 88 // b[1 : len(b)-1] cuts off the leading and trailing `"` in the JSON string. 89 hBytes, err := hex.DecodeString(string(b[1 : len(b)-1])) 90 if err != nil { 91 return errors.New("could not unmarshal crypto.Hash: " + err.Error()) 92 } 93 copy(h[:], hBytes) 94 return nil 95 }