github.com/lbryio/lbcd@v0.22.119/chaincfg/chainhash/hash.go (about)

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