EnfinitOSEnfinitOS
DevelopersVerification & trust
Open source · MIT

Auditor SDK — Rust

Fast, offline-first verifier. The crate of choice when verification is on a critical path or in an embedded auditor appliance.

enfinitos-sdk-auditorSubstrate AllRust
Install

Get the SDK

cargo add enfinitos-sdk-auditor

About this status badge

Published on GitHub under MIT. Anyone can fork, verify, fuzz, and ship in production. Used today by external auditors.

README

The developer-facing documentation in full

The same README the SDK package ships with — rendered here at build time so what you read matches exactly what you install.

enfinitos-sdk-auditor (Rust)

EnfinitOS Auditor / Verifier SDK for Rust — a fast, offline-first, cryptographic verification library that regulators, auditors, courts, and third-party compliance tools use to verify signed proof packs issued by EnfinitOS, without having to trust EnfinitOS as a vendor.

Companion to the reference @enfinitos/sdk-auditor TypeScript implementation and enfinitos-sdk-auditor Python implementation. The wire shapes, canonicalisation rules, and verification semantics are deliberately identical: a regulator auditing the same proof pack with any of the three SDKs MUST get the same VALID/INVALID verdict on every step.

Why Rust?

The Python and TypeScript SDKs cover most regulator and customer workflows. The Rust SDK exists to:

  1. Demonstrate offline verification works without our infrastructure. The crate has zero network code. It accepts pinned keys and proof packs from disk, computes a verdict, and shuts down.
  2. Enable high-throughput bulk verification. A central regulator or audit firm replaying millions of proof packs benefits from Rust's throughput and zero-allocation hot paths.
  3. Allow embedding inside an air-gapped audit appliance — the binary is small, dependency-light (5 crates), and has no FFI.

The trust model

"Don't trust us — verify". See the TypeScript README for the full framing. The short version:

  1. We Ed25519-sign every record. The public keys are published.
  2. Every proof receipt is hash-chained.
  3. Metering is a deterministic projection of proof receipts.
  4. Settlement is a deterministic projection of metering.
  5. This crate ships byte-exact replicas of every encoder, projector, and signature primitive the platform uses, and so re-derives every claim independently.

Installation

[dependencies]
enfinitos-sdk-auditor = "0.0.1"

Or — for an air-gapped regulator build — vendor it:

cargo vendor packages/sdks/auditor-rs

The crate has exactly five runtime dependencies, all of which are well-known and well-audited:

CrateWhy
ed25519-dalekPure-Rust Ed25519 signature verify primitive
serde + serde_jsonJSON parse / re-serialise for proof packs
sha2SHA-256 hashing
base64base64url encode/decode for signature + public key
chronoISO-8601 parsing for key validity windows
thiserrorErgonomic error types

Five-minute getting started

use std::fs;
use enfinitos_auditor::{AuditBundle, Auditor, SignedProofPack, VerificationKey};

fn main() {
    // 1. Load the pinned verification key set (regulator path).
    let keys_json = fs::read_to_string("./pinned-keys.json").unwrap();
    let keys: Vec<VerificationKey> = serde_json::from_str(&keys_json).unwrap();

    // 2. Load the proof pack the operator handed over.
    let pack_json = fs::read_to_string("./pack.json").unwrap();
    let pack: SignedProofPack = serde_json::from_str(&pack_json).unwrap();

    // 3. Audit.
    let auditor = Auditor::new(keys);
    let report = auditor.verify_all(&AuditBundle {
        pack,
        metering: None,
        settlement: None,
    });

    // 4. Print verdict.
    println!("{:?}", report.status);
    if report.status != enfinitos_auditor::AuditStepStatus::Valid {
        for s in &report.pack.steps {
            if s.status == enfinitos_auditor::AuditStepStatus::Invalid {
                eprintln!("[{:?}] {}: {}", s.reason, s.target, s.message);
            }
        }
    }
}

Architecture

                ┌─────────────────────────────────────────┐
                │           SignedProofPack JSON          │
                │     (envelope.v1, signed by EnfinitOS)  │
                └────────────────────┬────────────────────┘
                                     │
                                     ▼
                ┌─────────────────────────────────────────┐
                │   serde_json::from_str → SignedProofPack │
                └────────────────────┬────────────────────┘
                                     │
                ┌────────────────────┴────────────────────┐
                │                                         │
                ▼                                         ▼
   ┌────────────────────────────┐         ┌─────────────────────────┐
   │   verify_proof_record × N  │         │   verify_proof_chain    │
   │   (proof_pack.rs)          │         │   (proof_chain.rs)      │
   └────────────────────────────┘         └─────────────────────────┘
                  │
                  ▼
   ┌────────────────────────────┐
   │  verify_metering_projection│
   │     (metering_audit.rs)    │
   └─────────────┬──────────────┘
                 │
                 ▼
   ┌────────────────────────────┐
   │ verify_settlement_reconcil.│
   │   (settlement_audit.rs)    │
   └─────────────┬──────────────┘
                 │
                 ▼
   ┌────────────────────────────┐
   │     FullAuditReport        │
   │   { status, sub-reports }  │
   └────────────────────────────┘

Sample workflows

"I'm a regulator inspecting a campaign's evidence"

let keys = load_pinned_keys();
let auditor = Auditor::new(keys);
let report = auditor.verify_all(&bundle);
// Every step has a stable reason code; cite them in your report.

"I'm an audit firm batch-verifying 100k packs"

let auditor = Auditor::new(keys);
let mut invalid_packs: Vec<String> = Vec::new();
for pack_path in pack_paths {
    let pack: SignedProofPack = serde_json::from_str(
        &std::fs::read_to_string(&pack_path).unwrap(),
    ).unwrap();
    let report = auditor.verify_all(&AuditBundle {
        pack,
        metering: None,
        settlement: None,
    });
    if report.status != AuditStepStatus::Valid {
        invalid_packs.push(pack_path);
    }
}

API reference

Auditor

impl Auditor {
    pub fn new(keys: Vec<VerificationKey>) -> Self;
    pub fn with_directory(dir: KeyDirectory) -> Self;
    pub fn from_runtime_keys_json(json: &str) -> Result<Self, AuditorError>;

    pub fn verify_proof_pack(&self, pack: &SignedProofPack) -> AuditReport;
    pub fn verify_proof_chain(&self, records: &[ProofRecord]) -> ChainAuditReport;
    pub fn verify_metering_projection(
        &self,
        records: &[ProofRecord],
        metering: &MeteringSummary,
        pack_org_id: Option<&str>,
    ) -> ProjectionAuditReport;
    pub fn verify_settlement_reconciliation(
        &self,
        metering: &MeteringSummary,
        settlement: &SettlementSummary,
    ) -> SettlementAuditReport;
    pub fn verify_all(&self, bundle: &AuditBundle) -> FullAuditReport;
}

See src/types.rs for the full data model. Every wire field uses the same JSON name as the TS/Py ports, so a JSON proof pack flows through all three SDKs unchanged.

Error model

Two failure classes (identical to the other SDKs):

  1. Audit failures — pack contents fail verification. Returned inside AuditReport.steps[] with a stable AuditReasonCode. Never panic.
  2. Operational errors — the SDK can't run. Returned as AuditorError with an AuditorErrorCode.

See the TypeScript README for the full stable reason-code table.

Verification

cd packages/sdks/auditor-rs
cargo build      # offline-friendly when ./vendor is populated
cargo test       # runs the integration suite

If cargo isn't available, the source compiles syntactically and is covered by the equivalent test suites in the TS and Python ports.

Cross-language parity

The three SDKs are kept byte-for-byte identical at the wire boundary:

ConcernTypeScriptPythonRust
Canonical proof payloadcanonicaliseProofPayloadcanonicalise_proof_payloadcanonicalise_proof_payload
Sort-key encodercanonicalSortKeyscanonical_sort_keyscanonical_sort_keys
Meter idem keymeterIdemKeymeter_idem_keymeter_idem_key
Settlement idem keysettlementIdemKeysettlement_idem_keysettlement_idem_key
Ed25519 verify@noble/ed25519cryptographyed25519-dalek
Decimal scalingbigint at 10^6int at 10^6i128 at 10^6
Reason codesidentical enumidentical enumidentical enum

A proof pack that verifies VALID in one SDK MUST verify VALID in the other two — the test suite reproduces the same fixtures across languages so regressions are caught immediately.

API reference

Hit the HTTP surface directly

The Auditor SDK — Rust is a thin client over the same governed HTTP API every other SDK calls. The full OpenAPI 3.1 reference lives on the docs site, published alongside the April 2027 platform launch.

Sandbox

Run this SDK against a real tenant

The browser demo at enfinitos.com/sandbox runs today against a shared synthetic tenant. The dedicated developer sandbox — your own persistent tenant, API keys, full HTTP-contract coverage — opens ahead of the April 2027 platform launch.