Runner ​
The Runner is a Rust service running in Intel TDX that executes confidential computations on encrypted data. It pulls computation requests from a NATS JetStream queue — populated by the Ingestor from on-chain events — decrypts the input handles, performs the operation, encrypts the results, and stores them back in the Handle Gateway.
Role in the Protocol ​
The Runner is the computation engine of the Nox protocol. It is the only component that manipulates plaintext values (in memory, never on disk). For supported Solidity types, it produces results identical to their on-chain equivalents. The off-chain execution model also opens the door to operations not natively supported by the EVM (e.g. larger integer types).
Current Implementation
The current implementation runs a single Runner. In the long-term architecture, multiple Runners will operate in parallel, coordinated by a TDX orchestrator that assigns tasks and supervises execution.
How It Works ​
- Pull event from NATS: the Runner fetches the next
TransactionMessagecontaining input handles, output handles, and the operation to perform. - Fetch operands from the Handle Gateway: the Runner sends its RSA public key, and the Handle Gateway handles KMS delegation internally, returning the ciphertext, encrypted shared secret, and nonce for each input handle.
- Decrypt inputs locally (RSA decrypt shared secret, HKDF, AES-GCM).
- Execute the computation primitive.
- Encrypt results with ECIES using the protocol public key.
- Submit encrypted results to the Handle Gateway.
- Acknowledge the event in NATS (removes it from the queue) and pull the next one.
PlaintextToEncrypted (Special Case) ​
This operation has no input handles and does not need to call the Handle Gateway to fetch operands. The plaintext value and target type of the data to encrypt are embedded directly in the NATS event. The Runner performs the ECIES encryption, then forwards encrypted data and crypto materials to the Handle Gateway.
Handle Requirements ​
Each operation defines its input/output handles:
| Operation | Inputs | Outputs | Description |
|---|---|---|---|
| PlaintextToEncrypted | 0 | 1 | Encrypt a plaintext value |
| Arithmetic (add…) | 2 | 1 | Two operands → one result |
| Safe arithmetic | 2 | 2 | Two operands → (success, result) |
| Comparisons | 2 | 1 | Two operands → bool result |
| Select | 3 | 1 | (condition, ifTrue, ifFalse) → one |
| Transfer | 3 | 3 | (amount, balFrom, balTo) → 3 |
| Mint | 3 | 3 | (amount, balTo, supply) → 3 |
| Burn | 3 | 3 | (amount, balFrom, supply) → 3 |
Validation rules:
- All input handles must exist in the Gateway database
- All output handles must not exist in the Gateway database
Computation Primitives ​
All arithmetic uses wrapping semantics, matching Solidity's unchecked behavior. On overflow or underflow, values wrap around the type boundary instead of reverting. Token operations (Transfer, Mint, Burn) never revert either: they silently cap at available balances to prevent leaking information.
For the complete reference of all operations, including Solidity signatures, edge cases and examples, see the Solidity Library.
Learn More ​
- Solidity Library - Full reference of all operations with signatures and edge cases
- Handle Gateway - Handle storage and encryption
- KMS - Key management and decryption delegation
- Nox Smart Contracts - On-chain computation requests
- Global Architecture Overview
