Multihash Interface ExampleΒΆ

This example focuses on hash function choice and CID outcomes:

  • hash the same payload with sha2-256,

  • build a CID from the resulting multihash,

  • build a second CID using the JS-example-compatible sha3-512-style path,

  • compare digest lengths and CID strings to documented JS expected values.

Run it with:

python -m examples.multihash_interface.multihash_interface
python -m examples.multihash_interface.multihash_interface --json

Expected result:

  • printed digest lengths for both hash paths,

  • printed CIDs,

  • booleans indicating whether output matches the JS reference comments.

 1"""Equivalent of js-multiformats/examples/multihash-interface.js."""
 2
 3import argparse
 4import hashlib
 5import json
 6
 7import multihash
 8from cid import make_cid
 9
10JS_EXPECTED = {
11    "sha2_256_digest_len": 32,
12    "sha2_256_cid_base32": "bagaaierasords4njcts6vs7qvdjfcvgnume4hqohf65zsfguprqphs3icwea",
13    "sha3_512_digest_len": 64,
14    "sha3_512_cid_base32": (
15        "bagaaifca7d5wrebdi6rmqkgtrqyodq3bo6gitrqtemxtliymakwswbazbu7ai763747ljp7ycqfv7aqx4xlgiugcx62quo2te45pcgjbg4qjsvq"
16    ),
17}
18
19
20def _js_style_sha3_512_multihash(payload: bytes) -> bytes:
21    """Reproduce the JS example's explicit code=0x14 behavior.
22
23    The upstream JS example labels the second hasher as `sha3-512` (code `0x14`)
24    while using Node's `sha512` digest bytes. We mirror that encoded multihash
25    byte layout to compare with the documented JS comment output exactly.
26    """
27    digest = hashlib.sha512(payload).digest()
28    return bytes((0x14, len(digest))) + digest
29
30
31def build_report() -> dict[str, object]:
32    payload_obj = {"hello": "world"}
33    payload = json.dumps(payload_obj, separators=(",", ":"), sort_keys=True).encode("utf-8")
34
35    digest_256 = multihash.digest(payload, "sha2-256")
36    cid_256 = make_cid(1, "json", digest_256.encode())
37    cid_256_b32 = cid_256.encode("base32").decode("ascii")
38
39    js_style_512_mh = _js_style_sha3_512_multihash(payload)
40    cid_js_style_512 = make_cid(1, "json", js_style_512_mh)
41    cid_js_style_512_b32 = cid_js_style_512.encode("base32").decode("ascii")
42
43    matches = {
44        "sha2_256_digest_len": digest_256.length == JS_EXPECTED["sha2_256_digest_len"],
45        "sha2_256_cid_base32": cid_256_b32 == JS_EXPECTED["sha2_256_cid_base32"],
46        "sha3_512_digest_len": len(hashlib.sha512(payload).digest()) == JS_EXPECTED["sha3_512_digest_len"],
47        "sha3_512_cid_base32": cid_js_style_512_b32 == JS_EXPECTED["sha3_512_cid_base32"],
48    }
49
50    return {
51        "input": payload_obj,
52        "codec": "json",
53        "sha2_256": {
54            "digest_length": digest_256.length,
55            "cid_base32": cid_256_b32,
56            "cid_default_string": str(cid_256),
57        },
58        "sha3_512_js_style": {
59            "digest_length": len(hashlib.sha512(payload).digest()),
60            "multihash_code_hex": "0x14",
61            "cid_base32": cid_js_style_512_b32,
62            "cid_default_string": str(cid_js_style_512),
63        },
64        "js_expected": JS_EXPECTED,
65        "matches_js_comments": matches,
66    }
67
68
69def main() -> None:
70    parser = argparse.ArgumentParser(description="Multihash interface example")
71    parser.add_argument("--json", action="store_true", help="Print structured JSON report")
72    args = parser.parse_args()
73
74    report = build_report()
75    if args.json:
76        print(json.dumps(report, indent=2, sort_keys=True))
77        return
78
79    print(f"sha2-256 digest length: {report['sha2_256']['digest_length']} bytes")
80    print(f"sha2-256 CID: {report['sha2_256']['cid_default_string']}")
81    print(f"sha3-512 digest length: {report['sha3_512_js_style']['digest_length']} bytes")
82    print(f"sha3-512 CID: {report['sha3_512_js_style']['cid_default_string']}")
83    print(
84        "Matches js comments (sha2-256/sha3-512 CID): "
85        f"{report['matches_js_comments']['sha2_256_cid_base32']}/"
86        f"{report['matches_js_comments']['sha3_512_cid_base32']}"
87    )
88
89
90if __name__ == "__main__":
91    main()