R-205 — Model-hash canonical specification
Research deliverable for the canonical weight-hash specification referenced
at [SPEC §4.1] line 242 ("model_hash is *hash of model weights, attested byHerald*"), elaborated at [EXT §3.1] (consent graph vs training graph), bound
to a Herald-attestation registry entry by the registry shape in
registries/standard-attestations.md §2.4(thespecfield of the
attestation value). This document is research, not normative spec; the
normative spec it recommends should land in EXT §3 (and a registry entryat registries/model-hash-specs/) once the open questions in §7 areresolved.
0. TL;DR
Naive sha256(weights.bin) is insufficient for HERALD's purposes. Two
inference servers running behaviourally identical weights — same numeric
tensor values, same architecture — will routinely produce different
file-byte hashes. The canonical model hash MUST be computed over a
format-independent, tensor-level canonical encoding: a deterministic
serialisation of (layer_name, dtype, shape, raw_bytes) tuples in
lexicographic name order, framed with explicit length prefixes, hashed under
a versioned domain-separation tag.
This document recommends:
1. The canonical hash is computed over tensors-as-data, not files-as-bytes.
2. The hash spec is versioned and registered at
registries/model-hash-specs/<spec-id>.md. The spec field of a
model_hash attestation (registries/standard-attestations.md §2.4) names
the registry entry.
3. One spec per quantisation regime. FP16 weights and the same model's
Q4_K_M quantisation get different model_hash values under different
spec-ids. They are different artefacts; pretending otherwise is a
laundering vector ([THREATS §6.5]).
4. LoRA / fine-tune composition is out-of-scope for the base spec and is
handled by a separate model_hash_composed attestation form referencing
base + adapter hashes.
5. *Closed-weight commercial models cannot be canonically hashed by an
external Herald without vendor cooperation. This is acknowledged
honestly. For closed weights, the protocol falls back to Herald-attested
operational* claims ("Herald X verifies, by means it discloses in its
Charter, that this sigil is operating model M"). The cryptographic claim
degrades to a procedural one. See §7.
1. Problem statement
[SPEC §4.1] specifies a model_hash attestation field but defers to
"Herald's canonical specification" without defining what canonicalisation
means. [EXT §3.1] makes the call sharper: a model_hash attestation is
authoritative only when "signed by a Herald that has independently verified
the weights against a published canonical model-hash specification." The
canonical spec is a hole in v0.2.
The hole matters because the threat in [THREATS §6.5] (reputation laundering
pipelines) is amplified if model_hash is fragile. If two Heralds
independently load the same model from different file containers and
compute different hashes, an attacker can:
- Train two near-identical Heralds, each with its own file convention;
- Get the same underlying weights attested under two different hashes;
- Sell the "fresh" hash as a "new model" or as a hash for a sigil that has
no actual relation to the underlying weights;
- Equivalently: fork-attack the hash space such that no single value is
authoritative.
The naive defence — "everyone hashes the file" — fails in seven ways
catalogued in §3 below.
2. What the field has to be
A model-hash specification fit for HERALD's purposes must satisfy:
1. Equality semantics: two artefacts with byte-identical numerical
tensor contents (under their declared dtype) MUST hash equal, regardless
of file format, shard layout, metadata padding, or storage order on disk.
2. Inequality semantics: any change to numerical tensor contents that
would alter inference behaviour MUST change the hash. (Equivalently: no
collisions of behaviourally distinct models under feasible attack.)
3. Format-independence: a model exported as safetensors, GGUF,
ONNX, raw pt, or sharded safetensors-N-of-M MUST produce the same
hash if the underlying tensors are numerically identical and the
architecture is the same.
4. Quantisation explicitness: a quantised version of the same model is
a different artefact and MUST hash differently. The hash MUST be
computed over the post-quantisation tensor bytes; the quantisation
regime is part of the spec ID.
5. Verifiability without proprietary tooling: the spec MUST be
implementable from a published document by a third party with access to
the weights, in any major language, in <500 lines of code. (Excludes
anything that requires a particular framework's serialiser.)
6. Versioned: the spec ID changes when the algorithm changes; old
attestations are not silently re-interpreted under the new rules.
7. Domain-separated: the hash is computed under an explicit domain tag
so it cannot collide with arbitrary other Merkle/SHA constructions used
by the protocol or by attackers (cross-protocol-signature defence,
parallel to [SPEC §3.6] and [THREATS §4.6]).
These criteria rule out file-bytes hashing (fails 3), framework-dependent
serialisers (fails 5), un-versioned formats (fails 6), and any approach
that doesn't bind the dtype/shape together with bytes (fails 1 in pathological
cases — see §3).
3. Why naive sha256(file_bytes) fails
Seven concrete reasons, with citations:
3.1 Storage format is not the model
The same Llama-3 8B FP16 weights can be written as:
- A single
model.safetensorsfile (HuggingFace convention; header is
JSON; tensor data follows; tensor data section starts at variable offset
depending on header length)
[[safetensors format spec, last checked 2026-05-05]](https://huggingface.co/docs/safetensors/index)
- A two-shard set
model-00001-of-00002.safetensors/
model-00002-of-00002.safetensors with model.safetensors.index.json
(HuggingFace convention for >5GB models).
- A single
consolidated.00.pth(Meta's release convention; pickle). - A single
model.gguf(llama.cpp convention; binary KV store)
[[GGUF spec, DeepWiki, last checked 2026-05-05]](https://deepwiki.com/ggml-org/llama.cpp/7.1-gguf-file-format)
- A single
model.onnx/model.onnx.datapair (protobuf graph + raw
tensor blob)
[[ONNX serialization, last checked 2026-05-05]](https://onnx.ai/onnx/api/serialization.html)
All five represent the same model. None of them produce the same SHA256
of file bytes.
3.2 JSON header non-determinism in safetensors
The safetensors header is JSON. JSON specifies neither key order nor
whitespace. Two safetensors writers that emit the same logical header with
different key orders or different whitespace produce different file bytes.
The format does not mandate canonical JSON
[[safetensors header structure, last checked 2026-05-05]](https://malcolm-mill.github.io/LLM/safetensors_file_structure/).
The same applies to safetensors __metadata__, which is a free-form
key-value map that callers populate with author/date/framework strings. Any
training run that injects a timestamp into __metadata__ produces a hash
that's a function of training run timestamp, not of weights.
3.3 Header padding and offset drift
Safetensors permits the data section to start at any offset; some writers
pad the JSON header to a 512-byte or 4096-byte alignment for fast mmap
reads. The padding bytes are unspecified and can differ between writers
[[safetensors spec, last checked 2026-05-05]](https://huggingface.co/docs/safetensors/index).
Two writers producing semantically identical files with different header
padding produce different SHA256.
3.4 Sharding is a packaging choice, not a model choice
A 70B-parameter model can ship as a single 140GB file, as 14×10GB shards,
as 70×2GB shards, or as one shard per layer. The tensors are identical;
the files are not. HuggingFace's model.safetensors.index.json records
which tensor lives in which shard, but the index itself is shard-layout
metadata, not model identity.
3.5 dtype encoding ambiguity (BF16 vs FP16 byte patterns)
BF16 and FP16 are both 16-bit, but their bit layouts differ. A naive
hasher that ignores dtype labels and just hashes the raw 2-byte chunks
will produce the same hash for a tensor stored as BF16 and a tensor
stored as FP16 if the bytes happen to coincide — which they can in
sparse tensors with many zeros. Conversely, a tensor mathematically
identical at full precision but stored once as FP16 and once as BF16 will
correctly hash differently — but the byte hasher will disguise this
under the same field. The hash must bind dtype.
3.6 Layer-name normalisation drift
Different framework versions produce different layer-name conventions for
the same architecture: model.layers.0.self_attn.q_proj.weight vstransformer.h.0.attn.q.weight vs blocks.0.attention.wq.weight.
Round-tripping a checkpoint through HuggingFace from_pretrained /save_pretrained can rewrite these names. The tensor bytes are identical;
the names differ. A hash that includes layer names verbatim will fork on
naming convention. A hash that ignores names entirely allows an attacker
to permute layers and produce an inference-incorrect model with the same
hash — clearly worse.
3.7 Optimiser state and training-checkpoint metadata
A training checkpoint includes optimiser moments (Adam m, v),
LR-scheduler state, RNG state, gradient clipping state, and similar. These
are absent from an inference-only artefact. A naive byte-hasher hashes
both; they hash differently for what is, behaviourally, the same model. In
practice, deployers strip optimiser state before publishing inference
weights; but the canonical spec must be insensitive to whether stripping
happened.
3.8 (Bonus) Floating-point representation legality
Floats have multiple representations of NaN (any value with the
exponent set to all-1s and a non-zero mantissa). A model with NaNs in a
tensor (which is itself a bug, but happens) can hash differently after a
round-trip through any framework that normalises NaN representations. The
canonical spec should either define a NaN-canonicalisation rule or
explicitly refuse to hash artefacts containing NaN.
4. Survey of prior art
4.1 sigstore / model-transparency (Google + OpenSSF, 2025)
Sigstore's model-signing library hashes models by walking the directory
tree, hashing each file with SHA-256, and emitting an in-toto Statement
listing path:hash entries
[[sigstore model-transparency, last checked 2026-05-05]](https://github.com/sigstore/model-transparency)
[[Sigstore blog: model signing v1.0, last checked 2026-05-05]](https://blog.sigstore.dev/model-transparency-v1.0/).
This is file-bytes hashing wrapped in a Merkle/in-toto envelope. It
solves tamper detection of a specific distribution but does not
solve format-independent canonicalisation: re-export the same model
through a different framework and the in-toto statement no longer
verifies. The library acknowledges this — the README explicitly notes
that future versions intend to support "file shards" and "tensors" as
hashable components, but the v1.0 release supports only files and file
shards. Conclusion: sigstore solves a different problem (verifying
that the artefact a publisher uploaded is the same artefact a consumer
downloaded). It is complementary to, not a substitute for, a canonical
weight hash.
4.2 C2PA AI/ML guidance (2024-2025)
C2PA's AI/ML model attestation guidance uses *per-file SHA-256 in an
asset-reference assertion*: for an OpenVINO model, the .xml
(topology) and .bin (parameters) files are hashed separately
[[C2PA AI/ML guidance, last checked 2026-05-05]](https://spec.c2pa.org/specifications/specifications/2.4/ai-ml/ai_ml.html).
This is, again, file-bytes hashing. Same critique. C2PA is good at saying
"this artefact bundle is what the publisher signed"; it is not a
canonical model identifier.
4.3 HuggingFace Hub SHA256
The HuggingFace Hub displays per-file SHA-256 hashes alongside model
files. There is a closed-as-not-planned issue
[[huggingface/safetensors#220, last checked 2026-05-05]](https://github.com/safetensors/safetensors/issues/220)
proposing a sha256sum field in safetensors __metadata__. The proposal
was for integrity (catching corrupted downloads), not canonicalisation;
the maintainers correctly noted that adding a checksum to a format
already protected by HTTPS-layer integrity was redundant for that use
case. The community has not converged on a canonical-hash convention.
4.4 ML-research weight-equality literature
A 2023 ACM paper on "Integrated Reproducibility with Self-describing
Machine Learning Models" proposes hashing weights via xxhash of
linearised vectors sorted by name, then combining with a hash of the
architecture description
[[ACM DOI 10.1145/3589806.3600039, last checked 2026-05-05]](https://dl.acm.org/doi/fullHtml/10.1145/3589806.3600039).
Later implementations switched to BLAKE2b. This is the closest published
approach to what HERALD needs. It is not a fully-specified standard, and
it does not address quantisation regimes.
4.5 RepDL / batch-invariance (2025-2026)
A separate research thread (RepDL; Thinking Machines Lab "defeating
nondeterminism in LLM inference") addresses bit-level reproducibility of
forward passes, by replacing non-batch-invariant kernels (RMSNorm, attn,
matmul) with batch-invariant equivalents
[[Thinking Machines Lab blog, last checked 2026-05-05]](https://thinkingmachines.ai/blog/defeating-nondeterminism-in-llm-inference/)
[[arXiv:2510.09180, last checked 2026-05-05]](https://arxiv.org/pdf/2510.09180).
This is a complementary problem: they ensure the outputs are
reproducible given the same weights. HERALD's canonical hash ensures the
identity of the weights is canonical. Different layers of the stack.
4.6 NIST AI 100-4 / C2PA / NTIA work
The NIST AI 100-4 ("Reducing Risks Posed by Synthetic Content") and the
C2PA guidance treat model attestation as a content-credential problem,
not a weight-canonicalisation problem
[[NIST AI 100-4, last checked 2026-05-05]](https://nvlpubs.nist.gov/nistpubs/ai/NIST.AI.100-4.pdf).
The framing is regulatory and content-provenance, not protocol-level
verification of weight identity.
Summary of prior art: nobody has shipped a production-grade
canonical weight hash. The closest published designs hash file bytes
(sigstore, C2PA, HF Hub), which fails our format-independence criterion.
The ACM paper sketches the right shape but is incomplete for quantised
and adapter-composed models. HERALD has to specify this itself.
5. Recommended canonicalisation
This is the recommended algorithm for the v0.2 base spec, registered as
registries/model-hash-specs/transformer-fp16-canonical-v1.md
(spec ID: model-hash-spec/v0.2/transformer-fp16-canonical-v1).
5.1 Inputs
A materialised model: a directory or in-memory mapping from layer-name
strings to (dtype, shape, raw-bytes) triples. The materialisation step
loads any of {safetensors, GGUF, ONNX, raw pickle, sharded safetensors}
into this canonical in-memory form. The materialiser is per-format
adapter code; the canonical hash is independent of which adapter ran.
A spec ID specifies the materialisation rules: which dtype each tensor
must be loaded as, what canonical layer-name mapping table to use, and
which architecture this spec applies to.
5.2 Canonical encoding (the binary string the hash digests)
Conceptually:
canonical_bytes :=
DOMAIN_TAG ||
SPEC_ID_LEN || SPEC_ID ||
ARCH_ID_LEN || ARCH_ID ||
TENSOR_COUNT ||
for each tensor in lexicographic-sorted layer_name order:
LAYER_NAME_LEN || LAYER_NAME ||
DTYPE_TAG ||
SHAPE_NDIM || (SHAPE_DIM_0 ... SHAPE_DIM_NDIM-1) ||
TENSOR_BYTES_LEN || TENSOR_BYTESWhere:
DOMAIN_TAGis the ASCII stringherald.model_hash.v1followed by a
single 0x00 byte (cross-protocol-signature separation).
- All length and count fields are unsigned 64-bit big-endian integers.
- All shape dims are unsigned 64-bit big-endian integers.
LAYER_NAMEis UTF-8, after passing through the canonical-name
rewriter declared in the spec entry (e.g.
transformer.h.{i}.attn.{q,k,v,o}_proj.weight →
model.layers.{i}.self_attn.{q,k,v,o}_proj.weight).
DTYPE_TAGis a fixed 1-byte enum: `0x01=F32, 0x02=F16, 0x03=BF16,
0x04=I8, 0x05=Q4_0, 0x06=Q4_K_M, ...` declared in the spec entry.
Tensors whose dtype does not appear in the spec's enum are not
hashable under that spec; the materialiser refuses.
TENSOR_BYTESis the tensor's raw bytes in the dtype's native
little-endian byte order (matches safetensors' choice
[[safetensors spec, last checked 2026-05-05]](https://huggingface.co/docs/safetensors/index)),
in canonical row-major (C) order regardless of source storage order.
Stride/transposition during materialisation is performed before
hashing.
- Lexicographic ordering of layer names is byte-wise on the
UTF-8-encoded canonical names, not Unicode-collation; deterministic
across implementations.
5.3 The hash
model_hash := SHA-256( canonical_bytes )(Recorded in the registry entry. SHA-256 is chosen for ubiquity and
parity with envelope hashing in [SPEC §3]. BLAKE3 is acceptable for
performance variants; each goes in its own spec ID.)
5.4 Why this passes the criteria of §2
- Format-independence (criterion 3): anything that materialises into
the same (name, dtype, shape, bytes) triples produces the same hash.
- Quantisation explicitness (criterion 4): the dtype enum is part of
the canonical bytes; a quantised tensor and an unquantised tensor
with the same numeric values but different dtypes hash differently.
- Equality (criterion 1): two FP16 safetensors with byte-identical
tensor data and identical shapes, after canonical name rewriting,
hash identically.
- Inequality (criterion 2): any change to a tensor's bytes, shape,
or dtype changes the canonical bytes and hence the hash. SHA-256
collisions are computationally infeasible.
- Verifiability (criterion 5): the algorithm is <300 lines of code
per language, modulo per-format materialisers (which exist in every
major language already).
- Versioning (criterion 6): the spec ID is in the canonical bytes
and in the registry. v2 of the spec gets a new ID.
- Domain separation (criterion 7):
DOMAIN_TAGprevents
cross-protocol reuse of the digest.
5.5 What this spec does NOT include
It does NOT include:
- Optimiser state (no Adam
m/v, no scheduler, no RNG). - Free-form
__metadata__(timestamps, author strings). - Tokenizer files. (Tokenizer hashing is a separate registry entry,
model-hash-spec/.../tokenizer-vN, because tokenizers are
independently versioned and may be shared across model checkpoints.)
- Architecture code. The spec ID names the architecture; it does not
hash the implementation. Two implementations of "Llama 3" that
compute identical outputs given identical weights are
protocol-equivalent.
6. Quantisation regimes
Quantisation is the place where naive specs go to die. The recommendation
is one spec per (architecture × quantisation-regime) pair, not one spec
per architecture with quantisation as a parameter. This is more
registry entries but vastly simpler verifier logic.
6.1 Per-regime spec IDs
| Regime | Spec ID suffix | Source of truth for the bit-layout |
|---|---|---|
| FP32 | -fp32-canonical-v1 | IEEE 754 binary32 |
| FP16 | -fp16-canonical-v1 | IEEE 754 binary16 |
| BF16 | -bf16-canonical-v1 | bfloat16, IEEE-style |
| Q8_0 | -q8_0-canonical-v1 | GGUF Q8_0 block layout |
| Q4_0 | -q4_0-canonical-v1 | GGUF Q4_0 block layout |
| Q4_K_M | -q4_k_m-canonical-v1 | GGUF Q4_K_M block layout |
| AWQ-INT4 | -awq_int4-canonical-v1 | AWQ scheme reference impl |
| GPTQ-INT4 | -gptq_int4-canonical-v1 | GPTQ exllamav2 reference impl |
Each registry entry references an external bit-layout spec (e.g.
[[GGUF tensor encoding schemes, last checked 2026-05-05]](https://github.com/ggml-org/llama.cpp/wiki/Tensor-Encoding-Schemes))
as the authority for the byte layout of quantised tensors of that regime.
6.2 Why per-regime is the right choice
The same FP16 weights, quantised by GPTQ at int4 vs by AWQ at int4 vs by
llama.cpp at Q4_K_M, produce *three different artefacts that compute
three different forward passes. They are not the same model; they
should not share a hash. This is the same principle as not hashing the
file bytes: the hash should track behavioural* identity, and quantised
variants of a model behave (subtly) differently from each other and
from the FP16 source.
[[Survey of quantization methods, last checked 2026-05-05]](https://arxiv.org/pdf/2103.13630)
6.3 What this rules out
A model_hash attestation cannot say "this sigil is running the int4
or FP16 variant of Llama-3-8B-Instruct" — the hash names exactly one of
those, and the choice is part of the spec ID. This is correct: a
verifier that wants "either int4 or FP16" semantics has to accept either
of two specific hashes, not a wildcard.
7. Open problems
7.1 Closed-weight commercial models
The unfixable problem. For Anthropic Claude, OpenAI GPT, Google Gemini —
the weights are not published. An external Herald cannot compute a
canonical hash of weights it cannot read. Three partial answers:
(a) Vendor cooperation. The vendor publishes a model_hash for
each released checkpoint, computed under a published spec, and signs it
with their Herald sigil. Verifiers trust the vendor's Herald the same
way they trust any other Herald — through the operator transparency
baseline at [EXT §3.5] and through CT-log inclusion at [EXT §3.4]. The
hash is real given the vendor signs it; it is non-falsifiable to
external parties only as long as the vendor's Herald is honest. This is
no worse than the current trust posture for vendor-attested anything.
See R-206 ("Vendor-Herald engagement strategy"), already done, for the
engagement framing.
(b) Operational attestation as fallback. Where vendor cooperation
is unavailable, the protocol degrades from a cryptographic claim
("the weights have hash X") to an operational claim ("Herald Y, whose
charter discloses procedure Z, certifies that this sigil is operating
model M"). The attestation type changes accordingly: a non-cryptographicmodel_operational attestation, distinct from model_hash. This is
honest about the gap; downstream reputation systems can weigh
operational attestations differently from cryptographic ones. *This
proposal exposes a follow-on TODO* — see NOTES.md.
(c) TEE / remote attestation. A vendor running inference in a
trusted execution environment (Intel TDX, AMD SEV-SNP, Nvidia
Confidential Compute) can produce a hardware-rooted attestation that a
specific binary loaded specific weights. The TEE boundary becomes the
hash. This is an active area; C2PA's AI/ML work
[[C2PA AI/ML guidance, last checked 2026-05-05]](https://spec.c2pa.org/specifications/specifications/2.4/ai-ml/ai_ml.html)
gestures at "hardware-backed attestation during certificate enrollment."
HERALD should accept TEE-attested model_hash values as a future spec
variant (model-hash-spec/v0.x/tee-attested-...). This is not v0.2
work.
7.2 LoRA / fine-tune composition
A LoRA adapter applied to a base model can be (a) merged into the base
weights to produce a new artefact (different hash) or (b) kept as a
runtime delta (same base hash, separate adapter hash). Naively merging
LoRA into a quantised base is known-broken
[[merging LoRA into quantised base, last checked 2026-05-05]](https://medium.com/@praggrt/from-lora-to-qlora-the-right-way-to-merge-weights-for-inference-bf4618c4ae39).
The recommendation: a separate attestation typemodel_hash_composed (out of [SPEC §4.1] core; in EXT §3.x or in a new
registry entry):
{
"type": "model_hash_composed",
"value": {
"subject": "<sigil>",
"base": "<model_hash hex>",
"base_spec": "<spec ID>",
"adapters": [
{ "name": "...", "hash": "<adapter hash>",
"adapter_spec": "...", "rank": 16, "alpha": 32 },
...
],
"compose_op": "linear-add" | "scaled-add" | "ties-merge" | ...,
"merged_hash": "<post-merge hash, optional>"
}
}Adapter hashes use a reduced spec (LoRA matrices A and B per layer; same
canonical encoding shape as §5.2 with LAYER_NAME carrying the.lora_A/.lora_B suffix). This is a follow-on task; the v0.2 base
spec does not need to specify it.
[[PEFT v0.9.0 multi-adapter merge methods, last checked 2026-05-05]](https://github.com/huggingface/peft/releases/tag/v0.9.0)
7.3 Mixture of Experts (MoE) with stochastic routing
MoE models route tokens to experts, sometimes stochastically. The
weights are deterministic; the forward pass is not (without
batch-invariant kernels — see [4.5 above]). The hash of the weights is
fine — §5 handles it the same as any other architecture. What is not
fine is treating two inference deployments of the same MoE weights as
producing the same outputs; they don't, generically. This is out of
scope for model_hash but in scope for [EXT §3] in the longer term:
the protocol may need a routing_canonical claim alongside model_hash
for MoE attestation to be meaningful.
7.4 Layer-name canonicalisation table
The spec recommends canonical-name rewriting (§5.2). Producing the
rewriter table is per-architecture work: someone has to decide, for
Llama-3, that the canonical name for the i-th layer's q-proj weight
is model.layers.{i}.self_attn.q_proj.weight and document the mapping
from all known framework conventions. This is annoying but tractable; it
is the cost of format-independence. The Herald-attestation registry
hosts these tables.
7.5 NaN / Inf / subnormal canonicalisation
The recommendation is to refuse to hash artefacts containing NaN or
Inf in any tensor. Subnormals are passed through unmodified. This needs
a binding test vector in the spec entry.
7.6 Hash agility
The spec uses SHA-256. If SHA-256 weakens, a v2 of every spec is
required (new spec IDs, new attestations, no silent rebinding). The
registry shape supports this. The reputation impact of mass spec churn
is non-trivial; verifiers should be prepared for a multi-year overlap
period during any future migration.
7.7 Shard-equivalent hashing without full materialisation
For a 70B-parameter model, materialising into a contiguous canonical
encoding is multi-hundred-GB. A practical implementation hashes
incrementally (SHA-256 streaming, one tensor at a time, in the canonical
order). The spec MUST require streaming-equivalent output (which it does
trivially because SHA-256 is streaming). Test vectors should explicitly
verify that streaming and one-shot implementations produce identical
hashes.
8. Recommendation for [EXT §3] specification work
Concretely, what should land in EXT §3 and the registry:
1. EXT §3.1 amendment: add a normative paragraph stating that
model_hash values MUST be computed under a registered spec, and
that the spec ID MUST appear in every model_hash attestation. The
shape in registries/standard-attestations.md §2.4 already requires
this; promote the requirement to EXT.
2. New registry directory: registries/model-hash-specs/ containing
one Markdown file per spec ID, structured per a template defined in
that directory's README. Template fields:
- Spec ID (URL-safe slug).
- Authoring Herald(s).
- Architecture (model family, parameter count, layer-name table).
- Quantisation regime (with bit-layout reference).
- Domain tag.
- Hash algorithm.
- Test vectors (a known model + its expected hash under this spec).
- Versioning policy.
- Deprecation status.
3. Initial spec entry:
registries/model-hash-specs/transformer-fp16-canonical-v1.md,
with the algorithm in §5 above, applicable to any
transformer-family model with a published layer-name mapping. This
is the minimum-viable spec; everything else is incremental.
4. Honest acknowledgement in [EXT §3.1] that closed-weight
commercial models cannot be hashed without vendor cooperation, and
that the protocol's recourse is the operator-transparency baseline
([EXT §3.5]) plus the (proposed) model_operational attestation.
This is a documentation patch; do not paper over the gap.
5. Test-vector requirement at test-vectors/model-hash/: every
spec entry MUST publish at least one (model URL, expected hash)
pair so that verifier implementations can be cross-checked.
6. Registry as RFC pipeline: new spec entries should be proposed
and reviewed through the same RFC process the project uses for
other registry additions. The Heralds that author a spec are listed
in the entry; the spec is not mutable after registration except via
versioned successor.
9. What is not in this document
- A reference Python implementation. (Belongs in
lib/herald-core-py/
as a Tier-1 task; not part of R-205.)
- Hash-agility guidance for post-quantum hash functions. (Out of scope;
parallel to the SPEC's signature-suite registry [EXT §6.6].)
- A treatment of training-data hashes (data provenance), which is
related but distinct. See R-201 (ZK provenance) for the parallel
research thread.
- A formal model of canonicalisation correctness. The argument here is
informal-but-careful; a formal model is welcome follow-on work.
Sources (last checked 2026-05-05)
- safetensors format spec — Hugging Face docs
- safetensors file format structure — Malcolm Mill
- safetensors GitHub
- safetensors checksum proposal — issue #220
- GGUF file format — DeepWiki
- GGUF — Hugging Face docs
- llama.cpp tensor encoding schemes
- ONNX serialization — onnx 1.22.0 docs
- Proto serialization is not canonical
- Sigstore model-transparency
- Sigstore blog: model-signing v1.0
- C2PA AI/ML guidance — spec 2.4
- C2PA NIST RFI response
- NIST AI 100-4: Reducing Risks of Synthetic Content
- Integrated Reproducibility with Self-describing ML Models — ACM
- Defeating Nondeterminism in LLM Inference — Thinking Machines Lab
- RepDL: Bit-level Reproducible Deep Learning — arXiv 2510.09180
- A Survey of Quantization Methods — arXiv 2103.13630
- PEFT v0.9.0 release notes — multi-adapter merge
- LoRA → QLoRA merging notes
Internal sources (HERALD project)
SPEC.md §4.1line 242 —model_hashfield definition.EXT.md §3.1line 215 — consent graph vs training graph; canonical-spec requirement.EXT.md §3.2line 221-228 — Herald-issued lineage certificates.EXT.md §3.4line 249-253 — Herald CT log requirement formodel_hashattestations.EXT.md §3.5— Herald operator transparency baseline.THREATS.md §6.5line 444-455 — reputation-laundering pipelines (the threat).THREATS.md §3.5(Persona E, Disgruntled Herald) and §A — state-actor Herald.registries/standard-attestations.md §2.4—model_hashregistry shape.research/vendor-engagement.md— R-206, vendor Herald engagement strategy.