Skip to content

Architecture

How Nanorix produces AuditProofs for regulated data workloads.


Core concept

A capsule is a sealed ephemeral workspace — an isolated Linux-namespace environment where regulated data lives, works, and dies. Customers route sensitive data (PHI, PII, financial, credentials) through capsules: upload data, run computation with their own code, get results out, then destroy. Every capsule produces an AuditProof: cryptographic evidence the destruction happened.

The capsule is the product. The AuditProof is the evidence.


Capsule lifecycle

┌─────────────┐     ┌──────────────┐     ┌─────────────┐     ┌──────────────┐
│   create    │ →   │   execute    │ →   │   destroy   │ →   │  AuditProof  │
└─────────────┘     └──────────────┘     └─────────────┘     └──────────────┘
   POST                 POST                 DELETE              GET
   /v1/capsules         /v1/capsules/        /v1/capsules/       /v1/proofs/
                          :id/exec             :id                 :id
  1. Create. Customer declares data_classification ("PHI" / "PII" / "financial" / "credentials" / "general") + jurisdiction ("US" / "EU" / "UK" / "CA" / "AU" / "IN" / "OTHER"). Optional: reference a Capsulefile (frozen environment definition) by capsulefile_id.
  2. Execute. Customer uploads input files, runs commands inside the capsule, downloads output files. Every outbound HTTPS call goes through the sealed daemon — a per-capsule sidecar that records every request as a SealedHttpRequest activity event in the AuditProof.
  3. Destroy. Customer issues DELETE /v1/capsules/:id. The capsule executes the 8-step destruction chain — namespace teardown, tmpfs unmount, multi-pass DoD-5220 memory wipe, key incineration, forensic verification — and emits the AuditProof.
  4. AuditProof. Customer retrieves the signed proof via GET /v1/proofs/:id (full proof, requires auth) or GET /v1/capsules/:id/cdp/verify (verification proof — public, rate-limited). Anyone with the proof can verify it offline using the nanorix verify CLI or the offline verifier modules in the Python + TypeScript SDKs.

Defense-in-depth (Linux isolation)

Each capsule runs inside a stack of Linux kernel isolation primitives:

Layer Mechanism What it blocks
6 Seccomp-BPF Syscalls outside the ~70-call allowlist
5 Cgroup v2 Memory limits, swap=0, OOM-group kill semantics
4 Network namespace Ambient network access (sealed by default; egress-filtered when an allowlist is declared)
3 UTS namespace Hostname disclosure (randomized per capsule)
2 Mount namespace Host filesystem visibility (private tmpfs only)
1 User namespace Privileged operations (UID-mapped to unprivileged)
0 Crypto shredding Multi-pass overwrite + Ed25519 attestation

The kernel enforces these primitives. Nanorix doesn't reimplement isolation — we compose what the Linux kernel already provides and bind the result into a cryptographic proof.


AuditProof structure

The AuditProof is an 8-step SHA-512 hash chain plus an Ed25519 signature over the chain. Each step records the destruction of one subsystem.

Step 1: eee_namespace        method: procfs_verification
Step 2: eee_tmpfs            method: mountinfo_verification
Step 3: eee_memory           method: dod_5220_multipass_wipe
Step 4: dire_keys            method: ed25519_key_destruction
Step 5: dire_identity        method: credential_incineration
Step 6: fgx_forensic         method: merkle_tree_verification
Step 7: rzl_audit            method: hash_chain_validation
Step 8: capsule_destroy      method: capsule_lifecycle_verification

Each step's hash is computed over the previous step's hash plus the step's subsystem + method + timestamp:

chain_hash[i] = SHA-512(
    chain_hash[i-1] || subsystem || "destroy" || method || timestamp
)
chain_hash[0] = SHA-512("")  (genesis hash)

The Ed25519 signature is over chain_hash[7] rendered as ASCII hex (128 bytes — not raw binary). This is required for cross-implementation verifier compatibility: Rust + Python + TypeScript verifiers compute byte-identical hashes against the same canonical input.

The full canonical-JSON form bound into the signature uses RFC 8785 JCS (JSON Canonicalization Scheme) via serde_jcs. This guarantees: re-canonicalize the same logical JSON object on any supported platform, get the same bytes, get the same hash, get the same signature verification result.


Activity trail

Beyond the AuditProof, every meaningful operation inside the capsule emits one or more ActivityEvent variants into an activity_trail array bound into the AuditProof's canonical hash. Variants currently shipped:

  • CapsuleStarted — capsule init, with data_classification, jurisdiction, region.
  • FileUploaded / FileDownloaded — per-file SHA-512 hash + size + direction.
  • ExecutionStarted / ExecutionCompleted / ExecutionOomKilled — per-exec lifecycle bounds.
  • SealedHttpRequest — per outbound HTTPS call. Carries request canonical hash, response body hash, TLS metadata (version, cipher, peer cert SHA-256, validation outcome), duration.
  • StreamingEgressStarted / StreamingEgressChunk / StreamingEgressCompleted / StreamingPolicyViolation — per-chunk SHA-512 + RFC 6962 Merkle root for SSE / chunked-transfer responses.
  • PostgresQueryExecuted / RedisCommandExecuted / MqttMessagePublished / DicomCStoreCompleted / RawTcpConnectionCompleted — per-protocol attestation for non-HTTP TCP egress.
  • McpToolInvoked — per MCP tools/call invocation. Carries tool_name, tool_args_hash (SHA-512 of canonical JSON of arguments), tool_result_hash (SHA-512 of canonical JSON of result content), duration_ms, outcome, client_session_id.
  • BatchRecordProcessed / BatchCompleted — per-record outcome + Merkle-root binding for batched-into-capsule pipelines.
  • MemoryArtifactLoaded / MemoryArtifactPersisted — for multi-capsule agents using the memory artifact pattern.
  • InputProvenanceVerified / InputProvenanceRejected — when input manifests with cryptographic provenance are declared.
  • SecretsInjected / SecretsInjectionRejected — for env-vars-as-secrets declarations.
  • DestructionInitiated — final event before the destruction chain runs.

Egress model

By default, capsules have no network. When a customer declares an egress allowlist (Team tier and above), a persistent network namespace is created with filtered outbound network access.

Inside the capsule, all outbound HTTPS flows through a sealed egress layer that:

  • Enforces the destination allowlist (defense-in-depth: runtime egress profile AND per-Capsulefile egress_declaration both must allow).
  • (For MCP-aware capsules) enforces the Capsulefile's mcp_policy.allowed_tools whitelist + mcp_policy.prohibited_tools blocklist on outbound JSON-RPC tools/call envelopes.
  • Pins TLS using per-host SHA-256 fingerprints declared in the Capsulefile.
  • Records each request as a SealedHttpRequest activity event with the cryptographic shape (request canonical hash, response body hash, TLS metadata, duration).
  • (For MCP-aware capsules) emits a per-tool-call McpToolInvoked event with cryptographic args + result hashes.

The capsule cannot bypass this layer — kernel-level isolation denies raw socket access and the network namespace has no default route.


Metadata + customer attestation

Capsules can carry customer-defined metadata (open string-keyed map) — Nanorix prescribes no structured keys (no patient_id, no matter_id, etc.). Customer-defined vocabulary; 4 KB total limit; the nanorix:* prefix is reserved.

For per-event customer attestation, Capsulefiles can declare a signing_config.endpoint — an HTTPS+mTLS service the customer hosts. Each ActivityEvent triggers one POST to that endpoint with the event's canonical hash; the customer's KMS-backed signing service returns an Ed25519 or RSA-PSS signature. Nanorix fire-and-buffers; signatures absorb at capsule destroy and bind into the AuditProof's per-event attestation reserved slot.

This produces two-party attestation: Nanorix attests to the boundary, the customer attests to each event with a key Nanorix never sees.


Compliance binding

The nanorix.compliance SDK module produces a regulatory_context reference map binding an AuditProof's activity trail to specific articles of regulatory frameworks: HIPAA Security Rule §164.312, GDPR Articles 5 / 9 / 25 / 30 / 32, SOC 2 Trust Services Criteria CC6 + CC7. The module uses related_to language only — never asserts compliance status. Customer's compliance officer makes the final determination.

The reference module is a static map — Nanorix does not execute compliance evaluations against customer data. The reference frame is the customer's audit prep tool, not a substitute for an audit.


What this means in practice

  • The design thesis: route the regulated fraction of your operations (typically a minority of workloads) through capsules, and let that fraction carry the bulk of your compliance evidence burden.
  • The customer's ML/AI workloads, business logic, and data shape are theirs — Nanorix does not inspect, classify, or score data content.
  • The customer holds compliance authority. Nanorix produces evidence; the customer's compliance team interprets it.
  • Verifiers (regulators, auditors, customers' compliance partners) can replay the AuditProof offline using the Rust CLI, the Python SDK module, or the TypeScript SDK module — all three reproduce identical hash chains via RFC 8785 + RFC 6962.

Where to go next