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.

artifactHash is a cryptographic commitment to the exact bytes of a KB’s off-chain artifact. It is stored alongside the kbHash (contentHash) in the registry contract, giving any verifier a way to confirm that artifact bytes retrieved from IPFS or another store match what the publisher committed to at registration time. artifactHash and kbHash are independent hashes. kbHash commits to the logical envelope (type, domain, payload structure, lineage), while artifactHash commits to the raw bytes of the serialized artifact file — including formatting whitespace and the embedded kbHash string itself. A mismatch between retrieved bytes and the stored artifactHash signals corruption, replacement, or incorrect retrieval.
import { artifactHashFromPayload, artifactHashFromBytes } from "@alx/protocol";

Signatures

artifactHashFromPayload

function artifactHashFromPayload(payload: CanonicalPayload): string
Canonicalizes the payload object with canonicalize() and then computes Keccak-256 over the resulting canonical JSON string. This is a convenience wrapper for the common case where the artifact bytes are derived from the payload object.

artifactHashFromBytes

function artifactHashFromBytes(bytes: Uint8Array): string
Computes Keccak-256 directly over a raw byte array. Use this variant when you have the artifact bytes already — for example, when reading a stored artifact file to verify it against the registry.

Parameters

payload
CanonicalPayload
required
For artifactHashFromPayload: a typed payload object that conforms to one of the ALX Protocol payload schemas (e.g. { type: "practice", rationale: "...", contexts: [], failureModes: [] }). The object is canonicalized before hashing, so key order in the input does not matter.
bytes
Uint8Array
required
For artifactHashFromBytes: the raw bytes of the artifact. This is typically the UTF-8 encoding of the pretty-printed artifact JSON file including its trailing newline, as described in the implementer guide.

Return value

artifactHash
string
A 0x-prefixed 64-character lowercase hex string representing the Keccak-256 hash of the input. This value is passed as the artifactHash field when building an envelope and is stored in the registry contract.

Computing the artifact hash for a published file

The implementer guide specifies that the artifact file is a pretty-printed JSON object with the kbHash embedded and a trailing newline. To compute artifactHash for that file, use artifactHashFromBytes over the UTF-8 encoding of that exact string:
import { artifactHashFromBytes } from "@alx/protocol";

// Assemble the artifact object with kbHash already included
const artifact = {
  ...envelope,
  kbHash, // embed the computed kbHash
};

// Pretty-print with 2-space indent + trailing newline (matches stored file format)
const artifactBytes = new TextEncoder().encode(
  JSON.stringify(artifact, null, 2) + "\n"
);

const artifactHash = artifactHashFromBytes(artifactBytes);
// "0x..." — store this in the envelope and pass to publishKB

Verification pattern

After retrieving a KB artifact, recompute its hash and compare it with what the registry stored:
import { artifactHashFromBytes } from "@alx/protocol";
import { ethers } from "ethers";
import { REGISTRY_ABI } from "@alx/protocol";

const CONTRACT_ADDRESS = "0xD1F216E872a9ed4b90E364825869c2F377155B29";
const registry = new ethers.Contract(CONTRACT_ADDRESS, REGISTRY_ABI, provider);

async function verifyArtifact(kbId: string, rawBytes: Uint8Array): Promise<boolean> {
  const [onChainHash, localHash] = await Promise.all([
    registry.getArtifactHash(kbId),
    Promise.resolve(artifactHashFromBytes(rawBytes)),
  ]);

  if (onChainHash !== localHash) {
    throw new Error(
      `Artifact integrity check failed: on-chain ${onChainHash}, computed ${localHash}`
    );
  }
  return true;
}

Notes

  • artifactHashFromPayload calls canonicalize() internally, so it rejects the same invalid inputs (null, BigInt, non-finite numbers).
  • When building an envelope to pass to buildDerivedEnvelope, omit artifactHash from DerivedEnvelopeInput and the builder will call artifactHashFromPayload(payload) automatically.
  • artifactHash uses Keccak-256, not SHA-256. Do not confuse it with the cidV1 computation, which uses SHA-256 over the canonical JSON bytes.