diff --git a/util/daghash/hash.go b/util/daghash/hash.go index 8d0da7725..9b70d093e 100644 --- a/util/daghash/hash.go +++ b/util/daghash/hash.go @@ -224,7 +224,16 @@ func HashToBig(hash *Hash) *big.Int { // +1 if hash > target // func (hash *Hash) Cmp(target *Hash) int { - return HashToBig(hash).Cmp(HashToBig(target)) + // We compare the hashes backwards because Hash is stored as a little endian byte array. + for i := HashSize - 1; i >= 0; i-- { + switch { + case hash[i] < target[i]: + return -1 + case hash[i] > target[i]: + return 1 + } + } + return 0 } // Less returns true iff hash a is less than hash b diff --git a/util/daghash/hash_test.go b/util/daghash/hash_test.go index 174777684..6088055e0 100644 --- a/util/daghash/hash_test.go +++ b/util/daghash/hash_test.go @@ -9,6 +9,7 @@ import ( "encoding/hex" "errors" "math/big" + "math/rand" "reflect" "testing" ) @@ -425,3 +426,43 @@ func TestSort(t *testing.T) { } } } + +func hashFlipBit(hash Hash, bit int) Hash { + word := bit / 8 + bit = bit % 8 + hash[word] ^= 1 << bit + return hash +} + +func TestHash_Cmp(t *testing.T) { + r := rand.New(rand.NewSource(1)) + + for i := 0; i < 100; i++ { + hash := Hash{} + n, err := r.Read(hash[:]) + if err != nil { + t.Fatalf("Failed generating a random hash '%s'", err) + } else if n != len(hash) { + t.Fatalf("Failed generating a random hash, expected reading: %d. instead read: %d.", len(hash), n) + + } + hashBig := HashToBig(&hash) + // Iterate bit by bit, flip it and compare. + for bit := 0; bit < HashSize*8; bit++ { + newHash := hashFlipBit(hash, bit) + if hash.Cmp(&newHash) != hashBig.Cmp(HashToBig(&newHash)) { + t.Errorf("Hash.Cmp disagrees with big.Int.Cmp newHash: %s, hash: %s", newHash, hash) + } + } + } +} + +func BenchmarkHash_Cmp(b *testing.B) { + hash0, err := NewHashFromStr("3333333333333333333333333333333333333333333333333333333333333333") + if err != nil { + b.Fatal(err) + } + for n := 0; n < b.N; n++ { + hash0.Cmp(hash0) + } +}