AI Initiative logoAI Initiative
Reading room / Manthan

HERALD CT Log — Schema and Wire Format

HERALD CT Log — Schema and Wire Format. Covers 1. Overview; 2. Log entry; 2.1 Minimum profile (default); 2.2 Broader-public profile.

Project explanation / technical method
This is the retained source text, not a new validation of its claims. Numerical results and comparative claims require the accompanying source review before public reuse.

Read the connected case study or article →

Not explicitly stated in source · Date not established

Provenance, authorship and editorial notes

HERALD CT Log — Schema and Wire Format

Id

manthan-herald-protocol-lib-herald-ct-log-schema

Project

Manthan

Source path

manthan/herald-protocol/lib/herald-ct-log/SCHEMA.md

Source sha256

1fecf670cf4e16d8616102da62f5841650e85108bb23afe9445406d60525902a

Local copy sha256

1fecf670cf4e16d8616102da62f5841650e85108bb23afe9445406d60525902a

Repo head

3a94084024a3434cef331fecac91c2c3b43f0313

Date
Not recorded
Date basis

Original publication date not established; Git revision date retained separately.

Author

Not explicitly stated in source

Author basis

Unknown; Git committer not substituted for document author.

Last source commit

8b75d1b0157c20a0a463f0e31008ef9f73099beb

Last source commit date

2026-06-08T07:40:14Z

Document status

Project explanation / technical method

Summary

HERALD CT Log — Schema and Wire Format. Covers 1. Overview; 2. Log entry; 2.1 Minimum profile (default); 2.2 Broader-public profile.

Topics
  • Exploration architecture and selection
  • 1. Overview
  • 2. Log entry
  • 2.1 Minimum profile (default)
Theme

Exploration architecture and selection

Priority

deep

Related ids
  • manthan-readme
  • manthan-docs-architecture
  • manthan-docs-business-overview
  • manthan-docs-demo-walkthrough
  • manthan-docs-principles
  • manthan-docs-qd-measurement-direction-plan
  • manthan-docs-swarm-evolution-integration
Evidence concerns
  • Recovered source text is preserved verbatim. Assertions, comparisons, commands and results belong to its original context; they were not re-executed or externally re-verified during this corpus review.
Word count

2438

Bytes

17516

Source relative

herald-protocol/lib/herald-ct-log/SCHEMA.md

Remote mirror

manthan/herald-protocol/lib/herald-ct-log/SCHEMA.md

Full text preserved

True

HERALD CT Log — Schema and Wire Format

Status: normative for HERALD v0.2 conformant CT logs.
Source: EXT §2 (audit-log specification), RFC 6962 (Certificate Transparency).
Distribution: as lib/herald-ct-log/SCHEMA.md in the HERALD repository; consumed by T-102 (basic CT log impl), T-103 (STH publication), T-104 (SIP generation), T-105 (consistency proofs), T-106 (LOTS template — already done).


1. Overview

A HERALD CT log is an append-only, publicly-readable Merkle tree whose leaves are signed records of submitted HERALD envelopes. Operators run logs; submitters submit envelopes; verifiers consult logs to confirm inclusion.

The structure is RFC 6962-derived. Differences from RFC 6962:

2. Log entry

2.1 Minimum profile (default)

A log entry under the minimum profile is a CBOR-deterministic structure (per SPEC §3.5) with exactly four fields:

LogEntry := {
  "id":          <bytes>,    # the envelope id, SPEC §3
  "parent_hash": <bytes>,    # SHA-256(envelope.parent) or 32 zero bytes for genesis
  "trace_hash":  <bytes>,    # SHA-256(envelope.trace)
  "hour_bucket": <uint64>    # Unix timestamp floored to the nearest 3600s boundary
}

Validation rules:

No other fields. The minimum profile is exact; logs operating in minimum profile MUST reject submissions with log_metadata_consent declaring additional fields.

2.2 Broader-public profile

A log operating in broader-public profile per its LOTS MAY include additional fields, but MUST publish the field-acceptance policy at a well-known URL and MUST honour each submitter's log_metadata_consent exactly:

LogEntry (broader-public) := {
  "id":           <bytes>,
  "parent_hash":  <bytes>,
  "trace_hash":   <bytes>,
  "hour_bucket":  <uint64>,
  # Following fields MUST appear if and only if submitter opted in:
  "from":            <text, optional>,    # full sigil
  "to":              <text, optional>,    # full sigil(s)
  "ts":              <uint64, optional>,  # full Unix seconds
  "attestation_types": <[text], optional>, # types only, not values
  "size_bytes":      <uint64, optional>,
  "manifest_ref":    <bytes, optional>    # capability-manifest reference
}

A log MUST publish the per-entry profile in the SCT/SIP so verifiers know what fields to expect.

2.3 Private-compliance profile

A log operating in private-compliance profile MAY accept submissions with broader fields and with submitter pre-acknowledgement (per [EXT §2.7]). The acknowledgement mechanism is declared in LOTS §4.2.

Per [EXT §2.7], private compliance logs that ingest envelopes without submitter awareness are non-conformant.

2.4 Forbidden content

Regardless of profile, a log MUST NOT publish:

A log that violates this rule is non-conformant and MUST be flagged via the misbehaviour gossip path ([EXT §2.5]).

3. Merkle tree construction

Per [EXT §2.1] and RFC 6962 §2:

The leaf-prefix 0x00 and internal-prefix 0x01 are domain-separation between leaves and inner nodes; they prevent second-preimage attacks on the tree shape.

The tree is append-only: leaves are added in submission order, never reordered or removed. The tree size monotonically increases.

4. Signed Tree Head (STH)

Per [EXT §2.3]. An STH is the operator's signed commitment to the log's state at a point in time.

4.1 STH structure

STH := {
  "tree_size":  <uint64>,    # number of leaves
  "root_hash":  <bytes>,     # 32 bytes, the Merkle root
  "timestamp":  <uint64>,    # Unix seconds at which the STH was minted
  "log_id":     <bytes>      # SHA-256 of the log operator's public key
}

4.2 STH signature

The STH is signed with domain-separation tag herald.audit_sth.v1:

sth_signature = Ed25519_sign(operator_privkey, "herald.audit_sth.v1" || cbor_canonical(STH))

The signed structure is:

SignedSTH := {
  "sth":       STH,
  "alg":       "ed25519",
  "sig":       <bytes, 64 bytes Ed25519 signature>,
  "scope":     "operator_attestation"
}

4.3 STH publication

4.4 STH validation

A verifier receiving an STH MUST:

1. Look up the log_id's pubkey via the log's LOTS.
2. Verify the Ed25519 signature using herald.audit_sth.v1 domain separation.
3. Reject if tree_size = 0 and root_hash != SHA-256("") (consistency check).
4. Reject if timestamp is absurd (e.g. 0 or far-future).

5. Submission Certificate (SCT)

Per [EXT §2.4]. An SCT is the operator's promise that the submitted envelope will be merged within MMD.

5.1 SCT structure

SCT := {
  "envelope_id":  <bytes>,    # the submitted envelope's id
  "log_id":       <bytes>,    # SHA-256 of operator's pubkey
  "submitted_at": <uint64>,   # Unix seconds at submission
  "mmd_seconds":  <uint64>,   # the MMD applied to this submission
  "profile":      "minimum" | "broader-public" | "private-compliance"
}

5.2 SCT signature

The SCT is signed with herald.audit_sct.v1:

sct_signature = Ed25519_sign(operator_privkey, "herald.audit_sct.v1" || cbor_canonical(SCT))

The signed structure is:

SignedSCT := {
  "sct":      SCT,
  "alg":      "ed25519",
  "sig":      <bytes>,
  "scope":    "operator_attestation"
}

5.3 SCT semantics

6. Signed Inclusion Proof (SIP)

Per [EXT §2.4]. An SIP proves a specific envelope is included in the tree at a published STH.

6.1 SIP structure

SIP := {
  "envelope_id":  <bytes>,
  "log_id":       <bytes>,
  "leaf_index":   <uint64>,   # 0-indexed position in the tree
  "audit_path":   <[bytes]>,  # array of 32-byte hashes for path-to-root
  "sth":          STH         # the STH at which inclusion is proven
}

6.2 SIP signature

The SIP itself is not separately signed; the inclusion is proven cryptographically by the audit path, and the STH is signed (§4). The combined audit_path + sth is sufficient.

For convenience, logs MAY emit a wrapping signature:

SignedSIP := {
  "sip":      SIP,
  "alg":      "ed25519",
  "sig":      <Ed25519 signature over cbor_canonical(SIP) with tag herald.audit_sip.v1>,
  "scope":    "operator_attestation"
}

But verifiers MUST verify the inclusion mathematically (audit-path-to-root) regardless of the wrapping signature. The signature is convenience, not normative.

6.3 SIP verification

A verifier receiving an SIP MUST:

1. Compute leaf_hash = SHA-256(0x00 || cbor_canonical(LogEntry)).
2. Walk audit_path from the leaf to the root, applying internal-node hashing.
3. Confirm the resulting root equals sip.sth.root_hash.
4. Verify sip.sth per §4.4.
5. (Optional) Verify the wrapping signature.

If steps 1–4 succeed, the envelope is provably included at sip.sth.tree_size leaves.

7. Consistency proofs

Per [EXT §2.5]. A consistency proof shows that two STHs on the same log are consistent (one is a strict prefix-superset of the other).

7.1 Consistency proof structure

ConsistencyProof := {
  "log_id":      <bytes>,
  "first_size":  <uint64>,   # tree size at STH1
  "second_size": <uint64>,   # tree size at STH2 (must be ≥ first_size)
  "proof":       <[bytes]>   # array of 32-byte hashes per RFC 6962 §2.1.2
}

7.2 Consistency proof verification

Per RFC 6962 §2.1.2 algorithm. A verifier given two STHs and a consistency proof MUST:

1. If first_size == second_size and STH1.root_hash == STH2.root_hash, the trees are equal — accept.
2. If first_size > second_size, the proof is malformed — reject.
3. Else, run RFC 6962's PROOF verification algorithm.

If verification fails, the log has produced inconsistent STHs — the log is forked. Verifiers MUST:

8. Gossip

Per [EXT §2.5]. A log MUST participate in at least one gossip channel.

8.1 STH gossip

Channels (any one suffices for conformance; multiple recommended):

DNS TXT record format:

"v=herald-sth-1; log_id=<base64url>; sth_root=<base64url>; sth_size=<uint>; sth_ts=<uint>; sig=<base64url>"

8.2 Trace-genesis gossip (per R-215)

If the operator implements R-215 trace-genesis pinning:

8.3 Misbehaviour reporting

The operator MUST consume gossiped misbehaviour reports and respond per LOTS §5.3 commitments.

9. Submission API

A HERALD CT log exposes a write API at the LOTS-declared endpoint:

POST /submit
Content-Type: application/cbor
Body: signed envelope per SPEC §3
Response: 200 OK + SignedSCT (CBOR), or
          4xx (rejection: malformed envelope, profile mismatch, etc.) + reason code, or
          429 (rate-limited; retry after Retry-After)

Rejection reason codes use the refusal reason-code registry (D-310) where applicable: envelope_invalid_signature, envelope_malformed, envelope_replay, policy_violation, rate_limit_exceeded.

10. Read API

A HERALD CT log exposes read APIs at the LOTS-declared endpoints:

GET /sth                           → SignedSTH (latest)
GET /sth/<tree_size>               → SignedSTH at the given size, or 404
GET /sip/<envelope_id>             → SignedSIP, or 202 (still pending) + Retry-After
GET /sip/<envelope_id>?at=<size>   → SignedSIP rooted at the STH for tree_size=<size>
GET /consistency/<size1>/<size2>   → ConsistencyProof
GET /entries?from=<idx>&to=<idx>   → JSON array of LogEntry within range, capped at 1000

These endpoints are HTTP/1.1 or HTTP/2; CBOR is preferred for binary endpoints. JSON responses are permitted for /entries for ease of monitor tooling.

11. Inclusion semantics

11.1 When is an envelope "in" the log?

An envelope is provably included in a HERALD CT log at tree size N when:

11.2 When is an envelope NOT in the log?

A HERALD CT log does NOT support negative inclusion proofs ("envelope X is not in the log"). This is consistent with RFC 6962 — append-only logs do not commit to absence.

To assert an envelope's absence, a verifier asks the log for /sip/<envelope_id> and expects 404 (not found) at the latest STH. The 404 is non-cryptographic; it could be a lie. For high-stakes absence claims, the verifier consults multiple gossiped STHs and confirms the latest is the one they queried against.

12. MMD compliance

Per [EXT §2.3]. The operator declares MMD in LOTS; the log MUST honour it.

12.1 Real-time MMD metrics

A log MUST publish at the LOTS-declared MMD-metrics URL:

{
  "log_id":               <bytes>,
  "window":               <text, e.g. "last_24h">,
  "submissions":          <uint>,
  "merged_within_mmd":    <uint>,
  "merged_after_mmd":     <uint>,    # non-conformant if > 0 in window
  "average_merge_time_s": <float>,
  "p99_merge_time_s":     <float>
}

A log with merged_after_mmd > 0 is non-conformant and the operator MUST publish a SEV-1 incident notice per LOTS §8.

12.2 SCT-SIP delivery contract

When a submitter receives an SCT, they SHOULD be able to retrieve a corresponding SIP within MMD. Specifically:

13. Misbehaviour catalogue

A log is non-conformant if it does any of:

MisbehaviourDetection
Forked STHs (split-view attack)Cross-gossip of STHs reveals divergent root_hash at same tree_size
Stale STHs (not republished)STH series gap > MMD
Missing SIP after MMDSubmitter receives SCT, then 202 after MMD
Profile violationLog entry contains fields beyond submitter's consent
Forbidden content publicationLog contains payload or whisper.encrypted
MMD breachmerged_after_mmd > 0 in published metrics
Stale LOTSLOTS signature date > 12 months
Missing gossipNo declared gossip channel observable
Unsigned STHSTH lacks sth_signature or signature fails

Each is reportable via the misbehaviour gossip path. Logs accumulate non-conformance signals; reputation systems and verifiers progressively distrust persistently-non-conformant logs.

14. Implementation roadmap

This schema is consumed by:

15. Test vectors

Reference implementations MUST pass a conformance suite covering:

A sibling task (T-101-vectors or part of T-017 extension) should produce these.

16. Cross-references


— T-101 schema, by driver-claude, 2026-05-05.

Maintained at lib/herald-ct-log/SCHEMA.md in the HERALD repository.

Continue exploring