chainhash: Implement a new chainhash package. (#730)
This is a backport of the chainhash package made in Decred along with a few additional things cleaned up, finished test coverage, and rewording of some documentation to make it more generic. In particular, the new package provides the definition of the hash type and associated hashing functions which will allow the rest of the code to be agnostic to the specific hash algorithm. This only implements the package and does not change any of the code base over to use it.
This commit is contained in:
parent
d406d9e52b
commit
711f33450c
6 changed files with 530 additions and 0 deletions
42
chaincfg/chainhash/README.md
Normal file
42
chaincfg/chainhash/README.md
Normal file
|
@ -0,0 +1,42 @@
|
|||
chainhash
|
||||
=========
|
||||
|
||||
[![Build Status](http://img.shields.io/travis/btcsuite/btcd.svg)]
|
||||
(https://travis-ci.org/btcsuite/btcd) [![ISC License]
|
||||
(http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
|
||||
[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)]
|
||||
(http://godoc.org/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.
|
5
chaincfg/chainhash/doc.go
Normal file
5
chaincfg/chainhash/doc.go
Normal file
|
@ -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
|
118
chaincfg/chainhash/hash.go
Normal file
118
chaincfg/chainhash/hash.go
Normal file
|
@ -0,0 +1,118 @@
|
|||
// 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 (
|
||||
"encoding/hex"
|
||||
"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
|
||||
|
||||
// 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)
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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.
|
||||
func NewHashFromStr(hash string) (*Hash, error) {
|
||||
// Return error if hash string is too long.
|
||||
if len(hash) > MaxHashStringSize {
|
||||
return nil, ErrHashStrSize
|
||||
}
|
||||
|
||||
// Hex decoder expects the hash to be a multiple of two.
|
||||
if len(hash)%2 != 0 {
|
||||
hash = "0" + hash
|
||||
}
|
||||
|
||||
// Convert string hash to bytes.
|
||||
buf, err := hex.DecodeString(hash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Un-reverse the decoded bytes, copying into in leading bytes of a
|
||||
// Hash. There is no need to explicitly pad the result as any
|
||||
// missing (when len(buf) < HashSize) bytes from the decoded hex string
|
||||
// will remain zeros at the end of the Hash.
|
||||
var ret Hash
|
||||
blen := len(buf)
|
||||
mid := blen / 2
|
||||
if blen%2 != 0 {
|
||||
mid++
|
||||
}
|
||||
blen--
|
||||
for i, b := range buf[:mid] {
|
||||
ret[i], ret[blen-i] = buf[blen-i], b
|
||||
}
|
||||
return &ret, nil
|
||||
}
|
196
chaincfg/chainhash/hash_test.go
Normal file
196
chaincfg/chainhash/hash_test.go
Normal file
|
@ -0,0 +1,196 @@
|
|||
// 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"
|
||||
"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 tests against the 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
|
||||
}
|
||||
}
|
||||
}
|
33
chaincfg/chainhash/hashfuncs.go
Normal file
33
chaincfg/chainhash/hashfuncs.go
Normal file
|
@ -0,0 +1,33 @@
|
|||
// Copyright (c) 2015 The Decred developers
|
||||
// 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 "github.com/btcsuite/fastsha256"
|
||||
|
||||
// HashB calculates hash(b) and returns the resulting bytes.
|
||||
func HashB(b []byte) []byte {
|
||||
hash := fastsha256.Sum256(b)
|
||||
return hash[:]
|
||||
}
|
||||
|
||||
// HashH calculates hash(b) and returns the resulting bytes as a Hash.
|
||||
func HashH(b []byte) Hash {
|
||||
return Hash(fastsha256.Sum256(b))
|
||||
}
|
||||
|
||||
// DoubleHashB calculates hash(hash(b)) and returns the resulting bytes.
|
||||
func DoubleHashB(b []byte) []byte {
|
||||
first := fastsha256.Sum256(b)
|
||||
second := fastsha256.Sum256(first[:])
|
||||
return second[:]
|
||||
}
|
||||
|
||||
// DoubleHashH calculates hash(hash(b)) and returns the resulting bytes as a
|
||||
// Hash.
|
||||
func DoubleHashH(b []byte) Hash {
|
||||
first := fastsha256.Sum256(b)
|
||||
return Hash(fastsha256.Sum256(first[:]))
|
||||
}
|
136
chaincfg/chainhash/hashfuncs_test.go
Normal file
136
chaincfg/chainhash/hashfuncs_test.go
Normal file
|
@ -0,0 +1,136 @@
|
|||
// 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"
|
||||
"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
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue