mirror of
https://github.com/eth-act/ere.git
synced 2026-02-19 11:54:42 -05:00
In ZisK verify method checks rom digest is expected as the preprocessed one (#99)
This commit is contained in:
10
Cargo.lock
generated
10
Cargo.lock
generated
@@ -2386,7 +2386,9 @@ dependencies = [
|
||||
"bincode",
|
||||
"blake3",
|
||||
"build-utils",
|
||||
"dashmap",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tempfile",
|
||||
"test-utils",
|
||||
"thiserror 2.0.12",
|
||||
@@ -3124,9 +3126,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.9"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
||||
checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
@@ -4519,9 +4521,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.16.0"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
|
||||
checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
|
||||
@@ -35,6 +35,7 @@ borsh = "1.5.7"
|
||||
bytemuck = "1.23.1"
|
||||
cargo_metadata = "0.19.0"
|
||||
clap = "4.5.42"
|
||||
dashmap = "6.1.0"
|
||||
erased-serde = "0.4.6"
|
||||
indexmap = "2.10.0"
|
||||
serde = "1.0.219"
|
||||
|
||||
@@ -8,7 +8,9 @@ license.workspace = true
|
||||
[dependencies]
|
||||
bincode.workspace = true
|
||||
blake3.workspace = true
|
||||
dashmap.workspace = true
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json.workspace = true
|
||||
tempfile.workspace = true
|
||||
thiserror.workspace = true
|
||||
toml.workspace = true
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use std::{io, path::PathBuf, process::ExitStatus};
|
||||
use crate::RomDigest;
|
||||
use std::{io, num::ParseIntError, path::PathBuf, process::ExitStatus};
|
||||
use thiserror::Error;
|
||||
use zkvm_interface::zkVMError;
|
||||
|
||||
@@ -8,6 +9,12 @@ impl From<ZiskError> for zkVMError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CommonError> for zkVMError {
|
||||
fn from(value: CommonError) -> Self {
|
||||
zkVMError::Other(Box::new(value))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ZiskError {
|
||||
#[error(transparent)]
|
||||
@@ -101,13 +108,6 @@ pub enum ProveError {
|
||||
TempDir(io::Error),
|
||||
#[error("Failed to serialize input: {0}")]
|
||||
SerializeInput(Box<dyn std::error::Error + Send + Sync>),
|
||||
#[error("Failed to execute `cargo-zisk rom-setup`: {source}")]
|
||||
CargoZiskRomSetup {
|
||||
#[source]
|
||||
source: io::Error,
|
||||
},
|
||||
#[error("`cargo-zisk rom-setup` failed with status: {status}")]
|
||||
CargoZiskRomSetupFailed { status: ExitStatus },
|
||||
#[error("Failed to execute `cargo prove`: {source}")]
|
||||
CargoZiskProve {
|
||||
#[source]
|
||||
@@ -117,7 +117,7 @@ pub enum ProveError {
|
||||
CargoZiskProveFailed { status: ExitStatus },
|
||||
#[error("Serialising proof with `bincode` failed: {0}")]
|
||||
Bincode(#[from] bincode::Error),
|
||||
#[error("Failed to obtain prove lock")]
|
||||
#[error("Prove lock poisoned")]
|
||||
ProveLockPoisoned,
|
||||
}
|
||||
|
||||
@@ -134,4 +134,37 @@ pub enum VerifyError {
|
||||
},
|
||||
#[error("Invalid proof: {0}")]
|
||||
InvalidProof(String),
|
||||
#[error("Invalid public values: {0}")]
|
||||
DeserializePublicValues(serde_json::Error),
|
||||
#[error("Invalid public value: {0}")]
|
||||
ParsePublicValue(ParseIntError),
|
||||
#[error("Unexpected ROM digest")]
|
||||
UnexpectedRomDigest {
|
||||
preprocessed: RomDigest,
|
||||
public_values: Vec<u64>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum CommonError {
|
||||
#[error("IO failure in temporary directory: {0}")]
|
||||
TempDir(io::Error),
|
||||
#[error("ROM digest map poisoned")]
|
||||
RomDigestMapPoisoned,
|
||||
#[error("Failed to execute `cargo-zisk rom-setup`: {source}")]
|
||||
CargoZiskRomSetup {
|
||||
#[source]
|
||||
source: io::Error,
|
||||
},
|
||||
#[error("`cargo-zisk rom-setup` failed with status: {status}")]
|
||||
CargoZiskRomSetupFailed { status: ExitStatus },
|
||||
#[error("Failed to find ROM digest")]
|
||||
RomDigestNotFound,
|
||||
#[error("Failed to execute `cargo-zisk check-setup`: {source}")]
|
||||
CargoZiskCheckSetup {
|
||||
#[source]
|
||||
source: io::Error,
|
||||
},
|
||||
#[error("`cargo-zisk check-setup` failed with status: {status}")]
|
||||
CargoZiskCheckSetupFailed { status: ExitStatus },
|
||||
}
|
||||
|
||||
@@ -2,16 +2,18 @@
|
||||
|
||||
use crate::{
|
||||
compile::compile_zisk_program,
|
||||
error::{ExecuteError, ProveError, VerifyError, ZiskError},
|
||||
error::{CommonError, ExecuteError, ProveError, VerifyError, ZiskError},
|
||||
};
|
||||
use blake3::Hash;
|
||||
use dashmap::{DashMap, Entry};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
fs,
|
||||
io::{self, Write},
|
||||
io::{self, BufRead, Write},
|
||||
os::unix::fs::symlink,
|
||||
path::{Path, PathBuf},
|
||||
process::{Command, Stdio},
|
||||
sync::Mutex,
|
||||
sync::{LazyLock, Mutex},
|
||||
time,
|
||||
};
|
||||
use tempfile::{TempDir, tempdir};
|
||||
@@ -29,10 +31,16 @@ mod error;
|
||||
/// Lock for the command `cargo-zisk check-setup` to avoid multiple runs.
|
||||
static SETUP_LOCK: Mutex<bool> = Mutex::new(false);
|
||||
|
||||
/// Mapping from ELF hash to ROM digest. It uses `blake3` for ELF hash as ZisK.
|
||||
static ROM_DIGEST_MAP: LazyLock<DashMap<Hash, RomDigest>> = LazyLock::new(DashMap::new);
|
||||
|
||||
/// It panics if `EreZisk::prove` is called concurrently, so we need a lock here
|
||||
/// to avoid that.
|
||||
static PROVE_LOCK: Mutex<()> = Mutex::new(());
|
||||
|
||||
/// Merkle root of ROM trace generated by `cargo-zisk rom-setup`.
|
||||
pub type RomDigest = [u64; 4];
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
pub struct RV64_IMA_ZISK_ZKVM_ELF;
|
||||
|
||||
@@ -74,7 +82,7 @@ impl zkVM for EreZisk {
|
||||
.map_err(ZiskError::Execute)?;
|
||||
|
||||
let mut tempdir =
|
||||
ZiskTempDir::new(false).map_err(|e| ZiskError::Execute(ExecuteError::TempDir(e)))?;
|
||||
ZiskTempDir::new().map_err(|e| ZiskError::Execute(ExecuteError::TempDir(e)))?;
|
||||
tempdir
|
||||
.write_elf(&self.elf)
|
||||
.map_err(|e| ZiskError::Execute(ExecuteError::TempDir(e)))?;
|
||||
@@ -96,10 +104,9 @@ impl zkVM for EreZisk {
|
||||
.map_err(|e| ZiskError::Execute(ExecuteError::Ziskemu { source: e }))?;
|
||||
|
||||
if !output.status.success() {
|
||||
return Err(ZiskError::Execute(ExecuteError::ZiskemuFailed {
|
||||
Err(ZiskError::Execute(ExecuteError::ZiskemuFailed {
|
||||
status: output.status,
|
||||
})
|
||||
.into());
|
||||
}))?
|
||||
}
|
||||
let execution_duration = start.elapsed();
|
||||
|
||||
@@ -126,6 +133,9 @@ impl zkVM for EreZisk {
|
||||
// Make sure proving key setup is done.
|
||||
check_setup()?;
|
||||
|
||||
// Run ELF specific setup
|
||||
rom_setup(&self.elf)?;
|
||||
|
||||
// Obtain the prove lock to make sure proving can't be called concurrently.
|
||||
let _guard = PROVE_LOCK
|
||||
.lock()
|
||||
@@ -139,7 +149,7 @@ impl zkVM for EreZisk {
|
||||
.map_err(ZiskError::Prove)?;
|
||||
|
||||
let mut tempdir =
|
||||
ZiskTempDir::new(true).map_err(|e| ZiskError::Prove(ProveError::TempDir(e)))?;
|
||||
ZiskTempDir::new().map_err(|e| ZiskError::Prove(ProveError::TempDir(e)))?;
|
||||
tempdir
|
||||
.write_elf(&self.elf)
|
||||
.map_err(|e| ZiskError::Prove(ProveError::TempDir(e)))?;
|
||||
@@ -147,29 +157,6 @@ impl zkVM for EreZisk {
|
||||
.write_input(&input_bytes)
|
||||
.map_err(|e| ZiskError::Prove(ProveError::TempDir(e)))?;
|
||||
|
||||
// Setup ROM.
|
||||
|
||||
if !is_bin_exists(&self.elf, tempdir.elf_path()) {
|
||||
info!("Running command `cargo-zisk rom-setup` ...");
|
||||
|
||||
let status = Command::new("cargo-zisk")
|
||||
.arg("rom-setup")
|
||||
.arg("--elf")
|
||||
.arg(tempdir.elf_path())
|
||||
.arg("--zisk-path")
|
||||
.arg(tempdir.zisk_dir_path())
|
||||
.status()
|
||||
.map_err(|e| ZiskError::Prove(ProveError::CargoZiskRomSetup { source: e }))?;
|
||||
|
||||
if !status.success() {
|
||||
return Err(
|
||||
ZiskError::Prove(ProveError::CargoZiskRomSetupFailed { status }).into(),
|
||||
);
|
||||
}
|
||||
|
||||
info!("Command `cargo-zisk rom-setup` succeeded");
|
||||
}
|
||||
|
||||
// Prove.
|
||||
|
||||
// TODO: Use `mpirun --np {num_processes} cargo-zisk prove ...` to
|
||||
@@ -198,9 +185,9 @@ impl zkVM for EreZisk {
|
||||
.map_err(|e| ZiskError::Prove(ProveError::CargoZiskProve { source: e }))?;
|
||||
|
||||
if !status.success() {
|
||||
return Err(
|
||||
ZiskError::Prove(ProveError::CargoZiskProveFailed { status }).into(),
|
||||
);
|
||||
Err(ZiskError::Prove(ProveError::CargoZiskProveFailed {
|
||||
status,
|
||||
}))?
|
||||
}
|
||||
}
|
||||
ProverResourceType::Gpu => {
|
||||
@@ -233,9 +220,9 @@ impl zkVM for EreZisk {
|
||||
.map_err(|e| ZiskError::Prove(ProveError::CargoZiskProve { source: e }))?;
|
||||
|
||||
if !status.success() {
|
||||
return Err(
|
||||
ZiskError::Prove(ProveError::CargoZiskProveFailed { status }).into(),
|
||||
);
|
||||
Err(ZiskError::Prove(ProveError::CargoZiskProveFailed {
|
||||
status,
|
||||
}))?
|
||||
}
|
||||
}
|
||||
ProverResourceType::Network(_) => {
|
||||
@@ -263,13 +250,16 @@ impl zkVM for EreZisk {
|
||||
}
|
||||
|
||||
fn verify(&self, bytes: &[u8]) -> Result<(), zkVMError> {
|
||||
// Run ELF specific setup
|
||||
let rom_digest = rom_setup(&self.elf)?;
|
||||
|
||||
// Write proof and public values to file.
|
||||
|
||||
let proof_with_public_values: ZiskProofWithPublicValues = bincode::deserialize(bytes)
|
||||
.map_err(|err| ZiskError::Verify(VerifyError::Bincode(err)))?;
|
||||
|
||||
let mut tempdir =
|
||||
ZiskTempDir::new(false).map_err(|e| ZiskError::Verify(VerifyError::TempDir(e)))?;
|
||||
ZiskTempDir::new().map_err(|e| ZiskError::Verify(VerifyError::TempDir(e)))?;
|
||||
tempdir
|
||||
.write_proof(&proof_with_public_values.proof)
|
||||
.map_err(|e| ZiskError::Verify(VerifyError::TempDir(e)))?;
|
||||
@@ -289,10 +279,26 @@ impl zkVM for EreZisk {
|
||||
.map_err(|e| ZiskError::Verify(VerifyError::CargoZiskVerify { source: e }))?;
|
||||
|
||||
if !output.status.success() {
|
||||
return Err(ZiskError::Verify(VerifyError::InvalidProof(
|
||||
Err(ZiskError::Verify(VerifyError::InvalidProof(
|
||||
String::from_utf8_lossy(&output.stderr).to_string(),
|
||||
))
|
||||
.into());
|
||||
)))?
|
||||
}
|
||||
|
||||
// Deserialize public values as json string sequence.
|
||||
let public_values =
|
||||
serde_json::from_slice::<Vec<String>>(&proof_with_public_values.public_values)
|
||||
.map_err(|e| ZiskError::Verify(VerifyError::DeserializePublicValues(e)))?
|
||||
.into_iter()
|
||||
.map(|v| v.parse())
|
||||
.collect::<Result<Vec<u64>, _>>()
|
||||
.map_err(|e| ZiskError::Verify(VerifyError::ParsePublicValue(e)))?;
|
||||
|
||||
// The first 4 elements of public values should be equal to preprocessed ROM digest.
|
||||
if public_values.len() < 4 || public_values[..4] != rom_digest {
|
||||
Err(ZiskError::Verify(VerifyError::UnexpectedRomDigest {
|
||||
preprocessed: rom_digest,
|
||||
public_values,
|
||||
}))?
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -327,6 +333,7 @@ fn dot_zisk_dir_path() -> PathBuf {
|
||||
PathBuf::from(std::env::var("HOME").expect("env `$HOME` should be set")).join(".zisk")
|
||||
}
|
||||
|
||||
/// Run ELF independent proving key setup.
|
||||
fn check_setup() -> Result<(), zkVMError> {
|
||||
let mut setup = SETUP_LOCK
|
||||
.lock()
|
||||
@@ -335,23 +342,13 @@ fn check_setup() -> Result<(), zkVMError> {
|
||||
if !*setup {
|
||||
info!("Running command `cargo-zisk check-setup --aggregation`...");
|
||||
|
||||
let output = Command::new("cargo-zisk")
|
||||
let status = Command::new("cargo-zisk")
|
||||
.args(["check-setup", "--aggregation"])
|
||||
.output()
|
||||
.map_err(|e| {
|
||||
zkVMError::Other(
|
||||
format!("Failed to run command `cargo-zisk check-setup`: {e}").into(),
|
||||
)
|
||||
})?;
|
||||
.status()
|
||||
.map_err(|e| CommonError::CargoZiskCheckSetup { source: e })?;
|
||||
|
||||
if !output.status.success() {
|
||||
return Err(zkVMError::Other(
|
||||
format!(
|
||||
"Command `cargo-zisk check-setup` failed: {}",
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
)
|
||||
.into(),
|
||||
));
|
||||
if !status.success() {
|
||||
Err(CommonError::CargoZiskCheckSetupFailed { status })?
|
||||
}
|
||||
|
||||
info!("Command `cargo-zisk check-setup --aggregation` succeeded");
|
||||
@@ -362,96 +359,117 @@ fn check_setup() -> Result<(), zkVMError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Check if these files exists in `$HOME/.zisk/cache`:
|
||||
///
|
||||
/// - `{elf_file_stem}-{elf_hash}-mo.bin`
|
||||
/// - `{elf_file_stem}-{elf_hash}-mt.bin`
|
||||
/// - `{elf_file_stem}-{elf_hash}-rh.bin`
|
||||
///
|
||||
/// Which are generated by `cargo-zisk rom-setup ...`.
|
||||
fn is_bin_exists(elf: &[u8], elf_path: impl AsRef<Path>) -> bool {
|
||||
let stem = elf_path
|
||||
.as_ref()
|
||||
.file_stem()
|
||||
.expect("ELF file has name")
|
||||
.to_str()
|
||||
.expect("ELF file name is valid UTF-8");
|
||||
let hash = blake3::hash(elf).to_hex().to_string();
|
||||
["mo", "mt", "rh"].into_iter().all(|suffix| {
|
||||
fs::exists(
|
||||
dot_zisk_dir_path()
|
||||
.join("cache")
|
||||
.join(format!("{stem}-{hash}-{suffix}.bin")),
|
||||
)
|
||||
.ok()
|
||||
== Some(true)
|
||||
})
|
||||
/// Run ELF specific setup and returns digest of ROM.
|
||||
fn rom_setup(elf: &[u8]) -> Result<RomDigest, zkVMError> {
|
||||
let mut tempdir = ZiskTempDir::new().map_err(CommonError::TempDir)?;
|
||||
tempdir.create_zisk_dir().map_err(CommonError::TempDir)?;
|
||||
tempdir.write_elf(elf).map_err(CommonError::TempDir)?;
|
||||
|
||||
let rom_digest = match ROM_DIGEST_MAP.entry(blake3::hash(elf)) {
|
||||
Entry::Occupied(entry) => *entry.get(),
|
||||
Entry::Vacant(entry) => {
|
||||
info!("Running command `cargo-zisk rom-setup` ...");
|
||||
|
||||
let output = Command::new("cargo-zisk")
|
||||
.arg("rom-setup")
|
||||
.arg("--elf")
|
||||
.arg(tempdir.elf_path())
|
||||
.arg("--zisk-path")
|
||||
.arg(tempdir.zisk_dir_path())
|
||||
.output()
|
||||
.map_err(|e| CommonError::CargoZiskRomSetup { source: e })?;
|
||||
|
||||
if !output.status.success() {
|
||||
Err(CommonError::CargoZiskRomSetupFailed {
|
||||
status: output.status,
|
||||
})?;
|
||||
}
|
||||
|
||||
let rom_digest = output
|
||||
.stdout
|
||||
.lines()
|
||||
.find_map(|line| {
|
||||
let line = line.ok()?;
|
||||
let line = line.split_once("Root hash: [")?.1;
|
||||
let line = line.strip_suffix("]")?;
|
||||
line.split(", ")
|
||||
.filter_map(|word| word.parse::<u64>().ok())
|
||||
.collect::<Vec<_>>()
|
||||
.try_into()
|
||||
.ok()
|
||||
})
|
||||
.ok_or(CommonError::RomDigestNotFound)?;
|
||||
|
||||
info!("Command `cargo-zisk rom-setup` succeeded");
|
||||
|
||||
*entry.insert(rom_digest)
|
||||
}
|
||||
};
|
||||
|
||||
Ok(rom_digest)
|
||||
}
|
||||
|
||||
struct ZiskTempDir {
|
||||
tempdir: TempDir,
|
||||
elf_hash: Option<String>,
|
||||
}
|
||||
|
||||
impl ZiskTempDir {
|
||||
/// Create temporary directories for:
|
||||
/// - `guest.elf` - ELF compiled from guest program.
|
||||
/// - `zisk/` - Directory for building process during `rom-setup`.
|
||||
/// - `input.bin` - Input of execution or proving.
|
||||
/// - `output/vadcop_final_proof.json` - Aggregated proof generated by proving.
|
||||
/// - `output/publics.json` - Public values generated by proving.
|
||||
///
|
||||
/// Set `with_zisk_dir` only when `rom-setup` is to be used.
|
||||
fn new(with_zisk_dir: bool) -> io::Result<Self> {
|
||||
fn new() -> io::Result<Self> {
|
||||
let tempdir = Self {
|
||||
tempdir: tempdir()?,
|
||||
elf_hash: None,
|
||||
};
|
||||
|
||||
fs::create_dir(tempdir.output_dir_path())?;
|
||||
|
||||
if with_zisk_dir {
|
||||
fs::create_dir_all(tempdir.zisk_dir_path())?;
|
||||
|
||||
// Check the global zisk directory exists.
|
||||
let global_zisk_dir_path = dot_zisk_dir_path().join("zisk");
|
||||
if !global_zisk_dir_path.exists() {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::NotFound,
|
||||
format!(
|
||||
"Global .zisk/zisk directory not found at: {}",
|
||||
global_zisk_dir_path.display()
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
// Symlink necessary files for `make` command of `cargo-zisk rom-setup`.
|
||||
// The `Makefile` can be found https://github.com/0xPolygonHermez/zisk/blob/main/emulator-asm/Makefile.
|
||||
symlink(
|
||||
dot_zisk_dir_path().join("bin"),
|
||||
tempdir.dot_zisk_dir_path().join("bin"),
|
||||
)?;
|
||||
let temp_zisk_dir_path = tempdir.zisk_dir_path();
|
||||
fs::create_dir_all(temp_zisk_dir_path.join("emulator-asm").join("build"))?;
|
||||
symlink(
|
||||
global_zisk_dir_path.join("emulator-asm").join("Makefile"),
|
||||
temp_zisk_dir_path.join("emulator-asm").join("Makefile"),
|
||||
)?;
|
||||
symlink(
|
||||
global_zisk_dir_path.join("emulator-asm").join("src"),
|
||||
temp_zisk_dir_path.join("emulator-asm").join("src"),
|
||||
)?;
|
||||
symlink(
|
||||
global_zisk_dir_path.join("lib-c"),
|
||||
temp_zisk_dir_path.join("lib-c"),
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(tempdir)
|
||||
}
|
||||
|
||||
/// Create temporary directory `zisk` for `rom-setup`.
|
||||
fn create_zisk_dir(&mut self) -> io::Result<()> {
|
||||
fs::create_dir_all(self.zisk_dir_path())?;
|
||||
|
||||
// Check the global zisk directory exists.
|
||||
let global_zisk_dir_path = dot_zisk_dir_path().join("zisk");
|
||||
if !global_zisk_dir_path.exists() {
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::NotFound,
|
||||
format!(
|
||||
"Global .zisk/zisk directory not found at: {}",
|
||||
global_zisk_dir_path.display()
|
||||
),
|
||||
))?
|
||||
}
|
||||
|
||||
// Symlink necessary files for `make` command of `cargo-zisk rom-setup`.
|
||||
// The `Makefile` can be found https://github.com/0xPolygonHermez/zisk/blob/v0.10.0/emulator-asm/Makefile.
|
||||
symlink(
|
||||
dot_zisk_dir_path().join("bin"),
|
||||
self.dot_zisk_dir_path().join("bin"),
|
||||
)?;
|
||||
let temp_zisk_dir_path = self.zisk_dir_path();
|
||||
fs::create_dir_all(temp_zisk_dir_path.join("emulator-asm").join("build"))?;
|
||||
symlink(
|
||||
global_zisk_dir_path.join("emulator-asm").join("Makefile"),
|
||||
temp_zisk_dir_path.join("emulator-asm").join("Makefile"),
|
||||
)?;
|
||||
symlink(
|
||||
global_zisk_dir_path.join("emulator-asm").join("src"),
|
||||
temp_zisk_dir_path.join("emulator-asm").join("src"),
|
||||
)?;
|
||||
symlink(
|
||||
global_zisk_dir_path.join("lib-c"),
|
||||
temp_zisk_dir_path.join("lib-c"),
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_elf(&mut self, elf: &[u8]) -> io::Result<()> {
|
||||
self.elf_hash = Some(blake3::hash(elf).to_hex().to_string());
|
||||
fs::write(self.elf_path(), elf)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user