Skip to content

Rust SDK

The Rust SDK is byte-for-byte interoperable with Go, TypeScript, and Python. Rust 1.75+. Uses ed25519-dalek and pqcrypto-mldsa for the underlying primitives.

Terminal window
cargo add ratify-protocol@1.0.0-alpha.6

Or from source:

Terminal window
git clone https://github.com/identities-ai/ratify-protocol
cd ratify-protocol/sdks/rust
cargo build --all-targets
cargo test
use std::time::{SystemTime, UNIX_EPOCH};
use ratify_protocol::{
generate_human_root, generate_agent, issue_delegation,
sign_challenge, generate_challenge, verify_bundle,
DelegationCert, ProofBundle, VerifyOptions,
PROTOCOL_VERSION, SCOPE_MEETING_ATTEND, SCOPE_MEETING_SPEAK,
};
fn main() -> Result<(), Box<dyn std::error::Error>> {
// 1. Alice generates her hybrid root identity.
let (alice, alice_priv) = generate_human_root()?;
// 2. Her AI agent generates its own hybrid keypair.
let (agent, agent_priv) = generate_agent("Alice's Scheduler", "custom")?;
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)?
.as_secs() as i64;
// 3. Alice signs a delegation cert.
let mut cert = DelegationCert {
version: PROTOCOL_VERSION,
cert_id: uuid::Uuid::new_v4().to_string(),
issuer_id: alice.id.clone(),
issuer_pub_key: alice.public_key.clone(),
subject_id: agent.id.clone(),
subject_pub_key: agent.public_key.clone(),
scope: vec![SCOPE_MEETING_ATTEND.into(), SCOPE_MEETING_SPEAK.into()],
issued_at: now,
expires_at: now + 7 * 24 * 3600,
..Default::default()
};
issue_delegation(&mut cert, &alice_priv)?;
// 4. Verifier issues a challenge. Agent signs it.
let challenge = generate_challenge();
let challenge_at = now;
let challenge_sig = sign_challenge(&challenge, challenge_at, &agent_priv)?;
// 5. Agent assembles a proof bundle.
let bundle = ProofBundle {
agent_id: agent.id.clone(),
agent_pub_key: agent.public_key.clone(),
delegations: vec![cert],
challenge,
challenge_at,
challenge_sig,
};
// 6. Verifier runs the verifier.
let result = verify_bundle(
&bundle,
&VerifyOptions {
required_scope: Some(SCOPE_MEETING_ATTEND.into()),
..Default::default()
},
)?;
if result.valid {
println!("✓ Authorized: {}", result.agent_id);
println!(" granted: {:?}", result.granted_scope);
} else {
println!("✗ Rejected: {:?} — {:?}", result.identity_status, result.error_reason);
}
Ok(())
}
use ratify_protocol::{verify_bundle, IdentityStatus, VerifyOptions};
let result = verify_bundle(
&bundle,
&VerifyOptions {
required_scope: Some("meeting:attend".into()),
required_custom_scope: None,
now_override: None,
revocation_list: Some(signed_rev_list),
},
)?;
// Branch on identity status — fail-closed
match result.identity_status {
IdentityStatus::Valid => accept_request(),
IdentityStatus::BadSignature => reject("tampered"),
IdentityStatus::Expired => reject("expired"),
IdentityStatus::ScopeDenied => reject("insufficient scope"),
IdentityStatus::Revoked => reject("revoked"),
IdentityStatus::Replay => reject("challenge too old"),
}

The SDK uses serde for serialization. Every protocol object has Serialize + Deserialize implementations that produce canonical JSON (byte-identical to every other SDK).

use serde_json;
// Serialize for transmission
let bundle_json = serde_json::to_string(&bundle)?;
// Deserialize on the receiving side
let bundle: ProofBundle = serde_json::from_str(&bundle_json)?;

The canonical-JSON guarantee is verified by the conformance fixtures — any non-canonical output fails CI.

The verifier path supports no_std (with the alloc extension) for embedded targets — drones, robots, edge inference appliances. Disable default features and explicitly enable the verifier:

[dependencies]
ratify-protocol = { version = "1.0.0-alpha.6", default-features = false, features = ["verifier"] }

The signer path requires the OS RNG and thus std.

Terminal window
cd sdks/rust
cargo test

Expected output: test result: ok. 1 passed. That single test (run_all_fixtures) loads all 59 fixtures from ../../testvectors/v1/ and asserts byte-identical behavior against the Go reference.