Every LLM provider says your data is "encrypted." Almost none of them tell you from whom. TLS encrypts your prompt from the coffee-shop Wi-Fi, not from the provider. "Encrypted at rest" protects against a stolen disk, not against the platform reading its own database. If you're sending contracts, medical notes, or unreleased source code through an inference API, the question that matters is narrower: who, at any point in the job's life, holds both your data and the key that opens it?
This post answers that question for MicroDC.ai's encrypted jobs, precisely. No hand-waving, and no claims we can't back with the actual code paths.
One thing no provider can avoid.
Let's clear this up first, because it's the most common misconception we hear: the model must see plaintext. An LLM computes on tokens; there is no homomorphic-encryption scheme that runs a 70B-parameter transformer on ciphertext at practical speed. Anyone who implies their model reads encrypted prompts is selling you something that doesn't exist.
So the real design question is not "can the model avoid seeing the data" — it can't, anywhere, on any platform — but "how small can we make the circle of machines that ever hold plaintext, and how do we keep everything outside that circle cryptographically blind?" Our answer: the circle is exactly two machines. Yours, and one MicroDC-managed worker with no external network path for your data.
The cast of keys.
An encrypted job involves three keys. Keeping them straight makes everything else obvious.
- Your RSA keypair. Generated by the Python client on your machine — 4096-bit by platform convention. The public key travels with the job; the private key never leaves your machine. Ever. We have no endpoint that could receive it.
- The payload key. An AES-256 key, generated on your machine, used with AES-256-GCM (96-bit IV) to encrypt the request payload before transmission.
- The result key. A brand-new AES-256 key generated on the worker, per job, used once to encrypt the result, then wrapped with your RSA public key using OAEP (SHA-256) and discarded.
Step by step: the life of an encrypted job.
1. Your machine encrypts.
Before the request leaves your process, the client encrypts the payload — messages, documents, everything sensitive — with the payload key under AES-256-GCM. GCM is authenticated encryption: tampering with the ciphertext in transit or at rest is detectable, not just unreadable. The job submission carries the ciphertext, the IV, and your RSA public key.
2. The server stores ciphertext and routes blind.
The platform stores the encrypted payload as an opaque blob. It does not — and by design cannot usefully — inspect the contents for routing: encrypted jobs are automatically routed to the highest context tier because the server can't even see how long your prompt is. Job contents are never written to logs; our logging paths explicitly skip payload fields when a job is flagged encrypted.
The payload key is escrowed server-side alongside the job, for one purpose: handing it to the worker that claims the job. We'll come back to this, because it's the part of the design that deserves scrutiny.
3. Only managed workers can claim.
MicroDC.ai is a distributed marketplace — community operators run most of the fleet. Encrypted jobs never touch that pool. A worker becomes eligible for encrypted work only when its encryption capability has been both approved by a platform administrator and confirmed by the worker at runtime. Both flags are required; either one alone routes zero encrypted jobs. In practice this capability is granted exclusively to workers that MicroDC operates end to end — hardware we control, images we build, nodes we monitor.
Workers without the capability don't just fail to claim encrypted jobs — the scheduler filters encrypted jobs out of their available-job list entirely. They never see that the job exists. And if an unapproved worker tries to claim one anyway, the claim is rejected server-side — the eligibility check runs again at claim time, not just at listing time.
4. The worker decrypts in memory and runs locally.
On claim, the worker receives the payload key and IV, decrypts the payload in memory, and runs inference against a model hosted on that machine — the inference engines themselves are encryption-unaware; they see a normal plaintext prompt that never existed outside RAM. The decrypted prompt is never sent to a third-party API, never proxied through another service, never written to disk as plaintext. Worker logs record sizes and metadata only — never key material, decrypted payloads, or plaintext results. The model that reads your prompt is silicon we manage, in the same box that did the decryption.
5. The result is encrypted to you — and only you.
This is the strongest link in the chain. The worker generates a fresh one-time AES-256 key and a random 96-bit IV, encrypts the result with them, wraps that key with your RSA public key (RSA-OAEP, MGF1 + SHA-256), and submits the bundle. From that moment, the result is readable by exactly one key on Earth: the private key sitting on your machine.
The hybrid construction isn't a design preference — it's required. RSA can't encrypt bulk data: a 4096-bit key caps out at 446 bytes per OAEP-SHA-256 operation. So RSA seals only the 32-byte result key, and that key encrypts the arbitrarily-sized result. The wrapped key travels inside the result blob itself:
encrypted_output = base64(
<4-byte big-endian uint: length of wrapped_key>
<wrapped_key: RSA-OAEP(MGF1+SHA-256) of the 32-byte AES key>
<ciphertext: AES-256-GCM(result JSON), 16-byte GCM tag appended>
)
result_iv = base64(<12-byte GCM IV>)
Your client mirrors the packing to decrypt: read the length prefix, split off the wrapped key, unwrap it with your RSA private key, then AES-256-GCM-decrypt the remainder. The SDK does all of this for you — the format is documented so your security team can verify it independently.
Not the worker (it discards the result key). Not the platform (we never had your private key). Not MicroDC under subpoena, not a malicious insider, not an attacker with a full copy of our database. This isn't policy — it's arithmetic. We rely on it ourselves: our billing pipeline can't inspect encrypted results even for its own bookkeeping, and has a dedicated code path because of it.
6. Acknowledgment burns the evidence.
When your client fetches the result and acknowledges the job, the platform deletes the escrowed key record and purges the encrypted payload and result blobs. What remains is billing metadata — token counts, timestamps, model name. That metadata is cleartext by design: the server can't count tokens in ciphertext, so the worker reports estimated token counts alongside the encrypted result, and job type, model, and timings stay readable so scheduling, routing, and billing work without ever decrypting content. The content itself, and every means of recovering it, is gone.
The honest part: cryptography vs. operational trust.
Here's the section most providers won't write, and the reason you can trust the rest of this post.
The result path is zero-knowledge in the strict sense: the platform is cryptographically incapable of reading results, because decryption requires a private key we never possess.
The request path is not, and we won't pretend otherwise. The payload key transits the server and sits in escrow until the job is acknowledged — that's how the claiming worker gets it. During that window, a hypothetical MicroDC that violated its own design could combine the escrowed key with the stored ciphertext and read your prompt. We don't: no code path does it, contents are never logged, and the key is destroyed at acknowledgment. But for the request payload, "we can't" is really "we don't, verifiably narrow window, deleted on ack" — an operational guarantee, not a mathematical one.
| Stage | Who could read it | Guarantee type |
|---|---|---|
| Prompt in transit | No one (AES-256-GCM + TLS 1.3) | Cryptographic |
| Prompt at rest, pre-claim | You; the platform if it broke its design (escrowed key) | Operational |
| Prompt during inference | The one managed worker running your job | Operational (managed hardware, no external egress) |
| Result, everywhere after the worker | You, and no one else | Cryptographic |
| Everything after acknowledgment | No one (keys and blobs purged) | Cryptographic (data no longer exists) |
Why does the request key touch the server at all? Because the alternative — a key-exchange handshake directly between your client and a worker that hasn't been chosen yet — requires workers to hold long-lived identity keypairs and clients to verify them, which is a meaningfully larger trust surface for community-scale hardware. Direct client-to-worker key wrapping is on our roadmap; it will convert the one operational cell in that table to a cryptographic one. We'd rather ship the honest version of today's table than a flattering description of a system we haven't built.
Using it.
One flag. The SDK handles key generation, encryption, and result decryption transparently:
from microdc import Client
client = Client(api_key=os.environ["MDC_KEY"])
job = client.jobs.create(
model="llama-3.3-70b",
messages=[{"role": "user", "content": confidential_prompt}],
encrypt=True,
)
result = client.jobs.wait(job.id) # decrypted locally with your private key
client.jobs.acknowledge(job.id) # purges keys + blobs server-side
Encrypted jobs require the encryption entitlement on your account — it's enabled on request so we can make sure managed-worker capacity matches demand. Ask us to turn it on.
The takeaway.
Every inference provider's model sees your plaintext — that's physics, not a vendor choice. What differs is everything around it. On MicroDC.ai, plaintext exists in exactly two places: your machine, and one MicroDC-managed worker with no external path for your data. The platform in between routes ciphertext, holds the payload key only in a deletion-bounded escrow, and receives results it is mathematically incapable of reading. And when you acknowledge the job, even the ciphertext stops existing.
If your security team wants to go deeper — key sizes, claim-time gating, purge semantics — send them this post, then put them in a room with our engineers. We built it to survive that conversation.
Encryption in the developer guide → Try it with free credits →