github.com/koko1123/flow-go-1@v0.29.6/fvm/crypto/hash.go (about)

     1  package crypto
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  
     7  	"github.com/koko1123/flow-go-1/model/flow"
     8  	"github.com/onflow/flow-go/crypto/hash"
     9  )
    10  
    11  // constant tag length
    12  const tagLength = flow.DomainTagLength
    13  
    14  // prefixedHashing embeds a crypto hasher and implements
    15  // hashing with a prefix : prefixedHashing(data) = hasher(prefix || data)
    16  //
    17  // Prefixes are padded tags till 32 bytes to guarantee prefixedHashers are independant
    18  // hashers.
    19  // Prefixes are disabled with the particular tag value ""
    20  type prefixedHashing struct {
    21  	hash.Hasher
    22  	usePrefix bool
    23  	tag       [tagLength]byte
    24  }
    25  
    26  // paddedDomainTag converts a string into a padded byte array.
    27  func paddedDomainTag(s string) ([tagLength]byte, error) {
    28  	var tag [tagLength]byte
    29  	if len(s) > tagLength {
    30  		return tag, fmt.Errorf("domain tag cannot be longer than %d characters, got %s", tagLength, s)
    31  	}
    32  	copy(tag[:], s)
    33  	return tag, nil
    34  }
    35  
    36  var hasherCreators = map[hash.HashingAlgorithm](func() hash.Hasher){
    37  	hash.SHA2_256:   hash.NewSHA2_256,
    38  	hash.SHA3_256:   hash.NewSHA3_256,
    39  	hash.SHA2_384:   hash.NewSHA2_384,
    40  	hash.SHA3_384:   hash.NewSHA3_384,
    41  	hash.Keccak_256: hash.NewKeccak_256,
    42  }
    43  
    44  // NewPrefixedHashing returns a new hasher that prefixes the tag for all
    45  // hash computations (only when tag is not empty).
    46  //
    47  // Supported algorithms are SHA2-256, SHA2-384, SHA3-256, SHA3-384 and Keccak256.
    48  func NewPrefixedHashing(algo hash.HashingAlgorithm, tag string) (hash.Hasher, error) {
    49  
    50  	hasherCreator, hasCreator := hasherCreators[algo]
    51  	if !hasCreator {
    52  		return nil, errors.New("hashing algorithm is not supported for prefixed algorithm")
    53  	}
    54  
    55  	paddedTag, err := paddedDomainTag(tag)
    56  	if err != nil {
    57  		return nil, fmt.Errorf("prefixed hashing failed: %w", err)
    58  	}
    59  
    60  	return &prefixedHashing{
    61  		Hasher: hasherCreator(),
    62  		// if tag is empty, do not use any prefix (standard hashing)
    63  		usePrefix: tag != "",
    64  		tag:       paddedTag,
    65  	}, nil
    66  }
    67  
    68  // ComputeHash calculates and returns the digest of input byte array prefixed by a tag.
    69  // Not thread-safe
    70  func (s *prefixedHashing) ComputeHash(data []byte) hash.Hash {
    71  	s.Reset()
    72  	_, _ = s.Write(data)
    73  	return s.Hasher.SumHash()
    74  }
    75  
    76  // Reset gets the hasher back to its original state.
    77  func (s *prefixedHashing) Reset() {
    78  	s.Hasher.Reset()
    79  	// include the tag only when using a prefix is enabled
    80  	if s.usePrefix {
    81  		_, _ = s.Write(s.tag[:])
    82  	}
    83  }