A generic, payload-agnostic IETF SCITT + COSE Receipts substrate for Python:
build/verify COSE_Sign1 Signed Statements, verify Receipts and RFC 9162
inclusion / consistency proofs, with the Merkle + receipt-signing
primitives. A separate module, scitt_cose.cll, verifies a Checkpointed
Local Log (MMR inclusion, consistency and range proofs against a checkpoint);
it is narrower than the rest of the package, see
CLL verification.
It is NOT a transparency service (operating a log — a hosted registration
endpoint — is a separate concern), and it carries NO application profile —
bring your own statement semantics. The only third-party dependencies anywhere
in the package are cbor2 and
cryptography, plus the standard
library. COSE_Sign1 (RFC 9052) is implemented here from scratch — it does not
use python-cwt or any other COSE library.
Name note.
scitt-coseis the finalized package name, claimed on PyPI and GitHub (action-state-group/scitt-cose) in the same pass.
Does:
- Verify a SCITT Signed Statement (
COSE_Sign1) signature against a supplied key — EdDSA and ES256 — and report its issuer / subject / content-type / alg. - Verify a COSE Receipt carrying either of two verifiable data structures:
RFC9162_SHA256(vds = 1, the tree algorithm registered by RFC 9942) or CCFccf.v1(vds = 2, Microsoft CCF's Merkle format, used by scitt-ccf-ledger v7+) — the RFC 9162 SHA-256 inclusion proof and the log's signature over the reconstructed root — i.e. "this statement is provably in the log" — without trusting the log operator. The vds value is read from the protected header only and anything other than these two registered structures is rejected, not silently accepted. - Provide the RFC 9162 Merkle primitives (root, inclusion, consistency) and a
build_receiptprimitive. - Verify a Checkpointed Local Log offline (
scitt_cose.cll): that a leaf is under a checkpoint's MMR root, that one checkpoint extends an earlier one, and that a range of leaves is complete, with the checkpoint's own receipt checked byverify_receipt.
Does NOT:
- Operate a Transparency Service. It never registers statements, issues receipts, witnesses, or stores anything. Running a log is a separate concern with its own operational trust obligations.
- Validate any application profile's payload semantics. The statement payload
is treated as opaque bytes. There is no application-profile awareness —
SBOMs, agent actions, or anything else; that neutrality is deliberate, and is
what makes this reusable by anyone in the SCITT ecosystem. The one
exception is honest to name:
scitt_cose.cllknows one log format, the CLL checkpoint record (below). Its leaves are still opaque digests. - Depend on a COSE library for wire values.
COSE_Sign1is implemented from scratch overcbor2+cryptography; code points are pinned to the IANA registries, not to a library's enum.
This is a standalone, profile-opaque, cross-validated generic SCITT/COSE verifier: it verifies anyone's SCITT Signed Statements and COSE Receipts, treats the payload as opaque bytes, and its conformance is checked against independent, external references (the published RFC 6962/9162 Merkle vectors, a third-party COSE library, and a separate Go implementation — see Correctness & cross-implementation evidence).
It is intended to be useful as neutral substrate: the parts that exist today
don't fit that gap cleanly — python-cwt is COSE-only (no SCITT/Receipts), and a
transparency-service emulator is a server, not a verification library you depend
on. So this is the small building block — a second, independent implementation
you can verify against, with no profile baked in. (No primacy is claimed; the
value is neutrality + verifiable conformance, not being "first".)
An agent-action profile is one example consumer that builds its statement/claim semantics on top of this substrate — but nothing profile-specific lives here.
Three things an adopter should know up front:
- Built by Action State Group. We built this for our own SCITT use and publish it as community substrate under Apache-2.0.
- Neutral by design. No application profile, no vendor coupling,
payload-opaque. The package imports only
cbor2,cryptography, and the standard library — it does not import any Action State code, and a test gate (tests/test_iana_codepoints.py) enforces that this stays true. - Foundation intent. We intend to contribute this project to a neutral open-source foundation so its governance does not rest with any single vendor. Which foundation is deliberately not yet decided; until then it is governed in the open under DCO + Apache-2.0 (see CONTRIBUTING.md).
- Development. This project is built and maintained by Action State Group, with AI-assisted engineering (Claude Code) used as a development tool. Every contribution is human-reviewed and DCO-signed. Correctness does not rest on trusting any author — human or otherwise: conformance is enforced in CI by the published RFC 6962/9162 test vectors, an independent clean-room Go implementation, and cross-checks against a third-party COSE library, none of which can be skipped.
In scope (library plumbing):
- Build / parse / verify Signed Statements and Transparent Statements.
- Verify Receipts + RFC 9162 inclusion and consistency proofs.
- RFC 9162 SHA-256 Merkle primitives and the receipt-signing primitive
(
build_receipt) — so you can mint receipts as a building block.
Out of scope (documented, deliberately not built):
- Operating a transparency log / service. A hosted registration endpoint, log storage, monitoring, witnessing, gossip — none of that is here. The primitives needed to build one (Merkle tree, receipt signing) are included.
pip install cbor2 cryptography # runtime deps
# from a checkout (package root):
pip install -e .from cryptography.hazmat.primitives.asymmetric import ed25519
from cryptography.hazmat.primitives import serialization
from scitt_cose import (
build_signed_statement, parse_signed_statement,
merkle_root, inclusion_proof, verify_inclusion,
consistency_proof, verify_consistency,
build_receipt, verify_receipt,
attach_receipts, extract_receipts,
)
# --- a key (caller supplies everything) ---
sk = ed25519.Ed25519PrivateKey.generate()
priv = sk.private_bytes(serialization.Encoding.PEM,
serialization.PrivateFormat.PKCS8,
serialization.NoEncryption())
pub = sk.public_key().public_bytes(serialization.Encoding.PEM,
serialization.PublicFormat.SubjectPublicKeyInfo)
# --- Signed Statement (generic; no profile) ---
stmt = build_signed_statement(
b'{"hello":"world"}',
alg="EdDSA", private_key_pem=priv,
issuer="https://issuer.example",
subject="my-artifact",
content_type="application/json",
extra_cwt_claims={"my_claim": "x", 99: 1}, # str- or int-keyed
)
parsed = parse_signed_statement(stmt, public_key_pem=pub)
assert parsed["signature_verified"] is True
assert parsed["issuer"] == "https://issuer.example"
# --- Merkle (RFC 9162 SHA-256; hex in/out) ---
entries = [b"a".hex(), b"b".hex(), b"c".hex(), b"d".hex()]
root = merkle_root(entries)
path = inclusion_proof(entries, 2)
assert verify_inclusion(entries[2], 2, len(entries), path, root)
cproof = consistency_proof(entries, 2, 4)
assert verify_consistency(merkle_root(entries[:2]), root, 2, 4, cproof)
# --- Receipt (primitive) + verify ---
receipt = build_receipt(
leaf_entry_hex=entries[2], leaf_index=2, tree_entries_hex=entries,
alg="EdDSA", log_private_key_pem=priv, # here the "log" key is our key
)
res = verify_receipt(receipt, leaf_entry_hex=entries[2], log_public_key_pem=pub)
assert res.ok and res.root == root
# --- Transparent Statement = Signed Statement + Receipts ---
transparent = attach_receipts(stmt, [receipt])
assert extract_receipts(transparent) == [receipt]scitt-cose --statement stmt.cose --statement-pubkey issuer.pem
scitt-cose --receipt receipt.cose --receipt-log-pubkey log.pem --leaf-entry-hex 61
scitt-cose --statement stmt.cose --receipt receipt.cose \
--receipt-log-pubkey log.pem --leaf-entry-hex 61 --json| Area | Functions / types |
|---|---|
| COSE_Sign1 | sign_sign1, verify_sign1, Sign1, CoseError |
| Statements | build_signed_statement, parse_signed_statement, attach_receipts, extract_receipts |
| Merkle | leaf_hash, merkle_root, inclusion_proof, verify_inclusion, consistency_proof, verify_consistency |
| Receipts | build_receipt, verify_receipt, ReceiptResult |
CLL (scitt_cose.cll, its own namespace) |
verify_leaf_against_checkpoint, verify_checkpoint_chain, verify_range_against_checkpoint, witness_status_line; the proof types InclusionProof, ConsistencyProof, RangeProof, Checkpoint; the MMR primitives (leaf_hash, interior_hash, root_from_peaks, peaks, verify_inclusion, verify_consistency, verify_range) |
| Status | DRAFT_TRACKING_NOTICE, RFC_SCITT_ARCHITECTURE, RFC_COSE_RECEIPTS, SUBSTRATE_RFCS (DRAFT_* names kept as aliases) |
A verifier's behaviour on hostile and malformed input is part of its API, so it
is spelled out here and enforced by tests (tests/test_hardening.py) and by
continuous differential fuzzing (see below).
parse_signed_statementandverify_receiptnever raise on input. Every outcome — bad signature, malformed CBOR, truncation, a hostile length or tree size — is reported in the returned value (signature_verified/ReceiptResult.ok), never as a leakedcbor2/RecursionError/ other exception. ACoseErroris reserved for the low-level primitiveverify_sign1(a building block), which raises on failure by design.- Identity is authenticated-only.
parse_signed_statementpopulatesissuer/subject/content_type/alg/claimsonly whensignature_verified is True. When the signature did not verify (wrong key, bad signature) or no key was supplied, those top-level fields areNone, and the structurally-decoded values are fenced under an explicitunverifiedsub-dict — so an integrator can never mistake an attacker-chosen issuer for a signed one.verified ⇒ trust the fields; not verified ⇒ they are underunverified`, clearly labelled. - Strict, non-malleable decoding. Both verify paths reject trailing bytes after the COSE_Sign1, indefinite-length / non-deterministic encodings, and duplicate protected-header keys — so one signature cannot be presented in many byte encodings, and the Python and Go verifiers agree on accept and reject.
- Bounded cost. Messages are size-capped; tree sizes and inclusion-proof
lengths are bounded and length-checked before any hashing or allocation, and
no decoded integer is ever coerced to
bytesbefore validation. A tiny hostile receipt cannot trigger a multi-gigabyte allocation or an unbounded loop on either runtime.
See docs/hardening-review.md for the review, the
finding-by-finding resolutions, and the consciously-accepted items.
sign_sign1 / statements support "EdDSA" (code point −8), "Ed25519"
(−19, RFC 9864's fully-specified Ed25519; verified identically to −8) and
"ES256" (−7). For ES256, COSE carries the signature as raw r || s (64 bytes), not
DER; the conversion happens at the cryptography boundary. ML-DSA code points
(RFC 9964) are recognized in the status notice but signing is not
implemented here.
ES256 signatures are accepted in their canonical form as verified by
cryptography; s-value malleability (high-s) is not rejected — see the
Security Considerations in docs/hardening-review.md
for why that is a documented, accepted property rather than a bug.
Signed-Statement CWT Claims are placed in the protected header at label 15,
the "CWT Claims" header parameter registered by RFC 9597 §2. Label 13 is
a different parameter (kcwt, RFC 9528) and is sometimes mistakenly used for the
claims map; this library always reads and writes the claims at 15.
The Receipt's verifiable-data-proof shape is RFC 9942 (COSE Receipts; unchanged from draft-ietf-cose-merkle-tree-proofs-18, which this library was first built against):
- protected
1= alg, protected395= vds (1=RFC9162_SHA256); - unprotected
396= vdp map with key-1→ array of inclusion-proof bstrs; - each inclusion-proof bstr =
cbor([tree_size, leaf_index, [audit_path bstrs]]); - payload = the Merkle root, always detached;
verify_receiptrejects a receipt with an attached payload.
verify_receipt reads vds from the protected header only (it is
security-relevant and must be integrity-protected), reconstructs the root from
the proof, and verifies the COSE_Sign1 over that root with the log key. This
exact CBOR shape is validated by round-trip in this library's own tests and
against the code points RFC 9942 registers (vds 395, vdp 396, RFC9162_SHA256 = 1).
A Checkpointed Local Log appends records locally, commits to them with a
Merkle Mountain Range (MMR), and registers a signed checkpoint of that
MMR with a Transparency Service. scitt_cose.cll is the verifier for it: a
third party holding a record digest, a proof and a checkpoint can check,
offline,
- that the leaf is under the checkpoint's MMR root (inclusion);
- that a later checkpoint extends an earlier one, with no rollback (consistency);
- that a run of leaves is complete, with none left out (range);
- and that the checkpoint was registered, through the checkpoint's own COSE
Receipt and the unchanged
verify_receipt.
Every result reports "witnessed up to size S at time T", never a bare boolean, and shows the lag when it is known.
What it is not, honestly:
- It is not RFC 9162. An MMR is a different tree construction, which is
why the module keeps its own namespace and is not exported at the top
level: its
verify_inclusionwould otherwise collide with the RFC 9162 one. - It knows one format.
Checkpoint.digest()is a byte-identical port of the checkpoint record that checkpointed-local-log andcapsule-emitproduce. It is a port, not an import, so this package still depends only oncbor2andcryptography. The records under the leaves stay opaque: the module sees only their digests. - It does not check the checkpoint's own signature. The producer signs checkpoints with a scheme it chooses, which a neutral verifier cannot check generically. The receipt is what this module verifies.
It is checked against the vectors in test-vectors/mmr/
(KAT39, proof and range vectors) and in tests/test_cll.py.
The SCITT Architecture is now RFC 9943 (published June 2026). This library implements RFC 9943 as its normative SCITT base.
COSE Receipts is RFC 9942
(formerly draft-ietf-cose-merkle-tree-proofs-18). This library implements its
Receipt encoding and the RFC9162_SHA256 verifiable data structure.
No unassigned RFC number is claimed anywhere (enforced by a test that scans shipped source + docs).
Published RFCs whose mechanisms this library implements / relies on (titles verified against the RFC Editor / IANA registries):
- RFC 9052 — CBOR Object Signing and Encryption (COSE): Structures and Process (COSE_Sign1, Sig_structure).
- RFC 9053 — COSE: Initial Algorithms (EdDSA −8, ES256 −7).
- RFC 9864 — Fully-Specified Algorithms for JOSE and COSE (Ed25519 −19, accepted for verification alongside EdDSA −8).
- RFC 9162 — Certificate Transparency Version 2 (SHA-256 Merkle tree; inclusion and consistency proofs; reuses the RFC 6962 tree hash).
- RFC 9597 — CBOR Web Token (CWT) Claims in COSE Headers — the CWT Claims
header parameter at label 15 (IANA COSE Header Parameters registry). Label
13 is
kcwtand 14 iskccs, both from RFC 9528 (EDHOC) — not the CWT Claims map; using 13 for claims is the python-cwt bug this library avoids. - RFC 9964 — ML-DSA for JOSE and COSE (code points recognized; ML-DSA signing not implemented here).
scitt_cose/ imports only cbor2, cryptography, and the standard library.
It does not import cwt / python-cwt, pycose, or any consuming
product/profile package. Verify:
grep -rnE 'import (cwt|pycose)\b' scitt_cose/ # → nothingTwo tests keep this true: the COSE-library import guard and the
no-downstream-code neutrality gate (both in tests/test_iana_codepoints.py).
For a community verifier, "trust me, it's conformant" is worthless. The correctness story rests on agreement with things outside this library, not on self-consistency:
- Cross-language agreement (in CI). An independent Go verifier
(the
scitt-cose-go-verifydirectory, built onveraison/go-cose+fxamacker/cbor, with a clean-room Merkle fold) verifies the statements and receipts this library emits, agrees on the reconstructed Merkle root, and rejects tampered inputs. CI runs it withSCITT_REQUIRE_GO=1, so the cross-check can never silently skip. (tests/test_crosslang_go.py) - A second, receipt-only cross-language check: Rust.
rust/scitt-cose(onciborium+ed25519-dalek/p256, with its own clean-room RFC 9162 Merkle fold inrust/scitt-cose/src/merkle.rs) independently verifies receipts this library emits, including theiat/gradeprotected-header labels and the two booleans (witness_time_established,grade_cryptographically_bound) derived from them. Receipt-only by design — it never reads a Signed Statement. CI runs it withSCITT_REQUIRE_RUST=1. (tests/test_crosslang_rust.py) - The standard's own test vectors. The Merkle code is checked against the
published RFC 6962 / RFC 9162 reference vectors (8-leaf root
5dc9da79…, the canonical inclusion/consistency proofs) — external values, not ours. (tests/test_rfc9162_vectors.py) - A third-party COSE library.
pycose(independent of us, and notpython-cwt) both verifies our statements and emits statements we verify — so the round-trip isn't self-referential. (tests/test_thirdparty_cose.py) - The COSE standard's own reference-signed vector. We verify the canonical
COSE_Sign1 the COSE WG published (RFC 9052 §C.2.1, ES256, from the
cose-wg/Examplescorpus) — anchoring the signature layer to the spec's reference output, just as the RFC 6962 vectors anchor the Merkle layer. (tests/test_cose_wg_vectors.py) - A real Transparency-Service verifier. A downstream Transparency
Service's own verifier — written independently of this package, on a
different COSE stack (
python-cwt, vs this package's from-scratchcbor2/cryptography) — cross-verifies the same Signed Statements and the same TS-issued Receipts and agrees on the reconstructed Merkle root, in both directions. This exercises the real register→issue→verify shape; the integration test lives in the consuming repo (so this package stays standalone). This is not the hosted verify endpoint: that endpoint runs this package unchanged (a convenience deployment, deliberately the same library), so it is not an independent oracle — the python-cwt verifier is. - IANA values, not library enums. Every wire code point is asserted against
its registry/RFC number (CWT Claims 15, not python-cwt's
13). (tests/test_iana_codepoints.py) - Spec-driven negative suite. The MUST-reject conditions — alg confusion,
critical-header (
crit) handling,vdsdowngrade, wrong-leaf/wrong-log receipts, Merkle edge cases, malformed CBOR — each have a test. (tests/test_negative_conformance.py)
Evaluated and not used: the SCITT API emulator. The
scitt-community/scitt-api-emulatorwas considered as an ecosystem oracle and rejected: it is archived/unmaintained (final "pre-archive" tag, Nov 2024) and emits the obsolete pre-standard receipt format (draft-birkholz-scitt-receipts— string labelsservice_id/tree_alg, not a COSE_Sign1 receipt, not thevds=395 /vdp=396 RFC 9162 structure this library verifies); its statements usepycose, already covered above. Pinning a non-conformant, drift-prone implementation would be a misleading oracle, so the COSE WG spec vector is used in its place.
At IETF 126 (Vienna, Jul 2026), receipt verification was cross-validated:
microsoft/scitt-ccf-ledger PR #424
pins the published pyscitt test inputs as vectors-ietf126; ccf.v1 + RFC 9162
SHA-256 receipts were verified under one dispatch path against this library's
verify_receipt().
hosted_profiles.hosted is a stateless, read-only wrapper over the same
verify functions, so you can offer verification without anyone installing
anything — and without the submitter having to trust the operator with their
data (nothing stored, nothing logged, payload-opaque; the receipt path needs
only the leaf digest, never the payload). tests/test_hosted_parity.py
asserts the hosted verdict equals the local verdict on a fixture set,
including the ASGI path.
Not part of the published scitt-cose package. hosted_profiles/ (the
hosted HTTP wrapper plus its application-profile renderers) is excluded from
the built wheel — the neutral, pip install-able package is verifier APIs
only. hosted_profiles.hosted only runs from a full repo checkout (see the
Dockerfile, or clone + run below).
This is a SCITT-only verifier, and it is NOT a Transparency Service. It verifies statements and receipts; it never registers, issues receipts, or witnesses. Running a Transparency Service is a separate offering with its own operational trust obligations — deliberately out of scope here.
Run it standalone from a repo checkout (no other service involved):
# Under a production ASGI server (pip install ".[serve]" from the checkout):
uvicorn hosted_profiles.hosted:make_asgi_app --factory --host 0.0.0.0 --port 8080
# Or containerized (Dockerfile ships in the repo):
docker build -t scitt-verifier . && docker run -p 8080:8080 scitt-verifierGET / -> capabilities (what it does / does not do)
POST /verify -> {valid, statement, receipt, reasons} # JSON body, see below
GET / is content-negotiated: browsers (Accept: text/html) get a static
landing page that renders the verifier-vs-Transparency-Service boundary table
on the page itself — not buried in docs — while API clients get the same data
as JSON (including a boundary field). Both are generated from the same
constants (hosted_profiles.hosted.BOUNDARY_TABLE), so page and API can't
drift; tests/test_hosted_page.py pins the table's presence on both.
It can also ride along inside an existing ASGI app via
app.mount("/scitt-verify", hosted_profiles.hosted.make_asgi_app()) — same
logic, shared deployment, still standalone code. The full design, submitter-safety
constraints, and proposed deployment shape are in
docs/hosted-verifier-design.md. A hosted
instance is live at https://verify.agentactioncapsule.org — this package unchanged
(the parity-tested wrappers, deployed); its landing page renders the
verifier-vs-Transparency-Service boundary table and states the privacy posture.
You don't need it: the verifier runs anywhere.
GET /v/<capsule_id> and GET /bundle are the recipient-side viewers behind
capsule bundle's permalinks. The record never leaves the browser in
either mode — it rides in the URL fragment (the part after #), which
HTTP never transmits, so the server serving the viewer's HTML/JS never sees
the bytes being verified. Integrity, Sequence and (bundle-only) Range membership/
Cross-check are checkable with zero network: download the self-contained
copy from GET /bundle/offline-shell and it still verifies opened straight
from file://. Authenticity (the COSE signature) isn't evaluated by this
browser page yet — that stage renders an honest skip, never a fabricated
pass — but is checkable with zero network too, via the CLI's
permalink --check or scitt-cose installed locally. Witness needs a
network by definition — it's a claim about a log someone else keeps — and
when the witness is unreachable the viewer renders that stage skipped, not
failed. Full trust model, including exactly what a server does learn (a
viewed capsule_id, and — until you've downloaded and diffed it — trust in
served JS): docs/verification-trust-model.md.
Drop a file instead of opening a link. GET / and GET /bundle both
accept a dropped (or chosen) file: an Evidence Bundle (.json), or a
self-contained report page (.html) whose embedded bundle
(window.__BUNDLE__ = …;</script>) is read out of it. The file is read with
the browser's FileReader and checked on the page; it is never uploaded. A
file dropped on / is handed to /bundle in sessionStorage (same origin,
that tab only), never sent to the server. Files over 16 MiB are refused.
test-vectors/ is a frozen, append-only vector set for
other SCITT/COSE implementations to check themselves against: four happy-path
vectors (EdDSA, ES256, a real CCF ccf.v1 receipt, a multi-proof receipt) and
four negative vectors (tampered inclusion path, unsupported vds, bad statement
signature, zero-size proof), each with committed bytes, TEST-ONLY
keys, and an expected.json documenting every protected-header field a
verifier needs. Verify from a clean checkout:
git clone https://github.com/action-state-group/scitt-cose
cd scitt-cose && pip install -e . && python -m scitt_cose.vectorsor from the published package (the runner ships in scitt-cose ≥ 0.1.0):
pip install "scitt-cose>=0.1.0", download test-vectors/, then
python -m scitt_cose.vectors path/to/test-vectors (add --json for a
machine-readable report). The Go clean-room implementation runs the same
manifest (go test ./... in scitt-cose-go-verify/); the Rust clean-room
implementation runs it too (cargo test --test vectors in
rust/). The append-only promise is enforced, not just stated:
test-vectors/SHA256SUMS pins every published byte and CI fails on any
mutation. A mismatch against your implementation is exactly the report we
want — please open an issue. Details and the stability promise:
test-vectors/README.md.
A second, receipt-only vector set,
test-vectors/receipt-v1/, exercises the iat
and private-use grade (-65537) protected-header labels — including a
real captured receipt from a live TRACE-registry witness alongside synthetic
EdDSA/ES256 vectors and two post-signature tamper vectors. Same append-only
promise, own SHA256SUMS. Details:
test-vectors/receipt-v1/README.md.
| Set | What it pins | Checked by |
|---|---|---|
test-vectors/mmr/ |
MMR known answers (KAT39), inclusion and consistency proofs, and range proofs | scitt_cose.cll (tests/test_cll.py) and the browser range check |
test-vectors/capsule-id/ |
the browser port of the Agent Action Capsule id recompute, against that library's Python reference | the hosted viewers only (hosted_profiles/); not the package |
test-vectors/tamper-states/ |
four bundle states (offline pass, digest mismatch, chain gap, witness downgrade) for the bundle viewer's checks | the hosted viewers only (hosted_profiles/); not the package |
The last two exist for the hosted viewers, which render one application profile. The package itself never reads them.
The published package is scitt_cose/ alone. Everything else is here for
cross-checking, hosting or history, and stays out of the wheel:
| Path | What it is |
|---|---|
scitt-cose-go-verify/ |
the independent Go verifier CI cross-checks against (above) |
rust/scitt-cose/ |
the independent, receipt-only Rust verifier (above) |
hosted_profiles/ |
the hosted HTTP verifier and its viewers (above). Unlike the package, it renders application profiles: aac.py for Agent Action Capsules and machine_mandate.py, plus published-witnesses.json |
viewer/ |
the source of the hosted viewers' bundled browser checks (aac-crypto.js, witness-check.js), built from vendored copies of the agent-action-capsule and CLL TypeScript libraries |
demo/ |
a synthetic, worked example: a fictional bank's three-capsule refund chain registered on a live Transparency Service. It shows one application profile on top of this substrate; nothing in it is part of the package |
interop/ccf/ |
the IETF 126 cross-service check: one statement with receipts from two independent Transparency Services (an RFC 9162 log and a CCF node), both verified by verify_receipt |
interop/vcp/ |
an envelope probe: a VeritasChain VCP event payload wrapped in a Signed Statement verifies through parse_signed_statement as opaque bytes |
scripts/ |
one-time vector generators (each says what it pins), the Python-vs-Go differential fuzzer, and smoke_verify.py, which checks a running verifier |
docs/ |
the hardening review, the hosted-verifier design, the verification trust model and the launch checklist |
INTEROP.md |
a pointer: the interop registry moved to agent-action-capsule |
python3 -m pytest -q # unit + conformance suite (package root)
SCITT_REQUIRE_GO=1 python3 -m pytest -q # also forces the Go cross-check
python3 -m ruff check .Apache-2.0 — see LICENSE and NOTICE. Contributions are
accepted under the Developer Certificate of Origin (sign your commits with
git commit -s); scope rules and the standards-honesty gates are in
CONTRIBUTING.md. Releases are cut through a reviewed version-bump pull
request; see RELEASING.md.