// Package htrutils defines HashTreeRoot utility functions. package htrutils import ( "bytes" "encoding/binary" "github.com/pkg/errors" ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" "github.com/prysmaticlabs/prysm/shared/bytesutil" "github.com/prysmaticlabs/prysm/shared/hashutil" "github.com/prysmaticlabs/prysm/shared/params" ) // Uint64Root computes the HashTreeRoot Merkleization of // a simple uint64 value according to the eth2 // Simple Serialize specification. func Uint64Root(val uint64) [32]byte { buf := make([]byte, 8) binary.LittleEndian.PutUint64(buf, val) root := bytesutil.ToBytes32(buf) return root } // ForkRoot computes the HashTreeRoot Merkleization of // a Fork struct value according to the eth2 // Simple Serialize specification. func ForkRoot(fork *pb.Fork) ([32]byte, error) { fieldRoots := make([][]byte, 3) if fork != nil { prevRoot := bytesutil.ToBytes32(fork.PreviousVersion) fieldRoots[0] = prevRoot[:] currRoot := bytesutil.ToBytes32(fork.CurrentVersion) fieldRoots[1] = currRoot[:] forkEpochBuf := make([]byte, 8) binary.LittleEndian.PutUint64(forkEpochBuf, fork.Epoch) epochRoot := bytesutil.ToBytes32(forkEpochBuf) fieldRoots[2] = epochRoot[:] } return BitwiseMerkleize(hashutil.CustomSHA256Hasher(), fieldRoots, uint64(len(fieldRoots)), uint64(len(fieldRoots))) } // CheckpointRoot computes the HashTreeRoot Merkleization of // a InitWithReset struct value according to the eth2 // Simple Serialize specification. func CheckpointRoot(hasher HashFn, checkpoint *ethpb.Checkpoint) ([32]byte, error) { fieldRoots := make([][]byte, 2) if checkpoint != nil { epochBuf := make([]byte, 8) binary.LittleEndian.PutUint64(epochBuf, checkpoint.Epoch) epochRoot := bytesutil.ToBytes32(epochBuf) fieldRoots[0] = epochRoot[:] ckpRoot := bytesutil.ToBytes32(checkpoint.Root) fieldRoots[1] = ckpRoot[:] } return BitwiseMerkleize(hasher, fieldRoots, uint64(len(fieldRoots)), uint64(len(fieldRoots))) } // HistoricalRootsRoot computes the HashTreeRoot Merkleization of // a list of [32]byte historical block roots according to the eth2 // Simple Serialize specification. func HistoricalRootsRoot(historicalRoots [][]byte) ([32]byte, error) { result, err := BitwiseMerkleize(hashutil.CustomSHA256Hasher(), historicalRoots, uint64(len(historicalRoots)), params.BeaconConfig().HistoricalRootsLimit) if err != nil { return [32]byte{}, errors.Wrap(err, "could not compute historical roots merkleization") } historicalRootsBuf := new(bytes.Buffer) if err := binary.Write(historicalRootsBuf, binary.LittleEndian, uint64(len(historicalRoots))); err != nil { return [32]byte{}, errors.Wrap(err, "could not marshal historical roots length") } // We need to mix in the length of the slice. historicalRootsOutput := make([]byte, 32) copy(historicalRootsOutput, historicalRootsBuf.Bytes()) mixedLen := MixInLength(result, historicalRootsOutput) return mixedLen, nil } // SlashingsRoot computes the HashTreeRoot Merkleization of // a list of uint64 slashing values according to the eth2 // Simple Serialize specification. func SlashingsRoot(slashings []uint64) ([32]byte, error) { slashingMarshaling := make([][]byte, params.BeaconConfig().EpochsPerSlashingsVector) for i := 0; i < len(slashings) && i < len(slashingMarshaling); i++ { slashBuf := make([]byte, 8) binary.LittleEndian.PutUint64(slashBuf, slashings[i]) slashingMarshaling[i] = slashBuf } slashingChunks, err := Pack(slashingMarshaling) if err != nil { return [32]byte{}, errors.Wrap(err, "could not pack slashings into chunks") } return BitwiseMerkleize(hashutil.CustomSHA256Hasher(), slashingChunks, uint64(len(slashingChunks)), uint64(len(slashingChunks))) }