What changed, and why it matters
This commit is a pure refactoring move: the chainhash package is relocated from `chaincfg/chainhash` to a top-level `chainhash` directory and its Go module path is bumped to `github.com/btcsuite/btcd/chainhash/v2`. The actual source code, tests, and behavior are identical to the previous location. There is no security fix or vulnerability introduced here.
No security action required. Consumers of the package should update their import paths to `github.com/btcsuite/btcd/chainhash/v2` when upgrading.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The diff deletes the chaincfg/chainhash module and recreates the same files under chainhash, changing only the module path in go.mod from github.com/btcsuite/btcd/chaincfg/chainhash to github.com/btcsuite/btcd/chainhash/v2 and the GoDoc import path in README.md. The hash.go, hashfuncs.go, and their tests are byte-for-byte copies. No functional code changes are present.
Changed components
chainhash package module pathchaincfg/chainhash directory (removed)chainhash directory (added)Inspect captured patch +924 / −924
diff --git a/chaincfg/chainhash/README.md b/chaincfg/chainhash/README.md
deleted file mode 100644
index b7ddf19..0000000
--- a/chaincfg/chainhash/README.md
+++ /dev/null
@@ -1,41 +0,0 @@
-chainhash
-=========
-
-[](https://github.com/btcsuite/btcd/actions)
-[](http://copyfree.org)
-[](https://pkg.go.dev/github.com/btcsuite/btcd/chaincfg/chainhash)
-=======
-
-chainhash provides a generic hash type and associated functions that allows the
-specific hash algorithm to be abstracted.
-
-## Installation and Updating
-
-```bash
-$ go get -u github.com/btcsuite/btcd/chaincfg/chainhash
-```
-
-## GPG Verification Key
-
-All official release tags are signed by Conformal so users can ensure the code
-has not been tampered with and is coming from the btcsuite developers. To
-verify the signature perform the following:
-
-- Download the public key from the Conformal website at
- https://opensource.conformal.com/GIT-GPG-KEY-conformal.txt
-
-- Import the public key into your GPG keyring:
- ```bash
- gpg --import GIT-GPG-KEY-conformal.txt
- ```
-
-- Verify the release tag with the following command where `TAG_NAME` is a
- placeholder for the specific tag:
- ```bash
- git tag -v TAG_NAME
- ```
-
-## License
-
-Package chainhash is licensed under the [copyfree](http://copyfree.org) ISC
-License.
diff --git a/chaincfg/chainhash/doc.go b/chaincfg/chainhash/doc.go
deleted file mode 100644
index c3eb43d..0000000
--- a/chaincfg/chainhash/doc.go
+++ /dev/null
@@ -1,5 +0,0 @@
-// Package chainhash provides abstracted hash functionality.
-//
-// This package provides a generic hash type and associated functions that
-// allows the specific hash algorithm to be abstracted.
-package chainhash
diff --git a/chaincfg/chainhash/go.mod b/chaincfg/chainhash/go.mod
deleted file mode 100644
index 3f7b82a..0000000
--- a/chaincfg/chainhash/go.mod
+++ /dev/null
@@ -1,3 +0,0 @@
-module github.com/btcsuite/btcd/chaincfg/chainhash
-
-go 1.25
diff --git a/chaincfg/chainhash/hash.go b/chaincfg/chainhash/hash.go
deleted file mode 100644
index 5cac411..0000000
--- a/chaincfg/chainhash/hash.go
+++ /dev/null
@@ -1,282 +0,0 @@
-// Copyright (c) 2013-2016 The btcsuite developers
-// Copyright (c) 2015 The Decred developers
-// Use of this source code is governed by an ISC
-// license that can be found in the LICENSE file.
-
-package chainhash
-
-import (
- "crypto/sha256"
- "encoding/hex"
- "encoding/json"
- "fmt"
-)
-
-// HashSize of array used to store hashes. See Hash.
-const HashSize = 32
-
-// MaxHashStringSize is the maximum length of a Hash hash string.
-const MaxHashStringSize = HashSize * 2
-
-var (
- // TagBIP0340Challenge is the BIP-0340 tag for challenges.
- TagBIP0340Challenge = []byte("BIP0340/challenge")
-
- // TagBIP0340Aux is the BIP-0340 tag for aux data.
- TagBIP0340Aux = []byte("BIP0340/aux")
-
- // TagBIP0340Nonce is the BIP-0340 tag for nonces.
- TagBIP0340Nonce = []byte("BIP0340/nonce")
-
- // TagTapSighash is the tag used by BIP 341 to generate the sighash
- // flags.
- TagTapSighash = []byte("TapSighash")
-
- // TagTagTapLeaf is the message tag prefix used to compute the hash
- // digest of a tapscript leaf.
- TagTapLeaf = []byte("TapLeaf")
-
- // TagTapBranch is the message tag prefix used to compute the
- // hash digest of two tap leaves into a taproot branch node.
- TagTapBranch = []byte("TapBranch")
-
- // TagTapTweak is the message tag prefix used to compute the hash tweak
- // used to enable a public key to commit to the taproot branch root
- // for the witness program.
- TagTapTweak = []byte("TapTweak")
-
- // precomputedTags is a map containing the SHA-256 hash of the BIP-0340
- // tags.
- precomputedTags = map[string]Hash{
- string(TagBIP0340Challenge): sha256.Sum256(TagBIP0340Challenge),
- string(TagBIP0340Aux): sha256.Sum256(TagBIP0340Aux),
- string(TagBIP0340Nonce): sha256.Sum256(TagBIP0340Nonce),
- string(TagTapSighash): sha256.Sum256(TagTapSighash),
- string(TagTapLeaf): sha256.Sum256(TagTapLeaf),
- string(TagTapBranch): sha256.Sum256(TagTapBranch),
- string(TagTapTweak): sha256.Sum256(TagTapTweak),
- }
-)
-
-// ErrHashStrSize describes an error that indicates the caller specified a hash
-// string that has too many characters.
-var ErrHashStrSize = fmt.Errorf("max hash string length is %v bytes", MaxHashStringSize)
-
-// ErrHashStrSizeMismatch describes an error that indicates the caller
-// specified a hash string that does not meet the exact length required for
-// strict parsing.
-var ErrHashStrSizeMismatch = fmt.Errorf("hash string must be exactly %d "+
- "characters", MaxHashStringSize)
-
-// Hash is used in several of the bitcoin messages and common structures. It
-// typically represents the double sha256 of data.
-type Hash [HashSize]byte
-
-// String returns the Hash as the hexadecimal string of the byte-reversed
-// hash.
-func (hash Hash) String() string {
- for i := 0; i < HashSize/2; i++ {
- hash[i], hash[HashSize-1-i] = hash[HashSize-1-i], hash[i]
- }
- return hex.EncodeToString(hash[:])
-}
-
-// CloneBytes returns a copy of the bytes which represent the hash as a byte
-// slice.
-//
-// NOTE: It is generally cheaper to just slice the hash directly thereby reusing
-// the same bytes rather than calling this method.
-func (hash *Hash) CloneBytes() []byte {
- newHash := make([]byte, HashSize)
- copy(newHash, hash[:])
-
- return newHash
-}
-
-// SetBytes sets the bytes which represent the hash. An error is returned if
-// the number of bytes passed in is not HashSize.
-func (hash *Hash) SetBytes(newHash []byte) error {
- nhlen := len(newHash)
- if nhlen != HashSize {
- return fmt.Errorf("invalid hash length of %v, want %v", nhlen,
- HashSize)
- }
- copy(hash[:], newHash)
-
- return nil
-}
-
-// IsEqual returns true if target is the same as hash.
-func (hash *Hash) IsEqual(target *Hash) bool {
- if hash == nil && target == nil {
- return true
- }
- if hash == nil || target == nil {
- return false
- }
- return *hash == *target
-}
-
-// MarshalJSON serialises the hash as a JSON appropriate string value.
-func (hash Hash) MarshalJSON() ([]byte, error) {
- return json.Marshal(hash.String())
-}
-
-// UnmarshalJSON parses the hash with JSON appropriate string value.
-func (hash *Hash) UnmarshalJSON(input []byte) error {
- // If the first byte indicates an array, the hash could have been marshalled
- // using the legacy method and e.g. persisted.
- if len(input) > 0 && input[0] == '[' {
- return decodeLegacy(hash, input)
- }
-
- var sh string
- err := json.Unmarshal(input, &sh)
- if err != nil {
- return err
- }
- newHash, err := NewHashFromStr(sh)
- if err != nil {
- return err
- }
-
- return hash.SetBytes(newHash[:])
-}
-
-// NewHash returns a new Hash from a byte slice. An error is returned if
-// the number of bytes passed in is not HashSize.
-func NewHash(newHash []byte) (*Hash, error) {
- var sh Hash
- err := sh.SetBytes(newHash)
- if err != nil {
- return nil, err
- }
- return &sh, err
-}
-
-// TaggedHash implements the tagged hash scheme described in BIP-340. We use
-// sha-256 to bind a message hash to a specific context using a tag:
-// sha256(sha256(tag) || sha256(tag) || msg).
-func TaggedHash(tag []byte, msgs ...[]byte) *Hash {
- // Check to see if we've already pre-computed the hash of the tag. If
- // so then this'll save us an extra sha256 hash.
- shaTag, ok := precomputedTags[string(tag)]
- if !ok {
- shaTag = sha256.Sum256(tag)
- }
-
- // h = sha256(sha256(tag) || sha256(tag) || msg)
- h := sha256.New()
- h.Write(shaTag[:])
- h.Write(shaTag[:])
-
- for _, msg := range msgs {
- h.Write(msg)
- }
-
- taggedHash := h.Sum(nil)
-
- // The function can't error out since the above hash is guaranteed to
- // be 32 bytes.
- hash, _ := NewHash(taggedHash)
-
- return hash
-}
-
-// NewHashFromStr creates a Hash from a hash string. The string should be
-// the hexadecimal string of a byte-reversed hash, but any missing characters
-// result in zero padding at the end of the Hash.
-//
-// NOTE: This function accepts short and odd-length hex strings and pads them.
-// Typical parsing of full txids or block hashes should use NewHashFromStrStrict
-// instead.
-func NewHashFromStr(hash string) (*Hash, error) {
- ret := new(Hash)
- err := Decode(ret, hash)
- if err != nil {
- return nil, err
- }
- return ret, nil
-}
-
-// NewHashFromStrStrict creates a Hash from a hash string. The string must be
-// the full hexadecimal string of a byte-reversed hash.
-func NewHashFromStrStrict(hash string) (*Hash, error) {
- ret := new(Hash)
- err := DecodeStrict(ret, hash)
- if err != nil {
- return nil, err
- }
- return ret, nil
-}
-
-// Decode decodes the byte-reversed hexadecimal string encoding of a Hash to a
-// destination.
-//
-// NOTE: This function accepts short and odd-length hex strings and pads them.
-// Typical parsing of full txids or block hashes should use DecodeStrict
-// instead.
-func Decode(dst *Hash, src string) error {
- // Return error if hash string is too long.
- if len(src) > MaxHashStringSize {
- return ErrHashStrSize
- }
-
- // Hex decoder expects the hash to be a multiple of two. When not, pad
- // with a leading zero.
- var srcBytes []byte
- if len(src)%2 == 0 {
- srcBytes = []byte(src)
- } else {
- srcBytes = make([]byte, 1+len(src))
- srcBytes[0] = '0'
- copy(srcBytes[1:], src)
- }
-
- return decodeHash(dst, srcBytes)
-}
-
-// DecodeStrict decodes the byte-reversed hexadecimal string encoding of a Hash
-// to a destination. The source string must be exactly MaxHashStringSize
-// bytes, or ErrHashStrSizeMismatch is returned.
-func DecodeStrict(dst *Hash, src string) error {
- if len(src) != MaxHashStringSize {
- return ErrHashStrSizeMismatch
- }
-
- return decodeHash(dst, []byte(src))
-}
-
-// decodeHash decodes the provided byte-reversed hexadecimal bytes into dst.
-// The caller is responsible for applying any caller-specific length validation
-// before invoking this helper.
-func decodeHash(dst *Hash, src []byte) error {
- // Hex decode the source bytes to a temporary destination.
- var reversedHash Hash
- _, err := hex.Decode(reversedHash[HashSize-hex.DecodedLen(len(src)):], src)
- if err != nil {
- return err
- }
-
- // Reverse copy from the temporary hash to destination. Because the
- // temporary was zeroed, the written result will be correctly padded.
- for i, b := range reversedHash[:HashSize/2] {
- dst[i], dst[HashSize-1-i] = reversedHash[HashSize-1-i], b
- }
-
- return nil
-}
-
-// decodeLegacy decodes an Hash that has been encoded with the legacy method
-// (i.e. represented as a bytes array) to a destination.
-func decodeLegacy(dst *Hash, src []byte) error {
- var hashBytes []byte
- err := json.Unmarshal(src, &hashBytes)
- if err != nil {
- return err
- }
- if len(hashBytes) != HashSize {
- return ErrHashStrSize
- }
- return dst.SetBytes(hashBytes)
-}
diff --git a/chaincfg/chainhash/hash_test.go b/chaincfg/chainhash/hash_test.go
deleted file mode 100644
index f0dc207..0000000
--- a/chaincfg/chainhash/hash_test.go
+++ /dev/null
@@ -1,383 +0,0 @@
-// Copyright (c) 2013-2016 The btcsuite developers
-// Use of this source code is governed by an ISC
-// license that can be found in the LICENSE file.
-
-package chainhash
-
-import (
- "bytes"
- "encoding/hex"
- "encoding/json"
- "strings"
- "testing"
-)
-
-// mainNetGenesisHash is the hash of the first block in the block chain for the
-// main network (genesis block).
-var mainNetGenesisHash = Hash([HashSize]byte{ // Make go vet happy.
- 0x6f, 0xe2, 0x8c, 0x0a, 0xb6, 0xf1, 0xb3, 0x72,
- 0xc1, 0xa6, 0xa2, 0x46, 0xae, 0x63, 0xf7, 0x4f,
- 0x93, 0x1e, 0x83, 0x65, 0xe1, 0x5a, 0x08, 0x9c,
- 0x68, 0xd6, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00,
-})
-
-// TestHash tests the Hash API.
-func TestHash(t *testing.T) {
- // Hash of block 234439.
- blockHashStr := "14a0810ac680a3eb3f82edc878cea25ec41d6b790744e5daeef"
- blockHash, err := NewHashFromStr(blockHashStr)
- if err != nil {
- t.Errorf("NewHashFromStr: %v", err)
- }
-
- // Hash of block 234440 as byte slice.
- buf := []byte{
- 0x79, 0xa6, 0x1a, 0xdb, 0xc6, 0xe5, 0xa2, 0xe1,
- 0x39, 0xd2, 0x71, 0x3a, 0x54, 0x6e, 0xc7, 0xc8,
- 0x75, 0x63, 0x2e, 0x75, 0xf1, 0xdf, 0x9c, 0x3f,
- 0xa6, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- }
-
- hash, err := NewHash(buf)
- if err != nil {
- t.Errorf("NewHash: unexpected error %v", err)
- }
-
- // Ensure proper size.
- if len(hash) != HashSize {
- t.Errorf("NewHash: hash length mismatch - got: %v, want: %v",
- len(hash), HashSize)
- }
-
- // Ensure contents match.
- if !bytes.Equal(hash[:], buf) {
- t.Errorf("NewHash: hash contents mismatch - got: %v, want: %v",
- hash[:], buf)
- }
-
- // Ensure contents of hash of block 234440 don't match 234439.
- if hash.IsEqual(blockHash) {
- t.Errorf("IsEqual: hash contents should not match - got: %v, want: %v",
- hash, blockHash)
- }
-
- // Set hash from byte slice and ensure contents match.
- err = hash.SetBytes(blockHash.CloneBytes())
- if err != nil {
- t.Errorf("SetBytes: %v", err)
- }
- if !hash.IsEqual(blockHash) {
- t.Errorf("IsEqual: hash contents mismatch - got: %v, want: %v",
- hash, blockHash)
- }
-
- // Ensure nil hashes are handled properly.
- if !(*Hash)(nil).IsEqual(nil) {
- t.Error("IsEqual: nil hashes should match")
- }
- if hash.IsEqual(nil) {
- t.Error("IsEqual: non-nil hash matches nil hash")
- }
-
- // Invalid size for SetBytes.
- err = hash.SetBytes([]byte{0x00})
- if err == nil {
- t.Errorf("SetBytes: failed to received expected err - got: nil")
- }
-
- // Invalid size for NewHash.
- invalidHash := make([]byte, HashSize+1)
- _, err = NewHash(invalidHash)
- if err == nil {
- t.Errorf("NewHash: failed to received expected err - got: nil")
- }
-}
-
-// TestHashString tests the stringized output for hashes.
-func TestHashString(t *testing.T) {
- // Block 100000 hash.
- wantStr := "000000000003ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506"
- hash := Hash([HashSize]byte{ // Make go vet happy.
- 0x06, 0xe5, 0x33, 0xfd, 0x1a, 0xda, 0x86, 0x39,
- 0x1f, 0x3f, 0x6c, 0x34, 0x32, 0x04, 0xb0, 0xd2,
- 0x78, 0xd4, 0xaa, 0xec, 0x1c, 0x0b, 0x20, 0xaa,
- 0x27, 0xba, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
- })
-
- hashStr := hash.String()
- if hashStr != wantStr {
- t.Errorf("String: wrong hash string - got %v, want %v",
- hashStr, wantStr)
- }
-}
-
-// TestNewHashFromStr executes compatibility tests against the lenient
-// NewHashFromStr function.
-func TestNewHashFromStr(t *testing.T) {
- tests := []struct {
- in string
- want Hash
- err error
- }{
- // Genesis hash.
- {
- "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
- mainNetGenesisHash,
- nil,
- },
-
- // Genesis hash with stripped leading zeros.
- {
- "19d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
- mainNetGenesisHash,
- nil,
- },
-
- // Empty string.
- {
- "",
- Hash{},
- nil,
- },
-
- // Single digit hash.
- {
- "1",
- Hash([HashSize]byte{ // Make go vet happy.
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- }),
- nil,
- },
-
- // Block 203707 with stripped leading zeros.
- {
- "3264bc2ac36a60840790ba1d475d01367e7c723da941069e9dc",
- Hash([HashSize]byte{ // Make go vet happy.
- 0xdc, 0xe9, 0x69, 0x10, 0x94, 0xda, 0x23, 0xc7,
- 0xe7, 0x67, 0x13, 0xd0, 0x75, 0xd4, 0xa1, 0x0b,
- 0x79, 0x40, 0x08, 0xa6, 0x36, 0xac, 0xc2, 0x4b,
- 0x26, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- }),
- nil,
- },
-
- // Hash string that is too long.
- {
- "01234567890123456789012345678901234567890123456789012345678912345",
- Hash{},
- ErrHashStrSize,
- },
-
- // Hash string that is contains non-hex chars.
- {
- "abcdefg",
- Hash{},
- hex.InvalidByteError('g'),
- },
- }
-
- unexpectedErrStr := "NewHashFromStr #%d failed to detect expected error - got: %v want: %v"
- unexpectedResultStr := "NewHashFromStr #%d got: %v want: %v"
- t.Logf("Running %d tests", len(tests))
- for i, test := range tests {
- result, err := NewHashFromStr(test.in)
- if err != test.err {
- t.Errorf(unexpectedErrStr, i, err, test.err)
- continue
- } else if err != nil {
- // Got expected error. Move on to the next test.
- continue
- }
- if !test.want.IsEqual(result) {
- t.Errorf(unexpectedResultStr, i, result, &test.want)
- continue
- }
- }
-}
-
-// TestNewHashFromStrStrict executes tests against the NewHashFromStrStrict
-// function.
-func TestNewHashFromStrStrict(t *testing.T) {
- tests := []struct {
- name string
- in string
- want Hash
- err error
- }{
- {
- name: "genesis hash",
- in: "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
- want: mainNetGenesisHash,
- err: nil,
- },
- {
- name: "stripped leading zeros",
- in: "19d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
- want: Hash{},
- err: ErrHashStrSizeMismatch,
- },
- {
- name: "odd length hash",
- in: "1",
- want: Hash{},
- err: ErrHashStrSizeMismatch,
- },
- {
- name: "empty string",
- in: "",
- want: Hash{},
- err: ErrHashStrSizeMismatch,
- },
- {
- name: "hash string that is too long",
- in: "01234567890123456789012345678901234567890123456789012345678912345",
- want: Hash{},
- err: ErrHashStrSizeMismatch,
- },
- {
- name: "hash string that contains non-hex chars",
- in: "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26g",
- want: Hash{},
- err: hex.InvalidByteError('g'),
- },
- }
-
- unexpectedErrStr := "NewHashFromStrStrict #%d failed to detect expected error - got: %v want: %v"
- unexpectedResultStr := "NewHashFromStrStrict #%d got: %v want: %v"
- t.Logf("Running %d tests", len(tests))
- for i, test := range tests {
- test := test
-
- t.Run(test.name, func(t *testing.T) {
- result, err := NewHashFromStrStrict(test.in)
- if err != test.err {
- t.Errorf(unexpectedErrStr, i, err, test.err)
- return
- } else if err != nil {
- return
- }
- if !test.want.IsEqual(result) {
- t.Errorf(unexpectedResultStr, i, result, &test.want)
- }
- })
- }
-}
-
-// TestDecodeStrict executes tests against the DecodeStrict function.
-func TestDecodeStrict(t *testing.T) {
- tests := []struct {
- name string
- in string
- want Hash
- err error
- }{
- {
- name: "genesis hash",
- in: "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
- want: mainNetGenesisHash,
- err: nil,
- },
- {
- name: "odd length hash",
- in: "1",
- want: Hash{},
- err: ErrHashStrSizeMismatch,
- },
- {
- name: "even length hash that is too short, 32 chars",
- in: "deadbeef" + strings.Repeat("0", 24),
- want: Hash{},
- err: ErrHashStrSizeMismatch,
- },
- {
- name: "hash string that contains non-hex chars",
- in: "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26g",
- want: Hash{},
- err: hex.InvalidByteError('g'),
- },
- {
- name: "hash string that is too long",
- in: "01234567890123456789012345678901234567890123456789012345678912345",
- want: Hash{},
- err: ErrHashStrSizeMismatch,
- },
- }
-
- unexpectedErrStr := "DecodeStrict #%d failed to detect expected error - got: %v want: %v"
- unexpectedResultStr := "DecodeStrict #%d got: %v want: %v"
- t.Logf("Running %d tests", len(tests))
- for i, test := range tests {
- test := test
-
- t.Run(test.name, func(t *testing.T) {
- var result Hash
- err := DecodeStrict(&result, test.in)
- if err != test.err {
- t.Errorf(unexpectedErrStr, i, err, test.err)
- return
- } else if err != nil {
- return
- }
- if !test.want.IsEqual(&result) {
- t.Errorf(unexpectedResultStr, i, &result, &test.want)
- }
- })
- }
-}
-
-// BenchmarkDecodeStrict benchmarks DecodeStrict on a valid canonical hash.
-func BenchmarkDecodeStrict(b *testing.B) {
- // Use a canonical 64-character hash to exercise the successful strict path.
- hashStr := "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"
- var result Hash
-
- b.ReportAllocs()
- for i := 0; i < b.N; i++ {
- if err := DecodeStrict(&result, hashStr); err != nil {
- b.Fatalf("unexpected decode error: %v", err)
- }
- }
-
- if !mainNetGenesisHash.IsEqual(&result) {
- b.Fatalf("unexpected decode result: got %v want %v",
- &result, &mainNetGenesisHash)
- }
-}
-
-// TestHashJsonMarshal tests json marshal and unmarshal.
-func TestHashJsonMarshal(t *testing.T) {
- hashStr := "000000000003ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506"
- legacyHashStr := []byte("[6,229,51,253,26,218,134,57,31,63,108,52,50,4,176,210,120,212,170,236,28,11,32,170,39,186,3,0,0,0,0,0]")
-
- hash, err := NewHashFromStr(hashStr)
- if err != nil {
- t.Errorf("NewHashFromStr error:%v, hashStr:%s", err, hashStr)
- }
-
- hashBytes, err := json.Marshal(hash)
- if err != nil {
- t.Errorf("Marshal json error:%v, hash:%v", err, hashBytes)
- }
-
- var newHash Hash
- err = json.Unmarshal(hashBytes, &newHash)
- if err != nil {
- t.Errorf("Unmarshal json error:%v, hash:%v", err, hashBytes)
- }
-
- if !hash.IsEqual(&newHash) {
- t.Errorf("String: wrong hash string - got %v, want %v", newHash.String(), hashStr)
- }
-
- err = newHash.UnmarshalJSON(legacyHashStr)
- if err != nil {
- t.Errorf("Unmarshal legacy json error:%v, hash:%v", err, legacyHashStr)
- }
-
- if !hash.IsEqual(&newHash) {
- t.Errorf("String: wrong hash string - got %v, want %v", newHash.String(), hashStr)
- }
-}
diff --git a/chaincfg/chainhash/hashfuncs.go b/chaincfg/chainhash/hashfuncs.go
deleted file mode 100644
index 5be8a4d..0000000
--- a/chaincfg/chainhash/hashfuncs.go
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright (c) 2015 The Decred developers
-// Copyright (c) 2016-2017 The btcsuite developers
-// Use of this source code is governed by an ISC
-// license that can be found in the LICENSE file.
-
-package chainhash
-
-import (
- "crypto/sha256"
- "io"
-)
-
-// HashB calculates hash(b) and returns the resulting bytes.
-func HashB(b []byte) []byte {
- hash := sha256.Sum256(b)
- return hash[:]
-}
-
-// HashH calculates hash(b) and returns the resulting bytes as a Hash.
-func HashH(b []byte) Hash {
- return Hash(sha256.Sum256(b))
-}
-
-// DoubleHashB calculates hash(hash(b)) and returns the resulting bytes.
-func DoubleHashB(b []byte) []byte {
- first := sha256.Sum256(b)
- second := sha256.Sum256(first[:])
- return second[:]
-}
-
-// DoubleHashH calculates hash(hash(b)) and returns the resulting bytes as a
-// Hash.
-func DoubleHashH(b []byte) Hash {
- first := sha256.Sum256(b)
- return Hash(sha256.Sum256(first[:]))
-}
-
-// DoubleHashRaw calculates hash(hash(w)) where w is the resulting bytes from
-// the given serialize function and returns the resulting bytes as a Hash.
-func DoubleHashRaw(serialize func(w io.Writer) error) Hash {
- // Encode the transaction into the hash. Ignore the error returns
- // since the only way the encode could fail is being out of memory
- // or due to nil pointers, both of which would cause a run-time panic.
- h := sha256.New()
- _ = serialize(h)
-
- // This buf is here because Sum() will append the result to the passed
- // in byte slice. Pre-allocating here saves an allocation on the second
- // hash as we can reuse it. This allocation also does not escape to the
- // heap, saving an allocation.
- buf := make([]byte, 0, HashSize)
- first := h.Sum(buf)
- h.Reset()
- h.Write(first)
- res := h.Sum(buf)
- return *(*Hash)(res)
-}
diff --git a/chaincfg/chainhash/hashfuncs_test.go b/chaincfg/chainhash/hashfuncs_test.go
deleted file mode 100644
index 6b9ff9a..0000000
--- a/chaincfg/chainhash/hashfuncs_test.go
+++ /dev/null
@@ -1,153 +0,0 @@
-// Copyright (c) 2016 The btcsuite developers
-// Use of this source code is governed by an ISC
-// license that can be found in the LICENSE file.
-
-package chainhash
-
-import (
- "fmt"
- "io"
- "testing"
-)
-
-// TestHashFuncs ensures the hash functions which perform hash(b) work as
-// expected.
-func TestHashFuncs(t *testing.T) {
- tests := []struct {
- out string
- in string
- }{
- {"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", ""},
- {"ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb", "a"},
- {"fb8e20fc2e4c3f248c60c39bd652f3c1347298bb977b8b4d5903b85055620603", "ab"},
- {"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", "abc"},
- {"88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589", "abcd"},
- {"36bbe50ed96841d10443bcb670d6554f0a34b761be67ec9c4a8ad2c0c44ca42c", "abcde"},
- {"bef57ec7f53a6d40beb640a780a639c83bc29ac8a9816f1fc6c5c6dcd93c4721", "abcdef"},
- {"7d1a54127b222502f5b79b5fb0803061152a44f92b37e23c6527baf665d4da9a", "abcdefg"},
- {"9c56cc51b374c3ba189210d5b6d4bf57790d351c96c47c02190ecf1e430635ab", "abcdefgh"},
- {"19cc02f26df43cc571bc9ed7b0c4d29224a3ec229529221725ef76d021c8326f", "abcdefghi"},
- {"72399361da6a7754fec986dca5b7cbaf1c810a28ded4abaf56b2106d06cb78b0", "abcdefghij"},
- {"a144061c271f152da4d151034508fed1c138b8c976339de229c3bb6d4bbb4fce", "Discard medicine more than two years old."},
- {"6dae5caa713a10ad04b46028bf6dad68837c581616a1589a265a11288d4bb5c4", "He who has a shady past knows that nice guys finish last."},
- {"ae7a702a9509039ddbf29f0765e70d0001177914b86459284dab8b348c2dce3f", "I wouldn't marry him with a ten foot pole."},
- {"6748450b01c568586715291dfa3ee018da07d36bb7ea6f180c1af6270215c64f", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
- {"14b82014ad2b11f661b5ae6a99b75105c2ffac278cd071cd6c05832793635774", "The days of the digital watch are numbered. -Tom Stoppard"},
- {"7102cfd76e2e324889eece5d6c41921b1e142a4ac5a2692be78803097f6a48d8", "Nepal premier won't resign."},
- {"23b1018cd81db1d67983c5f7417c44da9deb582459e378d7a068552ea649dc9f", "For every action there is an equal and opposite government program."},
- {"8001f190dfb527261c4cfcab70c98e8097a7a1922129bc4096950e57c7999a5a", "His money is twice tainted: 'taint yours and 'taint mine."},
- {"8c87deb65505c3993eb24b7a150c4155e82eee6960cf0c3a8114ff736d69cad5", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
- {"bfb0a67a19cdec3646498b2e0f751bddc41bba4b7f30081b0b932aad214d16d7", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
- {"7f9a0b9bf56332e19f5a0ec1ad9c1425a153da1c624868fda44561d6b74daf36", "size: a.out: bad magic"},
- {"b13f81b8aad9e3666879af19886140904f7f429ef083286195982a7588858cfc", "The major problem is with sendmail. -Mark Horton"},
- {"b26c38d61519e894480c70c8374ea35aa0ad05b2ae3d6674eec5f52a69305ed4", "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
- {"049d5e26d4f10222cd841a119e38bd8d2e0d1129728688449575d4ff42b842c1", "If the enemy is within range, then so are you."},
- {"0e116838e3cc1c1a14cd045397e29b4d087aa11b0853fc69ec82e90330d60949", "It's well we cannot hear the screams/That we create in others' dreams."},
- {"4f7d8eb5bcf11de2a56b971021a444aa4eafd6ecd0f307b5109e4e776cd0fe46", "You remind me of a TV show, but that's all right: I watch it anyway."},
- {"61c0cc4c4bd8406d5120b3fb4ebc31ce87667c162f29468b3c779675a85aebce", "C is as portable as Stonehedge!!"},
- {"1fb2eb3688093c4a3f80cd87a5547e2ce940a4f923243a79a2a1e242220693ac", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
- {"395585ce30617b62c80b93e8208ce866d4edc811a177fdb4b82d3911d8696423", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
- {"4f9b189a13d030838269dce846b16a1ce9ce81fe63e65de2f636863336a98fe6", "How can you write a big system without C++? -Paul Glick"},
- }
-
- // Ensure the hash function which returns a byte slice returns the
- // expected result.
- for _, test := range tests {
- h := fmt.Sprintf("%x", HashB([]byte(test.in)))
- if h != test.out {
- t.Errorf("HashB(%q) = %s, want %s", test.in, h, test.out)
- continue
- }
- }
-
- // Ensure the hash function which returns a Hash returns the expected
- // result.
- for _, test := range tests {
- hash := HashH([]byte(test.in))
- h := fmt.Sprintf("%x", hash[:])
- if h != test.out {
- t.Errorf("HashH(%q) = %s, want %s", test.in, h, test.out)
- continue
- }
- }
-}
-
-// TestDoubleHashFuncs ensures the hash functions which perform hash(hash(b))
-// work as expected.
-func TestDoubleHashFuncs(t *testing.T) {
- tests := []struct {
- out string
- in string
- }{
- {"5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456", ""},
- {"bf5d3affb73efd2ec6c36ad3112dd933efed63c4e1cbffcfa88e2759c144f2d8", "a"},
- {"a1ff8f1856b5e24e32e3882edd4a021f48f28a8b21854b77fdef25a97601aace", "ab"},
- {"4f8b42c22dd3729b519ba6f68d2da7cc5b2d606d05daed5ad5128cc03e6c6358", "abc"},
- {"7e9c158ecd919fa439a7a214c9fc58b85c3177fb1613bdae41ee695060e11bc6", "abcd"},
- {"1d72b6eb7ba8b9709c790b33b40d8c46211958e13cf85dbcda0ed201a99f2fb9", "abcde"},
- {"ce65d4756128f0035cba4d8d7fae4e9fa93cf7fdf12c0f83ee4a0e84064bef8a", "abcdef"},
- {"dad6b965ad86b880ceb6993f98ebeeb242de39f6b87a458c6510b5a15ff7bbf1", "abcdefg"},
- {"b9b12e7125f73fda20b8c4161fb9b4b146c34cf88595a1e0503ca2cf44c86bc4", "abcdefgh"},
- {"546db09160636e98405fbec8464a84b6464b32514db259e235eae0445346ffb7", "abcdefghi"},
- {"27635cf23fdf8a10f4cb2c52ade13038c38718c6d7ca716bfe726111a57ad201", "abcdefghij"},
- {"ae0d8e0e7c0336f0c3a72cefa4f24b625a6a460417a921d066058a0b81e23429", "Discard medicine more than two years old."},
- {"eeb56d02cf638f87ea8f11ebd5b0201afcece984d87be458578d3cfb51978f1b", "He who has a shady past knows that nice guys finish last."},
- {"dc640bf529608a381ea7065ecbcd0443b95f6e4c008de6e134aff1d36bd4b9d8", "I wouldn't marry him with a ten foot pole."},
- {"42e54375e60535eb07fc15c6350e10f2c22526f84db1d6f6bba925e154486f33", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
- {"4ed6aa9b88c84afbf928710b03714de69e2ad967c6a78586069adcb4c470d150", "The days of the digital watch are numbered. -Tom Stoppard"},
- {"590c24d1877c1919fad12fe01a8796999e9d20cfbf9bc9bc72fa0bd69f0b04dd", "Nepal premier won't resign."},
- {"37d270687ee8ebafcd3c1a32f56e1e1304b3c93f252cb637d57a66d59c475eca", "For every action there is an equal and opposite government program."},
- {"306828fd89278838bb1c544c3032a1fd25ea65c40bba586437568828a5fbe944", "His money is twice tainted: 'taint yours and 'taint mine."},
- {"49965777eac71faf1e2fb0f6b239ba2fae770977940fd827bcbfe15def6ded53", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
- {"df99ee4e87dd3fb07922dee7735997bbae8f26db20c86137d4219fc4a37b77c3", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
- {"920667c84a15b5ee3df4620169f5c0ec930cea0c580858e50e68848871ed65b4", "size: a.out: bad magic"},
- {"5e817fe20848a4a3932db68e90f8d54ec1b09603f0c99fdc051892b776acd462", "The major problem is with sendmail. -Mark Horton"},
- {"6a9d47248ed38852f5f4b2e37e7dfad0ce8d1da86b280feef94ef267e468cff2", "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
- {"2e7aa1b362c94efdbff582a8bd3f7f61c8ce4c25bbde658ef1a7ae1010e2126f", "If the enemy is within range, then so are you."},
- {"e6729d51240b1e1da76d822fd0c55c75e409bcb525674af21acae1f11667c8ca", "It's well we cannot hear the screams/That we create in others' dreams."},
- {"09945e4d2743eb669f85e4097aa1cc39ea680a0b2ae2a65a42a5742b3b809610", "You remind me of a TV show, but that's all right: I watch it anyway."},
- {"1018d8b2870a974887c5174360f0fbaf27958eef15b24522a605c5dae4ae0845", "C is as portable as Stonehedge!!"},
- {"97c76b83c6645c78c261dcdc55d44af02d9f1df8057f997fd08c310c903624d5", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
- {"6bcbf25469e9544c5b5806b24220554fedb6695ba9b1510a76837414f7adb113", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
- {"1041988b06835481f0845be2a54f4628e1da26145b2de7ad1be3bb643cef9d4f", "How can you write a big system without C++? -Paul Glick"},
- }
-
- // Ensure the hash function which returns a byte slice returns the
- // expected result.
- for _, test := range tests {
- h := fmt.Sprintf("%x", DoubleHashB([]byte(test.in)))
- if h != test.out {
- t.Errorf("DoubleHashB(%q) = %s, want %s", test.in, h,
- test.out)
- continue
- }
- }
-
- // Ensure the hash function which returns a Hash returns the expected
- // result.
- for _, test := range tests {
- hash := DoubleHashH([]byte(test.in))
- h := fmt.Sprintf("%x", hash[:])
- if h != test.out {
- t.Errorf("DoubleHashH(%q) = %s, want %s", test.in, h,
- test.out)
- continue
- }
- }
-
- // Ensure the hash function which accepts a hash.Hash returns the expected
- // result when given a hash.Hash that is of type SHA256.
- for _, test := range tests {
- serialize := func(w io.Writer) error {
- w.Write([]byte(test.in))
- return nil
- }
- hash := DoubleHashRaw(serialize)
- h := fmt.Sprintf("%x", hash[:])
- if h != test.out {
- t.Errorf("DoubleHashRaw(%q) = %s, want %s", test.in, h,
- test.out)
- continue
- }
- }
-}
diff --git a/chainhash/README.md b/chainhash/README.md
new file mode 100644
index 0000000..fcffef7
--- /dev/null
+++ b/chainhash/README.md
@@ -0,0 +1,41 @@
+chainhash
+=========
+
+[](https://github.com/btcsuite/btcd/actions)
+[](http://copyfree.org)
+[](https://pkg.go.dev/github.com/btcsuite/btcd/chainhash/v2)
+=======
+
+chainhash provides a generic hash type and associated functions that allows the
+specific hash algorithm to be abstracted.
+
+## Installation and Updating
+
+```bash
+$ go get -u github.com/btcsuite/btcd/chainhash/v2
+```
+
+## GPG Verification Key
+
+All official release tags are signed by Conformal so users can ensure the code
+has not been tampered with and is coming from the btcsuite developers. To
+verify the signature perform the following:
+
+- Download the public key from the Conformal website at
+ https://opensource.conformal.com/GIT-GPG-KEY-conformal.txt
+
+- Import the public key into your GPG keyring:
+ ```bash
+ gpg --import GIT-GPG-KEY-conformal.txt
+ ```
+
+- Verify the release tag with the following command where `TAG_NAME` is a
+ placeholder for the specific tag:
+ ```bash
+ git tag -v TAG_NAME
+ ```
+
+## License
+
+Package chainhash is licensed under the [copyfree](http://copyfree.org) ISC
+License.
diff --git a/chainhash/doc.go b/chainhash/doc.go
new file mode 100644
index 0000000..c3eb43d
--- /dev/null
+++ b/chainhash/doc.go
@@ -0,0 +1,5 @@
+// Package chainhash provides abstracted hash functionality.
+//
+// This package provides a generic hash type and associated functions that
+// allows the specific hash algorithm to be abstracted.
+package chainhash
diff --git a/chainhash/go.mod b/chainhash/go.mod
new file mode 100644
index 0000000..1c44358
--- /dev/null
+++ b/chainhash/go.mod
@@ -0,0 +1,3 @@
+module github.com/btcsuite/btcd/chainhash/v2
+
+go 1.23.2
diff --git a/chainhash/hash.go b/chainhash/hash.go
new file mode 100644
index 0000000..5cac411
--- /dev/null
+++ b/chainhash/hash.go
@@ -0,0 +1,282 @@
+// Copyright (c) 2013-2016 The btcsuite developers
+// Copyright (c) 2015 The Decred developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package chainhash
+
+import (
+ "crypto/sha256"
+ "encoding/hex"
+ "encoding/json"
+ "fmt"
+)
+
+// HashSize of array used to store hashes. See Hash.
+const HashSize = 32
+
+// MaxHashStringSize is the maximum length of a Hash hash string.
+const MaxHashStringSize = HashSize * 2
+
+var (
+ // TagBIP0340Challenge is the BIP-0340 tag for challenges.
+ TagBIP0340Challenge = []byte("BIP0340/challenge")
+
+ // TagBIP0340Aux is the BIP-0340 tag for aux data.
+ TagBIP0340Aux = []byte("BIP0340/aux")
+
+ // TagBIP0340Nonce is the BIP-0340 tag for nonces.
+ TagBIP0340Nonce = []byte("BIP0340/nonce")
+
+ // TagTapSighash is the tag used by BIP 341 to generate the sighash
+ // flags.
+ TagTapSighash = []byte("TapSighash")
+
+ // TagTagTapLeaf is the message tag prefix used to compute the hash
+ // digest of a tapscript leaf.
+ TagTapLeaf = []byte("TapLeaf")
+
+ // TagTapBranch is the message tag prefix used to compute the
+ // hash digest of two tap leaves into a taproot branch node.
+ TagTapBranch = []byte("TapBranch")
+
+ // TagTapTweak is the message tag prefix used to compute the hash tweak
+ // used to enable a public key to commit to the taproot branch root
+ // for the witness program.
+ TagTapTweak = []byte("TapTweak")
+
+ // precomputedTags is a map containing the SHA-256 hash of the BIP-0340
+ // tags.
+ precomputedTags = map[string]Hash{
+ string(TagBIP0340Challenge): sha256.Sum256(TagBIP0340Challenge),
+ string(TagBIP0340Aux): sha256.Sum256(TagBIP0340Aux),
+ string(TagBIP0340Nonce): sha256.Sum256(TagBIP0340Nonce),
+ string(TagTapSighash): sha256.Sum256(TagTapSighash),
+ string(TagTapLeaf): sha256.Sum256(TagTapLeaf),
+ string(TagTapBranch): sha256.Sum256(TagTapBranch),
+ string(TagTapTweak): sha256.Sum256(TagTapTweak),
+ }
+)
+
+// ErrHashStrSize describes an error that indicates the caller specified a hash
+// string that has too many characters.
+var ErrHashStrSize = fmt.Errorf("max hash string length is %v bytes", MaxHashStringSize)
+
+// ErrHashStrSizeMismatch describes an error that indicates the caller
+// specified a hash string that does not meet the exact length required for
+// strict parsing.
+var ErrHashStrSizeMismatch = fmt.Errorf("hash string must be exactly %d "+
+ "characters", MaxHashStringSize)
+
+// Hash is used in several of the bitcoin messages and common structures. It
+// typically represents the double sha256 of data.
+type Hash [HashSize]byte
+
+// String returns the Hash as the hexadecimal string of the byte-reversed
+// hash.
+func (hash Hash) String() string {
+ for i := 0; i < HashSize/2; i++ {
+ hash[i], hash[HashSize-1-i] = hash[HashSize-1-i], hash[i]
+ }
+ return hex.EncodeToString(hash[:])
+}
+
+// CloneBytes returns a copy of the bytes which represent the hash as a byte
+// slice.
+//
+// NOTE: It is generally cheaper to just slice the hash directly thereby reusing
+// the same bytes rather than calling this method.
+func (hash *Hash) CloneBytes() []byte {
+ newHash := make([]byte, HashSize)
+ copy(newHash, hash[:])
+
+ return newHash
+}
+
+// SetBytes sets the bytes which represent the hash. An error is returned if
+// the number of bytes passed in is not HashSize.
+func (hash *Hash) SetBytes(newHash []byte) error {
+ nhlen := len(newHash)
+ if nhlen != HashSize {
+ return fmt.Errorf("invalid hash length of %v, want %v", nhlen,
+ HashSize)
+ }
+ copy(hash[:], newHash)
+
+ return nil
+}
+
+// IsEqual returns true if target is the same as hash.
+func (hash *Hash) IsEqual(target *Hash) bool {
+ if hash == nil && target == nil {
+ return true
+ }
+ if hash == nil || target == nil {
+ return false
+ }
+ return *hash == *target
+}
+
+// MarshalJSON serialises the hash as a JSON appropriate string value.
+func (hash Hash) MarshalJSON() ([]byte, error) {
+ return json.Marshal(hash.String())
+}
+
+// UnmarshalJSON parses the hash with JSON appropriate string value.
+func (hash *Hash) UnmarshalJSON(input []byte) error {
+ // If the first byte indicates an array, the hash could have been marshalled
+ // using the legacy method and e.g. persisted.
+ if len(input) > 0 && input[0] == '[' {
+ return decodeLegacy(hash, input)
+ }
+
+ var sh string
+ err := json.Unmarshal(input, &sh)
+ if err != nil {
+ return err
+ }
+ newHash, err := NewHashFromStr(sh)
+ if err != nil {
+ return err
+ }
+
+ return hash.SetBytes(newHash[:])
+}
+
+// NewHash returns a new Hash from a byte slice. An error is returned if
+// the number of bytes passed in is not HashSize.
+func NewHash(newHash []byte) (*Hash, error) {
+ var sh Hash
+ err := sh.SetBytes(newHash)
+ if err != nil {
+ return nil, err
+ }
+ return &sh, err
+}
+
+// TaggedHash implements the tagged hash scheme described in BIP-340. We use
+// sha-256 to bind a message hash to a specific context using a tag:
+// sha256(sha256(tag) || sha256(tag) || msg).
+func TaggedHash(tag []byte, msgs ...[]byte) *Hash {
+ // Check to see if we've already pre-computed the hash of the tag. If
+ // so then this'll save us an extra sha256 hash.
+ shaTag, ok := precomputedTags[string(tag)]
+ if !ok {
+ shaTag = sha256.Sum256(tag)
+ }
+
+ // h = sha256(sha256(tag) || sha256(tag) || msg)
+ h := sha256.New()
+ h.Write(shaTag[:])
+ h.Write(shaTag[:])
+
+ for _, msg := range msgs {
+ h.Write(msg)
+ }
+
+ taggedHash := h.Sum(nil)
+
+ // The function can't error out since the above hash is guaranteed to
+ // be 32 bytes.
+ hash, _ := NewHash(taggedHash)
+
+ return hash
+}
+
+// NewHashFromStr creates a Hash from a hash string. The string should be
+// the hexadecimal string of a byte-reversed hash, but any missing characters
+// result in zero padding at the end of the Hash.
+//
+// NOTE: This function accepts short and odd-length hex strings and pads them.
+// Typical parsing of full txids or block hashes should use NewHashFromStrStrict
+// instead.
+func NewHashFromStr(hash string) (*Hash, error) {
+ ret := new(Hash)
+ err := Decode(ret, hash)
+ if err != nil {
+ return nil, err
+ }
+ return ret, nil
+}
+
+// NewHashFromStrStrict creates a Hash from a hash string. The string must be
+// the full hexadecimal string of a byte-reversed hash.
+func NewHashFromStrStrict(hash string) (*Hash, error) {
+ ret := new(Hash)
+ err := DecodeStrict(ret, hash)
+ if err != nil {
+ return nil, err
+ }
+ return ret, nil
+}
+
+// Decode decodes the byte-reversed hexadecimal string encoding of a Hash to a
+// destination.
+//
+// NOTE: This function accepts short and odd-length hex strings and pads them.
+// Typical parsing of full txids or block hashes should use DecodeStrict
+// instead.
+func Decode(dst *Hash, src string) error {
+ // Return error if hash string is too long.
+ if len(src) > MaxHashStringSize {
+ return ErrHashStrSize
+ }
+
+ // Hex decoder expects the hash to be a multiple of two. When not, pad
+ // with a leading zero.
+ var srcBytes []byte
+ if len(src)%2 == 0 {
+ srcBytes = []byte(src)
+ } else {
+ srcBytes = make([]byte, 1+len(src))
+ srcBytes[0] = '0'
+ copy(srcBytes[1:], src)
+ }
+
+ return decodeHash(dst, srcBytes)
+}
+
+// DecodeStrict decodes the byte-reversed hexadecimal string encoding of a Hash
+// to a destination. The source string must be exactly MaxHashStringSize
+// bytes, or ErrHashStrSizeMismatch is returned.
+func DecodeStrict(dst *Hash, src string) error {
+ if len(src) != MaxHashStringSize {
+ return ErrHashStrSizeMismatch
+ }
+
+ return decodeHash(dst, []byte(src))
+}
+
+// decodeHash decodes the provided byte-reversed hexadecimal bytes into dst.
+// The caller is responsible for applying any caller-specific length validation
+// before invoking this helper.
+func decodeHash(dst *Hash, src []byte) error {
+ // Hex decode the source bytes to a temporary destination.
+ var reversedHash Hash
+ _, err := hex.Decode(reversedHash[HashSize-hex.DecodedLen(len(src)):], src)
+ if err != nil {
+ return err
+ }
+
+ // Reverse copy from the temporary hash to destination. Because the
+ // temporary was zeroed, the written result will be correctly padded.
+ for i, b := range reversedHash[:HashSize/2] {
+ dst[i], dst[HashSize-1-i] = reversedHash[HashSize-1-i], b
+ }
+
+ return nil
+}
+
+// decodeLegacy decodes an Hash that has been encoded with the legacy method
+// (i.e. represented as a bytes array) to a destination.
+func decodeLegacy(dst *Hash, src []byte) error {
+ var hashBytes []byte
+ err := json.Unmarshal(src, &hashBytes)
+ if err != nil {
+ return err
+ }
+ if len(hashBytes) != HashSize {
+ return ErrHashStrSize
+ }
+ return dst.SetBytes(hashBytes)
+}
diff --git a/chainhash/hash_test.go b/chainhash/hash_test.go
new file mode 100644
index 0000000..f0dc207
--- /dev/null
+++ b/chainhash/hash_test.go
@@ -0,0 +1,383 @@
+// Copyright (c) 2013-2016 The btcsuite developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package chainhash
+
+import (
+ "bytes"
+ "encoding/hex"
+ "encoding/json"
+ "strings"
+ "testing"
+)
+
+// mainNetGenesisHash is the hash of the first block in the block chain for the
+// main network (genesis block).
+var mainNetGenesisHash = Hash([HashSize]byte{ // Make go vet happy.
+ 0x6f, 0xe2, 0x8c, 0x0a, 0xb6, 0xf1, 0xb3, 0x72,
+ 0xc1, 0xa6, 0xa2, 0x46, 0xae, 0x63, 0xf7, 0x4f,
+ 0x93, 0x1e, 0x83, 0x65, 0xe1, 0x5a, 0x08, 0x9c,
+ 0x68, 0xd6, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00,
+})
+
+// TestHash tests the Hash API.
+func TestHash(t *testing.T) {
+ // Hash of block 234439.
+ blockHashStr := "14a0810ac680a3eb3f82edc878cea25ec41d6b790744e5daeef"
+ blockHash, err := NewHashFromStr(blockHashStr)
+ if err != nil {
+ t.Errorf("NewHashFromStr: %v", err)
+ }
+
+ // Hash of block 234440 as byte slice.
+ buf := []byte{
+ 0x79, 0xa6, 0x1a, 0xdb, 0xc6, 0xe5, 0xa2, 0xe1,
+ 0x39, 0xd2, 0x71, 0x3a, 0x54, 0x6e, 0xc7, 0xc8,
+ 0x75, 0x63, 0x2e, 0x75, 0xf1, 0xdf, 0x9c, 0x3f,
+ 0xa6, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ }
+
+ hash, err := NewHash(buf)
+ if err != nil {
+ t.Errorf("NewHash: unexpected error %v", err)
+ }
+
+ // Ensure proper size.
+ if len(hash) != HashSize {
+ t.Errorf("NewHash: hash length mismatch - got: %v, want: %v",
+ len(hash), HashSize)
+ }
+
+ // Ensure contents match.
+ if !bytes.Equal(hash[:], buf) {
+ t.Errorf("NewHash: hash contents mismatch - got: %v, want: %v",
+ hash[:], buf)
+ }
+
+ // Ensure contents of hash of block 234440 don't match 234439.
+ if hash.IsEqual(blockHash) {
+ t.Errorf("IsEqual: hash contents should not match - got: %v, want: %v",
+ hash, blockHash)
+ }
+
+ // Set hash from byte slice and ensure contents match.
+ err = hash.SetBytes(blockHash.CloneBytes())
+ if err != nil {
+ t.Errorf("SetBytes: %v", err)
+ }
+ if !hash.IsEqual(blockHash) {
+ t.Errorf("IsEqual: hash contents mismatch - got: %v, want: %v",
+ hash, blockHash)
+ }
+
+ // Ensure nil hashes are handled properly.
+ if !(*Hash)(nil).IsEqual(nil) {
+ t.Error("IsEqual: nil hashes should match")
+ }
+ if hash.IsEqual(nil) {
+ t.Error("IsEqual: non-nil hash matches nil hash")
+ }
+
+ // Invalid size for SetBytes.
+ err = hash.SetBytes([]byte{0x00})
+ if err == nil {
+ t.Errorf("SetBytes: failed to received expected err - got: nil")
+ }
+
+ // Invalid size for NewHash.
+ invalidHash := make([]byte, HashSize+1)
+ _, err = NewHash(invalidHash)
+ if err == nil {
+ t.Errorf("NewHash: failed to received expected err - got: nil")
+ }
+}
+
+// TestHashString tests the stringized output for hashes.
+func TestHashString(t *testing.T) {
+ // Block 100000 hash.
+ wantStr := "000000000003ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506"
+ hash := Hash([HashSize]byte{ // Make go vet happy.
+ 0x06, 0xe5, 0x33, 0xfd, 0x1a, 0xda, 0x86, 0x39,
+ 0x1f, 0x3f, 0x6c, 0x34, 0x32, 0x04, 0xb0, 0xd2,
+ 0x78, 0xd4, 0xaa, 0xec, 0x1c, 0x0b, 0x20, 0xaa,
+ 0x27, 0xba, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+ })
+
+ hashStr := hash.String()
+ if hashStr != wantStr {
+ t.Errorf("String: wrong hash string - got %v, want %v",
+ hashStr, wantStr)
+ }
+}
+
+// TestNewHashFromStr executes compatibility tests against the lenient
+// NewHashFromStr function.
+func TestNewHashFromStr(t *testing.T) {
+ tests := []struct {
+ in string
+ want Hash
+ err error
+ }{
+ // Genesis hash.
+ {
+ "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
+ mainNetGenesisHash,
+ nil,
+ },
+
+ // Genesis hash with stripped leading zeros.
+ {
+ "19d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
+ mainNetGenesisHash,
+ nil,
+ },
+
+ // Empty string.
+ {
+ "",
+ Hash{},
+ nil,
+ },
+
+ // Single digit hash.
+ {
+ "1",
+ Hash([HashSize]byte{ // Make go vet happy.
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ }),
+ nil,
+ },
+
+ // Block 203707 with stripped leading zeros.
+ {
+ "3264bc2ac36a60840790ba1d475d01367e7c723da941069e9dc",
+ Hash([HashSize]byte{ // Make go vet happy.
+ 0xdc, 0xe9, 0x69, 0x10, 0x94, 0xda, 0x23, 0xc7,
+ 0xe7, 0x67, 0x13, 0xd0, 0x75, 0xd4, 0xa1, 0x0b,
+ 0x79, 0x40, 0x08, 0xa6, 0x36, 0xac, 0xc2, 0x4b,
+ 0x26, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ }),
+ nil,
+ },
+
+ // Hash string that is too long.
+ {
+ "01234567890123456789012345678901234567890123456789012345678912345",
+ Hash{},
+ ErrHashStrSize,
+ },
+
+ // Hash string that is contains non-hex chars.
+ {
+ "abcdefg",
+ Hash{},
+ hex.InvalidByteError('g'),
+ },
+ }
+
+ unexpectedErrStr := "NewHashFromStr #%d failed to detect expected error - got: %v want: %v"
+ unexpectedResultStr := "NewHashFromStr #%d got: %v want: %v"
+ t.Logf("Running %d tests", len(tests))
+ for i, test := range tests {
+ result, err := NewHashFromStr(test.in)
+ if err != test.err {
+ t.Errorf(unexpectedErrStr, i, err, test.err)
+ continue
+ } else if err != nil {
+ // Got expected error. Move on to the next test.
+ continue
+ }
+ if !test.want.IsEqual(result) {
+ t.Errorf(unexpectedResultStr, i, result, &test.want)
+ continue
+ }
+ }
+}
+
+// TestNewHashFromStrStrict executes tests against the NewHashFromStrStrict
+// function.
+func TestNewHashFromStrStrict(t *testing.T) {
+ tests := []struct {
+ name string
+ in string
+ want Hash
+ err error
+ }{
+ {
+ name: "genesis hash",
+ in: "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
+ want: mainNetGenesisHash,
+ err: nil,
+ },
+ {
+ name: "stripped leading zeros",
+ in: "19d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
+ want: Hash{},
+ err: ErrHashStrSizeMismatch,
+ },
+ {
+ name: "odd length hash",
+ in: "1",
+ want: Hash{},
+ err: ErrHashStrSizeMismatch,
+ },
+ {
+ name: "empty string",
+ in: "",
+ want: Hash{},
+ err: ErrHashStrSizeMismatch,
+ },
+ {
+ name: "hash string that is too long",
+ in: "01234567890123456789012345678901234567890123456789012345678912345",
+ want: Hash{},
+ err: ErrHashStrSizeMismatch,
+ },
+ {
+ name: "hash string that contains non-hex chars",
+ in: "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26g",
+ want: Hash{},
+ err: hex.InvalidByteError('g'),
+ },
+ }
+
+ unexpectedErrStr := "NewHashFromStrStrict #%d failed to detect expected error - got: %v want: %v"
+ unexpectedResultStr := "NewHashFromStrStrict #%d got: %v want: %v"
+ t.Logf("Running %d tests", len(tests))
+ for i, test := range tests {
+ test := test
+
+ t.Run(test.name, func(t *testing.T) {
+ result, err := NewHashFromStrStrict(test.in)
+ if err != test.err {
+ t.Errorf(unexpectedErrStr, i, err, test.err)
+ return
+ } else if err != nil {
+ return
+ }
+ if !test.want.IsEqual(result) {
+ t.Errorf(unexpectedResultStr, i, result, &test.want)
+ }
+ })
+ }
+}
+
+// TestDecodeStrict executes tests against the DecodeStrict function.
+func TestDecodeStrict(t *testing.T) {
+ tests := []struct {
+ name string
+ in string
+ want Hash
+ err error
+ }{
+ {
+ name: "genesis hash",
+ in: "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
+ want: mainNetGenesisHash,
+ err: nil,
+ },
+ {
+ name: "odd length hash",
+ in: "1",
+ want: Hash{},
+ err: ErrHashStrSizeMismatch,
+ },
+ {
+ name: "even length hash that is too short, 32 chars",
+ in: "deadbeef" + strings.Repeat("0", 24),
+ want: Hash{},
+ err: ErrHashStrSizeMismatch,
+ },
+ {
+ name: "hash string that contains non-hex chars",
+ in: "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26g",
+ want: Hash{},
+ err: hex.InvalidByteError('g'),
+ },
+ {
+ name: "hash string that is too long",
+ in: "01234567890123456789012345678901234567890123456789012345678912345",
+ want: Hash{},
+ err: ErrHashStrSizeMismatch,
+ },
+ }
+
+ unexpectedErrStr := "DecodeStrict #%d failed to detect expected error - got: %v want: %v"
+ unexpectedResultStr := "DecodeStrict #%d got: %v want: %v"
+ t.Logf("Running %d tests", len(tests))
+ for i, test := range tests {
+ test := test
+
+ t.Run(test.name, func(t *testing.T) {
+ var result Hash
+ err := DecodeStrict(&result, test.in)
+ if err != test.err {
+ t.Errorf(unexpectedErrStr, i, err, test.err)
+ return
+ } else if err != nil {
+ return
+ }
+ if !test.want.IsEqual(&result) {
+ t.Errorf(unexpectedResultStr, i, &result, &test.want)
+ }
+ })
+ }
+}
+
+// BenchmarkDecodeStrict benchmarks DecodeStrict on a valid canonical hash.
+func BenchmarkDecodeStrict(b *testing.B) {
+ // Use a canonical 64-character hash to exercise the successful strict path.
+ hashStr := "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"
+ var result Hash
+
+ b.ReportAllocs()
+ for i := 0; i < b.N; i++ {
+ if err := DecodeStrict(&result, hashStr); err != nil {
+ b.Fatalf("unexpected decode error: %v", err)
+ }
+ }
+
+ if !mainNetGenesisHash.IsEqual(&result) {
+ b.Fatalf("unexpected decode result: got %v want %v",
+ &result, &mainNetGenesisHash)
+ }
+}
+
+// TestHashJsonMarshal tests json marshal and unmarshal.
+func TestHashJsonMarshal(t *testing.T) {
+ hashStr := "000000000003ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506"
+ legacyHashStr := []byte("[6,229,51,253,26,218,134,57,31,63,108,52,50,4,176,210,120,212,170,236,28,11,32,170,39,186,3,0,0,0,0,0]")
+
+ hash, err := NewHashFromStr(hashStr)
+ if err != nil {
+ t.Errorf("NewHashFromStr error:%v, hashStr:%s", err, hashStr)
+ }
+
+ hashBytes, err := json.Marshal(hash)
+ if err != nil {
+ t.Errorf("Marshal json error:%v, hash:%v", err, hashBytes)
+ }
+
+ var newHash Hash
+ err = json.Unmarshal(hashBytes, &newHash)
+ if err != nil {
+ t.Errorf("Unmarshal json error:%v, hash:%v", err, hashBytes)
+ }
+
+ if !hash.IsEqual(&newHash) {
+ t.Errorf("String: wrong hash string - got %v, want %v", newHash.String(), hashStr)
+ }
+
+ err = newHash.UnmarshalJSON(legacyHashStr)
+ if err != nil {
+ t.Errorf("Unmarshal legacy json error:%v, hash:%v", err, legacyHashStr)
+ }
+
+ if !hash.IsEqual(&newHash) {
+ t.Errorf("String: wrong hash string - got %v, want %v", newHash.String(), hashStr)
+ }
+}
diff --git a/chainhash/hashfuncs.go b/chainhash/hashfuncs.go
new file mode 100644
index 0000000..5be8a4d
--- /dev/null
+++ b/chainhash/hashfuncs.go
@@ -0,0 +1,57 @@
+// Copyright (c) 2015 The Decred developers
+// Copyright (c) 2016-2017 The btcsuite developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package chainhash
+
+import (
+ "crypto/sha256"
+ "io"
+)
+
+// HashB calculates hash(b) and returns the resulting bytes.
+func HashB(b []byte) []byte {
+ hash := sha256.Sum256(b)
+ return hash[:]
+}
+
+// HashH calculates hash(b) and returns the resulting bytes as a Hash.
+func HashH(b []byte) Hash {
+ return Hash(sha256.Sum256(b))
+}
+
+// DoubleHashB calculates hash(hash(b)) and returns the resulting bytes.
+func DoubleHashB(b []byte) []byte {
+ first := sha256.Sum256(b)
+ second := sha256.Sum256(first[:])
+ return second[:]
+}
+
+// DoubleHashH calculates hash(hash(b)) and returns the resulting bytes as a
+// Hash.
+func DoubleHashH(b []byte) Hash {
+ first := sha256.Sum256(b)
+ return Hash(sha256.Sum256(first[:]))
+}
+
+// DoubleHashRaw calculates hash(hash(w)) where w is the resulting bytes from
+// the given serialize function and returns the resulting bytes as a Hash.
+func DoubleHashRaw(serialize func(w io.Writer) error) Hash {
+ // Encode the transaction into the hash. Ignore the error returns
+ // since the only way the encode could fail is being out of memory
+ // or due to nil pointers, both of which would cause a run-time panic.
+ h := sha256.New()
+ _ = serialize(h)
+
+ // This buf is here because Sum() will append the result to the passed
+ // in byte slice. Pre-allocating here saves an allocation on the second
+ // hash as we can reuse it. This allocation also does not escape to the
+ // heap, saving an allocation.
+ buf := make([]byte, 0, HashSize)
+ first := h.Sum(buf)
+ h.Reset()
+ h.Write(first)
+ res := h.Sum(buf)
+ return *(*Hash)(res)
+}
diff --git a/chainhash/hashfuncs_test.go b/chainhash/hashfuncs_test.go
new file mode 100644
index 0000000..6b9ff9a
--- /dev/null
+++ b/chainhash/hashfuncs_test.go
@@ -0,0 +1,153 @@
+// Copyright (c) 2016 The btcsuite developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package chainhash
+
+import (
+ "fmt"
+ "io"
+ "testing"
+)
+
+// TestHashFuncs ensures the hash functions which perform hash(b) work as
+// expected.
+func TestHashFuncs(t *testing.T) {
+ tests := []struct {
+ out string
+ in string
+ }{
+ {"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", ""},
+ {"ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb", "a"},
+ {"fb8e20fc2e4c3f248c60c39bd652f3c1347298bb977b8b4d5903b85055620603", "ab"},
+ {"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", "abc"},
+ {"88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589", "abcd"},
+ {"36bbe50ed96841d10443bcb670d6554f0a34b761be67ec9c4a8ad2c0c44ca42c", "abcde"},
+ {"bef57ec7f53a6d40beb640a780a639c83bc29ac8a9816f1fc6c5c6dcd93c4721", "abcdef"},
+ {"7d1a54127b222502f5b79b5fb0803061152a44f92b37e23c6527baf665d4da9a", "abcdefg"},
+ {"9c56cc51b374c3ba189210d5b6d4bf57790d351c96c47c02190ecf1e430635ab", "abcdefgh"},
+ {"19cc02f26df43cc571bc9ed7b0c4d29224a3ec229529221725ef76d021c8326f", "abcdefghi"},
+ {"72399361da6a7754fec986dca5b7cbaf1c810a28ded4abaf56b2106d06cb78b0", "abcdefghij"},
+ {"a144061c271f152da4d151034508fed1c138b8c976339de229c3bb6d4bbb4fce", "Discard medicine more than two years old."},
+ {"6dae5caa713a10ad04b46028bf6dad68837c581616a1589a265a11288d4bb5c4", "He who has a shady past knows that nice guys finish last."},
+ {"ae7a702a9509039ddbf29f0765e70d0001177914b86459284dab8b348c2dce3f", "I wouldn't marry him with a ten foot pole."},
+ {"6748450b01c568586715291dfa3ee018da07d36bb7ea6f180c1af6270215c64f", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+ {"14b82014ad2b11f661b5ae6a99b75105c2ffac278cd071cd6c05832793635774", "The days of the digital watch are numbered. -Tom Stoppard"},
+ {"7102cfd76e2e324889eece5d6c41921b1e142a4ac5a2692be78803097f6a48d8", "Nepal premier won't resign."},
+ {"23b1018cd81db1d67983c5f7417c44da9deb582459e378d7a068552ea649dc9f", "For every action there is an equal and opposite government program."},
+ {"8001f190dfb527261c4cfcab70c98e8097a7a1922129bc4096950e57c7999a5a", "His money is twice tainted: 'taint yours and 'taint mine."},
+ {"8c87deb65505c3993eb24b7a150c4155e82eee6960cf0c3a8114ff736d69cad5", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+ {"bfb0a67a19cdec3646498b2e0f751bddc41bba4b7f30081b0b932aad214d16d7", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+ {"7f9a0b9bf56332e19f5a0ec1ad9c1425a153da1c624868fda44561d6b74daf36", "size: a.out: bad magic"},
+ {"b13f81b8aad9e3666879af19886140904f7f429ef083286195982a7588858cfc", "The major problem is with sendmail. -Mark Horton"},
+ {"b26c38d61519e894480c70c8374ea35aa0ad05b2ae3d6674eec5f52a69305ed4", "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
+ {"049d5e26d4f10222cd841a119e38bd8d2e0d1129728688449575d4ff42b842c1", "If the enemy is within range, then so are you."},
+ {"0e116838e3cc1c1a14cd045397e29b4d087aa11b0853fc69ec82e90330d60949", "It's well we cannot hear the screams/That we create in others' dreams."},
+ {"4f7d8eb5bcf11de2a56b971021a444aa4eafd6ecd0f307b5109e4e776cd0fe46", "You remind me of a TV show, but that's all right: I watch it anyway."},
+ {"61c0cc4c4bd8406d5120b3fb4ebc31ce87667c162f29468b3c779675a85aebce", "C is as portable as Stonehedge!!"},
+ {"1fb2eb3688093c4a3f80cd87a5547e2ce940a4f923243a79a2a1e242220693ac", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+ {"395585ce30617b62c80b93e8208ce866d4edc811a177fdb4b82d3911d8696423", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
+ {"4f9b189a13d030838269dce846b16a1ce9ce81fe63e65de2f636863336a98fe6", "How can you write a big system without C++? -Paul Glick"},
+ }
+
+ // Ensure the hash function which returns a byte slice returns the
+ // expected result.
+ for _, test := range tests {
+ h := fmt.Sprintf("%x", HashB([]byte(test.in)))
+ if h != test.out {
+ t.Errorf("HashB(%q) = %s, want %s", test.in, h, test.out)
+ continue
+ }
+ }
+
+ // Ensure the hash function which returns a Hash returns the expected
+ // result.
+ for _, test := range tests {
+ hash := HashH([]byte(test.in))
+ h := fmt.Sprintf("%x", hash[:])
+ if h != test.out {
+ t.Errorf("HashH(%q) = %s, want %s", test.in, h, test.out)
+ continue
+ }
+ }
+}
+
+// TestDoubleHashFuncs ensures the hash functions which perform hash(hash(b))
+// work as expected.
+func TestDoubleHashFuncs(t *testing.T) {
+ tests := []struct {
+ out string
+ in string
+ }{
+ {"5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456", ""},
+ {"bf5d3affb73efd2ec6c36ad3112dd933efed63c4e1cbffcfa88e2759c144f2d8", "a"},
+ {"a1ff8f1856b5e24e32e3882edd4a021f48f28a8b21854b77fdef25a97601aace", "ab"},
+ {"4f8b42c22dd3729b519ba6f68d2da7cc5b2d606d05daed5ad5128cc03e6c6358", "abc"},
+ {"7e9c158ecd919fa439a7a214c9fc58b85c3177fb1613bdae41ee695060e11bc6", "abcd"},
+ {"1d72b6eb7ba8b9709c790b33b40d8c46211958e13cf85dbcda0ed201a99f2fb9", "abcde"},
+ {"ce65d4756128f0035cba4d8d7fae4e9fa93cf7fdf12c0f83ee4a0e84064bef8a", "abcdef"},
+ {"dad6b965ad86b880ceb6993f98ebeeb242de39f6b87a458c6510b5a15ff7bbf1", "abcdefg"},
+ {"b9b12e7125f73fda20b8c4161fb9b4b146c34cf88595a1e0503ca2cf44c86bc4", "abcdefgh"},
+ {"546db09160636e98405fbec8464a84b6464b32514db259e235eae0445346ffb7", "abcdefghi"},
+ {"27635cf23fdf8a10f4cb2c52ade13038c38718c6d7ca716bfe726111a57ad201", "abcdefghij"},
+ {"ae0d8e0e7c0336f0c3a72cefa4f24b625a6a460417a921d066058a0b81e23429", "Discard medicine more than two years old."},
+ {"eeb56d02cf638f87ea8f11ebd5b0201afcece984d87be458578d3cfb51978f1b", "He who has a shady past knows that nice guys finish last."},
+ {"dc640bf529608a381ea7065ecbcd0443b95f6e4c008de6e134aff1d36bd4b9d8", "I wouldn't marry him with a ten foot pole."},
+ {"42e54375e60535eb07fc15c6350e10f2c22526f84db1d6f6bba925e154486f33", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+ {"4ed6aa9b88c84afbf928710b03714de69e2ad967c6a78586069adcb4c470d150", "The days of the digital watch are numbered. -Tom Stoppard"},
+ {"590c24d1877c1919fad12fe01a8796999e9d20cfbf9bc9bc72fa0bd69f0b04dd", "Nepal premier won't resign."},
+ {"37d270687ee8ebafcd3c1a32f56e1e1304b3c93f252cb637d57a66d59c475eca", "For every action there is an equal and opposite government program."},
+ {"306828fd89278838bb1c544c3032a1fd25ea65c40bba586437568828a5fbe944", "His money is twice tainted: 'taint yours and 'taint mine."},
+ {"49965777eac71faf1e2fb0f6b239ba2fae770977940fd827bcbfe15def6ded53", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+ {"df99ee4e87dd3fb07922dee7735997bbae8f26db20c86137d4219fc4a37b77c3", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+ {"920667c84a15b5ee3df4620169f5c0ec930cea0c580858e50e68848871ed65b4", "size: a.out: bad magic"},
+ {"5e817fe20848a4a3932db68e90f8d54ec1b09603f0c99fdc051892b776acd462", "The major problem is with sendmail. -Mark Horton"},
+ {"6a9d47248ed38852f5f4b2e37e7dfad0ce8d1da86b280feef94ef267e468cff2", "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
+ {"2e7aa1b362c94efdbff582a8bd3f7f61c8ce4c25bbde658ef1a7ae1010e2126f", "If the enemy is within range, then so are you."},
+ {"e6729d51240b1e1da76d822fd0c55c75e409bcb525674af21acae1f11667c8ca", "It's well we cannot hear the screams/That we create in others' dreams."},
+ {"09945e4d2743eb669f85e4097aa1cc39ea680a0b2ae2a65a42a5742b3b809610", "You remind me of a TV show, but that's all right: I watch it anyway."},
+ {"1018d8b2870a974887c5174360f0fbaf27958eef15b24522a605c5dae4ae0845", "C is as portable as Stonehedge!!"},
+ {"97c76b83c6645c78c261dcdc55d44af02d9f1df8057f997fd08c310c903624d5", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+ {"6bcbf25469e9544c5b5806b24220554fedb6695ba9b1510a76837414f7adb113", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
+ {"1041988b06835481f0845be2a54f4628e1da26145b2de7ad1be3bb643cef9d4f", "How can you write a big system without C++? -Paul Glick"},
+ }
+
+ // Ensure the hash function which returns a byte slice returns the
+ // expected result.
+ for _, test := range tests {
+ h := fmt.Sprintf("%x", DoubleHashB([]byte(test.in)))
+ if h != test.out {
+ t.Errorf("DoubleHashB(%q) = %s, want %s", test.in, h,
+ test.out)
+ continue
+ }
+ }
+
+ // Ensure the hash function which returns a Hash returns the expected
+ // result.
+ for _, test := range tests {
+ hash := DoubleHashH([]byte(test.in))
+ h := fmt.Sprintf("%x", hash[:])
+ if h != test.out {
+ t.Errorf("DoubleHashH(%q) = %s, want %s", test.in, h,
+ test.out)
+ continue
+ }
+ }
+
+ // Ensure the hash function which accepts a hash.Hash returns the expected
+ // result when given a hash.Hash that is of type SHA256.
+ for _, test := range tests {
+ serialize := func(w io.Writer) error {
+ w.Write([]byte(test.in))
+ return nil
+ }
+ hash := DoubleHashRaw(serialize)
+ h := fmt.Sprintf("%x", hash[:])
+ if h != test.out {
+ t.Errorf("DoubleHashRaw(%q) = %s, want %s", test.in, h,
+ test.out)
+ continue
+ }
+ }
+}
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.