multiformats / multiformats/py-multihash

`get_prefix()` hardcodes 2-byte prefix — breaks for multi-byte varint codes

Open Beginner friendly
#46 0 comments 0 reactions 0 assignees View on GitHub

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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.