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.
Verification confirms two independent properties of a Knowledge Block: its identity (the kbHash you compute matches the on-chain kbId) and its integrity (the artifact you retrieved from IPFS matches the hash the curator committed at publish time). These properties are independent — a KB can be cryptographically valid even if its IPFS artifact is currently unavailable, because identity is anchored on-chain and does not depend on IPFS reachability.
Two independent properties
| Property | What it confirms | What it uses |
|---|
| Identity | The artifact content matches the registered kbId | kbHashFromEnvelope vs. on-chain kbId |
| Integrity | The IPFS artifact matches what was committed | artifactHash vs. registry.getArtifactHash(kbId) |
A KB whose IPFS artifact is temporarily unavailable is still cryptographically valid. Its kbHash remains on-chain and usable for attribution and settlement. Only retrieval is impaired, not identity.
Using verifyKBArtifact
ALX Protocol exports verifyKBArtifact, which wraps both checks into a single call. Pass the artifact object and a manifest (containing at least the expected kbHash and artifactHash) and inspect the result.
import { verifyKBArtifact } from "@alx/protocol";
const result = await verifyKBArtifact({ artifact, manifest });
console.log(result.valid); // true if both checks pass
console.log(result.kbHash); // recomputed identity hash
console.log(result.artifactHash); // recomputed artifact integrity hash
When result.valid is true, the artifact you hold matches both the on-chain identity and the committed integrity hash. When it is false, inspect result.kbHash and result.artifactHash individually to determine which check failed.
Manual verification steps
If you prefer to perform verification explicitly, or need to cross-check against the live registry, follow these steps:
Retrieve the artifact from IPFS
Fetch the artifact JSON from the IPFS CID recorded in the registry. Preserve the exact bytes — do not re-serialize the JSON before hashing.// Using a public IPFS gateway or your preferred IPFS client
const response = await fetch(`https://ipfs.io/ipfs/${rootCid}`);
const artifactJson = await response.text(); // preserve exact bytes
const artifact = JSON.parse(artifactJson);
A CID without an active IPFS pin should be treated as at-risk. If your fetch returns a timeout or 404, the artifact may have been garbage-collected. Identity remains valid on-chain, but you cannot complete an integrity check without the artifact bytes.
Recompute the kbHash
Strip the excluded fields from the artifact and recompute the identity hash using kbHashFromEnvelope. Compare the result against the kbId you looked up in the registry.import { kbHashFromEnvelope } from "@alx/protocol";
const {
kbHash: _k,
metadata: _m,
curator: _c,
createdAt: _d,
signature: _s,
...envelope
} = artifact;
const recomputedKbHash = kbHashFromEnvelope(envelope);
if (recomputedKbHash !== expectedKbId) {
throw new Error(
`Identity mismatch: computed ${recomputedKbHash}, expected ${expectedKbId}`
);
}
Recompute the artifactHash
Compute the SHA-256 digest of the artifact as it was stored: pretty-printed JSON with a trailing newline. This matches the format the curator used when publishing.import { createHash } from "crypto";
// Reproduce the exact serialization used at publish time:
// JSON.stringify with 2-space indent + trailing newline
const serialized = JSON.stringify(artifact, null, 2) + "\n";
const recomputedArtifactHash =
"0x" + createHash("sha256").update(serialized).digest("hex");
Compare against the on-chain record
Call registry.getArtifactHash(kbId) and compare the result with your locally computed artifactHash.import { ethers } from "ethers";
import { REGISTRY_ABI } from "@alx/protocol";
const CONTRACT_ADDRESS = "0xD1F216E872a9ed4b90E364825869c2F377155B29";
const provider = new ethers.JsonRpcProvider("https://mainnet.base.org");
const registry = new ethers.Contract(CONTRACT_ADDRESS, REGISTRY_ABI, provider);
// Pass the kbHash (= kbId) to retrieve the committed artifact hash
const onChainArtifactHash = await registry.getArtifactHash(kbId);
if (recomputedArtifactHash !== onChainArtifactHash) {
throw new Error(
`Integrity mismatch: artifact does not match on-chain commitment`
);
}
console.log("Verification passed — identity and integrity both confirmed.");
Full example
import { ethers } from "ethers";
import { REGISTRY_ABI, kbHashFromEnvelope } from "@alx/protocol";
import { createHash } from "crypto";
const CONTRACT_ADDRESS = "0xD1F216E872a9ed4b90E364825869c2F377155B29";
async function verifyKnowledgeBlock(kbId: string, rootCid: string) {
// 1. Fetch artifact from IPFS
const response = await fetch(`https://ipfs.io/ipfs/${rootCid}`);
if (!response.ok) {
throw new Error(`IPFS fetch failed: ${response.status} — artifact may be unpinned`);
}
const artifactJson = await response.text();
const artifact = JSON.parse(artifactJson);
// 2. Recompute identity hash
const {
kbHash: _k, metadata: _m, curator: _c,
createdAt: _d, signature: _s, ...envelope
} = artifact;
const recomputedKbHash = kbHashFromEnvelope(envelope);
if (recomputedKbHash !== kbId) {
return { valid: false, reason: "identity_mismatch", recomputedKbHash };
}
// 3. Recompute artifact integrity hash
const serialized = JSON.stringify(artifact, null, 2) + "\n";
const recomputedArtifactHash =
"0x" + createHash("sha256").update(serialized).digest("hex");
// 4. Compare against on-chain record
const provider = new ethers.JsonRpcProvider("https://mainnet.base.org");
const registry = new ethers.Contract(CONTRACT_ADDRESS, REGISTRY_ABI, provider);
const onChainArtifactHash = await registry.getArtifactHash(kbId);
if (recomputedArtifactHash !== onChainArtifactHash) {
return { valid: false, reason: "integrity_mismatch", recomputedArtifactHash, onChainArtifactHash };
}
return { valid: true, kbHash: recomputedKbHash, artifactHash: recomputedArtifactHash };
}
Why identity and retrievability are independent
When a KB is published, the registry records:
- The
kbHash (identity), derived purely from the envelope content.
- The
artifactHash (integrity), a commitment to the exact artifact bytes.
- The
rootCid (retrievability), the IPFS address of the artifact.
The registry never fetches from IPFS. If the artifact is unpinned, the on-chain record remains intact and the KB continues to participate in attribution and settlement. Verification that includes an IPFS fetch tests retrievability in addition to the on-chain properties. For use cases where retrievability is required (for example, before settling a query), check that the CID resolves before treating the KB as fully operational.