ReferenceSpec
Bindings API
The shared low-level contract for chio SDKs: canonical JSON, hashing, signing, verification, and cross-language conformance.
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 API
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): parses as a Chio public key. Bare hex is read as Ed25519 (64 lowercase hex characters); ap256:orp384:prefix selects an ECDSA key, and ahybrid:prefix selects a hybrid classical-plus-post-quantum key.is_valid_signature_hex(hex): parses as a Chio signature. Bare hex is read as Ed25519 (128 lowercase hex characters); the samep256:,p384:, andhybrid:prefixes select the matching algorithm.public_key_hex_matches(a, b): case-insensitive equality after normalizing the hex. This is an ordinary string comparison, not constant-time.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) -> ReceiptVerificationverify_receipt_with_trusted_signers(receipt, trusted_signers) -> ReceiptVerificationverify_receipt_with_trusted_signer_hex(receipt, trusted_signer_hex) -> ReceiptVerificationverify_receipt_json_with_trusted_signer_hex(json, trusted_signer_hex) -> ReceiptVerification
A receipt verifies when its canonical-body signature checks against the embedded kernel_key and the parameter hash in the receipt matches SHA-256 of the canonical action arguments. Signature verification is algorithm-aware: it dispatches on the key and signature prefix, accepting Ed25519 (bare hex), p256:, p384:, and hybrid: material. verify_receipt is verify_receipt_with_trusted_signers(receipt, &[]); the trusted-signer variants additionally require the receipt's kernel_key to appear in the supplied signer set.
ReceiptVerification carries signature_valid, parameter_hash_valid, receipt_id_valid, decision (a ReceiptDecisionKind of Allow, Deny, Cancelled, Incomplete, or None), receipt_kind, boundary_class, trust_level, result, authorized, signer_key_hex, signer_trusted, and ok. authorized is true only when the receipt is a mediated decision at the prevent boundary with an Allow decision and the signature, parameter-hash, receipt-id, and trusted-signer checks all pass. A valid trace or advisory receipt is evidence, never authorization.
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_shape_valid, time_valid, and a time_status of valid, not_yet_valid, or expired. The delegation-chain walk validates chain shape: each per-link signature, delegator-to-delegatee continuity, timestamp ordering, and chain length against max_delegation_depth. It does not compare parent and child scopes. Scope-attenuation and chain-binding enforcement is a separate, stricter path in chio-core that this binding call does not invoke, which is why the field is named delegation_chain_shape_valid rather than an attenuation-valid flag.
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_shape_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 API. 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 is planned after the wire shape stabilizes.Input and Output Rules
Prefer:
- JSON-string input for structured payloads.
- UTF-8 string input for signed text helpers.
- Byte-slice input when byte identity matters.
- 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 wrap reusable compiled objects.
- Async APIs in the invariants layer.
- Ownership-sensitive runtime state.
Stable Error Taxonomy
SDKs expose 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. |
invalid_tool_name | A manifest tool name is empty or otherwise invalid. |
invalid_input_schema | A tool input schema is not a JSON object. |
invalid_output_schema | A tool output schema is not a JSON object. |
duplicate_server_tool | A server-tool allowlist entry appears more than once. |
invalid_manifest_field | A required manifest field is missing or malformed. |
invalid_required_permission | A declared required permission is empty or malformed. |
duplicate_required_permission | A required permission is declared more than once. |
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 sdks/typescript/chio-ts && npm test # TypeScript
$ cd sdks/python/chio-py && pytest # Python
$ cd sdks/go/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 requirement
-0, infinities, and lone surrogates.Change Rules
The contract is frozen under the rules below. They keep the bindings contract separate from transport and runtime behavior.
- 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 API. 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
The following work is deferred pending package-backed remote-edge parity. It depends on the pure-TypeScript and pure-Python paths being available 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/sdks/go/chio-go) - Rust SDK (
chio-binding-helperscrate)