§
🌙 Toggle Dark Mode Home MoltGuard MoltProof MT Global · Regulated Markets MolTrust Sports MT Shopping MT Travel MT Skills MT Prediction MT Salesguard MT Music Integrity Dashboard VCOne Blog Developers Pricing Enterprise Partners Compliance About Publications Verify Us Status Contact API Docs
Canonical Skill Hash Specification · v1 · September 2026 · CC BY 4.0

Canonical Skill Hash Specification

Status: Stable Version: 1 Auditor: moltguard 1.2.0 Published: September 2026 Specification URL: https://moltrust.ch/skill-hash-spec.html


Why this exists

MolTrust issues a signed credential over a skill, and the credential names a hash rather than a file. Whoever holds the same SKILL.md can derive the same hash and check the credential without asking us anything.

That is the whole point of publishing this page. A track record only its issuer can compute is a reputation service; one any party can recompute is evidence. Without a written rule for the hash, the second kind is not available — so the rule is written here, in enough detail to reimplement.

The rule

Given the raw bytes of a SKILL.md, decoded as UTF-8, apply these steps in order:

  1. Strip a leading byte-order mark. If the first character is U+FEFF, drop it. Editors add it invisibly, and a file that looks identical on screen would otherwise hash differently.
  2. Normalise line endings. Replace every CRLF with LF, then every remaining lone CR with LF. A checkout on Windows must produce the same hash as one on Linux.
  3. Strip trailing whitespace on every line. Remove spaces and tabs at the end of each line. These are invisible and frequently rewritten by editors that had nothing to do with the content.
  4. Collapse runs of blank lines. Three or more consecutive newlines become exactly two, so one blank line is the maximum.
  5. Trim leading and trailing newlines from the document as a whole.
  6. Apply Unicode NFC. Composed and decomposed forms of the same character must not produce different hashes.
  7. Hash. SHA-256 over the UTF-8 encoding of the result.

The value is the lowercase hex digest, prefixed with the algorithm:

sha256:<64 lowercase hex characters>

Reference implementation

This is the code that runs. It is reproduced rather than paraphrased, because a paraphrase is one edit away from disagreeing with the thing it describes.

import { createHash } from 'node:crypto';

export function canonicalSkillHash(raw) {
  let s = raw;
  if (s.charCodeAt(0) === 0xFEFF) s = s.slice(1);
  s = s.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
  s = s.split('\n').map(line => line.replace(/[\t ]+$/, '')).join('\n');
  s = s.replace(/\n{3,}/g, '\n\n');
  s = s.replace(/^\n+/, '').replace(/\n+$/, '');
  s = s.normalize('NFC');
  const hash = createHash('sha256').update(s, 'utf8').digest('hex');
  return `sha256:${hash}`;
}

The same rule in Python:

import hashlib, re, unicodedata

def canonical_skill_hash(raw: str) -> str:
    s = raw.lstrip("\ufeff")
    s = s.replace("\r\n", "\n").replace("\r", "\n")
    s = "\n".join(line.rstrip(" \t") for line in s.split("\n"))
    s = re.sub(r"\n{3,}", "\n\n", s)
    s = s.strip("\n")
    s = unicodedata.normalize("NFC", s)
    return "sha256:" + hashlib.sha256(s.encode("utf-8")).hexdigest()

What is not normalised

Everything else is content and changes the hash:

This is deliberate. The normalisation covers what an editor changes without being asked; it does not attempt to decide which edits are meaningful. A reformatting that touches indentation produces a new hash and needs a new credential, which is the honest outcome — we cannot certify a file we did not read.

Verifying a credential

  1. Fetch the SKILL.md the credential refers to.
  2. Compute the canonical hash with the rule above.
  3. Compare it with credentialSubject.skillHash.
  4. Verify the credential signature against the MolTrust issuer key published at /.well-known/did.json.

A mismatch in step 3 means the file changed after the audit. It does not by itself mean anything is wrong — it means the credential describes different bytes than the ones in your hand, and a fresh audit is the way to settle it.

Stability

A change to any step above changes every hash and invalidates every issued credential, so this rule is versioned and will not change silently. A future revision would be published as version 2 alongside this page, and existing credentials would continue to name version 1.

Endpoints


MolTrust / CryptoKRI GmbH, Zurich | hello@moltrust.ch | moltrust.ch Released under Creative Commons Attribution 4.0 International (CC BY 4.0)