Skip to content

Commit

Permalink
free input data (#2239)
Browse files Browse the repository at this point in the history
This PR allows for free runtime data besides free compile time data,
based on `initial_memory`.

- Replaces `cbor` by `bincode` in prover queries (bincode is more
efficient and cbor crashed with `u128`)
- Allows the prover to pass a runtime initial memory, only possible with
continuations (from #2251, was
already merged into here, see commits list)
- Changes the `powdr` lib, which already always uses continuations, to
always use this mechanism for prover data
- Provides a new stdin-stream-like function to read inputs in sequence,
like other zkVMs.
- The function above is called `read_stdin` which I'm not super happy
with, ideally it'd just be called `read` but the QueryCalldata function
is already called `read`. I think we could just keep this as is and
change later.

---------

Co-authored-by: Lucas Clemente Vella <[email protected]>
  • Loading branch information
leonardoalt and lvella authored Dec 30, 2024
1 parent 816e8c7 commit c8d2703
Show file tree
Hide file tree
Showing 31 changed files with 551 additions and 73 deletions.
10 changes: 8 additions & 2 deletions .github/workflows/pr-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,14 @@ jobs:
run: rustup target add riscv32imac-unknown-none-elf --toolchain nightly-2024-08-01-x86_64-unknown-linux-gnu
- name: Install test dependencies
run: sudo apt-get update && sudo apt-get install -y binutils-riscv64-unknown-elf lld
- name: Run examples
run: cargo run --profile pr-tests --example hello_world && cargo run --profile pr-tests --example sqrt_with_publics && cargo run --profile pr-tests --example fibonacci
- name: Run examples that cargo accepts as examples
run: cargo run --profile pr-tests --example hello_world && cargo run --profile pr-tests --example sqrt_with_publics
- name: Run crate example serialized_inputs with the given branch
run: cd powdr-test/examples/serialized-inputs && cargo run -r
- name: Run crate example fibonacci with the given branch
run: cd powdr-test/examples/fibonacci && cargo run -r
- name: Run crate example fibonacci with the latest powdr release
run: cd examples/fibonacci && cargo run -r

test_estark_polygon:
needs: build
Expand Down
15 changes: 15 additions & 0 deletions pipeline/src/pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ pub struct Pipeline<T: FieldElement> {
arguments: Arguments<T>,
/// The context for the host.
host_context: HostContext,
/// Initial memory given by the prover.
initial_memory: Vec<Vec<u8>>,
}

impl<T: FieldElement> Clone for Artifacts<T> {
Expand Down Expand Up @@ -193,6 +195,7 @@ where
pilo: false,
arguments: Arguments::default(),
host_context: ctx,
initial_memory: vec![],
}
// We add the basic callback functionalities to support PrintChar and Hint.
.add_query_callback(Arc::new(handle_simple_queries_callback()))
Expand Down Expand Up @@ -322,6 +325,18 @@ impl<T: FieldElement> Pipeline<T> {
self
}

/// Adds data to the initial memory given by the prover.
/// This is a more efficient method of passing bytes from the host
/// to the guest.
pub fn add_to_initial_memory(mut self, data: Vec<u8>) -> Self {
self.initial_memory.push(data);
self
}

pub fn initial_memory(&self) -> &[Vec<u8>] {
&self.initial_memory
}

pub fn add_data<S: serde::Serialize>(self, channel: u32, data: &S) -> Self {
let bytes = serde_cbor::to_vec(&data).unwrap();
self.add_query_callback(Arc::new(serde_data_to_query_callback(channel, bytes)))
Expand Down
25 changes: 25 additions & 0 deletions powdr-test/examples/fibonacci/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[package]
name = "fibonacci"
version = "0.1.0"
edition = "2021"

[features]
default = []
simd = ["powdr/plonky3-simd"]

[dependencies]
powdr = { path = "../../../powdr", features = ["plonky3"] }

serde = { version = "1.0", default-features = false, features = [
"alloc",
"derive",
"rc",
] }
serde_cbor = { version = "0.11.2", default-features = false, features = [
"alloc",
] }

env_logger = "0.10.2"
log = "0.4.17"

[workspace]
9 changes: 9 additions & 0 deletions powdr-test/examples/fibonacci/guest/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "powdr-guest"
version = "0.1.0"
edition = "2021"

[dependencies]
powdr-riscv-runtime = { path = "../../../../riscv-runtime", features = ["std"]}

[workspace]
20 changes: 20 additions & 0 deletions powdr-test/examples/fibonacci/guest/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use powdr_riscv_runtime;
use powdr_riscv_runtime::commit;
use powdr_riscv_runtime::io::{read, write};

fn fib(n: u32) -> u32 {
if n <= 1 {
return n;
}
fib(n - 1) + fib(n - 2)
}

fn main() {
// Read input from stdin.
let n: u32 = read();
let r = fib(n);
// Write result to stdout.
write(1, r);
// Commit the result as a public.
commit::commit(r);
}
2 changes: 2 additions & 0 deletions powdr-test/examples/fibonacci/rust-toolchain.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[toolchain]
channel = "nightly-2024-09-21"
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ fn main() {

let n = 11;
let mut session = Session::builder()
.guest_path("./examples/fibonacci/guest")
.guest_path("./guest")
.out_path("powdr-target")
.build()
.write(0, &n);
.write(&n);

// Fast dry run to test execution.
session.run();
Expand All @@ -24,9 +24,6 @@ fn main() {
let publics = session.publics();
assert_eq!(
publics,
[
555233681, 1854640251, 3298928347, 2857173302, 2660189392, 1608424695, 543896544,
3870154745
]
[555233681, 1854640251, 3298928347, 2857173302, 2660189392, 1608424695, 543896544, 3870154745]
);
}
22 changes: 22 additions & 0 deletions powdr-test/examples/serialized-inputs/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[package]
name = "serialized-inputs"
version = "0.1.0"
edition = "2021"

[features]
default = []
simd = ["powdr/plonky3-simd"]

[dependencies]
powdr = { path = "../../../powdr", features = ["plonky3"] }

serde = { version = "1.0", default-features = false, features = [
"alloc",
"derive",
"rc",
] }

env_logger = "0.10.2"
log = "0.4.17"

[workspace]
15 changes: 15 additions & 0 deletions powdr-test/examples/serialized-inputs/guest/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[package]
name = "powdr-guest"
version = "0.1.0"
edition = "2021"

[dependencies]
powdr-riscv-runtime = { path = "../../../../riscv-runtime", features = ["std"]}

serde = { version = "1.0", default-features = false, features = [
"alloc",
"derive",
"rc",
] }

[workspace]
16 changes: 16 additions & 0 deletions powdr-test/examples/serialized-inputs/guest/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use powdr_riscv_runtime;
use powdr_riscv_runtime::io::read;

#[derive(serde::Serialize, serde::Deserialize)]
struct Data {
numbers: Vec<u32>,
sum: u32,
}

fn main() {
let data: Data = read();
let s: String = read();

assert_eq!(data.numbers.iter().sum::<u32>(), data.sum);
assert_eq!(s, "test");
}
2 changes: 2 additions & 0 deletions powdr-test/examples/serialized-inputs/rust-toolchain.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[toolchain]
channel = "nightly-2024-09-21"
32 changes: 32 additions & 0 deletions powdr-test/examples/serialized-inputs/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use powdr::Session;

#[derive(serde::Serialize, serde::Deserialize)]
struct Data {
numbers: Vec<u32>,
sum: u32,
}

fn main() {
env_logger::init();

let some_data = Data {
numbers: vec![1, 2, 3, 4, 5],
sum: 15,
};

let s: String = "test".to_string();

let mut session = Session::builder()
.guest_path("./guest")
.out_path("powdr-target")
.chunk_size_log2(18)
.build()
.write(&some_data)
.write(&s);

// Fast dry run to test execution.
session.run();

// Uncomment to compute the proof.
//session.prove();
}
6 changes: 5 additions & 1 deletion powdr/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ serde = { version = "1.0", default-features = false, features = [
"derive",
"alloc",
] }
serde_cbor = "0.11.2"

[features]
default = ["halo2", "plonky3"]
Expand All @@ -39,7 +40,10 @@ estark-polygon = [
stwo = ["powdr-backend/stwo", "powdr-pipeline/stwo"]

plonky3-simd = ["powdr-backend/plonky3-simd", "powdr-pipeline/plonky3-simd"]
estark-starky-simd = ["powdr-backend/estark-starky-simd", "powdr-pipeline/estark-starky-simd"]
estark-starky-simd = [
"powdr-backend/estark-starky-simd",
"powdr-pipeline/estark-starky-simd",
]

[lints.clippy]
uninlined_format_args = "deny"
Expand Down
17 changes: 13 additions & 4 deletions powdr/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,17 @@ impl Session {
}
}

pub fn write<S: serde::Serialize>(self, channel: u32, data: &S) -> Self {
Session {
pipeline: self.pipeline.add_data(channel, data),
pub fn write<S: serde::Serialize>(self, data: &S) -> Self {
let bytes = serde_cbor::to_vec(&data).unwrap();
Self {
pipeline: self.pipeline.add_to_initial_memory(bytes),
..self
}
}

pub fn write_bytes(self, bytes: Vec<u8>) -> Self {
Self {
pipeline: self.pipeline.add_to_initial_memory(bytes),
..self
}
}
Expand Down Expand Up @@ -278,7 +286,8 @@ pub fn run(pipeline: &mut Pipeline<GoldilocksField>) {
let start = Instant::now();

let asm = pipeline.compute_analyzed_asm().unwrap().clone();
let initial_memory = riscv::continuations::load_initial_memory(&asm);
let initial_memory = riscv::continuations::load_initial_memory(&asm, pipeline.initial_memory());

let trace_len = riscv_executor::execute_fast(
&asm,
initial_memory,
Expand Down
1 change: 1 addition & 0 deletions riscv-runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ serde = { version = "1.0", default-features = false, features = ["alloc", "deriv
serde_cbor = { version = "0.11.2", default-features = false, features = ["alloc"] }
powdr-riscv-syscalls = { path = "../riscv-syscalls", version = "0.1.4" }
getrandom = { version = "0.2", features = ["custom"], optional = true }
spin = "0.9"

[features]
std = ["serde/std", "serde_cbor/std"]
Expand Down
29 changes: 21 additions & 8 deletions riscv-runtime/powdr.x
Original file line number Diff line number Diff line change
@@ -1,17 +1,32 @@
# Powdr linker script.
#
# If you are using powdr-riscv-runtime, it expects the symbols
# "__global_pointer$" and "__powdr_stack_start" to be defined.
# If you are using powdr-riscv-runtime, it expects the following
# symbols to be defined:
# __global_pointer$
# __powdr_stack_start
# __powdr_prover_data_init
# __powdr_prover_data_end
#
# Where "__powdr_prover_data_init" and "__powdr_prover_data_end"
# defines a region bigger than 1 page (2 KB), whose size is a
# power of 2, and aligned to its size.
#
# This linker script provides usable definitions to these
# symbols, with a 256 MB stack. If you are not building via
# powdr-rs, you must manually specify "-C link-arg=-Tpowdr.x"
# symbols, with a stack of almost 256 MB. If you are not building
# via powdr-rs, you must manually specify "-C link-arg=-Tpowdr.x"
# in rustc to use this linker script (e.g. via RUSTFLAGS).

SECTIONS
{
# Data starts here, before is the stack.
. = 0x10000100;
# Stack starts backwards from here (one 2 KB page short of 256 MB)
__powdr_stack_start = 0x10000000 - 0x800;

# The prover data (the second 256 MB chunk of the address space)
__powdr_prover_data_start = 0x10000000;
__powdr_prover_data_end = 0x20000000;

# Data starts here, one page after the prover data.
. = 0x20000000 + 0x800;
.data : {
*(.data)
PROVIDE( __global_pointer$ = . + 0x800 );
Expand All @@ -20,8 +35,6 @@ SECTIONS

# Text addresses are fake in powdr, we use a different address space.
.text : { *(.text) }

__powdr_stack_start = 0x10000000;
}

# Specify the entry point function provided by powdr-riscv-runtime:
Expand Down
Loading

0 comments on commit c8d2703

Please sign in to comment.