hash.go raw

   1  // Copyright (c) 2013-2016 The btcsuite developers
   2  // Copyright (c) 2015 The Decred developers
   3  // Use of this source code is governed by an ISC
   4  // license that can be found in the LICENSE file.
   5  
   6  package chainhash
   7  
   8  import (
   9  	"crypto/sha256"
  10  	"encoding/hex"
  11  	"encoding/json"
  12  	"fmt"
  13  )
  14  
  15  // HashSize of array used to store hashes.  See Hash.
  16  const HashSize = 32
  17  
  18  // MaxHashStringSize is the maximum length of a Hash hash string.
  19  const MaxHashStringSize = HashSize * 2
  20  
  21  var (
  22  	// TagBIP0340Challenge is the BIP-0340 tag for challenges.
  23  	TagBIP0340Challenge = []byte("BIP0340/challenge")
  24  
  25  	// TagBIP0340Aux is the BIP-0340 tag for aux data.
  26  	TagBIP0340Aux = []byte("BIP0340/aux")
  27  
  28  	// TagBIP0340Nonce is the BIP-0340 tag for nonces.
  29  	TagBIP0340Nonce = []byte("BIP0340/nonce")
  30  
  31  	// TagTapSighash is the tag used by BIP 341 to generate the sighash
  32  	// flags.
  33  	TagTapSighash = []byte("TapSighash")
  34  
  35  	// TagTagTapLeaf is the message tag prefix used to compute the hash
  36  	// digest of a tapscript leaf.
  37  	TagTapLeaf = []byte("TapLeaf")
  38  
  39  	// TagTapBranch is the message tag prefix used to compute the
  40  	// hash digest of two tap leaves into a taproot branch node.
  41  	TagTapBranch = []byte("TapBranch")
  42  
  43  	// TagTapTweak is the message tag prefix used to compute the hash tweak
  44  	// used to enable a public key to commit to the taproot branch root
  45  	// for the witness program.
  46  	TagTapTweak = []byte("TapTweak")
  47  
  48  	// precomputedTags is a map containing the SHA-256 hash of the BIP-0340
  49  	// tags.
  50  	precomputedTags = map[string]Hash{
  51  		string(TagBIP0340Challenge): sha256.Sum256(TagBIP0340Challenge),
  52  		string(TagBIP0340Aux):       sha256.Sum256(TagBIP0340Aux),
  53  		string(TagBIP0340Nonce):     sha256.Sum256(TagBIP0340Nonce),
  54  		string(TagTapSighash):       sha256.Sum256(TagTapSighash),
  55  		string(TagTapLeaf):          sha256.Sum256(TagTapLeaf),
  56  		string(TagTapBranch):        sha256.Sum256(TagTapBranch),
  57  		string(TagTapTweak):         sha256.Sum256(TagTapTweak),
  58  	}
  59  )
  60  
  61  // ErrHashStrSize describes an error that indicates the caller specified a hash
  62  // string that has too many characters.
  63  var ErrHashStrSize = fmt.Errorf("max hash string length is %v bytes", MaxHashStringSize)
  64  
  65  // Hash is used in several of the bitcoin messages and common structures.  It
  66  // typically represents the double sha256 of data.
  67  type Hash [HashSize]byte
  68  
  69  // String returns the Hash as the hexadecimal string of the byte-reversed
  70  // hash.
  71  func (hash Hash) String() string {
  72  	for i := 0; i < HashSize/2; i++ {
  73  		hash[i], hash[HashSize-1-i] = hash[HashSize-1-i], hash[i]
  74  	}
  75  	return hex.EncodeToString(hash[:])
  76  }
  77  
  78  // CloneBytes returns a copy of the bytes which represent the hash as a byte
  79  // slice.
  80  //
  81  // NOTE: It is generally cheaper to just slice the hash directly thereby reusing
  82  // the same bytes rather than calling this method.
  83  func (hash *Hash) CloneBytes() []byte {
  84  	newHash := make([]byte, HashSize)
  85  	copy(newHash, hash[:])
  86  
  87  	return newHash
  88  }
  89  
  90  // SetBytes sets the bytes which represent the hash.  An error is returned if
  91  // the number of bytes passed in is not HashSize.
  92  func (hash *Hash) SetBytes(newHash []byte) error {
  93  	nhlen := len(newHash)
  94  	if nhlen != HashSize {
  95  		return fmt.Errorf("invalid hash length of %v, want %v", nhlen,
  96  			HashSize)
  97  	}
  98  	copy(hash[:], newHash)
  99  
 100  	return nil
 101  }
 102  
 103  // IsEqual returns true if target is the same as hash.
 104  func (hash *Hash) IsEqual(target *Hash) bool {
 105  	if hash == nil && target == nil {
 106  		return true
 107  	}
 108  	if hash == nil || target == nil {
 109  		return false
 110  	}
 111  	return *hash == *target
 112  }
 113  
 114  // MarshalJSON serialises the hash as a JSON appropriate string value.
 115  func (hash Hash) MarshalJSON() ([]byte, error) {
 116  	return json.Marshal(hash.String())
 117  }
 118  
 119  // UnmarshalJSON parses the hash with JSON appropriate string value.
 120  func (hash *Hash) UnmarshalJSON(input []byte) error {
 121  	// If the first byte indicates an array, the hash could have been marshalled
 122  	// using the legacy method and e.g. persisted.
 123  	if len(input) > 0 && input[0] == '[' {
 124  		return decodeLegacy(hash, input)
 125  	}
 126  
 127  	var sh string
 128  	err := json.Unmarshal(input, &sh)
 129  	if err != nil {
 130  		return err
 131  	}
 132  	newHash, err := NewHashFromStr(sh)
 133  	if err != nil {
 134  		return err
 135  	}
 136  
 137  	return hash.SetBytes(newHash[:])
 138  }
 139  
 140  // NewHash returns a new Hash from a byte slice.  An error is returned if
 141  // the number of bytes passed in is not HashSize.
 142  func NewHash(newHash []byte) (*Hash, error) {
 143  	var sh Hash
 144  	err := sh.SetBytes(newHash)
 145  	if err != nil {
 146  		return nil, err
 147  	}
 148  	return &sh, err
 149  }
 150  
 151  // TaggedHash implements the tagged hash scheme described in BIP-340. We use
 152  // sha-256 to bind a message hash to a specific context using a tag:
 153  // sha256(sha256(tag) || sha256(tag) || msg).
 154  func TaggedHash(tag []byte, msgs ...[]byte) *Hash {
 155  	// Check to see if we've already pre-computed the hash of the tag. If
 156  	// so then this'll save us an extra sha256 hash.
 157  	shaTag, ok := precomputedTags[string(tag)]
 158  	if !ok {
 159  		shaTag = sha256.Sum256(tag)
 160  	}
 161  
 162  	// h = sha256(sha256(tag) || sha256(tag) || msg)
 163  	h := sha256.New()
 164  	h.Write(shaTag[:])
 165  	h.Write(shaTag[:])
 166  
 167  	for _, msg := range msgs {
 168  		h.Write(msg)
 169  	}
 170  
 171  	taggedHash := h.Sum(nil)
 172  
 173  	// The function can't error out since the above hash is guaranteed to
 174  	// be 32 bytes.
 175  	hash, _ := NewHash(taggedHash)
 176  
 177  	return hash
 178  }
 179  
 180  // NewHashFromStr creates a Hash from a hash string.  The string should be
 181  // the hexadecimal string of a byte-reversed hash, but any missing characters
 182  // result in zero padding at the end of the Hash.
 183  func NewHashFromStr(hash string) (*Hash, error) {
 184  	ret := new(Hash)
 185  	err := Decode(ret, hash)
 186  	if err != nil {
 187  		return nil, err
 188  	}
 189  	return ret, nil
 190  }
 191  
 192  // Decode decodes the byte-reversed hexadecimal string encoding of a Hash to a
 193  // destination.
 194  func Decode(dst *Hash, src string) error {
 195  	// Return error if hash string is too long.
 196  	if len(src) > MaxHashStringSize {
 197  		return ErrHashStrSize
 198  	}
 199  
 200  	// Hex decoder expects the hash to be a multiple of two.  When not, pad
 201  	// with a leading zero.
 202  	var srcBytes []byte
 203  	if len(src)%2 == 0 {
 204  		srcBytes = []byte(src)
 205  	} else {
 206  		srcBytes = make([]byte, 1+len(src))
 207  		srcBytes[0] = '0'
 208  		copy(srcBytes[1:], src)
 209  	}
 210  
 211  	// Hex decode the source bytes to a temporary destination.
 212  	var reversedHash Hash
 213  	_, err := hex.Decode(reversedHash[HashSize-hex.DecodedLen(len(srcBytes)):], srcBytes)
 214  	if err != nil {
 215  		return err
 216  	}
 217  
 218  	// Reverse copy from the temporary hash to destination.  Because the
 219  	// temporary was zeroed, the written result will be correctly padded.
 220  	for i, b := range reversedHash[:HashSize/2] {
 221  		dst[i], dst[HashSize-1-i] = reversedHash[HashSize-1-i], b
 222  	}
 223  
 224  	return nil
 225  }
 226  
 227  // decodeLegacy decodes an Hash that has been encoded with the legacy method
 228  // (i.e. represented as a bytes array) to a destination.
 229  func decodeLegacy(dst *Hash, src []byte) error {
 230  	var hashBytes []byte
 231  	err := json.Unmarshal(src, &hashBytes)
 232  	if err != nil {
 233  		return err
 234  	}
 235  	if len(hashBytes) != HashSize {
 236  		return ErrHashStrSize
 237  	}
 238  	return dst.SetBytes(hashBytes)
 239  }
 240