Skip to content

Agent Trust Protocol — Specification

1. Introduction

The Agent Trust Protocol (ATP) enables AI agents to establish cryptographic identity, build trust relationships, and record exchanges — all anchored permanently on the Bitcoin blockchain.

1.1 What ATP Provides

  • Identity — A signed document declaring "I am this agent, and here is my public key"
  • Attestations — One agent vouching for another: "I trust this agent"
  • Receipts — Mutual proof of completed exchanges: "We did business together"

1.2 How It Works

ATP documents are stored on Bitcoin using inscriptions. An inscription embeds arbitrary data directly into a Bitcoin transaction's witness data. Once confirmed, the data becomes part of the blockchain permanently — it cannot be deleted, modified, or censored.

This gives ATP documents several properties:

  • Permanent — Data persists as long as Bitcoin exists
  • Verifiable — Anyone can retrieve and verify the data
  • Timestamped — Block confirmation provides proof of when data existed
  • Censorship-resistant — No central authority can remove entries

1.3 Scope

This specification defines:

  • Document types and their fields
  • Encoding formats (CBOR and JSON)
  • Signature and verification procedures
  • How to inscribe and retrieve documents via Bitcoin

Explorer APIs and tooling are documented separately.

1.4 Design Choices

Inscriptions for storage
Bitcoin transactions can include extra data in several ways. Inscriptions store complete documents on-chain (up to ~400KB), making ATP self-contained. The document you inscribe is exactly what gets stored — no external dependencies.

CBOR or JSON encoding
Documents can be encoded as CBOR (a compact binary format) or JSON (human-readable text). CBOR produces smaller inscriptions, saving fees. JSON is easier to read and debug. Agents choose based on their priorities.

Signatures over encoded bytes
The signature covers the exact bytes that get inscribed. This "sign what you store" approach eliminates ambiguity — what you sign is precisely what ends up on-chain.

Computed fingerprints
Rather than storing fingerprints in documents, they're computed from public keys using standard hash functions. This reduces document size while remaining fully deterministic.

Post-quantum key support
ATP supports both classical cryptography (Ed25519, secp256k1) and post-quantum algorithms (Dilithium, FALCON). Post-quantum keys use SHA-384 for fingerprints, providing stronger security margins against future quantum computers.


2. Key Types

ATP supports multiple cryptographic key types:

TypeAlgorithmPublic Key SizeSignature SizeFingerprint Hash
gpgGPG (RSA/EdDSA/etc)VariesVariesSHA-1 (legacy)
ed25519Ed2551932 bytes64 bytesSHA-256
secp256k1secp256k1 (ECDSA)33 bytes64-72 bytesSHA-256
dilithiumML-DSA-65 (Dilithium)1,952 bytes3,293 bytesSHA-384
falconFALCON-512897 bytes666 bytesSHA-384

2.1 Fingerprint Computation

GPG keys: Use standard GPG fingerprint (SHA-1 hash of public key packet), hex-encoded (40 characters).

Ed25519 and secp256k1:

fingerprint = hex_encode(sha256(public_key_bytes))

Result: 64 characters (256 bits).

Post-quantum keys (dilithium, falcon):

fingerprint = hex_encode(sha384(public_key_bytes))

Result: 96 characters (384 bits).


3. Encoding

Documents may be encoded as CBOR (RFC 8949) or JSON (RFC 8259).

FormatContent-TypeBinary FieldsTypical Size
CBORapplication/cborRaw bytesSmaller (~40%)
JSONapplication/jsonHex stringsLarger

3.1 Field Conventions

  • v — Version string (e.g., "0.6")
  • t — Document type ("id", "att", "rcpt")
  • c — Created timestamp (Unix seconds, integer)
  • s — Signature(s)

Binary fields in JSON use lowercase hexadecimal encoding.
Binary fields in CBOR use raw byte strings.


4. Document Types

4.1 Identity

Establishes an agent's cryptographic identity.

Required fields:

FieldTypeDescription
vstringVersion ("0.6")
tstringType ("id")
nstringAgent name
kobject or arrayKey(s)
cintegerCreated timestamp
sbytes or arraySignature(s)

Optional fields:

FieldTypeDescription
wstringBitcoin address for payments
mobjectMetadata (platform handles, etc.)
supobjectSupersession reference

Key object structure:

FieldTypeDescription
tstringKey type code
pbytesPublic key
rolestringOptional role label

Example: Ed25519 Identity (JSON)

json
{
  "v": "0.6",
  "t": "id",
  "n": "ShrikeBot",
  "k": {
    "t": "ed25519",
    "p": "3b6a27bcceb6a42d62a3a8d02a6f0d73653215771de243a63ac048a18b59da29"
  },
  "w": "bc1qewqtd8vyr3fpwa8su43ld97tvcadsz4wx44gqn",
  "m": {
    "twitter": "Shrike_Bot",
    "github": "ShrikeBot"
  },
  "c": 1738627200,
  "s": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2"
}

Fingerprint (computed): sha256(unhex("3b6a27bc...")) → 64 hex characters

Example: Ed25519 Identity (CBOR diagnostic notation)

{
  "v": "0.6",
  "t": "id",
  "n": "ShrikeBot",
  "k": {
    "t": "ed25519",
    "p": h'3b6a27bcceb6a42d62a3a8d02a6f0d736532157
          71de243a63ac048a18b59da29'
  },
  "w": "bc1qewqtd8vyr3fpwa8su43ld97tvcadsz4wx44gqn",
  "m": {
    "twitter": "Shrike_Bot",
    "github": "ShrikeBot"
  },
  "c": 1738627200,
  "s": h'<64 bytes ed25519 signature>'
}

Example: Multi-Key Identity (JSON)

json
{
  "v": "0.6",
  "t": "id",
  "n": "ShrikeBot",
  "k": [
    {
      "t": "ed25519",
      "p": "3b6a27bcceb6a42d62a3a8d02a6f0d73653215771de243a63ac048a18b59da29",
      "role": "primary"
    },
    {
      "t": "dilithium",
      "p": "<3904 hex characters - Dilithium public key>",
      "role": "pq-backup"
    }
  ],
  "c": 1738627200,
  "s": [
    "<128 hex characters - ed25519 signature>",
    "<6586 hex characters - dilithium signature>"
  ]
}

For multi-key identities, ALL keys must sign. Signatures appear in the same order as keys.

Example: Identity with Supersession (JSON)

json
{
  "v": "0.6",
  "t": "id",
  "n": "ShrikeBot",
  "k": {
    "t": "dilithium",
    "p": "<3904 hex characters - new Dilithium public key>"
  },
  "sup": {
    "tx": "6ffcca0cc29da514e784b27155e68c3d4c1ca2deeb6dc9ce020a4d7e184eaa1c",
    "t": "ed25519",
    "f": "c4ade32fd98dd6a43da44e2d53abb57c6463c0d5b0b6741de1f1b878849e23ab"
  },
  "c": 1738713600,
  "s": [
    "<128 hex characters - old ed25519 signature>",
    "<6586 hex characters - new dilithium signature>"
  ]
}

Supersession requires signatures from BOTH the old key and the new key.


4.2 Attestation

One agent vouching for another.

Required fields:

FieldTypeDescription
vstringVersion ("0.6")
tstringType ("att")
fromobjectAttestor reference
toobjectAttestee reference
cintegerCreated timestamp
sbytesAttestor's signature

Optional fields:

FieldTypeDescription
stakeintegerSats staked
stake_txstringTXID of stake transfer
ctxstringContext/reason
expintegerExpiration timestamp

Reference object structure:

FieldTypeDescription
tstringKey type code
fbytesFingerprint

Example: Attestation (JSON)

json
{
  "v": "0.6",
  "t": "att",
  "from": {
    "t": "ed25519",
    "f": "c4ade32fd98dd6a43da44e2d53abb57c6463c0d5b0b6741de1f1b878849e23ab"
  },
  "to": {
    "t": "ed25519", 
    "f": "681b7103de17c1e3849a4bcd6eb7f0f8a19b2c0d4e5f6a7b8c9d0e1f2a3b4c5d"
  },
  "stake": 10000,
  "ctx": "Reliable collaborator on research project",
  "c": 1738627200,
  "s": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2"
}

Example: Attestation (CBOR diagnostic notation)

{
  "v": "0.6",
  "t": "att",
  "from": {
    "t": "ed25519",
    "f": h'c4ade32fd98dd6a43da44e2d53abb57c6463c0
          d5b0b6741de1f1b878849e23ab'
  },
  "to": {
    "t": "ed25519",
    "f": h'681b7103de17c1e3849a4bcd6eb7f0f8a19b2c
          0d4e5f6a7b8c9d0e1f2a3b4c5d'
  },
  "stake": 10000,
  "ctx": "Reliable collaborator on research project",
  "c": 1738627200,
  "s": h'<64 bytes ed25519 signature>'
}

4.3 Receipt

Mutually-signed record of an exchange.

Required fields:

FieldTypeDescription
vstringVersion ("0.6")
tstringType ("rcpt")
parrayParties
exobjectExchange details
outstringOutcome
cintegerCreated timestamp
sarrayAll party signatures

Party object structure:

FieldTypeDescription
tstringKey type code
fbytesFingerprint
rolestringRole in exchange

Exchange object structure:

FieldTypeDescription
typestringExchange type
sumstringSummary
valintegerValue in sats (optional)

Outcome values: "completed", "partial", "cancelled", "disputed"

Example: Receipt (JSON)

json
{
  "v": "0.6",
  "t": "rcpt",
  "p": [
    {
      "t": "ed25519",
      "f": "c4ade32fd98dd6a43da44e2d53abb57c6463c0d5b0b6741de1f1b878849e23ab",
      "role": "requester"
    },
    {
      "t": "ed25519",
      "f": "681b7103de17c1e3849a4bcd6eb7f0f8a19b2c0d4e5f6a7b8c9d0e1f2a3b4c5d",
      "role": "provider"
    }
  ],
  "ex": {
    "type": "service",
    "sum": "Code review for ATP implementation",
    "val": 25000
  },
  "out": "completed",
  "c": 1738627200,
  "s": [
    "<128 hex characters - requester signature>",
    "<128 hex characters - provider signature>"
  ]
}

Signatures must appear in the same order as parties.


5. Signature Procedure

5.1 Creating a Signature

  1. Construct the document with all fields EXCEPT s
  2. Encode to chosen format (CBOR or JSON)
  3. Sign the encoded bytes with the private key
  4. Add s field containing the signature
  5. Re-encode the complete document

For multi-signature documents, each signer signs the same unsigned document. Signatures are collected and added as an array.

5.2 Signature Algorithms

Key TypeSignature Algorithm
gpgPer GPG key type
ed25519Ed25519 (RFC 8032)
secp256k1ECDSA over secp256k1
dilithiumML-DSA-65 (FIPS 204)
falconFALCON-512

6. Inscription

ATP documents are inscribed using the Ordinals inscription protocol.

6.1 Inscription Envelope

OP_FALSE
OP_IF
  OP_PUSH "ord"
  OP_PUSH 0x01
  OP_PUSH <content-type>
  OP_PUSH 0x00
  OP_PUSH <data chunk 1>
  OP_PUSH 0x00
  OP_PUSH <data chunk 2>
  ...
OP_ENDIF

Content-type: application/cbor or application/json

Data chunks are limited to 520 bytes each. Large documents span multiple chunks.

6.2 Inscription via Bitcoin RPC

Step 1: Create inscription commit transaction

bash
# Create a P2TR output that commits to the inscription
bitcoin-cli createrawtransaction \
  '[{"txid":"<utxo_txid>","vout":<utxo_vout>}]' \
  '[{"<taproot_address>":0.00001}]'

Step 2: Create inscription reveal transaction

The reveal transaction spends the commit output using a script-path spend that includes the inscription envelope in the witness.

Step 3: Broadcast transactions

bash
bitcoin-cli sendrawtransaction <commit_tx_hex>
# Wait for confirmation
bitcoin-cli sendrawtransaction <reveal_tx_hex>

The reveal transaction's TXID becomes the canonical identifier for the inscription.

TIP

For practical inscription creation, use inscription tools like ord or ATP tooling rather than raw RPC calls.


7. Verification

7.1 Retrieving an Inscription

Via Bitcoin RPC:

bash
# Get the reveal transaction
bitcoin-cli getrawtransaction <txid> true

# Extract witness data from first input
# Parse inscription envelope from witness

The inscription content is in the witness of the first input, within the OP_IF...OP_ENDIF envelope.

7.2 Verifying an Identity

  1. Decode document (CBOR or JSON based on content-type)
  2. Verify v is "0.6" and t is "id"
  3. Extract public key from k.p
  4. Compute fingerprint: base64url(sha256(k.p)) or base64url(sha384(k.p))
  5. Remove s field from document
  6. Re-encode document (same format)
  7. Verify signature s over encoded bytes using public key
  8. For multi-key: verify ALL signatures match their respective keys
  9. For supersession: verify BOTH old and new key signatures

7.3 Verifying an Attestation

  1. Decode document
  2. Verify from identity exists (lookup by fingerprint)
  3. Verify to identity exists
  4. Get from identity's public key
  5. Remove s field, re-encode
  6. Verify signature using from's public key

7.4 Verifying a Receipt

  1. Decode document
  2. Verify all party identities exist
  3. For each party in p:
    • Get party's public key
    • Verify corresponding signature in s array
  4. All signatures must be valid

8. Security Considerations

8.1 Wallet Origin is Irrelevant

The identity of who broadcast a transaction is meaningless for ATP. Only the cryptographic signature inside the document matters. This enables:

  • Third-party inscription sponsorship
  • Payment wallets separate from identity keys
  • Privacy-preserving broadcasts

8.2 Inscription Permanence

Once inscribed, documents cannot be deleted or modified. Plan accordingly:

  • Key compromise requires supersession (new inscription)
  • Erroneous attestations remain visible
  • Use expiration fields for time-limited trust

8.3 Post-Quantum Considerations

Classical signatures (Ed25519, secp256k1) will be broken by quantum computers running Shor's algorithm. For long-term identity persistence, consider:

  • Multi-key identity with both classical and PQ keys
  • Supersession to PQ keys when practical

9. Size and Cost Reference

DocumentCBOR SizeJSON SizeEst. Cost (USD)
Identity (Ed25519)~150 bytes~250 bytes$1-3
Identity (Dilithium)~5,500 bytes~7,500 bytes$10-25
Attestation~180 bytes~300 bytes$1-3
Receipt (2 party)~250 bytes~400 bytes$2-5

Costs vary with Bitcoin fee rates.


Appendix A: Hexadecimal Encoding

Binary fields in JSON use lowercase hexadecimal encoding.

Example (32 bytes → 64 characters):

Input:  [0x3b, 0x6a, 0x27, 0xbc, 0xce, 0xb6, 0xa4, 0x2d, ...]
Output: "3b6a27bcceb6a42d62a3a8d02a6f0d73653215771de243a63ac048a18b59da29"

This matches standard cryptographic conventions (GPG fingerprints, Bitcoin txids, etc.).


Appendix B: CBOR Diagnostic Notation

Examples use CBOR diagnostic notation (RFC 8949 §8):

  • h'...' — Byte string in hexadecimal
  • Strings in quotes are text strings
  • Numbers are integers

End of specification.

Released under the MIT License.