Description
There isn't a general way to clone the state of a hash.Hash, but #20573 introduced the concept of hash.Hash implementations also implementing encoding.BinaryMarshaler and encoding.BinaryUnmarshaler, and the hash.Hash docs commit our implementations to doing that.
Hash implementations in the standard library (e.g. hash/crc32 and crypto/sha256) implement the encoding.BinaryMarshaler and encoding.BinaryUnmarshaler interfaces.
That allows cloning the hash state without recomputing it, as done in HMAC.
Lines 96 to 103 in db40d1a
However, it's obscure and pretty clunky to use.
I propose we add a hash.Clone
helper function.
package hash
// Clone returns a separate Hash instance with the same state as h.
//
// h must implement encoding.BinaryMarshaler and encoding.BinaryUnmarshaler,
// or be provided by the Go standard library. Otherwise, Clone returns an error.
func Clone(h Hash) (Hash, error)
In practice, we should only fallback to BinaryMarshaler + BinaryUnmarshaler for the general case, while for standard library implementations we can do an undocumented interface upgrade to interface { Clone() Hash }
. In that sense, hash.Clone
is a way to hide the interface upgrade as a more discoverable and easier to use function.
(Yet another example of why we should be returning concrete types everywhere rather than interfaces.)
CloneXOF
If #69518 is accepted, I propose we also add hash.CloneXOF.
package hash
// CloneXOF returns a separate XOF instance with the same state as h.
//
// h must implement encoding.BinaryMarshaler and encoding.BinaryUnmarshaler,
// or be provided by the Go standard library or by the golang.org/x/crypto module
// (starting at version v0.x.y). Otherwise, Clone returns an error.
func CloneXOF(h XOF) (XOF, error)
None of our XOFs actually implement BinaryMarshaler + BinaryUnmarshaler, but they have their own interface methods Clone() ShakeHash
and Clone() XOF
that each return an interface. I can't really think of a way to use them from CloneXOF, so instead we can add hidden methods CloneXOF() hash.XOF
and interface upgrade to them.
As we look at moving packages from x/crypto to the standard library (#65269) we should switch x/crypto/sha3 and x/crypto/blake2[bs] from returning interfaces to returning concrete types, at least for XOFs. Then they can have a Clone()
method that returns a concrete type, and a CloneXOF()
method that returns a hash.XOF interface and enables hash.CloneXOF
.
(If anyone has better ideas for how to make this less redundant, I would welcome them. I considered and rejected using reflect to call the existing Clone methods because hash is a pretty core package. This sort of interface-method-that-needs-to-return-a-value-implementing-said-interface scenarios are always annoying.)
/cc @golang/security @cpu @qmuntal (who filed something similar in #69293, as I found while searching refs for this)
Metadata
Metadata
Assignees
Type
Projects
Status