Go's Sum() explicitly rejects identity hashes where the requested truncation length doesn't match the data length. Python's _do_digest() doesn't have this check, allowing invalid identity multihashes to be created.
Problem
In Go's sum.go:
func encodeHash(hasher hash.Hash, code uint64, length int) (Multihash, error) {
sum := hasher.Sum(nil)
if length >= 0 {
if code == IDENTITY {
if length != len(sum) {
return nil, fmt.Errorf(
"the length of the identity hash (%d) must be equal to the length of the data (%d)",
length, len(sum))
}
}
sum = sum[:length]
}
return Encode(sum, code)
}
Python's _do_digest() has no equivalent check:
def _do_digest(data, func, length=None):
# ... hash computation ...
# Handle truncation
if not is_shake and length is not None and length != -1:
if length > len(digest_bytes):
raise TruncationError(...)
digest_bytes = digest_bytes[:length] # ← No identity check!
return digest_bytes
This allows creating invalid identity multihashes:
from multihash import sum, Func
# Go would reject this, Python allows it:
mh = sum(b"hello world", Func.identity, length=5)
# Creates a multihash with truncated identity hash — invalid per spec
Proposed Solution
Add an identity hash check in _do_digest():
def _do_digest(data, func, length=None):
# ... existing code ...
if not is_shake and length is not None and length != -1:
if length < 0:
raise TruncationError(...)
if length == 0:
raise TruncationError("truncation length cannot be zero")
# Identity hash: length must equal data length
if func == Func.identity and length != len(digest_bytes):
raise TruncationError(
f"the length of the identity hash ({length}) must be equal "
f"to the length of the data ({len(digest_bytes)})"
)
if length > len(digest_bytes):
raise TruncationError(...)
digest_bytes = digest_bytes[:length]
return digest_bytes
Add the same check in sum_stream().
Add tests:
def test_identity_hash_length_must_match():
# Valid: length matches data
mh = sum(b"hello", Func.identity, length=5)
assert mh.digest == b"hello"
# Invalid: length doesn't match
with pytest.raises(TruncationError, match="identity hash"):
sum(b"hello", Func.identity, length=3)
Related
- Go implementation: go-multihash
sum.go encodeHash()
- Go test:
TestSmallerLengthHashID in sum_test.go
Go's
Sum()explicitly rejects identity hashes where the requested truncation length doesn't match the data length. Python's_do_digest()doesn't have this check, allowing invalid identity multihashes to be created.Problem
In Go's
sum.go:Python's
_do_digest()has no equivalent check:This allows creating invalid identity multihashes:
Proposed Solution
Add an identity hash check in
_do_digest():Add the same check in
sum_stream().Add tests:
Related
sum.goencodeHash()TestSmallerLengthHashIDinsum_test.go