github.com/prysmaticlabs/prysm@v1.4.4/shared/htrutils/htrutils.go (about)

     1  // Package htrutils defines HashTreeRoot utility functions.
     2  package htrutils
     3  
     4  import (
     5  	"bytes"
     6  	"encoding/binary"
     7  
     8  	"github.com/pkg/errors"
     9  	pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
    10  	ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
    11  	"github.com/prysmaticlabs/prysm/shared/bytesutil"
    12  	"github.com/prysmaticlabs/prysm/shared/hashutil"
    13  	"github.com/prysmaticlabs/prysm/shared/params"
    14  )
    15  
    16  // Uint64Root computes the HashTreeRoot Merkleization of
    17  // a simple uint64 value according to the Ethereum
    18  // Simple Serialize specification.
    19  func Uint64Root(val uint64) [32]byte {
    20  	buf := make([]byte, 8)
    21  	binary.LittleEndian.PutUint64(buf, val)
    22  	root := bytesutil.ToBytes32(buf)
    23  	return root
    24  }
    25  
    26  // ForkRoot computes the HashTreeRoot Merkleization of
    27  // a Fork struct value according to the Ethereum
    28  // Simple Serialize specification.
    29  func ForkRoot(fork *pb.Fork) ([32]byte, error) {
    30  	fieldRoots := make([][]byte, 3)
    31  	if fork != nil {
    32  		prevRoot := bytesutil.ToBytes32(fork.PreviousVersion)
    33  		fieldRoots[0] = prevRoot[:]
    34  		currRoot := bytesutil.ToBytes32(fork.CurrentVersion)
    35  		fieldRoots[1] = currRoot[:]
    36  		forkEpochBuf := make([]byte, 8)
    37  		binary.LittleEndian.PutUint64(forkEpochBuf, uint64(fork.Epoch))
    38  		epochRoot := bytesutil.ToBytes32(forkEpochBuf)
    39  		fieldRoots[2] = epochRoot[:]
    40  	}
    41  	return BitwiseMerkleize(hashutil.CustomSHA256Hasher(), fieldRoots, uint64(len(fieldRoots)), uint64(len(fieldRoots)))
    42  }
    43  
    44  // CheckpointRoot computes the HashTreeRoot Merkleization of
    45  // a InitWithReset struct value according to the Ethereum
    46  // Simple Serialize specification.
    47  func CheckpointRoot(hasher HashFn, checkpoint *ethpb.Checkpoint) ([32]byte, error) {
    48  	fieldRoots := make([][]byte, 2)
    49  	if checkpoint != nil {
    50  		epochBuf := make([]byte, 8)
    51  		binary.LittleEndian.PutUint64(epochBuf, uint64(checkpoint.Epoch))
    52  		epochRoot := bytesutil.ToBytes32(epochBuf)
    53  		fieldRoots[0] = epochRoot[:]
    54  		ckpRoot := bytesutil.ToBytes32(checkpoint.Root)
    55  		fieldRoots[1] = ckpRoot[:]
    56  	}
    57  	return BitwiseMerkleize(hasher, fieldRoots, uint64(len(fieldRoots)), uint64(len(fieldRoots)))
    58  }
    59  
    60  // HistoricalRootsRoot computes the HashTreeRoot Merkleization of
    61  // a list of [32]byte historical block roots according to the Ethereum
    62  // Simple Serialize specification.
    63  func HistoricalRootsRoot(historicalRoots [][]byte) ([32]byte, error) {
    64  	result, err := BitwiseMerkleize(hashutil.CustomSHA256Hasher(), historicalRoots, uint64(len(historicalRoots)), params.BeaconConfig().HistoricalRootsLimit)
    65  	if err != nil {
    66  		return [32]byte{}, errors.Wrap(err, "could not compute historical roots merkleization")
    67  	}
    68  	historicalRootsBuf := new(bytes.Buffer)
    69  	if err := binary.Write(historicalRootsBuf, binary.LittleEndian, uint64(len(historicalRoots))); err != nil {
    70  		return [32]byte{}, errors.Wrap(err, "could not marshal historical roots length")
    71  	}
    72  	// We need to mix in the length of the slice.
    73  	historicalRootsOutput := make([]byte, 32)
    74  	copy(historicalRootsOutput, historicalRootsBuf.Bytes())
    75  	mixedLen := MixInLength(result, historicalRootsOutput)
    76  	return mixedLen, nil
    77  }
    78  
    79  // SlashingsRoot computes the HashTreeRoot Merkleization of
    80  // a list of uint64 slashing values according to the Ethereum
    81  // Simple Serialize specification.
    82  func SlashingsRoot(slashings []uint64) ([32]byte, error) {
    83  	slashingMarshaling := make([][]byte, params.BeaconConfig().EpochsPerSlashingsVector)
    84  	for i := 0; i < len(slashings) && i < len(slashingMarshaling); i++ {
    85  		slashBuf := make([]byte, 8)
    86  		binary.LittleEndian.PutUint64(slashBuf, slashings[i])
    87  		slashingMarshaling[i] = slashBuf
    88  	}
    89  	slashingChunks, err := Pack(slashingMarshaling)
    90  	if err != nil {
    91  		return [32]byte{}, errors.Wrap(err, "could not pack slashings into chunks")
    92  	}
    93  	return BitwiseMerkleize(hashutil.CustomSHA256Hasher(), slashingChunks, uint64(len(slashingChunks)), uint64(len(slashingChunks)))
    94  }