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