self-agent-sdk
Rust SDK for Self Agent ID — on-chain AI agent identity with proof-of-human verification.
Sign requests in Rust, verify in TypeScript or Python, or vice versa. The signing protocol is language-agnostic — all SDKs produce identical signatures.
Install
With Axum middleware support:
Agent Side — Sign Requests
use ;
let agent = new?;
// Sign a request (returns HashMap of auth headers)
let headers = agent.sign_request.await?;
// Or use the built-in HTTP client (auto-signs)
let response = agent.fetch.await?;
// Check on-chain status
let registered = agent.is_registered.await?;
let info = agent.get_info.await?;
// AgentInfo { agent_id, is_verified, nullifier, agent_count, ... }
Agent Properties
agent.address; // Address
agent.agent_key; // B256 — zero-padded bytes32 for on-chain lookups
Credentials
// Fetch ZK-attested credentials (nationality, age, OFAC, etc.)
let creds = agent.get_credentials.await?;
// Some(AgentCredentials { issuing_state, nationality, older_than, ofac, ... })
let strength = agent.get_verification_strength.await?;
// 0 = unverified, 1 = basic, 2 = standard, 3 = enhanced
Service Side — Verify Requests
use ;
let mut verifier = new;
let result = verifier.verify.await;
if result.valid
VerifierBuilder
Chainable API for configuring verification requirements:
use ;
let verifier = create
.network
.require_age
.require_ofac
.require_nationality
.require_self_provider
.sybil_limit
.rate_limit // per_minute, per_hour
.replay_protection
.include_credentials
.max_age // 5 min timestamp window
.cache_ttl // 1 min cache
.build;
Axum Middleware (feature-gated)
use ;
use ;
let verifier = create
.require_age
.build;
let app = new
.route
.layer;
async
Static Factory
use ;
let verifier = from_config;
Proof Expiry & Refresh
Human proofs expire after maxProofAge (default: 365 days) or at passport document expiry, whichever is sooner. The expiry timestamp is set on-chain at registration.
// Check proof freshness
let info = agent.get_info.await?;
println!; // unix seconds, 0 if unregistered
// Check if expiring within 30 days
let thirty_days = 30 * 24 * 60 * 60;
let now = now
.duration_since?
.as_secs;
if info.proof_expires_at > 0 && info.proof_expires_at - now < thirty_days
Verifier-side: The verifier returns reason: ProofExpired when an agent's proof has lapsed.
Refreshing: There is no in-place refresh. Deregister (burn NFT) → re-register (new passport scan, new agentId, fresh expiry).
A2A Agent Card
Publish machine-readable identity metadata for agent-to-agent discovery:
// Read the on-chain agent card
let card = agent.get_agent_card.await?;
// Some(A2AAgentCard { name, self_protocol: { agent_id, verification_strength, ... } })
// Set or update the agent card (writes on-chain)
let tx_hash = agent.set_agent_card.await?;
// Generate a data URI for embedding
let data_uri = agent.to_agent_card_data_uri.await?;
Registration Helpers
Build the userDefinedData strings that Self Protocol expects during registration:
use *;
// Config index maps disclosure flags to one of 6 on-chain configs
let d = RegistrationDisclosures ;
get_registration_config_index; // 4
// Simple mode (verified-wallet) — human IS the agent
build_simple_register_user_data_ascii;
// "R1"
// Advanced mode (agent-identity) — agent has own keypair
let signed = sign_registration_challenge.await?;
build_advanced_register_user_data_ascii; // "K4{addr}{r}{s}{v}"
// Deregistration
build_simple_deregister_user_data_ascii; // "D4"
build_advanced_deregister_user_data_ascii; // "X4{addr}"
// Wallet-free mode — agent acts as guardian
build_wallet_free_register_user_data_ascii; // "W4{agent}{guardian}{r}{s}{v}"
REST Registration API
Programmatic registration without the CLI:
Set SELF_AGENT_API_BASE to override the default hosted API base.
use ;
// Start a registration session
let session = request.await?;
println!; // URL for the human to open
println!; // Steps for the human
// Wait for completion (polls on-chain)
let result = session.wait_for_completion.await?;
println!;
// Export the generated private key
let private_key = session.export_key.await?;
CLI
Interactive registration via the command line:
# Register an agent (agent-identity mode)
# Deregister
# Export private key (requires --unsafe flag)
Registration modes:
| Mode | Description | userDefinedData |
|---|---|---|
verified-wallet |
Human address = agent address | R{cfg} |
agent-identity |
Agent has own keypair, signed challenge | K{cfg}{addr}{r}{s}{v} |
wallet-free |
Agent as guardian, no human wallet needed | W{cfg}{addr}{guardian}{r}{s}{v} |
smart-wallet |
ZeroDev Kernel + passkeys | Smart wallet template |
Configuration
// Testnet
let agent = new?;
// Custom overrides
let verifier = new;
Security Chain
The verifier implements an 11-step security chain:
- Timestamp freshness — reject stale requests (default: 5 min window)
- Signature recovery — derive agent address from ECDSA signature
- Agent key derivation —
zeroPad(address, 32)for on-chain lookup - On-chain verification —
isVerifiedAgent(agentKey)confirms human backing - Provider check — ensures proof came from Self Protocol, not a third party
- Sybil resistance — limits agents per human (default: 1)
- Replay protection — reject duplicate
(signature, timestamp)pairs - Credential validation — verify ZK-attested credentials if configured
- Age verification — enforce minimum age from passport proof
- OFAC screening — verify agent passed sanctions screening
- Rate limiting — per-agent request throttling
Cross-Language Compatibility
This SDK is 100% compatible with the TypeScript SDK (@selfxyz/agent-sdk) and Python SDK (selfxyz-agent-sdk). All three produce byte-identical signatures and userDefinedData payloads for the same inputs.
Run Tests
Integration tests (require network access, skipped by default):
Networks
| Network | Registry | Chain ID |
|---|---|---|
| Mainnet (Celo) | 0xaC3DF9ABf80d0F5c020C06B04Cced27763355944 |
42220 |
| Testnet (Celo Sepolia) | 0x043DaCac8b0771DD5b444bCC88f2f8BBDBEdd379 |
11142220 |
License
Business Source License 1.1 (BUSL-1.1). See ../LICENSE.