C / C++ SDK
The C/C++ SDK wraps the Rust SDK via a C ABI and ships as libratify_c.a (static) and
libratify_c.so / libratify_c.dylib (shared). The header (include/ratify.h) is
auto-generated by cbindgen and includes extern "C" guards so it works in both C and C++.
Byte-for-byte interoperable with Go, TypeScript, Python, and Rust. Apache-2.0.
Stability: every primitive on this page is stable in 1.0.0-alpha.8.
When to use this SDK
Section titled “When to use this SDK”| You’re writing | Use |
|---|---|
| A Go service or CLI | Go SDK |
| A Node.js or browser app | TypeScript SDK |
| A Python script or ML pipeline | Python SDK |
| A Rust service or high-performance binary | Rust SDK — use directly, no FFI overhead |
| C or C++ code | This SDK |
| Firmware, RTOS, hardware driver | This SDK (static library, libratify_c.a) |
| A language that FFIs to C (Swift, Zig, Julia, Lua, etc.) | This SDK |
Install
Section titled “Install”Prerequisites: Rust toolchain 1.70+.
git clone https://github.com/identities-ai/ratify-protocolcd ratify-protocol/sdks/ccargo build --releaseOutputs:
target/release/libratify_c.a — static library (embed in firmware / link statically)target/release/libratify_c.so — shared library (Linux)target/release/libratify_c.dylib — shared library (macOS)include/ratify.h — C/C++ header (auto-generated, committed)You can also download pre-built libraries for common targets from the
GitHub Releases page. The
committed include/ratify.h lets you use pre-built libraries without installing Rust.
Cross-compile with cross
Section titled “Cross-compile with cross”cargo install cross --git https://github.com/cross-rs/cross
# ARM64 — Raspberry Pi 4, embedded Linux SBCscross build --release --target aarch64-unknown-linux-gnu
# ARM32 — Raspberry Pi 2/3, older embedded Linuxcross build --release --target armv7-unknown-linux-gnueabihf
# ARM Cortex-M4/M7 — FreeRTOS / Zephyrrustup target add thumbv7em-none-eabihfcargo build --release --target thumbv7em-none-eabihf
# RISC-V 64cross build --release --target riscv64gc-unknown-linux-gnuQuick start — Delegate → Present → Verify
Section titled “Quick start — Delegate → Present → Verify”The complete agent authorization flow in C. All API entry/exit conditions are explicitly handled.
#include <stdint.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <time.h>#include "ratify.h"
static int fail(const char *step, char *err) { fprintf(stderr, "FAIL: %s — %s\n", step, err ? err : "unknown error"); ratify_error_free(err); return 1;}
int main(void) { printf("Ratify %s — C SDK example\n\n", ratify_version());
char *err = NULL;
/* 1. Generate identities */ RatifyHumanRoot *root = NULL; if (ratify_human_root_generate(&root) != RatifyOk) return fail("ratify_human_root_generate", NULL);
RatifyAgent *agent = NULL; if (ratify_agent_generate("MyDroneBot", "drone", &agent) != RatifyOk) { ratify_human_root_free(root); return fail("ratify_agent_generate", NULL); }
/* 2. Issue a DelegationCert */ int64_t now = (int64_t)time(NULL); RatifyDelegationCert *cert = NULL; if (ratify_delegation_issue(root, agent, "[\"physical:enter\"]", now, now + 3600LL, &cert, &err) != RatifyOk) return fail("ratify_delegation_issue", err);
char *cert_json = ratify_delegation_cert_to_json(cert, &err); if (!cert_json) return fail("ratify_delegation_cert_to_json", err);
/* 3. Generate challenge and build ProofBundle */ uint8_t challenge[32]; if (ratify_challenge_generate(challenge, 32) != RatifyOk) return fail("ratify_challenge_generate", NULL);
RatifyProofBundle *bundle = NULL; if (ratify_proof_bundle_create(agent, cert_json, challenge, 32, now, &bundle, &err) != RatifyOk) return fail("ratify_proof_bundle_create", err); ratify_string_free(cert_json);
char *bundle_json = ratify_proof_bundle_to_json(bundle, &err); if (!bundle_json) return fail("ratify_proof_bundle_to_json", err);
/* 4. Verify */ RatifyVerifyResult *result = NULL; ratify_verify_bundle(bundle_json, "physical:enter", now, &result, &err);
if (ratify_verify_result_is_valid(result)) { char *agent_id = ratify_verify_result_agent_id(result); printf("authorized agent: %s\n", agent_id); ratify_string_free(agent_id); } else { char *status = ratify_verify_result_identity_status(result); printf("rejected: %s\n", status); ratify_string_free(status); }
/* 5. Cleanup */ ratify_verify_result_free(result); ratify_string_free(bundle_json); ratify_proof_bundle_free(bundle); ratify_delegation_cert_free(cert); ratify_agent_free(agent); ratify_human_root_free(root); return 0;}Build and run:
# macOScc example.c -I include -L target/release \ -lratify_c -lpthread -framework Security -framework CoreFoundation \ -o example && ./example
# Linuxcc example.c -I include -L target/release \ -lratify_c -lpthread -ldl -lm -o example && ./exampleIntegration
Section titled “Integration”cmake_minimum_required(VERSION 3.20)project(my_agent C)
set(RATIFY_SDK_DIR "${CMAKE_SOURCE_DIR}/vendor/ratify-c")
add_library(ratify STATIC IMPORTED)set_target_properties(ratify PROPERTIES IMPORTED_LOCATION "${RATIFY_SDK_DIR}/lib/libratify_c.a" INTERFACE_INCLUDE_DIRECTORIES "${RATIFY_SDK_DIR}/include")
add_executable(my_agent main.c)target_link_libraries(my_agent PRIVATE ratify pthread dl m)project('my_agent', 'c')
ratify_dep = declare_dependency( include_directories: include_directories('vendor/ratify-c/include'), link_args: [ '-L' + meson.source_root() / 'vendor/ratify-c/lib', '-lratify_c', '-lpthread', '-ldl', '-lm', ],)
executable('my_agent', 'main.c', dependencies: [ratify_dep])RATIFY_SDK = vendor/ratify-c
CFLAGS = -I$(RATIFY_SDK)/includeLDFLAGS = -L$(RATIFY_SDK)/lib -lratify_c -lpthread -ldl -lm
my_agent: main.c $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)#include "ratify.h" // extern "C" guards are built in — works as-is#include <string>#include <stdexcept>
class RatifyVerifier {public: bool verify(const std::string& bundle_json, const std::string& scope) { RatifyVerifyResult* result = nullptr; char* err = nullptr; auto status = ratify_verify_bundle( bundle_json.c_str(), scope.empty() ? nullptr : scope.c_str(), 0, // 0 = use system clock &result, &err ); if (status != RatifyOk || !result) { std::string msg = err ? err : "unknown error"; ratify_error_free(err); throw std::runtime_error("verify failed: " + msg); } bool valid = ratify_verify_result_is_valid(result) != 0; ratify_verify_result_free(result); return valid; }};Embedded / RTOS — FreeRTOS custom entropy
Section titled “Embedded / RTOS — FreeRTOS custom entropy”On standard OS targets (Linux, macOS, Raspberry Pi) entropy is automatic. On RTOS targets
without /dev/urandom, enable the custom-entropy Cargo feature and register your hardware TRNG:
Cargo.toml:
ratify-c = { path = "…", features = ["custom-entropy"] }Application startup (STM32 example):
#include "ratify.h"
static int my_entropy(uint8_t *buf, size_t len) { for (size_t i = 0; i < len; i += 4) { uint32_t rnd; if (HAL_RNG_GenerateRandomNumber(&hrng, &rnd) != HAL_OK) return -1; /* -1 = entropy unavailable → library halts */ size_t copy = (len - i < 4) ? (len - i) : 4; memcpy(buf + i, &rnd, copy); } return 0;}
int main(void) { /* Must be called before ratify_challenge_generate() or ratify_delegation_issue() */ ratify_set_entropy_source(my_entropy); /* … rest of your RTOS application */}The library halts if ratify_set_entropy_source() was never called when custom-entropy is
enabled — generating certs with weak randomness is worse than not running at all.
no_std + alloc
Section titled “no_std + alloc”The C SDK is compatible with RTOS environments that provide a heap (alloc) but not the full
Rust std. Bare-metal Cortex-M targets with no heap at all should use the Rust SDK directly
with #[no_std] + alloc.
Supported targets
Section titled “Supported targets”| Architecture | Target triple | Example hardware |
|---|---|---|
| x86-64 | x86_64-unknown-linux-gnu | Intel/AMD server, Linux PC |
| ARM64 | aarch64-unknown-linux-gnu | Raspberry Pi 4, embedded Linux, Apple Silicon |
| ARM32 | armv7-unknown-linux-gnueabihf | Raspberry Pi 2/3, older embedded Linux |
| ARM Cortex-M4/M7 | thumbv7em-none-eabihf | STM32, NXP — FreeRTOS, Zephyr |
| x86-32 | i686-unknown-linux-gnu | Legacy industrial, 32-bit Linux |
| RISC-V 64 | riscv64gc-unknown-linux-gnu | SiFive, emerging IoT |
| macOS ARM64 | aarch64-apple-darwin | Apple Silicon Mac |
| macOS x86-64 | x86_64-apple-darwin | Intel Mac |
| Windows x86-64 | x86_64-pc-windows-msvc | Native Windows |
A Raspberry Pi test script is available at
sdks/c/scripts/test-raspberry-pi.sh.
Conformance
Section titled “Conformance”The C SDK passes 42 conformance fixtures against the canonical cross-language test vectors (the same set used by Go, TypeScript, Python, and Rust). Run them with:
cargo test --test conformanceAdditional unit tests (null pointers, malformed JSON, round-trips, bad-argument detection):
cargo test --test apiTotal: 100 tests.
Memory management
Section titled “Memory management”Every function that returns a heap-allocated value documents which _free function to call.
NULL is always safe to pass to _free functions.
ratify_human_root_free(root);ratify_agent_free(agent);ratify_delegation_cert_free(cert);ratify_proof_bundle_free(bundle);ratify_verify_result_free(result);ratify_string_free(any_string); /* for *_to_json, *_id, *_status, *_reason */ratify_error_free(err); /* for err_out parameters */Where to next
Section titled “Where to next”- Physical AI guide — embedding the verifier on robots and controllers
- Protocol concepts: Delegate → Present → Verify — every primitive in depth
- Constraints — geo, time, amount, and rate gate vocabulary
- SDK packages — version table and publishing process
- C SDK README — full API reference