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  }