TAP provides cryptographic identity attestation for AI agents using Ed25519 and ECDSA-P256 signatures.
Overview
The Trust Anchor Protocol (TAP) solves the agent identity problem: how do you verify that an AI agent is who it claims to be, and that it has permission to act on behalf of a user or organization?
Problem: Without identity verification, malicious agents can impersonate legitimate agents, steal credentials, or make unauthorized transactions.
Solution: TAP uses cryptographic signatures to prove agent identity and link agents to their owners through a chain of trust.
Key Concepts
Agent Identity
Each agent has a unique cryptographic identity:
{
"agent_id" : "agent_abc123" ,
"public_key" : "0x..." ,
"algorithm" : "ed25519" ,
"owner_id" : "user_xyz" ,
"created_at" : "2026-03-03T10:00:00Z" ,
"metadata" : {
"name" : "Shopping Assistant" ,
"version" : "1.0.0" ,
"capabilities" : [ "payments" , "cart_management" ]
}
}
Trust Chain
Agents are linked to their owners through a cryptographic chain:
USER → AGENT → WALLET → TRANSACTION
User creates and signs agent registration
Agent signs all actions with its private key
Wallet is owned by the agent
Transaction is signed by both agent and wallet
Supported Algorithms
Ed25519 (Recommended)
Edwards-curve Digital Signature Algorithm
Fast - 64x faster than ECDSA
Small signatures - 64 bytes
Secure - 128-bit security level
Deterministic - Same message always produces same signature
Use for: Most agent applications
Example:
from cryptography.hazmat.primitives.asymmetric import ed25519
# Generate keypair
private_key = ed25519.Ed25519PrivateKey.generate()
public_key = private_key.public_key()
# Sign message
message = b "Agent action: transfer 50 USDC"
signature = private_key.sign(message)
# Verify signature
try :
public_key.verify(signature, message)
print ( "Signature valid" )
except :
print ( "Signature invalid" )
ECDSA-P256
Elliptic Curve Digital Signature Algorithm (P-256)
Compatible - Works with existing PKI infrastructure
Widely supported - Used in TLS, JWT, etc.
Secure - 128-bit security level
Hardware support - Available in TPM/HSM modules
Use for: Enterprise integrations, hardware security modules
Example:
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives import hashes
# Generate keypair
private_key = ec.generate_private_key(ec.SECP256R1())
public_key = private_key.public_key()
# Sign message
message = b "Agent action: transfer 50 USDC"
signature = private_key.sign(message, ec.ECDSA(hashes.SHA256()))
# Verify signature
try :
public_key.verify(signature, message, ec.ECDSA(hashes.SHA256()))
print ( "Signature valid" )
except :
print ( "Signature invalid" )
Agent Registration
1. Generate Keypair
from sardis import Sardis
sardis = Sardis( api_key = "sk_..." )
# Generate Ed25519 keypair
keypair = sardis.crypto.generate_keypair( algorithm = "ed25519" )
print ( f "Public key: { keypair.public_key } " )
print ( f "Private key: { keypair.private_key } " ) # Store securely!
2. Register Agent
# Register agent with public key
agent = sardis.agents.create(
name = "Shopping Assistant" ,
description = "AI agent for e-commerce purchases" ,
public_key = keypair.public_key,
algorithm = "ed25519" ,
capabilities = [ "payments" , "cart_management" ]
)
print ( f "Agent ID: { agent.agent_id } " )
print ( f "Trust anchor: { agent.trust_anchor } " )
3. User Approval
User signs agent registration to establish ownership:
# User signs agent registration
approval = sardis.agents.approve(
agent_id = agent.agent_id,
user_id = "user_123" ,
signature = user_wallet.sign(agent.registration_hash)
)
print ( f "Agent approved by user: { approval.approved_at } " )
Identity Verification
Signature Verification Flow
Agent Signs Action
# Agent signs the action
action = {
"agent_id" : "agent_abc123" ,
"action" : "transfer" ,
"amount" : "50.00" ,
"recipient" : "0x..." ,
"timestamp" : "2026-03-03T10:00:00Z" ,
"nonce" : "unique_nonce_123"
}
signature = agent_private_key.sign(json.dumps(action).encode())
Sardis Verifies Signature
# Sardis retrieves agent's public key
agent = sardis.agents.get(action[ "agent_id" ])
public_key = agent.public_key
# Verify signature
try :
verify_signature(
public_key = public_key,
message = json.dumps(action).encode(),
signature = signature,
algorithm = agent.algorithm
)
print ( "Agent identity verified" )
except InvalidSignatureError:
raise UnauthorizedAgentError( "Invalid agent signature" )
Check Trust Chain
# Verify agent is owned by user
if agent.owner_id != expected_user_id:
raise UnauthorizedAgentError( "Agent not owned by user" )
# Verify agent has capability
if "payments" not in agent.capabilities:
raise UnauthorizedAgentError( "Agent lacks payment capability" )
# Verify agent not revoked
if agent.status == "revoked" :
raise RevokedAgentError( "Agent credentials revoked" )
Execute Action
# All verification passed - execute action
result = execute_transfer(
from_wallet = agent.wallet_id,
to_address = action[ "recipient" ],
amount = action[ "amount" ]
)
Security Features
1. Nonce Prevention
Prevents replay attacks:
# Each action includes unique nonce
action = {
"agent_id" : "agent_abc123" ,
"action" : "transfer" ,
"nonce" : str (uuid.uuid4()), # Unique per action
"timestamp" : now().isoformat()
}
# Sardis checks nonce hasn't been used
if nonce_cache.exists(action[ "nonce" ]):
raise ReplayAttackError( "Nonce already used" )
nonce_cache.set(action[ "nonce" ], True , ttl = 86400 )
2. Timestamp Validation
Rejects old signatures:
timestamp = datetime.fromisoformat(action[ "timestamp" ])
if now() - timestamp > timedelta( minutes = 5 ):
raise ExpiredSignatureError( "Signature too old" )
3. Capability-Based Access
Agents can only perform authorized actions:
if action[ "action" ] == "transfer" :
if "payments" not in agent.capabilities:
raise UnauthorizedActionError( "Agent lacks payment capability" )
if action[ "action" ] == "issue_card" :
if "card_issuance" not in agent.capabilities:
raise UnauthorizedActionError( "Agent lacks card issuance capability" )
4. Revocation
Agents can be instantly revoked:
# Revoke compromised agent
sardis.agents.revoke(
agent_id = "agent_abc123" ,
reason = "Private key compromised"
)
# All future actions will be rejected
if agent.status == "revoked" :
raise RevokedAgentError( "Agent credentials revoked" )
Implementation Example
Python SDK
from sardis import Sardis
from cryptography.hazmat.primitives.asymmetric import ed25519
import json
# Initialize client
sardis = Sardis( api_key = "sk_..." )
# Generate agent keypair
private_key = ed25519.Ed25519PrivateKey.generate()
public_key = private_key.public_key()
# Register agent
agent = sardis.agents.create(
name = "Payment Agent" ,
public_key = public_key.public_bytes_raw().hex(),
algorithm = "ed25519" ,
capabilities = [ "payments" ]
)
print ( f "Agent registered: { agent.agent_id } " )
# Later: Sign an action
action = {
"agent_id" : agent.agent_id,
"action" : "transfer" ,
"amount" : "50.00" ,
"recipient" : "0x..." ,
"timestamp" : datetime.now().isoformat(),
"nonce" : str (uuid.uuid4())
}
# Sign with agent's private key
message = json.dumps(action, sort_keys = True ).encode()
signature = private_key.sign(message)
# Execute action with signature
result = sardis.payments.create(
agent_id = agent.agent_id,
action = action,
signature = signature.hex()
)
print ( f "Payment executed: { result.tx_hash } " )
TypeScript SDK
import { SardisClient } from '@sardis/sdk' ;
import * as ed from '@noble/ed25519' ;
const client = new SardisClient ({ apiKey: 'sk_...' });
// Generate keypair
const privateKey = ed . utils . randomPrivateKey ();
const publicKey = await ed . getPublicKey ( privateKey );
// Register agent
const agent = await client . agents . create ({
name: 'Payment Agent' ,
public_key: Buffer . from ( publicKey ). toString ( 'hex' ),
algorithm: 'ed25519' ,
capabilities: [ 'payments' ],
});
console . log ( `Agent registered: ${ agent . agent_id } ` );
// Sign action
const action = {
agent_id: agent . agent_id ,
action: 'transfer' ,
amount: '50.00' ,
recipient: '0x...' ,
timestamp: new Date (). toISOString (),
nonce: crypto . randomUUID (),
};
const message = Buffer . from ( JSON . stringify ( action ));
const signature = await ed . sign ( message , privateKey );
// Execute with signature
const result = await client . payments . create ({
agent_id: agent . agent_id ,
action ,
signature: Buffer . from ( signature ). toString ( 'hex' ),
});
console . log ( `Payment: ${ result . tx_hash } ` );
Best Practices
Use Ed25519 for New Agents
Ed25519 is faster, smaller, and just as secure as ECDSA. Use it unless you have a specific reason to use ECDSA-P256 (e.g., hardware requirements).
Never Expose Private Keys
Store private keys in environment variables or secret managers
Never log private keys
Never commit private keys to Git
Rotate keys regularly (every 90 days)
Use Hardware Security Modules
For production agents handling high-value transactions:
Store keys in HSM (AWS KMS, Google Cloud KMS, Turnkey)
Use TPM for local key storage
Require multi-signature for key operations
# Generate new keypair
new_keypair = sardis.crypto.generate_keypair( algorithm = "ed25519" )
# Update agent with new public key
sardis.agents.rotate_key(
agent_id = agent.agent_id,
new_public_key = new_keypair.public_key,
signature = old_private_key.sign(new_keypair.public_key)
)
# Old key remains valid for 24 hours (grace period)
# Then revoke old key
sardis.agents.revoke_key(
agent_id = agent.agent_id,
public_key = old_keypair.public_key
)
Monitor for Suspicious Activity
Alert on signature verification failures
Track nonce reuse attempts
Monitor for expired timestamp attacks
Flag rapid key rotation
Why TAP Matters
Prevents Impersonation Cryptographic proof of agent identity
Audit Trail Every action signed and traceable
Instant Revocation Compromised agents blocked immediately
Zero Trust Verify every action, trust nothing
Learn More
AP2 Protocol Payment mandate chain
A2A Protocol Agent-to-agent payments
API Reference Agent API documentation
Examples See TAP in action