Open Agent ID Rust SDK

用于Open Agent ID协议的Rust SDK,支持使用Ed25519签名和验证HTTP请求及P2P消息。

  • by open-agent-id
  • Rust
  • 本地部署
  • 更新于
在 GitHub 查看 open-agent-id/agent-id-rust

使用说明

开放代理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" => "<base64url 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