Identity System
Decentralized agent identity based on cryptographic keypairs, on-chain registration, and verifiable attestations.
Overview
The Opacus Identity System provides a decentralized, cryptographically secure way for AI agents to establish and prove their identity. Unlike traditional centralized identity systems, agent identities in Opacus are:
Identity Lifecycle
Key Generation
Each agent uses two cryptographic keypairs for different purposes:
1. Ed25519 Keypair (Digital Signatures)
🔐 Purpose: Authentication & Message Signing
Ed25519 is a modern elliptic curve signature algorithm that provides:
- High performance: ~60,000 signatures/second
- Small keys: 32-byte public keys, 64-byte signatures
- Strong security: 128-bit security level (equivalent to RSA-3072)
- Deterministic signatures: Same message always produces same signature
TypeScript Example
import { ed25519 } from '@noble/curves/ed25519';
// Generate Ed25519 keypair
const privateKey = ed25519.utils.randomPrivateKey();
const publicKey = ed25519.getPublicKey(privateKey);
console.log('Private key (keep secret!):', Buffer.from(privateKey).toString('hex'));
console.log('Public key (share freely):', Buffer.from(publicKey).toString('hex'));
// Sign a message
const message = new TextEncoder().encode('Hello from Agent!');
const signature = ed25519.sign(message, privateKey);
console.log('Signature:', Buffer.from(signature).toString('hex'));
// Verify signature
const isValid = ed25519.verify(signature, message, publicKey);
console.log('Valid:', isValid); // true
Rust Example
use ed25519_dalek::{SigningKey, VerifyingKey, Signature, Signer, Verifier};
use rand::rngs::OsRng;
// Generate Ed25519 keypair
let mut csprng = OsRng;
let signing_key = SigningKey::generate(&mut csprng);
let verifying_key = signing_key.verifying_key();
println!("Public key: {:?}", verifying_key.to_bytes());
// Sign a message
let message = b"Hello from Agent!";
let signature = signing_key.sign(message);
println!("Signature: {:?}", signature.to_bytes());
// Verify signature
assert!(verifying_key.verify(message, &signature).is_ok());
println!("Signature verified!");
2. X25519 Keypair (Key Exchange)
🔒 Purpose: Encryption & Secure Communication
X25519 is an elliptic curve Diffie-Hellman (ECDH) key exchange algorithm:
- Derive shared secrets between agents
- Enable end-to-end encryption without key exchange
- Fast: ~50,000 shared secret computations/second
- Same security level as Ed25519 (128-bit)
TypeScript Example
import { x25519 } from '@noble/curves/ed25519';
import { hkdf } from '@noble/hashes/hkdf';
import { sha256 } from '@noble/hashes/sha256';
// Alice generates her keypair
const alicePrivate = x25519.utils.randomPrivateKey();
const alicePublic = x25519.getPublicKey(alicePrivate);
// Bob generates his keypair
const bobPrivate = x25519.utils.randomPrivateKey();
const bobPublic = x25519.getPublicKey(bobPrivate);
// Alice derives shared secret with Bob's public key
const sharedAlice = x25519.getSharedSecret(alicePrivate, bobPublic);
// Bob derives the same shared secret with Alice's public key
const sharedBob = x25519.getSharedSecret(bobPrivate, alicePublic);
// Both shared secrets are identical!
console.log('Secrets match:', Buffer.from(sharedAlice).equals(Buffer.from(sharedBob)));
// Derive encryption key using HKDF
const encryptionKey = hkdf(sha256, sharedAlice, undefined, undefined, 32);
console.log('Encryption key:', Buffer.from(encryptionKey).toString('hex'));
Rust Example
use x25519_dalek::{StaticSecret, PublicKey};
use rand::rngs::OsRng;
// Alice generates her keypair
let alice_secret = StaticSecret::random_from_rng(OsRng);
let alice_public = PublicKey::from(&alice_secret);
// Bob generates his keypair
let bob_secret = StaticSecret::random_from_rng(OsRng);
let bob_public = PublicKey::from(&bob_secret);
// Both compute the same shared secret
let shared_alice = alice_secret.diffie_hellman(&bob_public);
let shared_bob = bob_secret.diffie_hellman(&alice_public);
assert_eq!(shared_alice.as_bytes(), shared_bob.as_bytes());
println!("Shared secret established!");
On-Chain Registration
After generating keypairs, agents must register on-chain to obtain a globally unique identity:
Registration Process
Code Example: Register Agent
import { OpacusClient } from '@opacus/sdk';
const client = new OpacusClient({
rpcUrl: 'https://evmrpc-testnet.0g.ai',
contractAddress: '0x...',
privateKey: process.env.PRIVATE_KEY!
});
// Register with metadata
const agentId = await client.registerAgent({
name: 'WeatherBot',
version: '1.0.0',
capabilities: ['weather-forecast', 'climate-analysis'],
description: 'AI agent for weather information',
endpoint: 'https://weather-bot.example.com'
});
console.log('✅ Agent registered with ID:', agentId);
console.log('🔗 View on explorer:', `https://explorer.0g.ai/agent/${agentId}`);
Agent ID Format
The agent ID is deterministically derived from the public keys:
agentId = keccak256(edPublicKey || xPublicKey)
Where || represents concatenation. This ensures:
- ✅ Uniqueness: Different keypairs always produce different IDs
- ✅ Determinism: Same keys always produce the same ID
- ✅ Collision Resistance: Keccak256 makes collisions computationally infeasible
- ✅ No Central Registry: IDs are self-generated, no coordination needed
Identity Verification
Other agents can verify an identity by:
- Fetch On-Chain Record: Query AgentRegistry contract for public keys
- Verify Signature: Use Ed25519 public key to verify message signatures
- Check Attestations: Review third-party attestations for reputation
- Validate Metadata: Ensure capabilities match claimed functionality
Verification Example
// Get agent from blockchain
const agent = await client.getAgent(agentId);
// Verify a message signature
const message = Buffer.from('Signed by agent');
const signature = Buffer.from('...signature bytes...');
const isValid = await ed25519.verify(
signature,
message,
agent.edPublicKey
);
if (isValid) {
console.log('✅ Signature valid - message is from', agent.metadata.name);
} else {
console.log('❌ Invalid signature - possible impersonation attempt!');
}
Key Security
Private keys never leave agent
Hardware wallet support
Optional key rotation
On-Chain
Immutable registration
Public key storage
~0.0001 0G cost
Global Resolution
Query any agent by ID
No DNS dependencies
Works across networks
Trustless
No identity provider
Math-based security
Cannot be censored
✅ Best Practices
- 🔐 Store private keys securely (hardware wallets, encrypted storage)
- 🔄 Implement key rotation for long-lived agents
- ✍️ Always sign important messages to prove authenticity
- 🔍 Verify signatures before trusting messages from other agents
- 📝 Keep metadata up-to-date as capabilities evolve