github.com/prysmaticlabs/prysm@v1.4.4/shared/hashutil/hash.go (about) 1 // Package hashutil includes all hash-function related helpers for Prysm. 2 package hashutil 3 4 import ( 5 "errors" 6 "hash" 7 "reflect" 8 "sync" 9 10 fastssz "github.com/ferranbt/fastssz" 11 "github.com/minio/highwayhash" 12 "github.com/minio/sha256-simd" 13 "github.com/prysmaticlabs/prysm/shared/bytesutil" 14 "golang.org/x/crypto/sha3" 15 "google.golang.org/protobuf/proto" 16 ) 17 18 // ErrNilProto can occur when attempting to hash a protobuf message that is nil 19 // or has nil objects within lists. 20 var ErrNilProto = errors.New("cannot hash a nil protobuf message") 21 22 var sha256Pool = sync.Pool{New: func() interface{} { 23 return sha256.New() 24 }} 25 26 // Hash defines a function that returns the sha256 checksum of the data passed in. 27 // https://github.com/ethereum/eth2.0-specs/blob/v0.9.3/specs/core/0_beacon-chain.md#hash 28 func Hash(data []byte) [32]byte { 29 h, ok := sha256Pool.Get().(hash.Hash) 30 if !ok { 31 h = sha256.New() 32 } 33 defer sha256Pool.Put(h) 34 h.Reset() 35 36 var b [32]byte 37 38 // The hash interface never returns an error, for that reason 39 // we are not handling the error below. For reference, it is 40 // stated here https://golang.org/pkg/hash/#Hash 41 42 // #nosec G104 43 h.Write(data) 44 h.Sum(b[:0]) 45 46 return b 47 } 48 49 // CustomSHA256Hasher returns a hash function that uses 50 // an enclosed hasher. This is not safe for concurrent 51 // use as the same hasher is being called throughout. 52 // 53 // Note: that this method is only more performant over 54 // hashutil.Hash if the callback is used more than 5 times. 55 func CustomSHA256Hasher() func([]byte) [32]byte { 56 hasher, ok := sha256Pool.Get().(hash.Hash) 57 if !ok { 58 hasher = sha256.New() 59 } else { 60 hasher.Reset() 61 } 62 var h [32]byte 63 64 return func(data []byte) [32]byte { 65 // The hash interface never returns an error, for that reason 66 // we are not handling the error below. For reference, it is 67 // stated here https://golang.org/pkg/hash/#Hash 68 69 // #nosec G104 70 hasher.Write(data) 71 hasher.Sum(h[:0]) 72 hasher.Reset() 73 74 return h 75 } 76 } 77 78 var keccak256Pool = sync.Pool{New: func() interface{} { 79 return sha3.NewLegacyKeccak256() 80 }} 81 82 // HashKeccak256 defines a function which returns the Keccak-256/SHA3 83 // hash of the data passed in. 84 func HashKeccak256(data []byte) [32]byte { 85 var b [32]byte 86 87 h, ok := keccak256Pool.Get().(hash.Hash) 88 if !ok { 89 h = sha3.NewLegacyKeccak256() 90 } 91 defer keccak256Pool.Put(h) 92 h.Reset() 93 94 // The hash interface never returns an error, for that reason 95 // we are not handling the error below. For reference, it is 96 // stated here https://golang.org/pkg/hash/#Hash 97 98 // #nosec G104 99 h.Write(data) 100 h.Sum(b[:0]) 101 102 return b 103 } 104 105 // HashProto hashes a protocol buffer message using sha256. 106 func HashProto(msg proto.Message) (result [32]byte, err error) { 107 if msg == nil || reflect.ValueOf(msg).IsNil() { 108 return [32]byte{}, ErrNilProto 109 } 110 var data []byte 111 if m, ok := msg.(fastssz.Marshaler); ok { 112 data, err = m.MarshalSSZ() 113 } else { 114 data, err = proto.Marshal(msg) 115 } 116 if err != nil { 117 return [32]byte{}, err 118 } 119 return Hash(data), nil 120 } 121 122 // Key used for FastSum64 123 var fastSumHashKey = bytesutil.ToBytes32([]byte("hash_fast_sum64_key")) 124 125 // FastSum64 returns a hash sum of the input data using highwayhash. This method is not secure, but 126 // may be used as a quick identifier for objects where collisions are acceptable. 127 func FastSum64(data []byte) uint64 { 128 return highwayhash.Sum64(data, fastSumHashKey[:]) 129 } 130 131 // FastSum256 returns a hash sum of the input data using highwayhash. This method is not secure, but 132 // may be used as a quick identifier for objects where collisions are acceptable. 133 func FastSum256(data []byte) [32]byte { 134 return highwayhash.Sum(data, fastSumHashKey[:]) 135 }