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:
| Type | Algorithm | Public Key Size | Signature Size | Fingerprint Hash |
|---|---|---|---|---|
gpg | GPG (RSA/EdDSA/etc) | Varies | Varies | SHA-1 (legacy) |
ed25519 | Ed25519 | 32 bytes | 64 bytes | SHA-256 |
secp256k1 | secp256k1 (ECDSA) | 33 bytes | 64-72 bytes | SHA-256 |
dilithium | ML-DSA-65 (Dilithium) | 1,952 bytes | 3,293 bytes | SHA-384 |
falcon | FALCON-512 | 897 bytes | 666 bytes | SHA-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).
| Format | Content-Type | Binary Fields | Typical Size |
|---|---|---|---|
| CBOR | application/cbor | Raw bytes | Smaller (~40%) |
| JSON | application/json | Hex strings | Larger |
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:
| Field | Type | Description |
|---|---|---|
v | string | Version ("0.6") |
t | string | Type ("id") |
n | string | Agent name |
k | object or array | Key(s) |
c | integer | Created timestamp |
s | bytes or array | Signature(s) |
Optional fields:
| Field | Type | Description |
|---|---|---|
w | string | Bitcoin address for payments |
m | object | Metadata (platform handles, etc.) |
sup | object | Supersession reference |
Key object structure:
| Field | Type | Description |
|---|---|---|
t | string | Key type code |
p | bytes | Public key |
role | string | Optional role label |
Example: Ed25519 Identity (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)
{
"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)
{
"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:
| Field | Type | Description |
|---|---|---|
v | string | Version ("0.6") |
t | string | Type ("att") |
from | object | Attestor reference |
to | object | Attestee reference |
c | integer | Created timestamp |
s | bytes | Attestor's signature |
Optional fields:
| Field | Type | Description |
|---|---|---|
stake | integer | Sats staked |
stake_tx | string | TXID of stake transfer |
ctx | string | Context/reason |
exp | integer | Expiration timestamp |
Reference object structure:
| Field | Type | Description |
|---|---|---|
t | string | Key type code |
f | bytes | Fingerprint |
Example: Attestation (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:
| Field | Type | Description |
|---|---|---|
v | string | Version ("0.6") |
t | string | Type ("rcpt") |
p | array | Parties |
ex | object | Exchange details |
out | string | Outcome |
c | integer | Created timestamp |
s | array | All party signatures |
Party object structure:
| Field | Type | Description |
|---|---|---|
t | string | Key type code |
f | bytes | Fingerprint |
role | string | Role in exchange |
Exchange object structure:
| Field | Type | Description |
|---|---|---|
type | string | Exchange type |
sum | string | Summary |
val | integer | Value in sats (optional) |
Outcome values: "completed", "partial", "cancelled", "disputed"
Example: Receipt (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
- Construct the document with all fields EXCEPT
s - Encode to chosen format (CBOR or JSON)
- Sign the encoded bytes with the private key
- Add
sfield containing the signature - 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 Type | Signature Algorithm |
|---|---|
gpg | Per GPG key type |
ed25519 | Ed25519 (RFC 8032) |
secp256k1 | ECDSA over secp256k1 |
dilithium | ML-DSA-65 (FIPS 204) |
falcon | FALCON-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_ENDIFContent-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
# 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
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:
# Get the reveal transaction
bitcoin-cli getrawtransaction <txid> true
# Extract witness data from first input
# Parse inscription envelope from witnessThe inscription content is in the witness of the first input, within the OP_IF...OP_ENDIF envelope.
7.2 Verifying an Identity
- Decode document (CBOR or JSON based on content-type)
- Verify
vis"0.6"andtis"id" - Extract public key from
k.p - Compute fingerprint:
base64url(sha256(k.p))orbase64url(sha384(k.p)) - Remove
sfield from document - Re-encode document (same format)
- Verify signature
sover encoded bytes using public key - For multi-key: verify ALL signatures match their respective keys
- For supersession: verify BOTH old and new key signatures
7.3 Verifying an Attestation
- Decode document
- Verify
fromidentity exists (lookup by fingerprint) - Verify
toidentity exists - Get
fromidentity's public key - Remove
sfield, re-encode - Verify signature using
from's public key
7.4 Verifying a Receipt
- Decode document
- Verify all party identities exist
- For each party in
p:- Get party's public key
- Verify corresponding signature in
sarray
- 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
| Document | CBOR Size | JSON Size | Est. 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.