Package and Hash Checks

Hashes bind what Root accepted to what clients later consume. They help detect tampering, stale metadata, accidental drift, wrong files, endpoint substitution, and serialization mistakes. Without hash checks, a client may verify one description but use different bytes.

Package and hash checks are therefore a core part of OAN verification, not an optional technical flourish.

The basic question is simple: is the thing I am about to use the same thing Root accepted? Hashes give the client a way to answer that question for DID Documents, metadata, packages, schemas, manifests, and artifacts.

Object responsibilities

What Hashes Bind

Hash What it protects
DID Document hash Identity-facing material, services, verification methods, and OAN metadata.
Metadata hash Descriptions, tags, domains, examples, searchable fields, and resource facts.
Package hash The publication unit accepted by Root.
Artifact hash External files such as skill packages, manifests, schemas, or bundles.
Schema hash API or tool contract material when schema is part of the accepted package.

Required hashes can vary by resource type, but the principle is constant: verify the material you plan to rely on.

For service resources, endpoint descriptors and schema references may be more important than downloadable package bytes. For skills, artifact and manifest hashes may be central. For MCP servers, endpoint and protocol-binding material matter. The hash set should follow the resource type.

Drift Examples

Hash checks catch problems such as:

  • a skill manifest changed after registration;
  • an API schema URL now serves a different document;
  • a DID Document endpoint was edited without publishing a new version;
  • CDN serves stale package bytes;
  • Discovery indexed old metadata;
  • a repository tag was moved;
  • a file was altered by line-ending or build-step differences;
  • a malicious endpoint returns different content than the package described.

Some of these are attacks. Some are ordinary mistakes. The check is useful either way.

This is one reason hash failures should not be treated as hostile by default in user messaging. A publisher may have edited a manifest after registration. A CDN may be stale. A repository tag may have moved. The client should reject the mismatch, but the error message can still guide the publisher or operator toward repair.

What To Do on Mismatch

A mismatch should not be quietly ignored. Reasonable responses include:

  • reject the candidate;
  • refetch from a trusted package route;
  • quarantine and require manual review;
  • show a precise error to the user;
  • request a new resource version from the publisher;
  • rebuild an index if the mismatch is caused by stale derived data.

Do not “fix” the mismatch by changing the local hash to match the downloaded file. That reverses the trust direction.

The accepted package facts are the reference. If the publisher wants the new file to be trusted, the publisher should publish a new version or updated package facts through the OAN lifecycle.

Version Binding

Hashes should be interpreted with version. If a resource is updated, the new version should have new package facts and proof. Clients should not use a hash from one version to verify another. Discovery should expose current lifecycle state so consumers know which package version they are selecting.

For fast-moving resources such as skills, this is especially important. Frequent updates are fine; untracked updates are not.

Version binding also protects reproducibility. A user may intentionally pin an older skill version for a workflow. That is acceptable when the old version’s proof and lifecycle are understood. It is different from accidentally using stale bytes because a mutable URL changed.

SDK Support

SDKs should provide hash helpers and structured verification errors. Developers should not have to guess whether the mismatch was in DID material, metadata, package bytes, or an external artifact. Good error categories make debugging and user support much easier.

Where possible, hash calculation should use canonical serialization rules so that harmless formatting differences do not cause avoidable failures.

Canonicalization rules should be documented and tested. Different SDKs should not compute different hashes for the same logical package. Shared test vectors are the practical way to keep TypeScript, Rust, Python, and future SDKs aligned.

Further Reading