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