2018-10-14 02:32:29 +00:00
|
|
|
package hashutil
|
|
|
|
|
|
|
|
import (
|
2019-03-07 16:32:01 +00:00
|
|
|
"errors"
|
|
|
|
"reflect"
|
|
|
|
|
2019-01-28 16:08:27 +00:00
|
|
|
"github.com/gogo/protobuf/proto"
|
2018-12-06 17:01:51 +00:00
|
|
|
"golang.org/x/crypto/sha3"
|
2018-10-14 02:32:29 +00:00
|
|
|
)
|
|
|
|
|
2019-03-07 16:32:01 +00:00
|
|
|
// ErrNilProto can occur when attempting to hash a protobuf message that is nil
|
|
|
|
// or has nil objects within lists.
|
|
|
|
var ErrNilProto = errors.New("cannot hash a nil protobuf message")
|
|
|
|
|
2018-10-14 02:32:29 +00:00
|
|
|
// Hash defines a function that returns the
|
2018-12-05 04:13:33 +00:00
|
|
|
// Keccak-256/SHA3 hash of the data passed in.
|
2018-11-16 03:14:33 +00:00
|
|
|
// https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#appendix
|
2018-10-14 02:32:29 +00:00
|
|
|
func Hash(data []byte) [32]byte {
|
|
|
|
var hash [32]byte
|
2018-12-05 04:13:33 +00:00
|
|
|
|
2018-12-06 17:01:51 +00:00
|
|
|
h := sha3.NewLegacyKeccak256()
|
|
|
|
|
|
|
|
// The hash interface never returns an error, for that reason
|
|
|
|
// we are not handling the error below. For reference, it is
|
|
|
|
// stated here https://golang.org/pkg/hash/#Hash
|
|
|
|
|
|
|
|
// #nosec G104
|
|
|
|
h.Write(data)
|
|
|
|
h.Sum(hash[:0])
|
|
|
|
|
2018-10-14 02:32:29 +00:00
|
|
|
return hash
|
|
|
|
}
|
2018-12-28 05:19:32 +00:00
|
|
|
|
|
|
|
// RepeatHash applies the Keccak-256/SHA3 hash function repeatedly
|
|
|
|
// numTimes on a [32]byte array.
|
|
|
|
func RepeatHash(data [32]byte, numTimes uint64) [32]byte {
|
|
|
|
if numTimes == 0 {
|
|
|
|
return data
|
|
|
|
}
|
|
|
|
return RepeatHash(Hash(data[:]), numTimes-1)
|
|
|
|
}
|
2019-01-28 16:08:27 +00:00
|
|
|
|
|
|
|
// HashProto hashes a protocol buffer message using Keccak-256/SHA3.
|
2019-03-07 16:32:01 +00:00
|
|
|
func HashProto(msg proto.Message) (result [32]byte, err error) {
|
|
|
|
// Hashing a proto with nil pointers will cause a panic in the unsafe
|
|
|
|
// proto.Marshal library.
|
|
|
|
defer func() {
|
|
|
|
if r := recover(); r != nil {
|
|
|
|
err = ErrNilProto
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
if msg == nil || reflect.ValueOf(msg).IsNil() {
|
|
|
|
return [32]byte{}, ErrNilProto
|
|
|
|
}
|
2019-01-28 16:08:27 +00:00
|
|
|
data, err := proto.Marshal(msg)
|
|
|
|
if err != nil {
|
|
|
|
return [32]byte{}, err
|
|
|
|
}
|
|
|
|
return Hash(data), nil
|
|
|
|
}
|