Chio/Docs
LOGIN · JOIN

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.

rust
# 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.

toml
[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.

CratePathRole
chio-binding-helperscrates/sdk/chio-binding-helpersCanonical JSON, SHA-256, Ed25519, and receipt, capability, and manifest verification. The contract every language binding implements.
chio-bindings-fficrates/sdk/chio-bindings-ffiA 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-fficrates/sdk/chio-cpp-kernel-ffiA 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-receiptcrates/sdk/chio-eval-receiptReference verifier and exporter for chio.eval-report.bundle.v1 receipt bundles, plus a chio-eval-receipt binary.
chio-guard-sdkcrates/sdk/chio-guard-sdkGuest-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-macroscrates/sdk/chio-guard-sdk-macrosThe 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).

ModuleRe-exported at the root
canonicalcanonicalize_json_str (canonical.rs:6).
hashingsha256_hex_bytes (hashing.rs:2) and sha256_hex_utf8 (:7).
signingpublic_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.
receiptparse_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.
capabilityparse_capability_json at line 25, capability_body_canonical_json at 29, verify_capability at 33, verify_capability_json at 57, plus CapabilityTimeStatus and CapabilityVerification.
manifestparse_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.
errorError, 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.

rust
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).

rust
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.

rust
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.

rust
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).

ModuleWhat it holds
typesGuardRequest, GuardVerdict, and GuestDenyResponse, with serde annotations matching the host ABI, plus the constants VERDICT_ALLOW and VERDICT_DENY.
hostWrappers 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.
glueread_request deserializes from linear memory, encode_verdict produces the ABI return code, and the crate exports chio_deny_reason for structured deny reasons.
allocThe 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.

rust
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-ffi exports 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 declares CHIO_FFI_ABI_VERSION and the CHIO_FFI_STATUS_* constants at src/lib.rs:14-20. The Bindings API page lists its exported symbols.
  • chio-cpp-kernel-ffi binds chio-core-types and chio-kernel-core for 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.

crates/protocol/chio-tower/README.md:70-81rust
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.

rust
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.

bash
cargo test -p chio-binding-helpers
cargo test -p chio-core
cargo test -p chio-conformance

The 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 testLineReason on the attribute
canonical_vector_fixture_matches_checked_in_json1159on-disk canonical corpus is the source of truth; run to regenerate after editing the fixture builder
hashing_vector_fixture_matches_checked_in_json1165on-disk JSON is the source of truth; the in-Rust generator is a regenerator helper
receipt_vector_fixture_matches_checked_in_json1171on-disk JSON is the source of truth; the in-Rust generator is a regenerator helper
signing_vector_fixture_matches_checked_in_json1177on-disk JSON is the source of truth; the in-Rust generator is a regenerator helper
capability_vector_fixture_matches_checked_in_json1183on-disk JSON is the source of truth; the in-Rust generator is a regenerator helper
manifest_vector_fixture_matches_checked_in_json1189on-disk JSON is the source of truth; manifest_vector_fixture() is a regenerator helper for a subset of cases
rebless_capability_vector_signatures1202regenerator: re-sign capability vectors after a signing-schema change; run with --ignored
print_vector_fixtures_for_bootstrap1535helper for regenerating checked-in vector fixtures during development
  • 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_receipt reads.
  • HTTP substrate: the sidecar endpoints a Rust service calls when it needs more than verification.