Bindings API
The Bindings API is the low-level invariants contract shared across every chio SDK. It defines the functions each binding must implement, the data shapes that cross the language boundary, and the cross-language conformance suite that keeps the four SDKs in byte-for-byte agreement.
Not a transport layer
Scope
The upstream crate chio-binding-helpers fixes this contract in Rust. Every other SDK (TypeScript, Python, Go) mirrors the same API shape, the same input and output rules, and the same stable error codes.
The Contract Owns
- Canonical JSON helpers (RFC 8785).
- SHA-256 hashing helpers for both bytes and UTF-8 strings.
- Ed25519 signing and verification helpers.
- Receipt parsing and verification helpers.
- Capability parsing and verification helpers.
- Signed manifest parsing and verification helpers.
- Delegation-chain validity as part of capability verification (walked via
chio-core). - Stable, bindings-oriented error codes.
The Contract Does Not Own
- Session state machines.
- Remote HTTP or stream transports.
- Auth discovery, OAuth, token exchange, token providers.
- Task orchestration or nested callback routers.
- Trust-control service clients.
- Kernel execution runtime.
Public Surface
Each binding must expose the functions below under its language-native naming convention. The snake_case names used here are the canonical reference names from chio-binding-helpers.
Canonical JSON
canonicalize_json_str(json: string) -> string
RFC 8785 JSON Canonicalization Scheme. Object keys are sorted lexicographically by UTF-16 code unit. Numbers are emitted in ECMAScript Number.prototype.toStringform. No insignificant whitespace. Output is deterministic for any input that parses to the same JSON value.
Hashing
sha256_hex_bytes(bytes) -> stringsha256_hex_utf8(text: string) -> string
SHA-256 over the input, hex-encoded lowercase. The UTF-8 form hashes the bytes of the UTF-8 encoding of the string without a BOM.
Ed25519 Signing
is_valid_public_key_hex(hex): 64 lowercase hex characters.is_valid_signature_hex(hex): 128 lowercase hex characters.public_key_hex_matches(a, b): constant-time equality.sign_utf8_message_ed25519(message, seed_hex) -> Utf8MessageSignatureverify_utf8_message_ed25519(message, signature, public_key_hex) -> boolsign_json_str_ed25519(json, seed_hex) -> CanonicalJsonSignatureverify_json_str_signature_ed25519(json, signature, public_key_hex) -> bool
JSON signing canonicalizes the input before signing. Signing an already-canonical JSON string and signing its non-canonical equivalent must produce the same signature.
Receipts
parse_receipt_json(json) -> ChioReceiptreceipt_body_canonical_json(receipt) -> stringverify_receipt(receipt) -> ReceiptVerificationverify_receipt_json(json) -> ReceiptVerification
A receipt verifies when its canonical-body Ed25519 signature checks against the kernel key and the parameter hash in the receipt matches SHA-256 of the canonical action arguments.
Capabilities
parse_capability_json(json) -> CapabilityTokencapability_body_canonical_json(cap) -> stringverify_capability(cap, now: u64, max_delegation_depth: Option<u32>) -> CapabilityVerificationverify_capability_json(json, now: u64, max_delegation_depth: Option<u32>) -> CapabilityVerification
verify_capability takes the parsed token, the current Unix timestamp in seconds, and an optional maximum delegation depth. The returned CapabilityVerification carries signature_valid, delegation_chain_valid, time_valid, and a time_status of valid, not_yet_valid, or expired. The delegation-chain walk checks each parent-to-child signature and enforces attenuation between consecutive scopes up to max_delegation_depth.
use std::time::{SystemTime, UNIX_EPOCH};
use chio_binding_helpers::{parse_capability_json, verify_capability};
let cap = parse_capability_json(&json)?;
let now = SystemTime::now().duration_since(UNIX_EPOCH)?.as_secs();
let max_delegation_depth = Some(8_u32);
let verification = verify_capability(&cap, now, max_delegation_depth)?;
assert!(verification.signature_valid);
assert!(verification.delegation_chain_valid);
assert!(verification.time_valid);Signed Manifests
parse_signed_manifest_json(json) -> SignedManifestsigned_manifest_body_canonical_json(manifest) -> stringverify_signed_manifest(manifest) -> ManifestVerificationverify_signed_manifest_json(json) -> ManifestVerification
Delegation-chain and Merkle helpers are planned
verify_delegation_chain, check_attenuation, and merkle_proof_verify are not part of the current chio-binding-helpers surface. Today, delegation-chain validity is returned as a field of CapabilityVerification; direct chain and attenuation inspection lives in chio-core. Merkle inclusion-proof verification for receipt stores will land once the wire shape stabilises.Input and Output Rules
Prefer:
- JSON-string input for structured payloads.
- UTF-8 string input for signed text helpers.
- Byte-slice input only where byte identity is the point.
- Explicit verification result structs (not raw booleans) when policy or receipt detail matters.
Avoid:
- Exposing deep internal Rust types across the binding boundary.
- Opaque handles unless they are genuinely reusable compiled objects.
- Async APIs in the invariants layer.
- Ownership-sensitive runtime state.
Stable Error Taxonomy
SDKs surface errors through a typed class that carries one of the snake_case error codes below. Depend on the code value, not on the Rust enum spelling or any message text.
| Code | Meaning |
|---|---|
invalid_public_key | Public key hex is malformed or wrong length. |
invalid_hex | Generic hex-decode failure. |
invalid_signature | Signature hex is malformed or wrong length. |
json | JSON parse failure. |
canonical_json | RFC 8785 canonicalization refused the input. |
capability_expired | Capability is past expires_at. |
capability_not_yet_valid | Capability is before issued_at. |
capability_revoked | Capability appears in a revocation list. |
delegation_chain_broken | A link in the delegation chain fails signature check. |
attenuation_violation | Child scope exceeds parent scope. |
scope_mismatch | Requested action not within the capability scope. |
signature_verification_failed | Ed25519 verification returned false. |
delegation_depth_exceeded | Chain depth exceeds the per-binding limit. |
invalid_hash_length | A hash field is not 32 bytes. |
merkle_proof_failed | Merkle inclusion proof did not reproduce the root. |
empty_tree | Merkle operation requested on an empty tree. |
invalid_proof_index | Merkle proof index is out of range. |
empty_manifest | Signed manifest has no tools. |
duplicate_tool_name | Signed manifest contains two tools with the same name. |
unsupported_schema | Schema identifier is unknown to this binding. |
manifest_verification_failed | Manifest body signature failed to verify. |
Cross-Language Conformance
The conformance harness lives in the chio monorepo. It ships a corpus of input vectors and expected outputs for every function above, plus a runner per language that compares the binding's output to the Rust reference byte for byte.
$ cargo test -p chio-conformance # Rust reference
$ cd packages/sdk/chio-ts && npm test # TypeScript
$ cd packages/sdk/chio-py && pytest # Python
$ cd packages/sdk/chio-go && go test ./... # GoThe suite covers:
- Canonical JSON for Unicode edge cases, nested objects, floats, and integer boundaries.
- SHA-256 vectors across byte and UTF-8 inputs including non-BMP characters.
- Ed25519 sign and verify with seeds from the RFC 8032 test vectors plus protocol-specific cases.
- Receipt verification against signatures produced by the Rust kernel.
- Capability verification and delegation chains of depth 0, 1, 3, and the depth limit.
- Signed manifest verification over the spec fixtures.
Canonical JSON is non-negotiable
-0, infinities, and lone surrogates. If your binding is failing, start there.Change Rules
The contract is frozen under the rules below. They exist so SDK work can proceed without the bindings layer turning into a second runtime.
- New public entrypoints require an owning use case, a unit test, or both.
- Changes that widen scope into transport or runtime behavior are rejected by default.
- Error code removals or renames are breaking changes and require a major bump.
- SDKs should consume helpers through this facade rather than reaching into
chio-coreorchio-manifestdirectly.
Versioning
The Bindings API follows semantic versioning. The current major version is 1. Patch releases add tests and fix bugs without changing the public surface. Minor releases add new helpers or new error codes without removing or renaming existing ones. Major releases are rare and are coordinated with an upgrade guide that walks every SDK through the change.
Deferred Work
A handful of directions are intentionally deferred until the package-backed remote-edge parity path is proven. They will only be picked up once the pure-TypeScript and pure-Python parity path is shipping cleanly in production.
chio-bindings-ffi: C ABI bindings for embedding in non-Rust hosts.chio-bindings-wasm: WASM module with JS glue.chio-native: Native-library companion to the pure-language SDKs.- Go CGO bridge work.
- Policy compilation helpers beyond plain verification.
Per-Language SDK References
- TypeScript SDK (
@chio-protocol/sdk) - Python SDK (
chio-sdk, imported aschio) - Go SDK (
github.com/backbay-labs/chio/packages/sdk/chio-go) - Rust SDK (
chio-binding-helperscrate)