mirror of
https://github.com/eth-act/ere.git
synced 2026-02-19 11:54:42 -05:00
feat: Impl zkVM for Nexus zkvm (#47)
Co-authored-by: Han <tinghan0110@gmail.com>
This commit is contained in:
33
.github/workflows/test-nexus-docker.yml
vendored
Normal file
33
.github/workflows/test-nexus-docker.yml
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
name: Test Nexus (Docker)
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
test-nexus-via-docker-build:
|
||||
name: Build Nexus Docker Image
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Build ere-base image
|
||||
run: |
|
||||
docker build \
|
||||
--tag ere-base:latest \
|
||||
--file docker/base/Dockerfile.base .
|
||||
|
||||
- name: Build ere-builder-nexus image
|
||||
run: |
|
||||
docker build \
|
||||
--tag ere-builder-nexus:latest \
|
||||
--file docker/nexus/Dockerfile .
|
||||
622
Cargo.lock
generated
622
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
11
Cargo.toml
11
Cargo.toml
@@ -1,15 +1,16 @@
|
||||
[workspace]
|
||||
members = [
|
||||
"crates/build-utils",
|
||||
# zkVM interface
|
||||
"crates/zkvm-interface",
|
||||
# zkVMs
|
||||
"crates/ere-sp1",
|
||||
"crates/ere-risczero",
|
||||
"crates/ere-jolt",
|
||||
"crates/ere-nexus",
|
||||
"crates/ere-openvm",
|
||||
"crates/ere-pico",
|
||||
"crates/ere-jolt",
|
||||
"crates/ere-risczero",
|
||||
"crates/ere-sp1",
|
||||
"crates/ere-zisk",
|
||||
# zkVM interface
|
||||
"crates/zkvm-interface",
|
||||
|
||||
# Guest compilers
|
||||
"docker/sp1",
|
||||
|
||||
29
Makefile
Normal file
29
Makefile
Normal file
@@ -0,0 +1,29 @@
|
||||
# Heavily inspired by Reth: https://github.com/paradigmxyz/reth/blob/4c39b98b621c53524c6533a9c7b52fc42c25abd6/Makefile
|
||||
.DEFAULT_GOAL := help
|
||||
|
||||
##@ Help
|
||||
.PHONY: help
|
||||
help: # Display this help.
|
||||
@awk 'BEGIN {FS = ":.*#"; printf "Usage:\n make \033[34m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?#/ { printf " \033[34m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) }' $(MAKEFILE_LIST)
|
||||
|
||||
##@ Build
|
||||
.PHONY: build
|
||||
build: # Build the Ream binary into `target` directory.
|
||||
@cargo build --verbose --release
|
||||
|
||||
|
||||
##@ Lint
|
||||
.PHONY: clean
|
||||
clean: # Run `cargo clean`.
|
||||
@cargo clean
|
||||
|
||||
.PHONY: lint pr
|
||||
lint: # Run `clippy` and `rustfmt`.
|
||||
cargo +nightly fmt --all
|
||||
cargo clippy --all --all-targets --no-deps -- --deny warnings
|
||||
|
||||
# clippy for bls with supranational feature
|
||||
cargo clippy --all-targets --no-deps -- --deny warnings
|
||||
|
||||
# cargo sort
|
||||
cargo sort --grouped
|
||||
@@ -153,7 +153,7 @@ mod tests {
|
||||
let test_guest_path = get_compile_test_guest_program_path();
|
||||
let program = JOLT_TARGET::compile(&test_guest_path, Path::new("")).unwrap();
|
||||
let mut inputs = Input::new();
|
||||
inputs.write(1 as u32);
|
||||
inputs.write(1_u32);
|
||||
|
||||
let zkvm = EreJolt::new(program, ProverResourceType::Cpu);
|
||||
let _execution = zkvm.execute(&inputs).unwrap();
|
||||
|
||||
26
crates/ere-nexus/Cargo.toml
Normal file
26
crates/ere-nexus/Cargo.toml
Normal file
@@ -0,0 +1,26 @@
|
||||
[package]
|
||||
name = "ere-nexus"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
zkvm-interface = { workspace = true }
|
||||
|
||||
nexus-sdk = { git = "https://github.com/nexus-xyz/nexus-zkvm.git", tag = "0.3.4", version = "0.3.4" }
|
||||
|
||||
thiserror = "2"
|
||||
bincode = "1.3"
|
||||
tracing = "0.1"
|
||||
toml = { version = "0.9.2", features = ["parse", "display", "serde"] }
|
||||
|
||||
[dev-dependencies]
|
||||
anyhow = "1.0"
|
||||
|
||||
[build-dependencies]
|
||||
build-utils.workspace = true
|
||||
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
5
crates/ere-nexus/build.rs
Normal file
5
crates/ere-nexus/build.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
use build_utils::detect_and_generate_name_and_sdk_version;
|
||||
|
||||
fn main() {
|
||||
detect_and_generate_name_and_sdk_version("nexus", "nexus-sdk");
|
||||
}
|
||||
51
crates/ere-nexus/src/error.rs
Normal file
51
crates/ere-nexus/src/error.rs
Normal file
@@ -0,0 +1,51 @@
|
||||
use std::path::PathBuf;
|
||||
use thiserror::Error;
|
||||
use zkvm_interface::zkVMError;
|
||||
|
||||
impl From<NexusError> for zkVMError {
|
||||
fn from(value: NexusError) -> Self {
|
||||
zkVMError::Other(Box::new(value))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum NexusError {
|
||||
#[error(transparent)]
|
||||
Compile(#[from] CompileError),
|
||||
|
||||
#[error(transparent)]
|
||||
Prove(#[from] ProveError),
|
||||
|
||||
#[error(transparent)]
|
||||
Verify(#[from] VerifyError),
|
||||
|
||||
/// Guest program directory does not exist.
|
||||
#[error("guest program directory not found: {0}")]
|
||||
PathNotFound(PathBuf),
|
||||
|
||||
/// Expected ELF file was not produced.
|
||||
#[error("ELF file not found at {0}")]
|
||||
ElfNotFound(PathBuf),
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum CompileError {
|
||||
#[error("nexus execution failed: {0}")]
|
||||
Client(#[source] Box<dyn std::error::Error + Send + Sync + 'static>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ProveError {
|
||||
#[error("nexus execution failed: {0}")]
|
||||
Client(#[source] Box<dyn std::error::Error + Send + Sync + 'static>),
|
||||
#[error("Serialising proof with `bincode` failed: {0}")]
|
||||
Bincode(#[from] bincode::Error),
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum VerifyError {
|
||||
#[error("nexus verification failed: {0}")]
|
||||
Client(#[source] Box<dyn std::error::Error + Send + Sync + 'static>),
|
||||
#[error("Deserialising proof failed: {0}")]
|
||||
Bincode(#[from] bincode::Error),
|
||||
}
|
||||
219
crates/ere-nexus/src/lib.rs
Normal file
219
crates/ere-nexus/src/lib.rs
Normal file
@@ -0,0 +1,219 @@
|
||||
#![allow(clippy::uninlined_format_args)]
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::time::Instant;
|
||||
|
||||
use nexus_sdk::compile::cargo::CargoPackager;
|
||||
use nexus_sdk::compile::{Compile, Compiler as NexusCompiler};
|
||||
use nexus_sdk::stwo::seq::{Proof, Stwo};
|
||||
use nexus_sdk::{Local, Prover, Verifiable};
|
||||
use tracing::info;
|
||||
use zkvm_interface::{
|
||||
Compiler, Input, ProgramExecutionReport, ProgramProvingReport, ProverResourceType, zkVM,
|
||||
zkVMError,
|
||||
};
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/name_and_sdk_version.rs"));
|
||||
|
||||
mod error;
|
||||
pub(crate) mod utils;
|
||||
|
||||
use crate::error::ProveError;
|
||||
use crate::utils::get_cargo_package_name;
|
||||
use error::{CompileError, NexusError, VerifyError};
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
pub struct NEXUS_TARGET;
|
||||
|
||||
impl Compiler for NEXUS_TARGET {
|
||||
type Error = NexusError;
|
||||
|
||||
type Program = PathBuf;
|
||||
|
||||
fn compile(
|
||||
workspace_directory: &Path,
|
||||
guest_relative: &Path,
|
||||
) -> Result<Self::Program, Self::Error> {
|
||||
let guest_path = workspace_directory.join(guest_relative);
|
||||
|
||||
// 1. Check guest path
|
||||
if !guest_path.exists() {
|
||||
return Err(NexusError::PathNotFound(guest_path.to_path_buf()));
|
||||
}
|
||||
std::env::set_current_dir(&guest_path).map_err(|e| CompileError::Client(e.into()))?;
|
||||
|
||||
let package_name = get_cargo_package_name(&guest_path)
|
||||
.ok_or(CompileError::Client(Box::from(format!(
|
||||
"Failed to get guest package name, where guest path: {:?}",
|
||||
guest_path
|
||||
))))
|
||||
.map_err(|e| CompileError::Client(e.into()))?;
|
||||
let mut prover_compiler = NexusCompiler::<CargoPackager>::new(&package_name);
|
||||
let elf_path = prover_compiler
|
||||
.build()
|
||||
.map_err(|e| CompileError::Client(e.into()))?;
|
||||
|
||||
Ok(elf_path)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EreNexus {
|
||||
program: <NEXUS_TARGET as Compiler>::Program,
|
||||
}
|
||||
|
||||
impl EreNexus {
|
||||
pub fn new(
|
||||
program: <NEXUS_TARGET as Compiler>::Program,
|
||||
_resource_type: ProverResourceType,
|
||||
) -> Self {
|
||||
Self { program }
|
||||
}
|
||||
}
|
||||
impl zkVM for EreNexus {
|
||||
fn execute(&self, inputs: &Input) -> Result<zkvm_interface::ProgramExecutionReport, zkVMError> {
|
||||
let start = Instant::now();
|
||||
|
||||
// let mut public_input = vec![];
|
||||
let mut private_input = vec![];
|
||||
for input in inputs.iter() {
|
||||
private_input.extend(
|
||||
input
|
||||
.as_bytes()
|
||||
.map_err(|err| NexusError::Prove(ProveError::Client(err)))
|
||||
.map_err(zkVMError::from)?,
|
||||
);
|
||||
}
|
||||
// TODO: Doesn't catch execute for guest in nexus. so only left some dummy code(parse input) here.
|
||||
// Besides, public input is not supported yet, so we just pass an empty tuple
|
||||
|
||||
Ok(ProgramExecutionReport {
|
||||
execution_duration: start.elapsed(),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
|
||||
fn prove(
|
||||
&self,
|
||||
inputs: &Input,
|
||||
) -> Result<(Vec<u8>, zkvm_interface::ProgramProvingReport), zkVMError> {
|
||||
let prover: Stwo<Local> = Stwo::new_from_file(&self.program.to_string_lossy().to_string())
|
||||
.map_err(|e| NexusError::Prove(ProveError::Client(e.into())))
|
||||
.map_err(zkVMError::from)?;
|
||||
|
||||
// One convention that may be useful for simplifying the design is that all inputs to the vm are private and all outputs are public.
|
||||
// If an input should be public, then it could just be returned from the function.
|
||||
// let mut public_input = vec![];
|
||||
let mut private_input = vec![];
|
||||
for input in inputs.iter() {
|
||||
private_input.extend(
|
||||
input
|
||||
.as_bytes()
|
||||
.map_err(|err| NexusError::Prove(ProveError::Client(err)))
|
||||
.map_err(zkVMError::from)?,
|
||||
);
|
||||
}
|
||||
|
||||
let now = Instant::now();
|
||||
let (_view, proof) = prover
|
||||
.prove_with_input(&private_input, &())
|
||||
.map_err(|e| NexusError::Prove(ProveError::Client(e.into())))
|
||||
.map_err(zkVMError::from)?;
|
||||
let elapsed = now.elapsed();
|
||||
|
||||
let bytes = bincode::serialize(&proof)
|
||||
.map_err(|err| NexusError::Prove(ProveError::Bincode(err)))?;
|
||||
|
||||
Ok((bytes, ProgramProvingReport::new(elapsed)))
|
||||
}
|
||||
|
||||
fn verify(&self, proof: &[u8]) -> Result<(), zkVMError> {
|
||||
info!("Verifying proof...");
|
||||
|
||||
let proof: Proof = bincode::deserialize(proof)
|
||||
.map_err(|err| NexusError::Verify(VerifyError::Bincode(err)))?;
|
||||
|
||||
let prover: Stwo<Local> = Stwo::new_from_file(&self.program.to_string_lossy().to_string())
|
||||
.map_err(|e| NexusError::Prove(ProveError::Client(e.into())))
|
||||
.map_err(zkVMError::from)?;
|
||||
let elf = prover.elf.clone(); // save elf for use with verification
|
||||
#[rustfmt::skip]
|
||||
proof
|
||||
.verify_expected::<(), ()>(
|
||||
&(), // no public input
|
||||
nexus_sdk::KnownExitCodes::ExitSuccess as u32,
|
||||
&(), // no public output
|
||||
&elf, // expected elf (program binary)
|
||||
&[], // no associated data,
|
||||
)
|
||||
.map_err(|e| NexusError::Verify(VerifyError::Client(e.into())))
|
||||
.map_err(zkVMError::from)?;
|
||||
|
||||
info!("Verify Succeeded!");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn name(&self) -> &'static str {
|
||||
NAME
|
||||
}
|
||||
|
||||
fn sdk_version(&self) -> &'static str {
|
||||
SDK_VERSION
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use zkvm_interface::Compiler;
|
||||
|
||||
use crate::NEXUS_TARGET;
|
||||
|
||||
use super::*;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn get_test_guest_program_path() -> PathBuf {
|
||||
let workspace_dir = env!("CARGO_WORKSPACE_DIR");
|
||||
PathBuf::from(workspace_dir)
|
||||
.join("tests")
|
||||
.join("nexus")
|
||||
.join("guest")
|
||||
.canonicalize()
|
||||
.expect("Failed to find or canonicalize test guest program at <CARGO_WORKSPACE_DIR>/tests/compile/nexus")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_compile() -> anyhow::Result<()> {
|
||||
let test_guest_path = get_test_guest_program_path();
|
||||
let elf_path = NEXUS_TARGET::compile(&test_guest_path, Path::new(""))?;
|
||||
let prover: Stwo<Local> = Stwo::new_from_file(&elf_path.to_string_lossy().to_string())?;
|
||||
let elf = prover.elf.clone();
|
||||
assert!(
|
||||
!elf.instructions.is_empty(),
|
||||
"ELF bytes should not be empty."
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_execute() {
|
||||
let test_guest_path = get_test_guest_program_path();
|
||||
let elf =
|
||||
NEXUS_TARGET::compile(&test_guest_path, Path::new("")).expect("compilation failed");
|
||||
let mut input = Input::new();
|
||||
input.write(10u64);
|
||||
|
||||
let zkvm = EreNexus::new(elf, ProverResourceType::Cpu);
|
||||
zkvm.execute(&input).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_prove_verify() -> anyhow::Result<()> {
|
||||
let test_guest_path = get_test_guest_program_path();
|
||||
let elf = NEXUS_TARGET::compile(&test_guest_path, Path::new(""))?;
|
||||
let mut input = Input::new();
|
||||
input.write(10u64);
|
||||
|
||||
let zkvm = EreNexus::new(elf, ProverResourceType::Cpu);
|
||||
let (proof, _) = zkvm.prove(&input).unwrap();
|
||||
zkvm.verify(&proof).expect("proof should verify");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
13
crates/ere-nexus/src/utils.rs
Normal file
13
crates/ere-nexus/src/utils.rs
Normal file
@@ -0,0 +1,13 @@
|
||||
use std::fs;
|
||||
use toml::Table;
|
||||
|
||||
pub fn get_cargo_package_name(crate_path: &std::path::Path) -> Option<String> {
|
||||
let cargo_contents = fs::read_to_string(crate_path.join("Cargo.toml")).ok()?;
|
||||
let cargo_toml: Table = toml::from_str(&cargo_contents).ok()?;
|
||||
|
||||
cargo_toml
|
||||
.get("package")?
|
||||
.get("name")?
|
||||
.as_str()
|
||||
.map(|s| s.to_string())
|
||||
}
|
||||
@@ -161,7 +161,7 @@ mod tests {
|
||||
"Attempting to find test guest program at: {}",
|
||||
path.display()
|
||||
);
|
||||
println!("Workspace dir is: {}", workspace_dir);
|
||||
println!("Workspace dir is: {workspace_dir}");
|
||||
|
||||
path.canonicalize()
|
||||
.expect("Failed to find or canonicalize test guest program at <CARGO_WORKSPACE_DIR>/tests/pico/compile/basic/app")
|
||||
@@ -176,11 +176,8 @@ mod tests {
|
||||
Ok(elf_bytes) => {
|
||||
assert!(!elf_bytes.is_empty(), "ELF bytes should not be empty.");
|
||||
}
|
||||
Err(e) => {
|
||||
panic!(
|
||||
"compile_sp1_program direct call failed for dedicated guest: {:?}",
|
||||
e
|
||||
);
|
||||
Err(err) => {
|
||||
panic!("compile_sp1_program direct call failed for dedicated guest: {err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,8 @@ license.workspace = true
|
||||
[dependencies]
|
||||
zkvm-interface = { workspace = true }
|
||||
anyhow = "1.0" #TODO: remove only needed in tests
|
||||
toml = "0.8"
|
||||
risc0-zkvm = { version = "^2.3.0", features = ["unstable"] }
|
||||
#toml = "0.8"
|
||||
risc0-zkvm = { version = "2.3.0", features = ["unstable"] }
|
||||
borsh = "1.5.7"
|
||||
hex = "*"
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ impl zkVM for EreRisc0 {
|
||||
env.write(serialize).unwrap();
|
||||
}
|
||||
InputItem::Bytes(items) => {
|
||||
env.write_frame(&items);
|
||||
env.write_frame(items);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -121,7 +121,7 @@ impl zkVM for EreRisc0 {
|
||||
|
||||
fn verify(&self, proof: &[u8]) -> Result<(), zkVMError> {
|
||||
let decoded: Receipt =
|
||||
borsh::from_slice(&proof).map_err(|err| zkVMError::Other(Box::new(err)))?;
|
||||
borsh::from_slice(proof).map_err(|err| zkVMError::Other(Box::new(err)))?;
|
||||
|
||||
decoded
|
||||
.verify(self.program.image_id)
|
||||
@@ -175,7 +175,7 @@ mod prove_tests {
|
||||
let proof_bytes = match zkvm.prove(&input_builder) {
|
||||
Ok((prove_result, _)) => prove_result,
|
||||
Err(err) => {
|
||||
panic!("Proving error in test: {:?}", err);
|
||||
panic!("Proving error in test: {err}",);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -238,8 +238,8 @@ mod execute_tests {
|
||||
|
||||
let result = zkvm.execute(&input_builder);
|
||||
|
||||
if let Err(e) = &result {
|
||||
panic!("Execution error: {:?}", e);
|
||||
if let Err(err) = &result {
|
||||
panic!("Execution error: {err}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -93,8 +93,8 @@ mod tests {
|
||||
Ok(elf_bytes) => {
|
||||
assert!(!elf_bytes.is_empty(), "ELF bytes should not be empty.");
|
||||
}
|
||||
Err(e) => {
|
||||
panic!("compile failed for dedicated guest: {:?}", e);
|
||||
Err(err) => {
|
||||
panic!("compile failed for dedicated guest: {err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -106,11 +106,8 @@ mod tests {
|
||||
Ok(elf_bytes) => {
|
||||
assert!(!elf_bytes.is_empty(), "ELF bytes should not be empty.");
|
||||
}
|
||||
Err(e) => {
|
||||
panic!(
|
||||
"compile_sp1_program direct call failed for dedicated guest: {:?}",
|
||||
e
|
||||
);
|
||||
Err(err) => {
|
||||
panic!("compile_sp1_program direct call failed for dedicated guest: {err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -264,8 +264,8 @@ mod execute_tests {
|
||||
|
||||
let result = zkvm.execute(&input_builder);
|
||||
|
||||
if let Err(e) = &result {
|
||||
panic!("Execution error: {:?}", e);
|
||||
if let Err(err) = &result {
|
||||
panic!("Execution error: {err}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,7 +325,7 @@ mod prove_tests {
|
||||
let proof_bytes = match zkvm.prove(&input_builder) {
|
||||
Ok((prove_result, _)) => prove_result,
|
||||
Err(err) => {
|
||||
panic!("Proving error in test: {:?}", err);
|
||||
panic!("Proving error in test: {err}");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -387,7 +387,7 @@ mod prove_tests {
|
||||
prove_result
|
||||
}
|
||||
Err(err) => {
|
||||
panic!("Network proving error: {:?}", err);
|
||||
panic!("Network proving error: {err}");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
40
docker/nexus/Dockerfile
Normal file
40
docker/nexus/Dockerfile
Normal file
@@ -0,0 +1,40 @@
|
||||
ARG BASE_IMAGE_TAG=latest
|
||||
FROM ere-base:${BASE_IMAGE_TAG}
|
||||
|
||||
# The ere-base image provides Rust, Cargo, and common tools.
|
||||
# We operate as root for SDK installation.
|
||||
|
||||
# Copy the Nexus SDK installer script from the workspace context
|
||||
COPY scripts/sdk_installers/install_nexus_sdk.sh /tmp/install_nexus_sdk.sh
|
||||
RUN chmod +x /tmp/install_nexus_sdk.sh
|
||||
|
||||
RUN rustup default nightly-2025-06-05 && \
|
||||
rustup target add riscv32i-unknown-none-elf
|
||||
|
||||
# Run the Nexus SDK installation script.
|
||||
# This script installs the specific Rust toolchain (nightly-2025-06-05)
|
||||
# and installs cargo-nexus
|
||||
# The CARGO_HOME from ere-base (e.g., /root/.cargo) will be used, and cargo-nexus will be in its bin.
|
||||
RUN /tmp/install_nexus_sdk.sh && rm /tmp/install_nexus_sdk.sh # Clean up the script
|
||||
|
||||
# Define the Nexus toolchain for convenience in subsequent commands if needed, though cargo-nexus should use it.
|
||||
ENV NEXUS_TOOLCHAIN_VERSION="nightly-2025-06-05"
|
||||
|
||||
# Verify Nexus installation
|
||||
RUN echo "Verifying Nexus installation in Dockerfile (post-script)..." && cargo-nexus --version
|
||||
|
||||
# Copy the entire ere project context
|
||||
# The WORKDIR is /app from the base image
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
|
||||
# Build
|
||||
RUN echo "Build tests for ere-nexus library..." && \
|
||||
cargo build --tests --release -p ere-nexus
|
||||
|
||||
# Run tests
|
||||
RUN echo "Running tests for ere-nexus library..." && \
|
||||
cargo test --release -p ere-nexus --lib -- --color always && \
|
||||
echo "Running Nexus tests Success..."
|
||||
|
||||
CMD ["/bin/bash"]
|
||||
@@ -20,7 +20,7 @@ RUN /tmp/install_pico_sdk.sh && rm /tmp/install_pico_sdk.sh # Clean up the scrip
|
||||
ENV PICO_TOOLCHAIN_VERSION="nightly-2024-11-27"
|
||||
|
||||
# Verify Pico installation
|
||||
RUN echo "Verifying Risc0 installation in Dockerfile (post-script)..." && cargo "+${PICO_TOOLCHAIN_VERSION}" pico --version
|
||||
RUN echo "Verifying Pico installation in Dockerfile (post-script)..." && cargo "+${PICO_TOOLCHAIN_VERSION}" pico --version
|
||||
|
||||
# Copy the entire ere project context
|
||||
# The WORKDIR is /app from the base image
|
||||
|
||||
54
scripts/sdk_installers/install_nexus_sdk.sh
Executable file
54
scripts/sdk_installers/install_nexus_sdk.sh
Executable file
@@ -0,0 +1,54 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# --- Utility functions (duplicated) ---
|
||||
# Checks if a tool is installed and available in PATH.
|
||||
is_tool_installed() {
|
||||
command -v "$1" &> /dev/null
|
||||
}
|
||||
|
||||
# Ensures a tool is installed. Exits with an error if not.
|
||||
ensure_tool_installed() {
|
||||
local tool_name="$1"
|
||||
local purpose_message="$2"
|
||||
if ! is_tool_installed "${tool_name}"; then
|
||||
echo "Error: Required tool '${tool_name}' could not be found." >&2
|
||||
if [ -n "${purpose_message}" ]; then
|
||||
echo " It is needed ${purpose_message}." >&2
|
||||
fi
|
||||
echo " Please install it first and ensure it is in your PATH." >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
# --- End of Utility functions ---
|
||||
|
||||
echo "Installing Nexus Toolchain and SDK using Nexus (prebuilt binaries)..."
|
||||
|
||||
# Prerequisites for Nexus (some of these are for the SDK itself beyond Nexus)
|
||||
#ensure_tool_installed "curl" "to download the Nexus installer"
|
||||
#ensure_tool_installed "bash" "to run the Nexus installer"
|
||||
ensure_tool_installed "rustup" "for managing Rust toolchains"
|
||||
ensure_tool_installed "cargo" "as cargo-nexus is a cargo subcommand"
|
||||
|
||||
# Step 1: Download and run the toolchain.
|
||||
|
||||
# Verify Nexus installation
|
||||
echo "Verifying Nexus installation..."
|
||||
|
||||
echo "Checking for RISC-V target..."
|
||||
if rustup target list | grep -q "riscv32i-unknown-none-elf"; then
|
||||
echo "RISC-V target 'riscv32i-unknown-none-elf' not found."
|
||||
else
|
||||
echo "RISC-V 'riscv32i-unknown-none-elf' not found after installation!" >&2
|
||||
echo "Install the RISC-V target:"
|
||||
rustup target add riscv32i-unknown-none-elf
|
||||
fi
|
||||
|
||||
echo "Checking for cargo-nexus..."
|
||||
if cargo --list | grep "nexus"; then
|
||||
echo "cargo-nexus found."
|
||||
else
|
||||
echo "cargo-nexus not found after installation!" >&2
|
||||
echo "Install the cargo-nexus:"
|
||||
cargo install --git https://github.com/nexus-xyz/nexus-zkvm cargo-nexus --tag 'v0.3.4'
|
||||
fi
|
||||
5
tests/nexus/guest/.cargo/config.toml
Normal file
5
tests/nexus/guest/.cargo/config.toml
Normal file
@@ -0,0 +1,5 @@
|
||||
[target.riscv32i-unknown-none-elf]
|
||||
rustflags = [
|
||||
"-C", "link-arg=-Tlink.x",
|
||||
]
|
||||
runner="nexus-run"
|
||||
14
tests/nexus/guest/Cargo.toml
Normal file
14
tests/nexus/guest/Cargo.toml
Normal file
@@ -0,0 +1,14 @@
|
||||
[package]
|
||||
name = "ere-nexus-guest"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
nexus-rt = { git = "https://github.com/nexus-xyz/nexus-zkvm.git", tag = "0.3.4", version = "0.3.4" }
|
||||
|
||||
# Generated by cargo-nexus, do not remove!
|
||||
#
|
||||
[features]
|
||||
cycles = [] # Enable cycle counting for run command
|
||||
[workspace]
|
||||
|
||||
18
tests/nexus/guest/src/main.rs
Normal file
18
tests/nexus/guest/src/main.rs
Normal file
@@ -0,0 +1,18 @@
|
||||
#![cfg_attr(target_arch = "riscv32", no_std, no_main)]
|
||||
|
||||
use nexus_rt::println;
|
||||
|
||||
#[nexus_rt::main]
|
||||
#[nexus_rt::private_input(x)]
|
||||
fn main(x: u32) {
|
||||
println!("Read public input: {}", x);
|
||||
let res = fibonacci(x);
|
||||
println!("fib result: {}", res);
|
||||
}
|
||||
pub fn fibonacci(n: u32) -> u32 {
|
||||
match n {
|
||||
0 => 1,
|
||||
1 => 1,
|
||||
_ => fibonacci(n - 1) + fibonacci(n - 2),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user