Skip to content

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

Description

@sumanjeet0012

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.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions