ReferenceSDKs
Rust SDK
The Rust crates under crates/sdk: binding invariants, the WASM guard SDK and its macro, two C ABI layers, and the eval-receipt verifier.
Source
This page reflects the crates under crates/sdk/ in the chio repository: chio-binding-helpers, chio-bindings-ffi, chio-cpp-kernel-ffi, chio-eval-receipt, chio-guard-sdk, and chio-guard-sdk-macros. It also covers the compatibility package sdks/rust/chio-guard-sdk-compat and the tower layer crates/protocol/chio-tower. The crate names, paths, and publish flags render from the crates dataset at the pin. None of these crates carries a specification status line or the RFC 2119 keywords; the Rust source is the truth for every name below.
On the Rust side chio is the name of the binary the chio-cli crate (crates/products/chio-cli) produces. No Rust library crate is called chio. The invariants a library consumer depends on live in chio-binding-helpers; the kernel types live in crates/core/chio-core and crates/core/chio-core-types.
Synopsis
Depend on the crate by path from a checkout, then import from the library name chio_binding_helpers.
# Cargo.toml
[dependencies]
chio-binding-helpers = { path = "../../crates/sdk/chio-binding-helpers" }
// src/main.rs
use chio_binding_helpers::{parse_receipt_json, verify_receipt};
let receipt = parse_receipt_json(&json)?;
let result = verify_receipt(&receipt)?;Installation
Every workspace member the crates dataset carries has publish = false, so a Rust consumer depends on a crate by path from a checkout rather than by version. sdks/rust/chio-guard-sdk-compat sets the same flag in its own manifest. The Go modules take the same shape: the worked Go application replaces the adapter with a local path (examples/hello-chi/go.mod:16), which the Go SDK page shows in full.
[dependencies]
chio-binding-helpers = { path = "../../crates/sdk/chio-binding-helpers" }Crate layout
The crates the crates dataset assigns to the sdk group, with the path each is read from.
| Crate | Path | Role |
|---|---|---|
chio-binding-helpers | crates/sdk/chio-binding-helpers | Canonical JSON, SHA-256, Ed25519, and receipt, capability, and manifest verification. The contract every language binding implements. |
chio-bindings-ffi | crates/sdk/chio-bindings-ffi | A C ABI over chio-binding-helpers. UTF-8 strings and byte buffers in, UTF-8 buffers out, explicit Rust-side deallocation, no session state across the boundary. |
chio-cpp-kernel-ffi | crates/sdk/chio-cpp-kernel-ffi | A C ABI over chio-core-types and chio-kernel-core for the C++ offline kernel package, in the mobile adapter's JSON-in, JSON-out shape. |
chio-eval-receipt | crates/sdk/chio-eval-receipt | Reference verifier and exporter for chio.eval-report.bundle.v1 receipt bundles, plus a chio-eval-receipt binary. |
chio-guard-sdk | crates/sdk/chio-guard-sdk | Guest-side SDK for WASM guards targeting the chio:guard@0.2.0 WIT world: types, host bindings, ABI glue, and the guest allocator. |
chio-guard-sdk-macros | crates/sdk/chio-guard-sdk-macros | The chio_guard proc-macro attribute that wraps a guard author's evaluate function. |
Three crates outside that group appear on this page. crates/core/chio-core holds the kernel types (ChioReceipt, CapabilityToken, ChioScope) and validate_delegation_chain, which the invariants wrap. crates/platform/chio-manifest holds the signed tool manifest types. crates/protocol/chio-tower governs an HTTP service in process.
chio-binding-helpers
The crate exposes seven modules and re-exports their public names at the root (src/lib.rs:22-40). It implements RFC 8785 canonical JSON, SHA-256, Ed25519 sign and verify, receipt parsing and verification, capability parsing and verification including delegation-chain walking through chio-core, and signed manifest parsing and verification. Session runtime, transport, authentication, and callback orchestration stay in the language-native SDKs (src/lib.rs:1-12).
| Module | Re-exported at the root |
|---|---|
canonical | canonicalize_json_str (canonical.rs:6). |
hashing | sha256_hex_bytes (hashing.rs:2) and sha256_hex_utf8 (:7). |
signing | public_key_hex_matches at line 23, is_valid_public_key_hex at 28, is_valid_signature_hex at 33, sign_utf8_message_ed25519 at 37, verify_utf8_message_ed25519 at 46, sign_json_str_ed25519 at 56, verify_json_str_signature_ed25519 at 70, plus Utf8MessageSignature and CanonicalJsonSignature. |
receipt | parse_receipt_json at line 71, receipt_body_canonical_json at 75, verify_receipt at 79, verify_receipt_with_trusted_signers at 83, verify_receipt_with_trusted_signer_hex at 120, verify_receipt_json at 128, verify_receipt_json_with_trusted_signer_hex at 133, plus ReceiptDecisionKind and ReceiptVerification. |
capability | parse_capability_json at line 25, capability_body_canonical_json at 29, verify_capability at 33, verify_capability_json at 57, plus CapabilityTimeStatus and CapabilityVerification. |
manifest | parse_signed_manifest_json at line 15, signed_manifest_body_canonical_json at 19, verify_signed_manifest at 23, verify_signed_manifest_json at 39, plus ManifestVerification. |
error | Error, ErrorCode, and the Result alias. |
Receipt verification
ReceiptVerification (receipt.rs:56-68) carries signature_valid, parameter_hash_valid, receipt_id_valid, decision, receipt_kind, boundary_class, trust_level, result, authorized, signer_key_hex, signer_trusted, and ok. signer_trusted is true only when the caller supplies a signer list that contains the receipt's kernel_key, and both authorized and ok conjoin it (receipt.rs:95-117). verify_receipt passes an empty list (receipt.rs:80), so it reports the three validity booleans and leaves authorized false. Pass keys through the trusted-signer forms to get an authorization answer.
use chio_binding_helpers::{
parse_receipt_json,
verify_receipt,
ReceiptVerification,
};
fn main() -> anyhow::Result<()> {
let json = std::fs::read_to_string("receipt.json")?;
let receipt = parse_receipt_json(&json)?;
let result: ReceiptVerification = verify_receipt(&receipt)?;
assert!(result.signature_valid);
assert!(result.parameter_hash_valid);
Ok(())
}Capability verification
verify_capability takes the parsed token, a u64 Unix timestamp, and an Option<u32> maximum delegation depth (capability.rs:33-37). The returned CapabilityVerification carries signature_valid, delegation_chain_shape_valid, time_valid, and time_status, whose variants are Valid, NotYetValid, and Expired (capability.rs:11-15, with the struct at :18-23).
use std::time::{SystemTime, UNIX_EPOCH};
use chio_binding_helpers::{
parse_capability_json,
verify_capability,
CapabilityTimeStatus,
};
let cap = parse_capability_json(&json)?;
let now: u64 = SystemTime::now()
.duration_since(UNIX_EPOCH)?
.as_secs();
let max_delegation_depth: Option<u32> = Some(8);
let status = verify_capability(&cap, now, max_delegation_depth)?;
assert!(status.signature_valid);
assert!(status.delegation_chain_shape_valid);
match status.time_status {
CapabilityTimeStatus::Valid => {}
CapabilityTimeStatus::NotYetValid => return Err(anyhow::anyhow!("nbf")),
CapabilityTimeStatus::Expired => return Err(anyhow::anyhow!("expired")),
}Delegation-chain validity is folded into the same call: verify_capability passes the depth to chio_core::validate_delegation_chain and reports the outcome as delegation_chain_shape_valid (capability.rs:47-51). Inspecting a single link means calling chio-core directly.
Manifest verification
ManifestVerification (manifest.rs:8-13) carries structure_valid, signature_valid, embedded_public_key_valid, and embedded_public_key_matches_signer.
use chio_binding_helpers::{
parse_signed_manifest_json,
verify_signed_manifest,
};
let manifest = parse_signed_manifest_json(&json)?;
let result = verify_signed_manifest(&manifest)?;
assert!(result.signature_valid);Ed25519 and canonical JSON
sign_json_str_ed25519 canonicalizes the input and returns a CanonicalJsonSignature whose fields are canonical_json, public_key_hex, and signature_hex (signing.rs:12-16). verify_json_str_signature_ed25519 takes the input, then the public key, then the signature.
use chio_binding_helpers::{
canonicalize_json_str,
sha256_hex_bytes,
sha256_hex_utf8,
sign_json_str_ed25519,
verify_json_str_signature_ed25519,
sign_utf8_message_ed25519,
verify_utf8_message_ed25519,
};
let canonical = canonicalize_json_str(r#"{"b":2,"a":1}"#)?;
assert_eq!(canonical, r#"{"a":1,"b":2}"#);
let digest = sha256_hex_utf8("hello world");
let sig = sign_json_str_ed25519(&canonical, &seed_hex)?;
let ok = verify_json_str_signature_ed25519(&canonical, &sig.public_key_hex, &sig.signature_hex)?;
assert!(ok);chio-guard-sdk
crates/sdk/chio-guard-sdk is the guest-side SDK for writing WASM guards against the chio:guard@0.2.0 WIT world. It compiles to wasm32-unknown-unknown for production guards, and on native targets it compiles with no-op fallbacks for the host imports so cargo test runs without a WASM runtime (src/lib.rs:18-20).
| Module | What it holds |
|---|---|
types | GuardRequest, GuardVerdict, and GuestDenyResponse, with serde annotations matching the host ABI, plus the constants VERDICT_ALLOW and VERDICT_DENY. |
host | Wrappers for the host imports chio.log, chio.get_config, chio.get_time_unix_secs, and chio:guard/host.fetch-blob, exported as log, log_level, get_config, get_time, and fetch_blob, plus the PolicyContext bundle-handle wrapper. |
glue | read_request deserializes from linear memory, encode_verdict produces the ABI return code, and the crate exports chio_deny_reason for structured deny reasons. |
alloc | The chio_alloc and chio_free exports the host runtime probes for allocation in guest linear memory. |
The four module declarations sit at src/lib.rs:38-41 and the root re-exports at :44-46. chio_guard_sdk::prelude (:52-55) re-exports the glue functions, the host bindings, and the types other than GuestDenyResponse.
use chio_guard_sdk::prelude::*;
fn evaluate(req: GuardRequest) -> GuardVerdict {
if req.tool_name == "dangerous_tool" {
GuardVerdict::deny("tool is blocked by policy")
} else {
GuardVerdict::allow()
}
}crates/sdk/chio-guard-sdk-macros is a proc-macro crate whose one export is the chio_guard attribute (src/lib.rs:159-160), which wires an author's evaluate function to the exports above. sdks/rust/chio-guard-sdk-compat is a compatibility package that re-exports the same API under the library name chio_guard_sdk (sdks/README.md:18). It declares an empty [workspace] table, so it stands outside the root workspace and builds through --manifest-path.
The C ABI crates
Two crates carry a C ABI. Both declare crate-type = ["staticlib", "cdylib", "rlib"] so a C or C++ consumer links either form.
chio-bindings-ffiexports the invariants over a C boundary: UTF-8 strings and byte buffers in, UTF-8 buffers out, Rust-side deallocation, and no async or session state crossing the boundary (src/lib.rs:1-5). It declaresCHIO_FFI_ABI_VERSIONand theCHIO_FFI_STATUS_*constants atsrc/lib.rs:14-20. The Bindings API page lists its exported symbols.chio-cpp-kernel-ffibindschio-core-typesandchio-kernel-corefor the C++ offline kernel package. It mirrors the mobile adapter's JSON-in, JSON-out shape over a plain C ABI, so no UniFFI or Rust concept appears in a public C++ header (src/lib.rs:1-5).
chio-eval-receipt
crates/sdk/chio-eval-receipt verifies eval-report receipt bundles end to end: it validates the bundle envelope, recomputes the corpus SHA-256, and checks the detached memo signatures attached to each receipt, failing closed on any mismatch (src/lib.rs:3-7). It also exports scenario runs into the bundle format, and it ships a chio-eval-receipt binary at src/bin/cli.rs.
The two entry points are verify_bundle with verify_fixture_bundle, which parse a bundle JSON document into a VerifiedBundle, and export_scenario_run, which builds a Bundle from scenario inputs (src/lib.rs:9-11). The crate pins the schema it verifies as constants: BUNDLE_SCHEMA_ID is chio.eval-report.bundle.v1 and BUNDLE_SCHEMA_PATH is spec/eval/receipt-format.v1.json (src/lib.rs:34 and :37). It carries #![forbid(unsafe_code)] at src/lib.rs:13.
What the Rust crates cover
chio-binding-helpers and chio-core hold invariants and kernel types. Neither opens a remote session, signs a DPoP proof, mints a capability chain, or paginates a receipt query. Build those against the sidecar's HTTP endpoints, or drive them from the TypeScript, Python, or Go SDK. A Rust service that verifies what it was handed needs neither: no file in crates/sdk/chio-binding-helpers/src opens a socket.
Governing an HTTP service written in Rust is a different crate again. chio-tower is a tower::Layer that wraps any service speaking http::Request, including Axum. It runs the kernel in process rather than calling a sidecar.
use chio_tower::ChioLayer;
use chio_core_types::crypto::Keypair;
use tower::Layer;
let keypair = Keypair::generate();
let layer = ChioLayer::new(keypair, "policy-hash-abc".to_string());
// Wrap any tower Service with Chio evaluation.
let inner = tower::service_fn(|_req: http::Request<http_body_util::Full<bytes::Bytes>>| async {
Ok::<_, Box<dyn std::error::Error + Send + Sync>>(http::Response::new(()))
});
let _service = layer.layer(inner);ChioLayer::new (chio-tower/src/layer.rs:31) is fail-closed with no durable store attached. Use ChioLayer::builder (:48) to wire a ReceiptStore and a RevocationStore, or ChioLayer::new_ephemeral (:39) for a local scaffold.
Error model
chio_binding_helpers::Error (error.rs:37-46) is a thiserror enum with three variants: Core, Json, and Manifest. Each is produced only by #[from] conversion from the underlying crate's error, so there is no Error::new constructor: parse and verify helpers propagate with ?. Call .code() (error.rs:50) to map an Error onto an ErrorCode, the serde snake-case enum at error.rs:5-34 that the other bindings share.
use chio_binding_helpers::{Error, ErrorCode, parse_capability_json, verify_capability};
// Error has no `new` constructor. It is only ever produced by converting an
// underlying chio_core / chio_manifest / serde_json error via `?`. Call
// `.code()` to recover the stable ErrorCode for branching.
fn signature_ok(json: &str, now: u64) -> Result<bool, Error> {
let cap = parse_capability_json(json)?;
let status = verify_capability(&cap, now, Some(8))?;
Ok(status.signature_valid)
}
fn describe(err: &Error) -> &'static str {
match err.code() {
ErrorCode::CapabilityExpired => "expired",
ErrorCode::CapabilityNotYetValid => "not yet valid",
ErrorCode::DelegationChainBroken => "broken delegation chain",
_ => "other invariant failure",
}
}Conformance
The checked-in JSON under tests/bindings/vectors/ is the authority, and every language binding reads the same files. crates/sdk/chio-binding-helpers/tests/vector_fixtures.rs round-trips each corpus through the crate's public API.
cargo test -p chio-binding-helpers
cargo test -p chio-core
cargo test -p chio-conformanceThe same file also holds in-Rust generators that rewrite the checked-in JSON after a schema change. Running them as assertions would invert the direction of the check, so each carries #[ignore] with the reason on the attribute, and a manual run needs cargo test -- --ignored (vector_fixtures.rs:1155-1156).
| Ignored test | Line | Reason on the attribute |
|---|---|---|
canonical_vector_fixture_matches_checked_in_json | 1159 | on-disk canonical corpus is the source of truth; run to regenerate after editing the fixture builder |
hashing_vector_fixture_matches_checked_in_json | 1165 | on-disk JSON is the source of truth; the in-Rust generator is a regenerator helper |
receipt_vector_fixture_matches_checked_in_json | 1171 | on-disk JSON is the source of truth; the in-Rust generator is a regenerator helper |
signing_vector_fixture_matches_checked_in_json | 1177 | on-disk JSON is the source of truth; the in-Rust generator is a regenerator helper |
capability_vector_fixture_matches_checked_in_json | 1183 | on-disk JSON is the source of truth; the in-Rust generator is a regenerator helper |
manifest_vector_fixture_matches_checked_in_json | 1189 | on-disk JSON is the source of truth; manifest_vector_fixture() is a regenerator helper for a subset of cases |
rebless_capability_vector_signatures | 1202 | regenerator: re-sign capability vectors after a signing-schema change; run with --ignored |
print_vector_fixtures_for_bootstrap | 1535 | helper for regenerating checked-in vector fixtures during development |
Related
- Bindings API: the same contract stated for every language binding, with the C ABI symbol list.
- SDKs: the language bindings that implement this contract.
- Guards specification: the host side of the guard ABI the guard SDK targets.
- Receipt format: the fields
verify_receiptreads. - HTTP substrate: the sidecar endpoints a Rust service calls when it needs more than verification.