github.com/palcoin-project/palcd@v1.0.0/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 }