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.

kbHashFromEnvelope() is the primary identity function in ALX Protocol. Given a canonical envelope object, it projects only the hash-scoped fields, sorts sources, serializes the result with canonicalize(), and then computes keccak256("KB_V1" + canonicalJson). The resulting hex string is the kbId that the registry stores on-chain. Because identity is content-derived, any change to a hash-scoped field changes kbHash. Fields outside the hash scope — timestamps, curator address, signatures, and transport metadata — do not affect identity.
import { kbHashFromEnvelope, domainHashFromCanonical, domainHashFromObject, DOMAIN_TAGS } from "@alx/protocol";

Hash scope

Only the following fields from the envelope are included in the hash preimage. All other fields are stripped before hashing.
FieldTypeDescription
typestringKB type identifier
domainstringDomain string (e.g. "software.security")
sourcesstring[]Parent kbHash values; sorted lexicographically
artifactHashstringContent commitment to off-chain artifact bytes
tierstringAccess tier ("open", "verified", "premium", "restricted")
payloadobjectType-specific payload object
derivationobjectDerivation recipe when the KB is derived
Fields like metadata, curator, createdAt, signature, and the top-level kbHash replay field are excluded by design.

Signatures

kbHashFromEnvelope

function kbHashFromEnvelope(envelope: Record<string, unknown>): string
Projects the envelope to the hash-scoped fields, sorts sources lexicographically, runs canonicalize(), and returns keccak256("KB_V1" + canonical) as a 0x-prefixed 64-character hex string.

contentHashFromEnvelope (deprecated)

/** @deprecated Use kbHashFromEnvelope for all new code. */
function contentHashFromEnvelope(envelope: Record<string, unknown>): string
Computes keccak256(canonical) without the "KB_V1" domain prefix. The two functions produce different hashes. On-chain kbId values are derived with kbHashFromEnvelope; contentHashFromEnvelope is retained only for v1 conformance test vectors.

domainHashFromCanonical

function domainHashFromCanonical(domainTag: string, canonicalJson: string): string
Low-level primitive. Computes keccak256(UTF8(domainTag) + UTF8(canonicalJson)). You can use this to implement domain-tagged hashing for custom domain tags from DOMAIN_TAGS.

domainHashFromObject

function domainHashFromObject(domainTag: string, value: unknown): string
Calls canonicalize(value) then delegates to domainHashFromCanonical. Equivalent to kbHashFromEnvelope when called with DOMAIN_TAGS.KB and a pre-normalized envelope.

Parameters

envelope
Record<string, unknown>
required
A canonical envelope object. You do not need to pre-normalize it — kbHashFromEnvelope projects only the hash-scoped fields internally. However, ensure that sources contains valid kbHash hex strings and that payload conforms to your KB type schema.The wire format may supply parents instead of sources; the normalization step maps parentssources automatically.

Return value

kbHash
string
A 0x-prefixed 64-character lowercase hex string representing the Keccak-256 hash of the domain-tagged canonical preimage. This value is used as kbId in registry calls.

DOMAIN_TAGS

export const DOMAIN_TAGS = {
  KB:         "KB_V1",
  TASK:       "TASK_V1",
  TRANSITION: "TRANSITION_V1",
  CONSTRAINT: "CONSTRAINT_V1",
  TOOL:       "TOOL_V1",
  VALIDATION: "VALIDATION_V1",
  RESOLVER:   "RESOLVER_V1",
  STATE:      "STATE_V1",
  LEAF:       "LEAF_V1",
  EMPTY_TREE: "EMPTY_TREE_V1",
} as const;
Use DOMAIN_TAGS.KB when computing KB identity. Other tags are used internally by the protocol for sub-object hashing in state machines, task graphs, and constraint trees.

Example

import { kbHashFromEnvelope, DOMAIN_TAGS } from "@alx/protocol";

const envelope = {
  type: "practice",
  domain: "software.security",
  sources: [],
  artifactHash: "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890ab",
  tier: "open",
  payload: {
    type: "practice",
    rationale: "Validate all inputs at trust boundaries.",
    contexts: [],
    failureModes: [],
  },
  // Metadata fields below are stripped before hashing
  curator: "0xYourAddress",
  createdAt: 1713820800,
};

const kbHash = kbHashFromEnvelope(envelope);
// "0x..." — 66-character 0x-prefixed hex

console.log(DOMAIN_TAGS.KB); // "KB_V1"

Notes

  • kbHashFromEnvelope is the canonical function for new code. Never use contentHashFromEnvelope in production.
  • sources is treated as a set for identity: the order you supply does not matter. The normalization step sorts the array before hashing, so ["0xaaa", "0xbbb"] and ["0xbbb", "0xaaa"] produce the same kbHash.
  • If the envelope contains a top-level kbHash field, it is silently excluded from the hash preimage by the normalization step — only the seven hash-scope keys are included. That said, keeping your data model clean by storing kbHash separately is recommended.
  • A future breaking change to identity rules will use KB_V2 and a new vector set. Never hardcode the domain string; use DOMAIN_TAGS.KB.