# Runtime

## What’s a Runtime?

In the vast majority of modern software development, a developer never writes code that directly interacts with the platform it’s running on. Instead, the platforms for which developers write code offer runtimes: easy-to-use (and often standardized) APIs that provide high-level functionality while abstracting away most platform-specific details. Prominent examples include POSIX and `glibc`. Runtimes also provide controlled and abstracted access to platform-specific functionality that developers do need access to, which is especially relevant for the Nexus zkVM.

## The Nexus Runtime

The zkVM runtime environment is most similar to a bare-metal or embedded environment, though it has properties specific to being a zkVM. As is typical for embedded platforms, interaction with the platform (zkVM) is done via raw `ecall`s, custom instructions, and memory-mapped I/O. Uniquely to zkVMs, however, [the memory model changes fundamentally between executions of the same guest program](https://docs.nexus.xyz/zkvm/overview/architecture) (see the aside below). The Nexus runtime is a set of libraries and macros that allows developers to write higher-level programs that can run efficiently and correctly on the Nexus zkVM, agnostic to the subtleties of the zkVM’s varying executions.

{% hint style="info" %}
Aside: the zkVM’s first pass uses a Harvard-like architecture with distinct memory spaces for code, data, inputs, and output. During the first pass, the zkVM collects statistics about exactly how much memory is used in each of these spaces. Before the second pass, the zkVM lays out the program’s memory in a single address space whose size is minimized based on the statistics collected during the first pass. Because proving memory is expensive, this process significantly reduces proof sizes and proving times. The second pass maintains memory protections but uses a single address space for all memory segments.
{% endhint %}

More specifically, the Nexus runtime consists of a few parts:

* Macros that allow developers to work easily with input and output, which are memory-mapped and directly managed by the zkVM.
* A `main` macro that ensures the guest program’s `main` function can be correctly located and run by the zkVM.
* `print!` / `println!` macros that write to an output log, implemented by the zkVM via an `ecall`.
* A `#[panic_handler]`, required by Rust’s `core`, implemented by the zkVM via an `ecall`.
* A `#[global_allocator]` that operates correctly across the zkVM’s memory models.
* An assembly entry point for the program that configures zkVM-specific global state and calls the guest program’s `main` function; this ensures stack, heap, and input/output segments are usable during both passes of execution.
* Well-known locations that correspond to particular memory-mapped values provided or read by the zkVM.

The rest of this section discusses these components in more detail and with examples. For even more detail, see [the VM specification](https://docs.nexus.xyz/zkvm/specifications/the-complete-specification).

### Notable Macros & Functions

#### Main

The `nexus_rt::main` attribute marks the entry point of the guest program. It is a procedural macro that:

* Ensures that the main function can be located and run by the runtime’s entry-point assembly by re-exporting the main function with a non-mangled, well-known name referenced by the runtime’s entry-point assembly.
* Generates code that automatically reads in all inputs and writes to the output. Unless specified otherwise, inputs default to private.
* Re-orders the function’s attributes to ensure that input type specifications are evaluated before the `main` macro generates code that reads them.

Example use:

```rust
#[nexus_rt::main]
fn main(x: u32, y: u32) -> bool {
    x > y
}
```

The `main` macro also handles the program’s public output, which is simply the value returned from `main`. The macro internally uses the `write_public_output` function to serialize the output and write it to the output tape. The public output is written by the Nexus runtime’s `write_public_output`, which is a function that serializes the program’s output in a [COBS](https://en.wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing) representation [generated by](https://docs.rs/postcard/latest/postcard/fn.to_allocvec_cobs.html) [`postcard`](https://crates.io/crates/postcard).

The serialized bytes are written to the output tape using the Nexus runtime’s `write_output!(byte_index, value)` macro, which writes a byte-addressed word to the output tape by:

{% stepper %}
{% step %}
Read the public output address from well-known location `PUBLIC_OUTPUT_ADDRESS_LOCATION`.
{% endstep %}

{% step %}
Add `byte_index` to that address.
{% endstep %}

{% step %}
Emit a `wou` instruction, whose behavior depends on zkVM execution mode:

* In the zkVM’s first pass (Harvard-like architecture), `wou` writes the word to a unique memory address space that only contains public output.
* In the second pass, the zkVM replaces the binary’s `wou` instructions with ordinary `sw` instructions that write the output values from a location calculated and populated by the zkVM using data collected from the first pass.
  {% endstep %}
  {% endstepper %}

#### Public Input

Public inputs are input values known to the verifier, specified as arguments to `#[nexus_rt::main]` and tagged with `#[nexus_rt::public_input]`.

Example use:

```rust
#[nexus_rt::main]
#[nexus_rt::public_input(x)]
fn main(x: u32, y: u32) -> bool {
    x > y
}
```

In this example, `x` is a public input while `y` is private.

Public inputs are read by the Nexus runtime’s `read_public_input`, which reads the entire public input tape and [deserializes](https://docs.rs/postcard/latest/postcard/fn.from_bytes_cobs.html) it from a [COBS](https://en.wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing) representation [produced by](https://docs.rs/postcard/latest/postcard/fn.to_allocvec_cobs.html) [`postcard`](https://crates.io/crates/postcard).

The serialized bytes are read using the Nexus runtime’s `read_input!(byte_index)` macro, which reads a byte-addressed word from the serialized public input by:

{% stepper %}
{% step %}
Read the public input address from well-known location `PUBLIC_INPUT_ADDRESS_LOCATION`.
{% endstep %}

{% step %}
Add `byte_index` to that address.
{% endstep %}

{% step %}
Emit a `rin` instruction, whose behavior depends on zkVM execution mode:

* In the zkVM’s first pass (Harvard-like architecture), `rin` reads the word from a unique memory address space which only contains public input.
* In the second pass, the zkVM replaces the binary’s `rin` instructions with ordinary `lw` instructions that read the input values from a location calculated and populated by the zkVM using data collected from the first pass.
  {% endstep %}
  {% endstepper %}

#### Private Input

Private inputs are input values known only to the prover. They are specified as arguments to `#[nexus_rt::main]` and optionally tagged with `#[nexus_rt::private_input]`. Arguments default to being private, but developers can explicitly mark them private for clarity.

Example use:

```rust
#[nexus_rt::main]
#[nexus_rt::private_input(y)]
fn main(x: u32, y: u32) -> bool {
    x > y
}
```

In this example, both `x` and `y` are private inputs.

Private inputs are read by the Nexus runtime’s `read_private_input`, which sequentially reads a single byte from the private input tape via an `ecall`, returning `None` after each byte has been read once. The runtime provides no further special handling for private inputs; guest program developers are expected to handle the interpretation of the private input tape themselves.

#### Host-Native Execution

It is often useful to run and debug guest programs in a native environment (e.g., `cargo run`). The Nexus runtime itself cannot run outside the zkVM, but its macros support native handlers—functions compiled and executed only when the guest program is run natively on the host. These functions generate inputs and handle outputs without the zkVM’s presence.

Example:

```rust
#![cfg_attr(target_arch = "riscv32", no_std, no_main)]

#[cfg(not(target_arch = "riscv32"))]
fn native_input_handler() -> Option<u32> {
    let mut input = String::new();

    std::io::stdin().read_line(&mut input).ok()?;

    Some(input.trim().parse().ok()?)
}

#[cfg(not(target_arch = "riscv32"))]
fn native_output_handler(output: &u32) -> Option<()> {
    println!("Output: {}", output);

    Some(())
}

#[nexus_rt::main]
#[cfg_attr(target_arch = "riscv32", nexus_rt::public_input(x))]
#[cfg_attr(not(target_arch = "riscv32"), nexus_rt::custom_input(x, native_input_handler))]
#[cfg_attr(not(target_arch = "riscv32"), nexus_rt::custom_input(y, native_input_handler))]
#[cfg_attr(not(target_arch = "riscv32"), nexus_rt::custom_output(native_output_handler))]
fn main(x: u32, y: u32) -> u32 {
    x ^ 0xdeadbeef
}
```

This allows running the program natively to ensure correctness without relying on the zkVM’s limited debugging capabilities.

#### Functionality in a `no_std` Environment

The Nexus zkVM has no operating system and cannot implement large portions of the Rust standard library, so guest programs must be `no_std`. To help developers, the Nexus runtime implements particular parts of the Rust runtime:

* A simple global allocator and implementations for `panic` and `abort`, as required by `core`.
* Simple `print!` and `println!` implementations that wrap zkVM-specific system calls for logging.

In the future, the team plans to enable `std` for the Nexus zkVM where appropriate by gating functionality dependent on an operating system or incompatible with provable computation. For example, there are no plans to enable multi-threading or general I/O, but certain `std` functionality useful for the zkVM (e.g., some system calls like `exit`, algorithms, and data structures) may be supported.

### Memory Allocation

The Nexus runtime implements a simple allocator required for any data structures that rely on heap allocations (i.e., those in `alloc`). Currently, it uses a naive bump allocator that allocates bottom-up and never deallocates.

## Assumptions

Despite the conveniences offered by the Nexus runtime, there are still some requirements for guest programs:

* The guest program must depend on `nexus-rt` and provide a `nexus_rt::main`-decorated function as the entry point. Without these, the zkVM can’t properly load the program and behavior is undefined.
* The guest program must be annotated with `no_std` and `no_main` when compiled for the zkVM (i.e., for a `riscv32` target architecture).
* The guest program’s code must be position-independent (compiled with `-fPIC`).

The Nexus `cargo` CLI tool ensures these requirements are met for projects it creates; initializing projects with it is highly recommended.

Further reading:

* [SDK Documentation](https://docs.nexus.xyz/zkvm/development/broken-reference)
* [Precompiles](https://docs.nexus.xyz/zkvm/development/precompiles)
