Third-Party Audit
Bilateral audit exchange has a fundamental limitation: a malicious agent can maintain two different hash chains and show each counterparty a different history (split-view attack). Third-party audit services solve this by introducing an independent witness that neither party controls.
Architecture
Service Identity
A third-party audit service is a INK service role, not a standard INK agent:
| Concern | INK Agent | Audit Service |
|---|---|---|
| Identity | DID bound to human via agentLink | did:web or did:key, self-sovereign |
| Discovery | INKAgentEndpoint in DID doc (legacy TulpaAgentEndpoint also accepted) | Agent Card thirdPartyAudit.services |
| Auth (inbound) | INK auth S3.3 | INK auth S3.3 (same) |
| Auth (outbound) | Signs with agentLink key | Signs with its own Ed25519 key |
| Delegation proof | Required | Not applicable, configured trust |
Submission Protocol
Agents submit events alongside normal hash chain maintenance. Submission is asynchronous and non-blocking.
POST /ink/v1/audit/submit
{ "protocol": "ink/0.1", "type": "network.tulpa.audit_submit", "from": "did:plc:agent", "to": "did:web:audit.example.com", "event": { /* InkAuditEvent */ }, "nonce": "<base64url>", "timestamp": "2026-03-19T12:00:00Z"}Signed Inclusion Receipt
{ "protocol": "ink/0.1", "type": "network.tulpa.audit_inclusion", "eventId": "01JBTEST0001", "treeSize": 48291, "leafIndex": 48290, "rootHash": "<SHA-256 hex of Merkle tree root>", "timestamp": "2026-03-19T12:00:01Z", "serviceSignature": "<Ed25519 over (eventId + treeSize + rootHash + timestamp)>"}Submission + Inclusion Flow (Detailed)
What happens step-by-step when an agent submits an event to a third-party audit service.
Access Control
The service operates under access-controlled transparency (per SCITT):
- Events are tagged with
messageIdand sender/recipient DIDs - Only parties to a message (or holders of a valid delegation chain) can query
- The Merkle tree structure is public; event contents are access-controlled
Merkle Tree Structure
Trust Model
The audit service is a semi-trusted witness, not an arbiter:
- It CANNOT forge events (Ed25519 signatures from agents)
- It CANNOT modify events without breaking Merkle proofs
- It CAN suppress events (detectable via consistency proofs)
- It CAN be unavailable (agents fall back to bilateral exchange)
For high-stakes interactions, agents MAY submit to multiple independent services.
Agent Card Advertisement
{ "capabilities": { "auditExchange": true, "thirdPartyAudit": { "services": [ { "endpoint": "https://audit.example.com/ink/v1", "did": "did:web:audit.example.com", "publicKey": "<Ed25519 public key hex>" } ], "submitPolicy": "all" } }}submitPolicy: all | high_value | none
Implementation Tiers
Tier 1. Lowest effort, highest immediate value
| Approach | How it works | Privacy |
|---|---|---|
Witness cosigning (C2SP tlog-witness) | Periodic checkpoints, independent witnesses verify consistency | Witnesses see only tree size + root hash |
| Rekor hash notary (Sigstore) | Submit checkpoint hashes to Rekor’s public log | Hash-only, content stays private |
Tier 2. Medium effort, stronger guarantees
| Approach | How it works | Privacy |
|---|---|---|
| SCITT service | COSE_Sign1-wrapped events, Merkle inclusion receipts | Access-controlled |
| INK-native Merkle service | INK auth, INK message format | Full INK access control |
Tier 3. Infrastructure investment
| Approach | How it works | Privacy |
|---|---|---|
| Tessera-based log | Static tile serving with external witnesses | Full control |
| OpenTimestamps | Daily Bitcoin anchor for legally defensible timestamps | Hash-only |
Checkpoint Format
INK checkpoints are emitted as a lowercase-hex SHA-256 root hash plus an Ed25519 signature over the canonical checkpoint body. This matches the witness service output documented in Witness Service and keeps the hash encoding consistent across both the bilateral and third-party audit paths:
ink-audit/<agentDid><sequence number><hex root hash>
<Ed25519 signature>