multiformats / multiformats/py-multihash
`get_prefix()` hardcodes 2-byte prefix — breaks for multi-byte varint codes
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 17
- Forks
- 17
- Avg merge
- 1h 5m
- Merged PRs (30d)
- 3
Description
get_prefix() returns multihash[:2], assuming the code and length varints are each exactly 1 byte. For hash codes > 127 (e.g., sha2-224 at 0x1013, blake2b-256 at 0xB220), the varint encoding is multi-byte, so [:2] returns incorrect/incomplete data.
Problem
In multihash/multihash.py:
def get_prefix(multihash):
if is_valid(multihash):
return multihash[:2] # ← Always returns first 2 bytes
raise ValueError("invalid multihash")
For codes that fit in a single varint byte (0x00–0x7F), this works. But for codes > 0x7F, the varint encoding uses multiple bytes:
| Hash function | Code | Varint bytes | [:2] returns |
Correct prefix |
|---|---|---|---|---|
| sha2-256 | 0x12 | b'\x12' (1 byte) |
b'\x12\x20' ✅ |
b'\x12\x20' |
| sha2-224 | 0x1013 | b'\x93 ' (2 bytes) |
b'\x93 ' ❌ |
b'\x93 \x1c' |
| blake2b-256 | 0xB220 | b'\xa0\xe4\x02' (3 bytes) |
b'\xa0\xe4' ❌ |
b'\xa0\xe4\x02\x20' |
| ripemd-160 | 0x1053 | b'\xd3 ' (2 bytes) |
b'\xd3 ' ❌ |
b'\xd3 \x14' |
The "prefix" of a multihash is the varint-encoded code + varint-encoded length. Its size varies depending on the code and digest length.
Proposed Solution
Replace the hardcoded slice with proper varint decoding:
def get_prefix(multihash):
if not isinstance(multihash, bytes):
raise TypeError("multihash should be bytes")
if not is_valid(multihash):
raise ValueError("invalid multihash")
buffer = BytesIO(multihash)
# Read code varint
varint.decode_stream(buffer)
# Read length varint
varint.decode_stream(buffer)
# Everything up to current position is the prefix
return multihash[:buffer.tell()]
Add tests with multi-byte varint codes:
def test_get_prefix_multi_byte_code():
mh = sum(b"test", Func.sha2_224)
prefix = get_prefix(mh.encode())
assert prefix == mh.encode()[:3] # 2-byte code + 1-byte length
Related
- File:
multihash/multihash.py,get_prefix()function - Affected codes: All codes > 0x7F (sha2-224, sha2-512-224, sha2-512-256, ripemd-, blake2b-, blake2s-, keccak-, skein*, etc.)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in multihash/multihash.py at get_prefix() and inspect the existing is_valid() and varint.decode_stream() behavior. Add coverage for multi-byte codes such as sha2-224 and blake2b-256, then verify that the returned prefix includes the complete varint-encoded code and length while existing single-byte cases still pass.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- cryptography
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100