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 }