From 8d68a60de089c2cb7be5f1e8967e5a04af6b62e7 Mon Sep 17 00:00:00 2001 From: Marcin Bugaj <47246918+marcinbugaj@users.noreply.github.com> Date: Thu, 6 Nov 2025 13:15:45 +0100 Subject: [PATCH] TamaGo compilation support (#206) --- crates/compile-utils/src/error.rs | 10 ++ crates/dockerized/dockerized/src/lib.rs | 2 +- crates/zkvm/zisk/src/compiler.rs | 2 + .../zkvm/zisk/src/compiler/go_customized.rs | 72 +++++++++++ .../src/compiler/rust_rv64ima_customized.rs | 7 +- crates/zkvm/zisk/src/zkvm.rs | 2 +- docker/base/Dockerfile.base | 7 ++ scripts/install_tamago.sh | 119 ++++++++++++++++++ tests/zisk/basic_go/go.mod | 8 ++ tests/zisk/basic_go/go.sum | 4 + tests/zisk/basic_go/main.go | 14 +++ tests/zisk/{basic => basic_rust}/Cargo.toml | 0 tests/zisk/{basic => basic_rust}/src/main.rs | 0 13 files changed, 243 insertions(+), 4 deletions(-) create mode 100644 crates/zkvm/zisk/src/compiler/go_customized.rs create mode 100755 scripts/install_tamago.sh create mode 100644 tests/zisk/basic_go/go.mod create mode 100644 tests/zisk/basic_go/go.sum create mode 100644 tests/zisk/basic_go/main.go rename tests/zisk/{basic => basic_rust}/Cargo.toml (100%) rename tests/zisk/{basic => basic_rust}/src/main.rs (100%) diff --git a/crates/compile-utils/src/error.rs b/crates/compile-utils/src/error.rs index e8164cc..1226a42 100644 --- a/crates/compile-utils/src/error.rs +++ b/crates/compile-utils/src/error.rs @@ -48,6 +48,12 @@ pub enum CommonError { #[error("Root package not found in {manifest_dir}")] CargoRootPackageNotFound { manifest_dir: PathBuf }, + + #[error("Attempt to get {var} env variable results in {var_error}")] + Env { + var: String, + var_error: std::env::VarError, + }, } impl CommonError { @@ -117,4 +123,8 @@ impl CommonError { pub fn cargo_root_package_not_found(manifest_dir: PathBuf) -> Self { Self::CargoRootPackageNotFound { manifest_dir } } + + pub fn env_var_error(var: String, var_error: std::env::VarError) -> Self { + Self::Env { var, var_error } + } } diff --git a/crates/dockerized/dockerized/src/lib.rs b/crates/dockerized/dockerized/src/lib.rs index 3334ce6..5f92a4d 100644 --- a/crates/dockerized/dockerized/src/lib.rs +++ b/crates/dockerized/dockerized/src/lib.rs @@ -753,7 +753,7 @@ mod test { } mod zisk { - test_compile!(Zisk, "basic"); + test_compile!(Zisk, "basic_rust"); test_execute!( Zisk, BasicProgramInput::valid().into_output_sha256(), diff --git a/crates/zkvm/zisk/src/compiler.rs b/crates/zkvm/zisk/src/compiler.rs index 8a64704..dbecedc 100644 --- a/crates/zkvm/zisk/src/compiler.rs +++ b/crates/zkvm/zisk/src/compiler.rs @@ -1,5 +1,7 @@ mod error; +mod go_customized; mod rust_rv64ima_customized; pub use error::Error; +pub use go_customized::GoCustomized; pub use rust_rv64ima_customized::RustRv64imaCustomized; diff --git a/crates/zkvm/zisk/src/compiler/go_customized.rs b/crates/zkvm/zisk/src/compiler/go_customized.rs new file mode 100644 index 0000000..0952c76 --- /dev/null +++ b/crates/zkvm/zisk/src/compiler/go_customized.rs @@ -0,0 +1,72 @@ +use std::{env, fs, path::Path, process::Command}; + +use ere_compile_utils::CommonError; +use ere_zkvm_interface::Compiler; +use tracing::info; + +use crate::{compiler::Error, program::ZiskProgram}; + +pub struct GoCustomized; + +impl Compiler for GoCustomized { + type Error = Error; + + type Program = ZiskProgram; + + fn compile(&self, guest_directory: &Path) -> Result { + info!( + "Compiling TamaGo ZisK program at {}", + guest_directory.display() + ); + + let home_dir = env::var("HOME") + .map(std::path::PathBuf::from) + .map_err(|var_error| CommonError::env_var_error("HOME".to_string(), var_error))?; + + let ldflags = ["-ldflags", "-T 0x80001000 -D 0xa0020000"]; + let tags = [ + "-tags", + "tamago,linkcpuinit,linkramstart,linkramsize,linkprintk,tinygo.wasm,tinygo,riscv64", + ]; + let executable = guest_directory.join("program.elf"); + let mut cmd = Command::new(home_dir.join(".tamago").join("bin").join("go")); + let status = cmd + .current_dir(guest_directory) + .env("CGO_ENABLED", "0") + .env("GOROOT", home_dir.join(".tamago").as_os_str()) + .env("GOOS", "tamago") + .env("GOARCH", "riscv64") + .arg("build") + .arg("-buildvcs=false") + .args(ldflags) + .args(tags) + .args(["-o", executable.to_str().unwrap()]) + .arg(".") + .status() + .map_err(|err| CommonError::command(&cmd, err))?; + + if !status.success() { + return Err(CommonError::command_exit_non_zero(&cmd, status, None))?; + } + + let elf = + fs::read(&executable).map_err(|err| CommonError::read_file("elf", executable, err))?; + + Ok(ZiskProgram { elf }) + } +} + +#[cfg(test)] +mod tests { + use crate::compiler::GoCustomized; + use ere_test_utils::host::testing_guest_directory; + use ere_zkvm_interface::compiler::Compiler; + + #[test] + fn test_compile() { + let guest_directory = testing_guest_directory("zisk", "basic_go"); + println!("Guest directory is: {guest_directory:?}"); + let program = GoCustomized.compile(&guest_directory).unwrap(); + assert!(!program.elf().is_empty(), "ELF bytes should not be empty."); + } +} diff --git a/crates/zkvm/zisk/src/compiler/rust_rv64ima_customized.rs b/crates/zkvm/zisk/src/compiler/rust_rv64ima_customized.rs index dd3a832..9715f44 100644 --- a/crates/zkvm/zisk/src/compiler/rust_rv64ima_customized.rs +++ b/crates/zkvm/zisk/src/compiler/rust_rv64ima_customized.rs @@ -17,7 +17,10 @@ impl Compiler for RustRv64imaCustomized { type Program = ZiskProgram; fn compile(&self, guest_directory: &Path) -> Result { - info!("Compiling ZisK program at {}", guest_directory.display()); + info!( + "Compiling Rust ZisK program at {}", + guest_directory.display() + ); let metadata = cargo_metadata(guest_directory)?; let package = metadata.root_package().unwrap(); @@ -58,7 +61,7 @@ mod tests { #[test] fn test_compile() { - let guest_directory = testing_guest_directory("zisk", "basic"); + let guest_directory = testing_guest_directory("zisk", "basic_rust"); let program = RustRv64imaCustomized.compile(&guest_directory).unwrap(); assert!(!program.elf().is_empty(), "ELF bytes should not be empty."); } diff --git a/crates/zkvm/zisk/src/zkvm.rs b/crates/zkvm/zisk/src/zkvm.rs index d0704e8..67d8de8 100644 --- a/crates/zkvm/zisk/src/zkvm.rs +++ b/crates/zkvm/zisk/src/zkvm.rs @@ -153,7 +153,7 @@ mod tests { PROGRAM .get_or_init(|| { RustRv64imaCustomized - .compile(&testing_guest_directory("zisk", "basic")) + .compile(&testing_guest_directory("zisk", "basic_rust")) .unwrap() }) .clone() diff --git a/docker/base/Dockerfile.base b/docker/base/Dockerfile.base index e989921..a442b86 100644 --- a/docker/base/Dockerfile.base +++ b/docker/base/Dockerfile.base @@ -44,6 +44,13 @@ ENV RUSTUP_HOME=/usr/local/rustup \ RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain ${RUST_VERSION} --no-modify-path +# Copy the TamaGo installer script from the workspace context +COPY --chmod=755 scripts/install_tamago.sh /tmp/install_tamago.sh + +# Run the TamaGo installation script. +RUN /tmp/install_tamago.sh && \ + rm /tmp/install_tamago.sh + # Add a non-root user for subsequent stages or use in derived images # This is generally best practice. ARG USERNAME=ere_user diff --git a/scripts/install_tamago.sh b/scripts/install_tamago.sh new file mode 100755 index 0000000..02d6567 --- /dev/null +++ b/scripts/install_tamago.sh @@ -0,0 +1,119 @@ +#!/bin/bash + +set -e # Exit on error + +GO_BRANCH="tamago1.25.2-zkvm-dev" + +# Configuration +INSTALL_DIR="$HOME/.tamago" # that can't be empty nor "/"! +TEMP_DIR=$(mktemp -d) +GO_BRANCH="${GO_BRANCH:-master}" # Default to master, can override with env var + +# Stock Go configuration +STOCK_GO_VERSION="go1.25.3" +STOCK_GO_DIR="$TEMP_DIR/stock-go" +STOCK_GO_INSTALL=false + +echo "Building Go compiler..." +echo "Installation directory: $INSTALL_DIR" +echo "Version/branch: $GO_BRANCH" +echo "" + +# Clean up temp directory on exit +trap "rm -rf $TEMP_DIR" EXIT + +# Check if Go 1.25.3 is installed +echo "Checking for Go compiler..." +if command -v go &> /dev/null; then + CURRENT_GO_VERSION=$(go version | awk '{print $3}') + if [ "$CURRENT_GO_VERSION" = "$STOCK_GO_VERSION" ]; then + echo "Found Go $STOCK_GO_VERSION already installed" + else + echo "Found Go $CURRENT_GO_VERSION, but need $STOCK_GO_VERSION" + STOCK_GO_INSTALL=true + fi +else + echo "Go compiler not found, will install $STOCK_GO_VERSION" + STOCK_GO_INSTALL=true +fi + +# Install stock Go if needed +if [ "$STOCK_GO_INSTALL" = true ]; then + echo "Installing stock Go $STOCK_GO_VERSION..." + + # Detect OS and architecture + OS=$(uname -s | tr '[:upper:]' '[:lower:]') + ARCH=$(uname -m) + + case "$ARCH" in + x86_64) + ARCH="amd64" + ;; + aarch64|arm64) + ARCH="arm64" + ;; + *) + echo "Error: Unsupported architecture: $ARCH" + exit 1 + ;; + esac + + GO_ARCHIVE="${STOCK_GO_VERSION}.${OS}-${ARCH}.tar.gz" + GO_URL="https://go.dev/dl/${GO_ARCHIVE}" + + echo "Downloading from $GO_URL..." + cd "$TEMP_DIR" + + curl -L -O "$GO_URL" + + echo "Extracting Go archive..." + tar -xzf "$GO_ARCHIVE" + mv go "$STOCK_GO_DIR" + + # Add stock Go to PATH + export PATH="$STOCK_GO_DIR/bin:$PATH" + export GOROOT="$STOCK_GO_DIR" + + echo "Stock Go installed temporarily at $STOCK_GO_DIR" + go version +fi + +# Check if git is installed +if ! command -v git &> /dev/null; then + echo "Error: git is not installed. Please install git first." + exit 1 +fi + +# Clone Go repository +echo "Cloning Go repository..." +cd "$TEMP_DIR" +git clone --depth 1 --branch $GO_BRANCH https://github.com/eth-act/tamago-go.git go + +cd go + +# Remove .git directory to save space +echo "Removing .git directory..." +rm -rf .git + +# Build Go +echo "Building Go compiler..." +cd src +GOROOT_FINAL="$INSTALL_DIR" ./make.bash + +# Move built Go to installation directory +echo "Installing to $INSTALL_DIR..." +cd ../.. +rm -rf "$INSTALL_DIR" +mv go "$INSTALL_DIR" + +echo "" +echo "Go compiler successfully built and installed to: $INSTALL_DIR" +echo "" +echo "To use this Go installation, add the following to your shell profile:" +echo "" +echo " export GOROOT=$INSTALL_DIR" +echo " export PATH=\$GOROOT/bin:\$PATH" +echo "" +echo "Then run: source ~/.bashrc (or ~/.zshrc, depending on your shell)" +echo "" +echo "Verify installation with: go version" diff --git a/tests/zisk/basic_go/go.mod b/tests/zisk/basic_go/go.mod new file mode 100644 index 0000000..821f686 --- /dev/null +++ b/tests/zisk/basic_go/go.mod @@ -0,0 +1,8 @@ +module basic_go + +go 1.24.4 + +require ( + github.com/eth-act/skunkworks-tama v0.0.0-20251105112532-eff8e3af014b // indirect + github.com/usbarmory/tamago v0.0.0-20250710154000-3dd21eabac74 // indirect +) diff --git a/tests/zisk/basic_go/go.sum b/tests/zisk/basic_go/go.sum new file mode 100644 index 0000000..60b0460 --- /dev/null +++ b/tests/zisk/basic_go/go.sum @@ -0,0 +1,4 @@ +github.com/eth-act/skunkworks-tama v0.0.0-20251105112532-eff8e3af014b h1:Nm1FYhFjCWnKkaRZzSjGmeWdqevsunbpOnYOayWpuoM= +github.com/eth-act/skunkworks-tama v0.0.0-20251105112532-eff8e3af014b/go.mod h1:M9fXNuyicUdFmj5nBlXRTNcUbJIDLMMs4eY1QoZHM3g= +github.com/usbarmory/tamago v0.0.0-20250710154000-3dd21eabac74 h1:zH22Y68S2cpwW278H+9v4r2SWpdP+JwUk/AwVc9LOlw= +github.com/usbarmory/tamago v0.0.0-20250710154000-3dd21eabac74/go.mod h1:0Bc0GnC88LvCAoCRUcd3DBFl7cribfVbCsiMJUbXyAE= diff --git a/tests/zisk/basic_go/main.go b/tests/zisk/basic_go/main.go new file mode 100644 index 0000000..ad56970 --- /dev/null +++ b/tests/zisk/basic_go/main.go @@ -0,0 +1,14 @@ +//go:build tamago && riscv64 + +package main + +import ( + "fmt" + _ "github.com/eth-act/skunkworks-tama/tamaboards/zkvm" +) + +func main() { + x := 10 + y := 11 + fmt.Println("Hello World", x + y) +} diff --git a/tests/zisk/basic/Cargo.toml b/tests/zisk/basic_rust/Cargo.toml similarity index 100% rename from tests/zisk/basic/Cargo.toml rename to tests/zisk/basic_rust/Cargo.toml diff --git a/tests/zisk/basic/src/main.rs b/tests/zisk/basic_rust/src/main.rs similarity index 100% rename from tests/zisk/basic/src/main.rs rename to tests/zisk/basic_rust/src/main.rs