开放代理id
Rust SDK 打开代理ID 协议(V2)。使用Ed25519对HTTP请求和P2P消息进行签名和验证。
安装
[dependencies]
open-agent-id = "0.2"启用可选功能:
open-agent-id = { version = "0.2", features = ["client", "signer"] }快速开始
最常见的用例是向出站请求添加代理身份验证标头:
use open_agent_id::signing::sign_agent_auth;
let headers = sign_agent_auth(
"did:oaid:base:0x1234567890abcdef1234567890abcdef12345678",
&signing_key, // ed25519_dalek::SigningKey
);
// Returns HashMap with:
// "X-Agent-DID" => "did:oaid:base:0x1234..."
// "X-Agent-Timestamp" => "1708123456"
// "X-Agent-Nonce" => "a3f1b2c4d5e6f7089012abcd"
// "X-Agent-Signature" => ""
let resp = reqwest::Client::new()
.post("https://api.example.com/v1/tasks")
.headers(headers.try_into()?)
.json(&serde_json::json!({"task": "search"}))
.send()
.await?;注册表客户端
需要 client 功能。
use open_agent_id::client::RegistryClient;
let client = RegistryClient::new(None); // uses https://api.openagentid.org所有方法
| 方法 | 需要授权 | 描述 |
|---|---|---|
client.challenge(wallet_address) | 否 | 请求钱包身份验证挑战 |
client.wallet_auth(&WalletAuthRequest) | 否 | 验证钱包签名,返回身份验证令牌 |
client.register(token, &RegistrationRequest) | 是 | 注册新代理 |
client.lookup(did) | 否 | 通过DID查找代理 |
client.list_my_agents(token, cursor, limit) | 是 | 列出经过身份验证的钱包所拥有的代理 |
client.update_agent(token, did, &UpdateAgentRequest) | 是 | 更新代理元数据 |
client.revoke(token, did) | 是 | 撤销代理身份 |
client.rotate_key(token, did, &RotateKeyRequest) | 是 | 旋转代理的公钥 |
client.deploy_wallet(token, did) | 是 | 为代理部署链上智能钱包 |
client.get_credit(did) | 否 | 查询代理人的信用评分 |
client.verify(&VerifyRequest) | 否 | 根据代理的注册密钥验证签名 |
钱包身份验证流程
use open_agent_id::types::WalletAuthRequest;
// 1. Request challenge
let challenge = client.challenge(wallet_address).await?;
// 2. Sign the challenge text with your wallet
// let wallet_signature = ...;
// 3. Verify and get auth token
let auth = client.wallet_auth(&WalletAuthRequest {
wallet_address: wallet_address.to_string(),
challenge_id: challenge.challenge_id,
signature: wallet_signature,
}).await?;
let token = auth.token;注册代理
use open_agent_id::types::RegistrationRequest;
let agent = client.register(&token, &RegistrationRequest {
name: Some("my-agent".into()),
public_key: base64url_public_key,
capabilities: Some(vec!["search".into(), "summarize".into()]),
}).await?;查找并列出代理商
let info = client.lookup("did:oaid:base:0x1234...").await?;
let agents = client.list_my_agents(&token, None, None).await?;管理代理
client.update_agent(&token, "did:oaid:base:0x1234...", &updates).await?;
client.rotate_key(&token, "did:oaid:base:0x1234...", &rotate_req).await?;
client.revoke(&token, "did:oaid:base:0x1234...").await?;
client.deploy_wallet(&token, "did:oaid:base:0x1234...").await?;信用评分
let credit = client.get_credit("did:oaid:base:0x1234567890abcdef1234567890abcdef12345678").await?;
println!("Score: {}", credit.credit_score); // 300
println!("Level: {}", credit.level); // "verified"HTTP签名
对HTTP请求进行签名和验证
use open_agent_id::{crypto, signing};
let (signing_key, verifying_key) = crypto::generate_keypair();
let output = signing::sign_http(
&signing::HttpSignInput {
method: "POST",
url: "https://api.example.com/v1/agents",
body: b"{\"name\":\"bot\"}",
timestamp: None,
nonce: None,
},
&signing_key,
).unwrap();
let valid = signing::verify_http(
"POST",
"https://api.example.com/v1/agents",
b"{\"name\":\"bot\"}",
output.timestamp,
&output.nonce,
&output.signature,
&verifying_key,
).unwrap();
assert!(valid);签名者守护进程客户端
需要 signer 功能。
use open_agent_id::signer::SignerClient;
let client = SignerClient::connect("/var/run/oaid-signer.sock").await?;
let signature = client.sign("my-key-id", "http", b"payload").await?;消息签名
签署并验证P2P消息
use open_agent_id::{crypto, signing};
let (signing_key, verifying_key) = crypto::generate_keypair();
let body = serde_json::json!({"action": "ping"});
let output = signing::sign_msg(
&signing::MsgSignInput {
msg_type: "ping",
id: "019504a0-0000-7000-8000-000000000001",
from: "did:oaid:base:0x0000000000000000000000000000000000000001",
to: &["did:oaid:base:0x0000000000000000000000000000000000000002"],
reference: "",
timestamp: None,
expires_at: 0, // defaults to timestamp + 300s
body: &body,
},
&signing_key,
);
let valid = signing::verify_msg(
"ping",
"019504a0-0000-7000-8000-000000000001",
"did:oaid:base:0x0000000000000000000000000000000000000001",
&["did:oaid:base:0x0000000000000000000000000000000000000002"],
"",
output.timestamp,
output.timestamp + 300,
&body,
&output.signature,
&verifying_key,
).unwrap();
assert!(valid);E2E加密
use open_agent_id::crypto;
let ciphertext = crypto::encrypt_for(b"secret", &recipient_pub, &sender_signing_key)?;
let plaintext = crypto::decrypt_from(&ciphertext, &sender_pub, &recipient_signing_key)?;使用氯化钠箱(X25519-XSalsa20-Poly1305)。
DID实用程序
解析DID
use open_agent_id::Did;
let did = Did::parse("did:oaid:base:0x7f4e3d2c1b0a9f8e7d6c5b4a3f2e1d0c9b8a7f6e").unwrap();
assert_eq!(did.chain, "base");
println!("{did}"); // did:oaid:base:0x7f4e...规范助手
use open_agent_id::signing;
// Canonical URL (lowercased host, sorted query params, no fragment)
let url = signing::canonicalize_url("https://API.Example.com/path?z=1&a=2").unwrap();
assert_eq!(url, "https://api.example.com/path?a=2&z=1");
// Canonical JSON (sorted keys, no whitespace)
let val: serde_json::Value = serde_json::from_str(r#"{"z":1,"a":"hello"}"#).unwrap();
assert_eq!(signing::canonical_json(&val), r#"{"a":"hello","z":1}"#);测试
cargo test
cargo test --all-features许可证
阿帕奇-2.0
