hash.go raw

   1  package chainhash
   2  
   3  import (
   4  	"encoding/hex"
   5  	"fmt"
   6  )
   7  
   8  // HashSize of array used to store hashes.  See Hash.
   9  const HashSize = 32
  10  
  11  // MaxHashStringSize is the maximum length of a Hash hash string.
  12  const MaxHashStringSize = HashSize * 2
  13  
  14  // ErrHashStrSize describes an error that indicates the caller specified a hash string that has too many characters.
  15  var ErrHashStrSize = fmt.Errorf("max hash string length is %v bytes", MaxHashStringSize)
  16  
  17  // Hash is used in several of the bitcoin messages and common structures. It typically represents the double sha256 of
  18  // data.
  19  type Hash [HashSize]byte
  20  
  21  // String returns the Hash as the hexadecimal string of the byte-reversed hash.
  22  func (hash Hash) String() string {
  23  	for i := 0; i < HashSize/2; i++ {
  24  		hash[i], hash[HashSize-1-i] = hash[HashSize-1-i], hash[i]
  25  	}
  26  	return hex.EncodeToString(hash[:])
  27  }
  28  
  29  // CloneBytes returns a copy of the bytes which represent the hash as a byte slice. NOTE: It is generally cheaper to
  30  // just slice the hash directly thereby reusing the same bytes rather than calling this method.
  31  func (hash *Hash) CloneBytes() []byte {
  32  	newHash := make([]byte, HashSize)
  33  	copy(newHash, hash[:])
  34  	return newHash
  35  }
  36  
  37  // SetBytes sets the bytes which represent the hash. An error is returned if the number of bytes passed in is not
  38  // HashSize.
  39  func (hash *Hash) SetBytes(newHash []byte) (e error) {
  40  	nhlen := len(newHash)
  41  	if nhlen != HashSize {
  42  		return fmt.Errorf(
  43  			"invalid hash length of %v, want %v", nhlen,
  44  			HashSize,
  45  		)
  46  	}
  47  	copy(hash[:], newHash)
  48  	return nil
  49  }
  50  
  51  // IsEqual returns true if target is the same as hash.
  52  func (hash *Hash) IsEqual(target *Hash) bool {
  53  	if hash == nil && target == nil {
  54  		return true
  55  	}
  56  	if hash == nil || target == nil {
  57  		return false
  58  	}
  59  	return *hash == *target
  60  }
  61  
  62  // NewHash returns a new Hash from a byte slice. An error is returned if the number of bytes passed in is not HashSize.
  63  func NewHash(newHash []byte) (*Hash, error) {
  64  	var sh Hash
  65  	e := sh.SetBytes(newHash)
  66  	if e != nil {
  67  		E.Ln(e)
  68  		return nil, e
  69  	}
  70  	return &sh, e
  71  }
  72  
  73  // NewHashFromStr creates a Hash from a hash string. The string should be the hexadecimal string of a byte-reversed
  74  // hash, but any missing characters result in zero padding at the end of the Hash.
  75  func NewHashFromStr(hash string) (ret *Hash, e error) {
  76  	ret = new(Hash)
  77  	if e = Decode(ret, hash); E.Chk(e) {
  78  		return
  79  	}
  80  	return
  81  }
  82  
  83  // Decode decodes the byte-reversed hexadecimal string encoding of a Hash to a destination.
  84  func Decode(dst *Hash, src string) (e error) {
  85  	// Return error if hash string is too long.
  86  	if len(src) > MaxHashStringSize {
  87  		return ErrHashStrSize
  88  	}
  89  	// Hex decoder expects the hash to be a multiple of two.  When not, pad with a leading zero.
  90  	var srcBytes []byte
  91  	if len(src)%2 == 0 {
  92  		srcBytes = []byte(src)
  93  	} else {
  94  		srcBytes = make([]byte, 1+len(src))
  95  		srcBytes[0] = '0'
  96  		copy(srcBytes[1:], src)
  97  	}
  98  	// Hex decode the source bytes to a temporary destination.
  99  	var reversedHash Hash
 100  	if _, e = hex.Decode(reversedHash[HashSize-hex.DecodedLen(len(srcBytes)):], srcBytes); E.Chk(e) {
 101  		return e
 102  	}
 103  	// Reverse copy from the temporary hash to destination. Because the temporary was zeroed, the written result will be
 104  	// correctly padded.
 105  	for i, b := range reversedHash[:HashSize/2] {
 106  		dst[i], dst[HashSize-1-i] = reversedHash[HashSize-1-i], b
 107  	}
 108  	return
 109  }
 110