Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.xandrlabs.ai/llms.txt

Use this file to discover all available pages before exploring further.

The Python alx-protocol package implements kb_hash_from_envelope with identical semantics to the TypeScript reference implementation in @alx/protocol. Its primary purpose is conformance verification: given the same envelope input, it must produce the same kbHash output. The implementation is validated against the canonical test vectors in test-vectors/canonical/, the same vectors used by the TypeScript specification tests.
The Python implementation is for conformance verification. For building production integrations with ALX Protocol, use @alx/protocol (TypeScript), which is the primary SDK.

Requirements

  • Python 3.11 or later
  • eth-hash[pycryptodome] (installed automatically as a dependency)

Installation

1

Create and activate a virtual environment

python -m venv .venv
source .venv/bin/activate   # macOS / Linux
.venv\Scripts\activate      # Windows
2

Install the package

From the implementations/python directory:
pip install -e ".[dev]"
This installs the alx-protocol package in editable mode along with pytest for running the test suite.

Running the conformance suite

The conformance suite replays every vector under test-vectors/canonical/ and asserts that kb_hash_from_envelope produces the expected kbHash for each one.
# Run the full test suite (smoke tests + vector replay):
pytest

# Run vector replay only (equivalent to the CI entrypoint):
python verify_vectors.py
Both commands report a pass/fail result per vector. If any vector fails, the output shows the expected and actual hash values.

API

The public API is exported from the top-level alx_protocol module:
ExportDescription
kb_hash_from_envelope(envelope)Derives kbHash: keccak256("KB_V1" + JCS(normalizedEnvelope)). Mirrors kbHashFromEnvelope in TypeScript.
canonicalize(value)RFC 8785-style (JCS) deterministic JSON serializer. Raises ValueError on None or non-finite floats.
normalize_for_hash(envelope)Extracts the hash-scoped fields and sorts sources.
KB_DOMAIN_PREFIXThe string "KB_V1" prepended before hashing.

Example: computing kbHash in Python

The following produces the same kbHash as the equivalent TypeScript call to kbHashFromEnvelope:
from alx_protocol import kb_hash_from_envelope

envelope = {
    "type": "practice",
    "domain": "software.security",
    "sources": [],
    "tier": "open",
    "artifactHash": "0x5e71fc830e383453429f2b703db3eb456dc4a6bfd66b2a0fc7535330ab8b168a",
    "payload": {
        "type": "practice",
        "rationale": "Use constant-time comparison to prevent timing attacks on tokens.",
        "contexts": [],
        "failureModes": [],
    },
}

kb_hash = kb_hash_from_envelope(envelope)
print(kb_hash)
# 0x5c3415ff46569330de2d0820b55a31859f2c7efde1df96ce5bb59c731a872d51
This hash matches the value produced by the TypeScript reference implementation for the same input. The practice-minimal canonical test vector covers exactly this envelope.

How the hash is computed

The Python implementation follows the same three-step pipeline as the TypeScript reference:
1

Normalize the envelope

Extract only the hash-scoped fields: type, domain, sources, artifactHash, tier, payload, and derivation. Sort sources deterministically when there is more than one entry. Fall back to parents if sources is absent.
2

Canonicalize

Serialize the normalized envelope using JCS (RFC 8785): object keys sorted lexicographically, no whitespace, null values rejected.
3

Hash with domain prefix

Compute keccak256(b"KB_V1" + canonical_utf8). The KB_V1 domain prefix distinguishes Knowledge Block hashes from other domain-tagged hashes in the protocol.

Canonical test vectors

The vectors in test-vectors/canonical/ each contain two files:
  • envelope.json — the input envelope
  • expected.json — the expected kbHash (and related fields)
The test suite in tests/test_vectors.py loads each pair and asserts equality. Covered cases include all KB types, edge cases (unicode content, large payloads, max sources), and derivation scenarios (single parent, multi-parent, unsorted parent lists).