From a5fb8e07315ce1c40d28cfd88e5b2c8c783e249f Mon Sep 17 00:00:00 2001 From: Joe Tsai Date: Wed, 21 Jul 2021 09:23:04 -0700 Subject: [PATCH] util/deephash: introduce deliberate instability (#2477) Seed the hash upon first use with the current time. This ensures that the stability of the hash is bounded within the lifetime of one program execution. Hopefully, this prevents future bugs where someone assumes that this hash is stable. Signed-off-by: Joe Tsai --- util/deephash/deephash.go | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/util/deephash/deephash.go b/util/deephash/deephash.go index 1fe154fdb..a8d8a1411 100644 --- a/util/deephash/deephash.go +++ b/util/deephash/deephash.go @@ -2,8 +2,11 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package deephash hashes a Go value recursively, in a predictable -// order, without looping. +// Package deephash hashes a Go value recursively, in a predictable order, +// without looping. The hash is only valid within the lifetime of a program. +// Users should not store the hash on disk or send it over the network. +// The hash is sufficiently strong and unique such that +// Hash(x) == Hash(y) is an appropriate replacement for x == y. // // This package, like most of the tailscale.com Go module, should be // considered Tailscale-internal; we make no API promises. @@ -20,6 +23,7 @@ "reflect" "strconv" "sync" + "time" ) const scratchSize = 128 @@ -62,10 +66,19 @@ func (s Sum) String() string { return hex.EncodeToString(s.sum[:]) } +var ( + once sync.Once + seed uint64 +) + // Hash returns the hash of v. func (h *hasher) Hash(v interface{}) (hash Sum) { h.bw.Flush() h.h.Reset() + once.Do(func() { + seed = uint64(time.Now().UnixNano()) + }) + h.uint(seed) h.print(reflect.ValueOf(v)) h.bw.Flush() // Sum into scratch & copy out, as hash.Hash is an interface