feat: update riscv32 to riscv64 for sp1

This commit is contained in:
han0110
2026-02-16 13:45:19 +00:00
parent 1aa23405da
commit 67bad79dcf
8 changed files with 112 additions and 27 deletions

View File

@@ -3,5 +3,8 @@ mod rust;
pub use {
error::CommonError,
rust::{CargoBuildCmd, cargo_metadata, rustc_path, rustup_add_components, rustup_add_rust_src},
rust::{
CargoBuildCmd, RustTarget, cargo_metadata, rustc_path, rustup_add_components,
rustup_add_rust_src,
},
};

View File

@@ -10,6 +10,36 @@ use tempfile::tempdir;
const CARGO_ENCODED_RUSTFLAGS_SEPARATOR: &str = "\x1f";
/// Target specification for cargo build.
#[derive(Debug, Clone, Copy)]
pub enum RustTarget {
/// Built-in target name (e.g., "riscv64im-unknown-none-elf").
Name(&'static str),
/// Custom target specification JSON content.
SpecJson {
/// Target name (e.g., "riscv64ima-unknown-none-elf").
name: &'static str,
/// Raw JSON content of the target specification.
json: &'static str,
},
}
impl RustTarget {
/// Returns the target name.
pub const fn name(&self) -> &'static str {
match self {
Self::Name(name) => name,
Self::SpecJson { name, .. } => name,
}
}
}
impl From<&'static str> for RustTarget {
fn from(name: &'static str) -> Self {
Self::Name(name)
}
}
/// A builder for configuring `cargo build` invocation.
#[derive(Clone)]
pub struct CargoBuildCmd {
@@ -73,12 +103,12 @@ impl CargoBuildCmd {
self
}
/// Takes the path to the manifest directory and the target triple, then
/// Takes the path to the manifest directory and the target, then
/// runs configured `cargo build` and returns built ELF.
pub fn exec(
&self,
manifest_dir: impl AsRef<Path>,
target: impl AsRef<str>,
target: impl Into<RustTarget>,
) -> Result<Vec<u8>, CommonError> {
let metadata = cargo_metadata(manifest_dir.as_ref())?;
let package = metadata.root_package().unwrap();
@@ -103,6 +133,18 @@ impl CargoBuildCmd {
})?;
}
let target = target.into();
let target_arg = match target {
RustTarget::Name(name) => name.to_string(),
RustTarget::SpecJson { name, json } => {
let json_name = format!("{name}.json");
let json_path = tempdir.path().join(&json_name);
fs::write(&json_path, json.as_bytes())
.map_err(|err| CommonError::write_file(json_name, &json_path, err))?;
json_path.to_string_lossy().to_string()
}
};
let encoded_rustflags = iter::empty()
.chain(self.rustflags.iter().cloned())
.chain(
@@ -120,7 +162,7 @@ impl CargoBuildCmd {
.chain(["build".into()])
.chain(self.build_options.iter().cloned())
.chain(["--profile".into(), self.profile.clone()])
.chain(["--target".into(), target.as_ref().into()])
.chain(["--target".into(), target_arg])
.chain(["--manifest-path".into(), package.manifest_path.to_string()]);
let mut cmd = Command::new("cargo");
@@ -136,7 +178,7 @@ impl CargoBuildCmd {
let elf_path = metadata
.target_directory
.join(target.as_ref())
.join(target.name())
.join(&self.profile)
.join(&package.name);
let elf =

View File

@@ -228,11 +228,11 @@ fn compile(guest_dir: PathBuf, compiler_kind: CompilerKind) -> CompilationResult
use ere_sp1::compiler::*;
match compiler_kind {
CompilerKind::Rust => {
let program = RustRv32ima.compile(&guest_dir)?;
let program = RustRv64ima.compile(&guest_dir)?;
(Some(program.elf().to_vec()), None, program)
}
CompilerKind::RustCustomized => {
let program = RustRv32imaCustomized.compile(&guest_dir)?;
let program = RustRv64imaCustomized.compile(&guest_dir)?;
(Some(program.elf().to_vec()), None, program)
}
_ => bail!(unsupported_compiler_kind_err(

View File

@@ -1,7 +1,7 @@
mod error;
mod rust_rv32ima;
mod rust_rv32ima_customized;
mod rust_rv64ima;
mod rust_rv64ima_customized;
pub use error::Error;
pub use rust_rv32ima::RustRv32ima;
pub use rust_rv32ima_customized::RustRv32imaCustomized;
pub use rust_rv64ima::RustRv64ima;
pub use rust_rv64ima_customized::RustRv64imaCustomized;

View File

@@ -1,9 +1,22 @@
use crate::{compiler::Error, program::SP1Program};
use ere_compile_utils::CargoBuildCmd;
use ere_compile_utils::{CargoBuildCmd, RustTarget};
use ere_zkvm_interface::compiler::Compiler;
use std::{env, path::Path};
const TARGET_TRIPLE: &str = "riscv32ima-unknown-none-elf";
/// Target spec modified from `riscv64im-unknown-none-elf` with patch `atomic-cas = true`.
///
/// To reproduce:
///
/// ```bash
/// rustc +nightly -Z unstable-options --print target-spec-json --target riscv64im-unknown-none-elf \
/// | jq '.["atomic-cas"] = true' \
/// > ./crates/zkvm/sp1/src/compiler/rust_rv64ima/riscv64ima-unknown-none-elf.json
/// ```
const TARGET: RustTarget = RustTarget::SpecJson {
name: "riscv64ima-unknown-none-elf",
json: include_str!("./rust_rv64ima/riscv64ima-unknown-none-elf.json"),
};
/// According to https://github.com/succinctlabs/sp1/blob/v6.0.0/crates/build/src/command/utils.rs#L49.
const RUSTFLAGS: &[&str] = &[
"-C",
@@ -24,12 +37,14 @@ const RUSTFLAGS: &[&str] = &[
const CARGO_BUILD_OPTIONS: &[&str] = &[
// For bare metal we have to build core and alloc
"-Zbuild-std=core,alloc",
// For using json target spec
"-Zjson-target-spec",
];
/// Compiler for Rust guest program to RV32IMA architecture.
pub struct RustRv32ima;
/// Compiler for Rust guest program to RV64IMA architecture.
pub struct RustRv64ima;
impl Compiler for RustRv32ima {
impl Compiler for RustRv64ima {
type Error = Error;
type Program = SP1Program;
@@ -40,14 +55,14 @@ impl Compiler for RustRv32ima {
.toolchain(toolchain)
.build_options(CARGO_BUILD_OPTIONS)
.rustflags(RUSTFLAGS)
.exec(guest_directory, TARGET_TRIPLE)?;
.exec(guest_directory, TARGET)?;
Ok(SP1Program { elf })
}
}
#[cfg(test)]
mod tests {
use crate::{compiler::RustRv32ima, zkvm::EreSP1};
use crate::{compiler::RustRv64ima, zkvm::EreSP1};
use ere_test_utils::host::testing_guest_directory;
use ere_zkvm_interface::{
Input,
@@ -58,14 +73,14 @@ mod tests {
#[test]
fn test_compile() {
let guest_directory = testing_guest_directory("sp1", "stock_nightly_no_std");
let program = RustRv32ima.compile(&guest_directory).unwrap();
let program = RustRv64ima.compile(&guest_directory).unwrap();
assert!(!program.elf().is_empty(), "ELF bytes should not be empty.");
}
#[test]
fn test_execute() {
let guest_directory = testing_guest_directory("sp1", "stock_nightly_no_std");
let program = RustRv32ima.compile(&guest_directory).unwrap();
let program = RustRv64ima.compile(&guest_directory).unwrap();
let zkvm = EreSP1::new(program, ProverResource::Cpu).unwrap();
zkvm.execute(&Input::new()).unwrap();

View File

@@ -0,0 +1,25 @@
{
"arch": "riscv64",
"atomic-cas": true,
"code-model": "medium",
"cpu": "generic-rv64",
"crt-objects-fallback": "false",
"data-layout": "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128",
"eh-frame-header": false,
"emit-debug-gdb-scripts": false,
"features": "+m,+forced-atomics",
"linker": "rust-lld",
"linker-flavor": "gnu-lld",
"llvm-abiname": "lp64",
"llvm-target": "riscv64",
"max-atomic-width": 64,
"metadata": {
"description": "Bare RISC-V (RV64IM ISA)",
"host_tools": false,
"std": false,
"tier": 3
},
"panic-strategy": "abort",
"relocation-model": "static",
"target-pointer-width": 64
}

View File

@@ -5,11 +5,11 @@ use std::{fs, path::Path, process::Command};
use tempfile::tempdir;
use tracing::info;
/// Compiler for Rust guest program to RV32IMA architecture, using customized
/// Compiler for Rust guest program to RV64IMA architecture, using customized
/// Rust toolchain of Succinct.
pub struct RustRv32imaCustomized;
pub struct RustRv64imaCustomized;
impl Compiler for RustRv32imaCustomized {
impl Compiler for RustRv64imaCustomized {
type Error = Error;
type Program = SP1Program;
@@ -56,14 +56,14 @@ impl Compiler for RustRv32imaCustomized {
#[cfg(test)]
mod tests {
use crate::compiler::RustRv32imaCustomized;
use crate::compiler::RustRv64imaCustomized;
use ere_test_utils::host::testing_guest_directory;
use ere_zkvm_interface::compiler::Compiler;
#[test]
fn test_compile() {
let guest_directory = testing_guest_directory("sp1", "basic");
let program = RustRv32imaCustomized.compile(&guest_directory).unwrap();
let program = RustRv64imaCustomized.compile(&guest_directory).unwrap();
assert!(!program.elf().is_empty(), "ELF bytes should not be empty.");
}
}

View File

@@ -131,7 +131,7 @@ fn input_to_stdin(input: &Input) -> Result<SP1Stdin, Error> {
#[cfg(test)]
mod tests {
use crate::{compiler::RustRv32imaCustomized, program::SP1Program, zkvm::EreSP1};
use crate::{compiler::RustRv64imaCustomized, program::SP1Program, zkvm::EreSP1};
use ere_test_utils::{
host::{TestCase, run_zkvm_execute, run_zkvm_prove, testing_guest_directory},
io::serde::bincode::BincodeLegacy,
@@ -148,7 +148,7 @@ mod tests {
static PROGRAM: OnceLock<SP1Program> = OnceLock::new();
PROGRAM
.get_or_init(|| {
RustRv32imaCustomized
RustRv64imaCustomized
.compile(&testing_guest_directory("sp1", "basic"))
.unwrap()
})