From 5894486a4132f2b3861a6d6677a4ecc7912ca95b Mon Sep 17 00:00:00 2001 From: Angell Li Date: Wed, 19 Jun 2024 21:40:00 +0800 Subject: [PATCH 01/13] add zkvm runtime --- zkvm/entrypoint/Cargo.toml | 20 + zkvm/entrypoint/src/heap.rs | 16 + zkvm/entrypoint/src/lib.rs | 91 ++++ zkvm/entrypoint/src/libm.rs | 559 +++++++++++++++++++++++++ zkvm/entrypoint/src/memcpy.s | 335 +++++++++++++++ zkvm/entrypoint/src/memory.rs | 51 +++ zkvm/entrypoint/src/memset.s | 316 ++++++++++++++ zkvm/entrypoint/src/syscalls/halt.rs | 27 ++ zkvm/entrypoint/src/syscalls/io.rs | 72 ++++ zkvm/entrypoint/src/syscalls/memory.rs | 51 +++ zkvm/entrypoint/src/syscalls/mod.rs | 28 ++ zkvm/entrypoint/src/syscalls/sys.rs | 68 +++ zkvm/precompiles/Cargo.toml | 14 + zkvm/precompiles/src/io.rs | 90 ++++ zkvm/precompiles/src/lib.rs | 25 ++ zkvm/precompiles/src/utils.rs | 109 +++++ 16 files changed, 1872 insertions(+) create mode 100644 zkvm/entrypoint/Cargo.toml create mode 100644 zkvm/entrypoint/src/heap.rs create mode 100644 zkvm/entrypoint/src/lib.rs create mode 100644 zkvm/entrypoint/src/libm.rs create mode 100644 zkvm/entrypoint/src/memcpy.s create mode 100644 zkvm/entrypoint/src/memory.rs create mode 100644 zkvm/entrypoint/src/memset.s create mode 100644 zkvm/entrypoint/src/syscalls/halt.rs create mode 100644 zkvm/entrypoint/src/syscalls/io.rs create mode 100644 zkvm/entrypoint/src/syscalls/memory.rs create mode 100644 zkvm/entrypoint/src/syscalls/mod.rs create mode 100644 zkvm/entrypoint/src/syscalls/sys.rs create mode 100644 zkvm/precompiles/Cargo.toml create mode 100644 zkvm/precompiles/src/io.rs create mode 100644 zkvm/precompiles/src/lib.rs create mode 100644 zkvm/precompiles/src/utils.rs diff --git a/zkvm/entrypoint/Cargo.toml b/zkvm/entrypoint/Cargo.toml new file mode 100644 index 00000000..303100a0 --- /dev/null +++ b/zkvm/entrypoint/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "zkm-zkvm" +version = "0.1.0" +edition = "2021" + +[dependencies] +zkm-precompiles = { path = "../precompiles" } +bincode = "1.3.3" +cfg-if = "1.0.0" +getrandom = { version = "0.2.14", features = ["custom"] } +once_cell = "1.19.0" +rand = "0.8.5" +serde = { version = "1.0.201", features = ["derive"] } +libm = { version = "0.2.8", optional = true } +sha2 = { version = "0.10.8" } +lazy_static = "1.4.0" + +[features] +default = ["libm"] +libm = ["dep:libm"] diff --git a/zkvm/entrypoint/src/heap.rs b/zkvm/entrypoint/src/heap.rs new file mode 100644 index 00000000..86b3c0e1 --- /dev/null +++ b/zkvm/entrypoint/src/heap.rs @@ -0,0 +1,16 @@ +use core::alloc::{GlobalAlloc, Layout}; + +use crate::syscalls::sys_alloc_aligned; + +/// A simple heap allocator. +/// +/// Allocates memory from left to right, without any deallocation. +pub struct SimpleAlloc; + +unsafe impl GlobalAlloc for SimpleAlloc { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + sys_alloc_aligned(layout.size(), layout.align()) + } + + unsafe fn dealloc(&self, _: *mut u8, _: Layout) {} +} diff --git a/zkvm/entrypoint/src/lib.rs b/zkvm/entrypoint/src/lib.rs new file mode 100644 index 00000000..848fb03c --- /dev/null +++ b/zkvm/entrypoint/src/lib.rs @@ -0,0 +1,91 @@ +pub mod heap; +pub mod syscalls; +pub mod io { + pub use zkm_precompiles::io::*; +} +pub mod precompiles { + pub use zkm_precompiles::*; +} + +extern crate alloc; + +#[macro_export] +macro_rules! entrypoint { + ($path:path) => { + const ZKVM_ENTRY: fn() = $path; + + use $crate::heap::SimpleAlloc; + + #[global_allocator] + static HEAP: SimpleAlloc = SimpleAlloc; + + mod zkvm_generated_main { + + #[no_mangle] + fn main() { + super::ZKVM_ENTRY() + } + } + }; +} + +#[cfg(all(target_os = "zkvm", feature = "libm"))] +mod libm; + +/// The number of 32 bit words that the public values digest is composed of. +pub const PV_DIGEST_NUM_WORDS: usize = 8; +pub const POSEIDON_NUM_WORDS: usize = 8; + +#[cfg(target_os = "zkvm")] +mod zkvm { + use crate::syscalls::syscall_halt; + + use cfg_if::cfg_if; + use getrandom::{register_custom_getrandom, Error}; + use sha2::{Digest, Sha256}; + + pub static mut PUBLIC_VALUES_HASHER: Option = None; + + #[cfg(not(feature = "interface"))] + #[no_mangle] + unsafe extern "C" fn __start() { + { + PUBLIC_VALUES_HASHER = Some(Sha256::new()); + + extern "C" { + fn main(); + } + main() + } + + syscall_halt(0); + } + + static STACK_TOP: u32 = 0x0020_0400; + + core::arch::global_asm!(include_str!("memset.s")); + core::arch::global_asm!(include_str!("memcpy.s")); + + core::arch::global_asm!( + r#" + .section .text._start; + .globl _start; + _start: + la gp, __global_pointer$; + la sp, {0} + lw sp, 0(sp) + call __start; + "#, + sym STACK_TOP + ); + + fn zkvm_getrandom(s: &mut [u8]) -> Result<(), Error> { + unsafe { + crate::syscalls::sys_rand(s.as_mut_ptr(), s.len()); + } + + Ok(()) + } + + register_custom_getrandom!(zkvm_getrandom); +} diff --git a/zkvm/entrypoint/src/libm.rs b/zkvm/entrypoint/src/libm.rs new file mode 100644 index 00000000..304624d0 --- /dev/null +++ b/zkvm/entrypoint/src/libm.rs @@ -0,0 +1,559 @@ +#[no_mangle] +pub extern "C" fn acos(x: f64) -> f64 { + libm::acos(x) +} + +#[no_mangle] +pub extern "C" fn acosf(x: f32) -> f32 { + libm::acosf(x) +} + +#[no_mangle] +pub extern "C" fn acosh(x: f64) -> f64 { + libm::acosh(x) +} + +#[no_mangle] +pub extern "C" fn acoshf(x: f32) -> f32 { + libm::acoshf(x) +} + +#[no_mangle] +pub extern "C" fn asin(x: f64) -> f64 { + libm::asin(x) +} + +#[no_mangle] +pub extern "C" fn asinf(x: f32) -> f32 { + libm::asinf(x) +} + +#[no_mangle] +pub extern "C" fn asinh(x: f64) -> f64 { + libm::asinh(x) +} + +#[no_mangle] +pub extern "C" fn asinhf(x: f32) -> f32 { + libm::asinhf(x) +} + +#[no_mangle] +pub extern "C" fn atan(x: f64) -> f64 { + libm::atan(x) +} + +#[no_mangle] +pub extern "C" fn atan2(y: f64, x: f64) -> f64 { + libm::atan2(y, x) +} + +#[no_mangle] +pub extern "C" fn atan2f(y: f32, x: f32) -> f32 { + libm::atan2f(y, x) +} + +#[no_mangle] +pub extern "C" fn atanf(x: f32) -> f32 { + libm::atanf(x) +} + +#[no_mangle] +pub extern "C" fn atanh(x: f64) -> f64 { + libm::atanh(x) +} + +#[no_mangle] +pub extern "C" fn atanhf(x: f32) -> f32 { + libm::atanhf(x) +} + +#[no_mangle] +pub extern "C" fn cbrt(x: f64) -> f64 { + libm::cbrt(x) +} + +#[no_mangle] +pub extern "C" fn cbrtf(x: f32) -> f32 { + libm::cbrtf(x) +} + +#[no_mangle] +pub extern "C" fn ceil(x: f64) -> f64 { + libm::ceil(x) +} + +#[no_mangle] +pub extern "C" fn ceilf(x: f32) -> f32 { + libm::ceilf(x) +} + +#[no_mangle] +pub extern "C" fn copysign(x: f64, y: f64) -> f64 { + libm::copysign(x, y) +} + +#[no_mangle] +pub extern "C" fn copysignf(x: f32, y: f32) -> f32 { + libm::copysignf(x, y) +} + +#[no_mangle] +pub extern "C" fn cos(x: f64) -> f64 { + libm::cos(x) +} + +#[no_mangle] +pub extern "C" fn cosf(x: f32) -> f32 { + libm::cosf(x) +} + +#[no_mangle] +pub extern "C" fn cosh(x: f64) -> f64 { + libm::cosh(x) +} + +#[no_mangle] +pub extern "C" fn coshf(x: f32) -> f32 { + libm::coshf(x) +} + +#[no_mangle] +pub extern "C" fn erf(x: f64) -> f64 { + libm::erf(x) +} + +#[no_mangle] +pub extern "C" fn erfc(x: f64) -> f64 { + libm::erfc(x) +} + +#[no_mangle] +pub extern "C" fn erfcf(x: f32) -> f32 { + libm::erfcf(x) +} + +#[no_mangle] +pub extern "C" fn erff(x: f32) -> f32 { + libm::erff(x) +} + +#[no_mangle] +pub extern "C" fn exp(x: f64) -> f64 { + libm::exp(x) +} + +#[no_mangle] +pub extern "C" fn exp2(x: f64) -> f64 { + libm::exp2(x) +} + +#[no_mangle] +pub extern "C" fn exp2f(x: f32) -> f32 { + libm::exp2f(x) +} + +#[no_mangle] +pub extern "C" fn exp10(x: f64) -> f64 { + libm::exp10(x) +} + +#[no_mangle] +pub extern "C" fn exp10f(x: f32) -> f32 { + libm::exp10f(x) +} + +#[no_mangle] +pub extern "C" fn expf(x: f32) -> f32 { + libm::expf(x) +} + +#[no_mangle] +pub extern "C" fn expm1(x: f64) -> f64 { + libm::expm1(x) +} + +#[no_mangle] +pub extern "C" fn expm1f(x: f32) -> f32 { + libm::expm1f(x) +} + +#[no_mangle] +pub extern "C" fn fabs(x: f64) -> f64 { + libm::fabs(x) +} + +#[no_mangle] +pub extern "C" fn fabsf(x: f32) -> f32 { + libm::fabsf(x) +} + +#[no_mangle] +pub extern "C" fn fdim(x: f64, y: f64) -> f64 { + libm::fdim(x, y) +} + +#[no_mangle] +pub extern "C" fn fdimf(x: f32, y: f32) -> f32 { + libm::fdimf(x, y) +} + +#[no_mangle] +pub extern "C" fn floor(x: f64) -> f64 { + libm::floor(x) +} + +#[no_mangle] +pub extern "C" fn floorf(x: f32) -> f32 { + libm::floorf(x) +} + +#[no_mangle] +pub extern "C" fn fma(x: f64, y: f64, z: f64) -> f64 { + libm::fma(x, y, z) +} + +#[no_mangle] +pub extern "C" fn fmaf(x: f32, y: f32, z: f32) -> f32 { + libm::fmaf(x, y, z) +} + +#[no_mangle] +pub extern "C" fn fmax(x: f64, y: f64) -> f64 { + libm::fmax(x, y) +} + +#[no_mangle] +pub extern "C" fn fmaxf(x: f32, y: f32) -> f32 { + libm::fmaxf(x, y) +} + +#[no_mangle] +pub extern "C" fn fmin(x: f64, y: f64) -> f64 { + libm::fmin(x, y) +} + +#[no_mangle] +pub extern "C" fn fminf(x: f32, y: f32) -> f32 { + libm::fminf(x, y) +} + +#[no_mangle] +pub extern "C" fn fmod(x: f64, y: f64) -> f64 { + libm::fmod(x, y) +} + +#[no_mangle] +pub extern "C" fn fmodf(x: f32, y: f32) -> f32 { + libm::fmodf(x, y) +} + +#[no_mangle] +pub fn frexp(x: f64) -> (f64, i32) { + libm::frexp(x) +} + +#[no_mangle] +pub fn frexpf(x: f32) -> (f32, i32) { + libm::frexpf(x) +} + +#[no_mangle] +pub extern "C" fn hypot(x: f64, y: f64) -> f64 { + libm::hypot(x, y) +} + +#[no_mangle] +pub extern "C" fn hypotf(x: f32, y: f32) -> f32 { + libm::hypotf(x, y) +} + +#[no_mangle] +pub extern "C" fn ilogb(x: f64) -> i32 { + libm::ilogb(x) +} + +#[no_mangle] +pub extern "C" fn ilogbf(x: f32) -> i32 { + libm::ilogbf(x) +} + +#[no_mangle] +pub extern "C" fn j0(x: f64) -> f64 { + libm::j0(x) +} + +#[no_mangle] +pub extern "C" fn j0f(x: f32) -> f32 { + libm::j0f(x) +} + +#[no_mangle] +pub extern "C" fn j1(x: f64) -> f64 { + libm::j1(x) +} + +#[no_mangle] +pub extern "C" fn j1f(x: f32) -> f32 { + libm::j1f(x) +} + +#[no_mangle] +pub extern "C" fn jn(n: i32, x: f64) -> f64 { + libm::jn(n, x) +} + +#[no_mangle] +pub extern "C" fn jnf(n: i32, x: f32) -> f32 { + libm::jnf(n, x) +} + +#[no_mangle] +pub extern "C" fn ldexp(x: f64, n: i32) -> f64 { + libm::ldexp(x, n) +} + +#[no_mangle] +pub extern "C" fn ldexpf(x: f32, n: i32) -> f32 { + libm::ldexpf(x, n) +} + +#[no_mangle] +pub extern "C" fn lgamma(x: f64) -> f64 { + libm::lgamma(x) +} + +#[no_mangle] +pub fn lgamma_r(x: f64) -> (f64, i32) { + libm::lgamma_r(x) +} + +#[no_mangle] +pub fn lgammaf(x: f32) -> f32 { + libm::lgammaf(x) +} + +#[no_mangle] +pub fn lgammaf_r(x: f32) -> (f32, i32) { + libm::lgammaf_r(x) +} + +#[no_mangle] +pub extern "C" fn log(x: f64) -> f64 { + libm::log(x) +} + +#[no_mangle] +pub extern "C" fn log1p(x: f64) -> f64 { + libm::log1p(x) +} + +#[no_mangle] +pub extern "C" fn log1pf(x: f32) -> f32 { + libm::log1pf(x) +} + +#[no_mangle] +pub extern "C" fn log2(x: f64) -> f64 { + libm::log2(x) +} + +#[no_mangle] +pub extern "C" fn log2f(x: f32) -> f32 { + libm::log2f(x) +} + +#[no_mangle] +pub extern "C" fn log10(x: f64) -> f64 { + libm::log10(x) +} + +#[no_mangle] +pub extern "C" fn log10f(x: f32) -> f32 { + libm::log10f(x) +} + +#[no_mangle] +pub extern "C" fn logf(x: f32) -> f32 { + libm::logf(x) +} + +#[no_mangle] +pub fn modf(x: f64) -> (f64, f64) { + libm::modf(x) +} + +#[no_mangle] +pub fn modff(x: f32) -> (f32, f32) { + libm::modff(x) +} + +#[no_mangle] +pub extern "C" fn nextafter(x: f64, y: f64) -> f64 { + libm::nextafter(x, y) +} + +#[no_mangle] +pub extern "C" fn nextafterf(x: f32, y: f32) -> f32 { + libm::nextafterf(x, y) +} + +#[no_mangle] +pub extern "C" fn pow(x: f64, y: f64) -> f64 { + libm::pow(x, y) +} + +#[no_mangle] +pub extern "C" fn powf(x: f32, y: f32) -> f32 { + libm::powf(x, y) +} + +#[no_mangle] +pub extern "C" fn remainder(x: f64, y: f64) -> f64 { + libm::remainder(x, y) +} + +#[no_mangle] +pub extern "C" fn remainderf(x: f32, y: f32) -> f32 { + libm::remainderf(x, y) +} + +#[no_mangle] +pub fn remquo(x: f64, y: f64) -> (f64, i32) { + libm::remquo(x, y) +} + +#[no_mangle] +pub fn remquof(x: f32, y: f32) -> (f32, i32) { + libm::remquof(x, y) +} + +#[no_mangle] +pub extern "C" fn round(x: f64) -> f64 { + libm::round(x) +} + +#[no_mangle] +pub extern "C" fn roundf(x: f32) -> f32 { + libm::roundf(x) +} + +#[no_mangle] +pub extern "C" fn scalbn(x: f64, n: i32) -> f64 { + libm::scalbn(x, n) +} + +#[no_mangle] +pub extern "C" fn scalbnf(x: f32, n: i32) -> f32 { + libm::scalbnf(x, n) +} + +#[no_mangle] +pub extern "C" fn sin(x: f64) -> f64 { + libm::sin(x) +} + +#[no_mangle] +pub fn sincos(x: f64) -> (f64, f64) { + libm::sincos(x) +} + +#[no_mangle] +pub fn sincosf(x: f32) -> (f32, f32) { + libm::sincosf(x) +} + +#[no_mangle] +pub extern "C" fn sinf(x: f32) -> f32 { + libm::sinf(x) +} + +#[no_mangle] +pub extern "C" fn sinh(x: f64) -> f64 { + libm::sinh(x) +} + +#[no_mangle] +pub extern "C" fn sinhf(x: f32) -> f32 { + libm::sinhf(x) +} + +#[no_mangle] +pub extern "C" fn sqrt(x: f64) -> f64 { + libm::sqrt(x) +} + +#[no_mangle] +pub extern "C" fn sqrtf(x: f32) -> f32 { + libm::sqrtf(x) +} + +#[no_mangle] +pub extern "C" fn tan(x: f64) -> f64 { + libm::tan(x) +} + +#[no_mangle] +pub extern "C" fn tanf(x: f32) -> f32 { + libm::tanf(x) +} + +#[no_mangle] +pub extern "C" fn tanh(x: f64) -> f64 { + libm::tanh(x) +} + +#[no_mangle] +pub extern "C" fn tanhf(x: f32) -> f32 { + libm::tanhf(x) +} + +#[no_mangle] +pub extern "C" fn tgamma(x: f64) -> f64 { + libm::tgamma(x) +} + +#[no_mangle] +pub extern "C" fn tgammaf(x: f32) -> f32 { + libm::tgammaf(x) +} + +#[no_mangle] +pub extern "C" fn trunc(x: f64) -> f64 { + libm::trunc(x) +} + +#[no_mangle] +pub extern "C" fn truncf(x: f32) -> f32 { + libm::truncf(x) +} + +#[no_mangle] +pub extern "C" fn y0(x: f64) -> f64 { + libm::y0(x) +} + +#[no_mangle] +pub extern "C" fn y0f(x: f32) -> f32 { + libm::y0f(x) +} + +#[no_mangle] +pub extern "C" fn y1(x: f64) -> f64 { + libm::y1(x) +} + +#[no_mangle] +pub extern "C" fn y1f(x: f32) -> f32 { + libm::y1f(x) +} + +#[no_mangle] +pub extern "C" fn yn(n: i32, x: f64) -> f64 { + libm::yn(n, x) +} + +#[no_mangle] +pub extern "C" fn ynf(n: i32, x: f32) -> f32 { + libm::ynf(n, x) +} diff --git a/zkvm/entrypoint/src/memcpy.s b/zkvm/entrypoint/src/memcpy.s new file mode 100644 index 00000000..cea37dce --- /dev/null +++ b/zkvm/entrypoint/src/memcpy.s @@ -0,0 +1,335 @@ +// This is musl-libc commit 3b0a370020c4d5b80ff32a609e5322b7760f0dc4: +// +// src/string/memcpy.c +// +// This was compiled into assembly with: +// +// clang-10 -target mips -O3 -S memcpy.c -nostdlib -fno-builtin -funroll-loops +// +// and labels manually updated to not conflict. +// +// musl as a whole is licensed under the following standard MIT license: +// +// ---------------------------------------------------------------------- +// Copyright © 2005-2020 Rich Felker, et al. +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// ---------------------------------------------------------------------- +// +// Authors/contributors include: +// +// A. Wilcox +// Ada Worcester +// Alex Dowad +// Alex Suykov +// Alexander Monakov +// Andre McCurdy +// Andrew Kelley +// Anthony G. Basile +// Aric Belsito +// Arvid Picciani +// Bartosz Brachaczek +// Benjamin Peterson +// Bobby Bingham +// Boris Brezillon +// Brent Cook +// Chris Spiegel +// Clément Vasseur +// Daniel Micay +// Daniel Sabogal +// Daurnimator +// David Carlier +// David Edelsohn +// Denys Vlasenko +// Dmitry Ivanov +// Dmitry V. Levin +// Drew DeVault +// Emil Renner Berthing +// Fangrui Song +// Felix Fietkau +// Felix Janda +// Gianluca Anzolin +// Hauke Mehrtens +// He X +// Hiltjo Posthuma +// Isaac Dunham +// Jaydeep Patil +// Jens Gustedt +// Jeremy Huntwork +// Jo-Philipp Wich +// Joakim Sindholt +// John Spencer +// Julien Ramseier +// Justin Cormack +// Kaarle Ritvanen +// Khem Raj +// Kylie McClain +// Leah Neukirchen +// Luca Barbato +// Luka Perkov +// M Farkas-Dyck (Strake) +// Mahesh Bodapati +// Markus Wichmann +// Masanori Ogino +// Michael Clark +// Michael Forney +// Mikhail Kremnyov +// Natanael Copa +// Nicholas J. Kain +// orc +// Pascal Cuoq +// Patrick Oppenlander +// Petr Hosek +// Petr Skocik +// Pierre Carrier +// Reini Urban +// Rich Felker +// Richard Pennington +// Ryan Fairfax +// Samuel Holland +// Segev Finer +// Shiz +// sin +// Solar Designer +// Stefan Kristiansson +// Stefan O'Rear +// Szabolcs Nagy +// Timo Teräs +// Trutz Behn +// Valentin Ochs +// Will Dietz +// William Haddon +// William Pitcock +// +// Portions of this software are derived from third-party works licensed +// under terms compatible with the above MIT license: +// +// The TRE regular expression implementation (src/regex/reg* and +// src/regex/tre*) is Copyright © 2001-2008 Ville Laurikari and licensed +// under a 2-clause BSD license (license text in the source files). The +// included version has been heavily modified by Rich Felker in 2012, in +// the interests of size, simplicity, and namespace cleanliness. +// +// Much of the math library code (src/math/* and src/complex/*) is +// Copyright © 1993,2004 Sun Microsystems or +// Copyright © 2003-2011 David Schultz or +// Copyright © 2003-2009 Steven G. Kargl or +// Copyright © 2003-2009 Bruce D. Evans or +// Copyright © 2008 Stephen L. Moshier or +// Copyright © 2017-2018 Arm Limited +// and labelled as such in comments in the individual source files. All +// have been licensed under extremely permissive terms. +// +// The ARM memcpy code (src/string/arm/memcpy.S) is Copyright © 2008 +// The Android Open Source Project and is licensed under a two-clause BSD +// license. It was taken from Bionic libc, used on Android. +// +// The AArch64 memcpy and memset code (src/string/aarch64/*) are +// Copyright © 1999-2019, Arm Limited. +// +// The implementation of DES for crypt (src/crypt/crypt_des.c) is +// Copyright © 1994 David Burren. It is licensed under a BSD license. +// +// The implementation of blowfish crypt (src/crypt/crypt_blowfish.c) was +// originally written by Solar Designer and placed into the public +// domain. The code also comes with a fallback permissive license for use +// in jurisdictions that may not recognize the public domain. +// +// The smoothsort implementation (src/stdlib/qsort.c) is Copyright © 2011 +// Valentin Ochs and is licensed under an MIT-style license. +// +// The x86_64 port was written by Nicholas J. Kain and is licensed under +// the standard MIT terms. +// +// The mips and microblaze ports were originally written by Richard +// Pennington for use in the ellcc project. The original code was adapted +// by Rich Felker for build system and code conventions during upstream +// integration. It is licensed under the standard MIT terms. +// +// The mips64 port was contributed by Imagination Technologies and is +// licensed under the standard MIT terms. +// +// The powerpc port was also originally written by Richard Pennington, +// and later supplemented and integrated by John Spencer. It is licensed +// under the standard MIT terms. +// +// All other files which have no copyright comments are original works +// produced specifically for use as part of this library, written either +// by Rich Felker, the main author of the library, or by one or more +// contibutors listed above. Details on authorship of individual files +// can be found in the git version control history of the project. The +// omission of copyright and license comments in each file is in the +// interest of source tree size. +// +// In addition, permission is hereby granted for all public header files +// (include/* and arch/* /bits/* ) and crt files intended to be linked into +// applications (crt/*, ldso/dlstart.c, and arch/* /crt_arch.h) to omit +// the copyright notice and permission notice otherwise required by the +// license, and to use these files without any requirement of +// attribution. These files include substantial contributions from: +// +// Bobby Bingham +// John Spencer +// Nicholas J. Kain +// Rich Felker +// Richard Pennington +// Stefan Kristiansson +// Szabolcs Nagy +// +// all of whom have explicitly granted such permission. +// +// This file previously contained text expressing a belief that most of +// the files covered by the above exception were sufficiently trivial not +// to be subject to copyright, resulting in confusion over whether it +// negated the permissions granted in the license. In the spirit of +// permissive licensing, and of not having licensing issues being an +// obstacle to adoption, that text has been removed. + .text + .file "memcpy.c" + .globl memccpy # -- Begin function memccpy + .p2align 2 + .type memccpy,@function + .set nomicromips + .set nomips16 + .ent memccpy +memccpy: # @memccpy + .frame $fp,8,$ra + .mask 0xc0000000,-4 + .fmask 0x00000000,0 + .set noreorder + .set nomacro + .set noat +# %bb.0: + addiu $sp, $sp, -8 + sw $ra, 4($sp) # 4-byte Folded Spill + sw $fp, 0($sp) # 4-byte Folded Spill + move $fp, $sp + xor $1, $5, $4 + andi $1, $1, 3 + beqz $1, $BBmemcpy0_7 + andi $3, $6, 255 +$BBmemcpy0_1: + beqz $7, $BBmemcpy0_5 + nop +# %bb.2: + addiu $2, $4, 1 +$BBmemcpy0_3: # =>This Inner Loop Header: Depth=1 + lbu $1, 0($5) + beq $1, $3, $BBmemcpy0_6 + sb $1, -1($2) +# %bb.4: # in Loop: Header=BBmemcpy0_3 Depth=1 + addiu $2, $2, 1 + addiu $7, $7, -1 + bnez $7, $BBmemcpy0_3 + addiu $5, $5, 1 +$BBmemcpy0_5: + addiu $2, $zero, 0 +$BBmemcpy0_6: + move $sp, $fp + lw $fp, 0($sp) # 4-byte Folded Reload + lw $ra, 4($sp) # 4-byte Folded Reload + jr $ra + addiu $sp, $sp, 8 +$BBmemcpy0_7: + andi $6, $5, 3 + beqz $7, $BBmemcpy0_14 + sltu $2, $zero, $6 +# %bb.8: + beqz $6, $BBmemcpy0_14 + nop +# %bb.9: + addiu $2, $7, -1 + addiu $6, $zero, 0 +$BBmemcpy0_10: # =>This Inner Loop Header: Depth=1 + addu $9, $5, $6 + addu $8, $4, $6 + lbu $1, 0($9) + beq $1, $3, $BBmemcpy0_22 + sb $1, 0($8) +# %bb.11: # in Loop: Header=BBmemcpy0_10 Depth=1 + addiu $1, $9, 1 + addiu $8, $6, 1 + beq $2, $6, $BBmemcpy0_13 + andi $9, $1, 3 +# %bb.12: # in Loop: Header=BBmemcpy0_10 Depth=1 + bnez $9, $BBmemcpy0_10 + move $6, $8 +$BBmemcpy0_13: + sltu $2, $zero, $9 + subu $7, $7, $8 + addu $4, $4, $8 + addu $5, $5, $8 +$BBmemcpy0_14: + beqz $2, $BBmemcpy0_17 + nop +# %bb.15: + bnez $7, $BBmemcpy0_6 + addiu $2, $4, 1 +# %bb.16: + j $BBmemcpy0_5 + nop +$BBmemcpy0_17: + sltiu $1, $7, 4 + bnez $1, $BBmemcpy0_1 + nop +# %bb.18: + sll $1, $3, 8 + sll $2, $3, 16 + or $1, $1, $3 + or $1, $2, $1 + sll $2, $3, 24 + or $6, $2, $1 + lui $1, 65278 + andi $2, $7, 3 + ori $8, $1, 65279 + lui $1, 32896 + ori $9, $1, 32896 +$BBmemcpy0_19: # =>This Inner Loop Header: Depth=1 + lw $10, 0($5) + xor $1, $10, $6 + addu $11, $1, $8 + not $1, $1 + and $1, $1, $11 + and $1, $1, $9 + bnez $1, $BBmemcpy0_1 + nop +# %bb.20: # in Loop: Header=BBmemcpy0_19 Depth=1 + addiu $7, $7, -4 + sw $10, 0($4) + addiu $4, $4, 4 + sltiu $1, $7, 4 + beqz $1, $BBmemcpy0_19 + addiu $5, $5, 4 +# %bb.21: + j $BBmemcpy0_1 + move $7, $2 +$BBmemcpy0_22: + j $BBmemcpy0_6 + addiu $2, $8, 1 + .set at + .set macro + .set reorder + .end memccpy +$func_end0: + .size memccpy, ($func_end0)-memccpy + # -- End function + .ident "clang version 10.0.0-4ubuntu1 " + .section ".note.GNU-stack","",@progbits + .addrsig \ No newline at end of file diff --git a/zkvm/entrypoint/src/memory.rs b/zkvm/entrypoint/src/memory.rs new file mode 100644 index 00000000..b4c967ea --- /dev/null +++ b/zkvm/entrypoint/src/memory.rs @@ -0,0 +1,51 @@ +// Copyright 2023 RISC Zero, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +const SYSTEM_START: usize = 0x0C00_0000; + +#[allow(clippy::missing_safety_doc)] +#[no_mangle] +pub unsafe extern "C" fn sys_alloc_aligned(bytes: usize, align: usize) -> *mut u8 { + extern "C" { + // https://lld.llvm.org/ELF/linker_script.html#sections-command + static _end: u8; + } + + // Pointer to next heap address to use, or 0 if the heap has not yet been + // initialized. + static mut HEAP_POS: usize = 0; + + // SAFETY: Single threaded, so nothing else can touch this while we're working. + let mut heap_pos = unsafe { HEAP_POS }; + + if heap_pos == 0 { + heap_pos = unsafe { (&_end) as *const u8 as usize }; + } + + let offset = heap_pos & (align - 1); + if offset != 0 { + heap_pos += align - offset; + } + + let ptr = heap_pos as *mut u8; + heap_pos += bytes; + + // Check to make sure heap doesn't collide with SYSTEM memory. + if SYSTEM_START < heap_pos { + panic!(); + } + + unsafe { HEAP_POS = heap_pos }; + ptr +} diff --git a/zkvm/entrypoint/src/memset.s b/zkvm/entrypoint/src/memset.s new file mode 100644 index 00000000..35765659 --- /dev/null +++ b/zkvm/entrypoint/src/memset.s @@ -0,0 +1,316 @@ +// This is musl-libc memset commit 5613a1486e6a6fc3988be6561f41b07b2647d80f: +// +// src/string/memset.c +// +// This was compiled into assembly with: +// +// clang10 -target mips -O3 -S memset.c -nostdlib -fno-builtin -funroll-loops +// +// and labels manually updated to not conflict. +// +// musl as a whole is licensed under the following standard MIT license: +// +// ---------------------------------------------------------------------- +// Copyright © 2005-2020 Rich Felker, et al. +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// ---------------------------------------------------------------------- +// +// Authors/contributors include: +// +// A. Wilcox +// Ada Worcester +// Alex Dowad +// Alex Suykov +// Alexander Monakov +// Andre McCurdy +// Andrew Kelley +// Anthony G. Basile +// Aric Belsito +// Arvid Picciani +// Bartosz Brachaczek +// Benjamin Peterson +// Bobby Bingham +// Boris Brezillon +// Brent Cook +// Chris Spiegel +// Clément Vasseur +// Daniel Micay +// Daniel Sabogal +// Daurnimator +// David Carlier +// David Edelsohn +// Denys Vlasenko +// Dmitry Ivanov +// Dmitry V. Levin +// Drew DeVault +// Emil Renner Berthing +// Fangrui Song +// Felix Fietkau +// Felix Janda +// Gianluca Anzolin +// Hauke Mehrtens +// He X +// Hiltjo Posthuma +// Isaac Dunham +// Jaydeep Patil +// Jens Gustedt +// Jeremy Huntwork +// Jo-Philipp Wich +// Joakim Sindholt +// John Spencer +// Julien Ramseier +// Justin Cormack +// Kaarle Ritvanen +// Khem Raj +// Kylie McClain +// Leah Neukirchen +// Luca Barbato +// Luka Perkov +// M Farkas-Dyck (Strake) +// Mahesh Bodapati +// Markus Wichmann +// Masanori Ogino +// Michael Clark +// Michael Forney +// Mikhail Kremnyov +// Natanael Copa +// Nicholas J. Kain +// orc +// Pascal Cuoq +// Patrick Oppenlander +// Petr Hosek +// Petr Skocik +// Pierre Carrier +// Reini Urban +// Rich Felker +// Richard Pennington +// Ryan Fairfax +// Samuel Holland +// Segev Finer +// Shiz +// sin +// Solar Designer +// Stefan Kristiansson +// Stefan O'Rear +// Szabolcs Nagy +// Timo Teräs +// Trutz Behn +// Valentin Ochs +// Will Dietz +// William Haddon +// William Pitcock +// +// Portions of this software are derived from third-party works licensed +// under terms compatible with the above MIT license: +// +// The TRE regular expression implementation (src/regex/reg* and +// src/regex/tre*) is Copyright © 2001-2008 Ville Laurikari and licensed +// under a 2-clause BSD license (license text in the source files). The +// included version has been heavily modified by Rich Felker in 2012, in +// the interests of size, simplicity, and namespace cleanliness. +// +// Much of the math library code (src/math/* and src/complex/*) is +// Copyright © 1993,2004 Sun Microsystems or +// Copyright © 2003-2011 David Schultz or +// Copyright © 2003-2009 Steven G. Kargl or +// Copyright © 2003-2009 Bruce D. Evans or +// Copyright © 2008 Stephen L. Moshier or +// Copyright © 2017-2018 Arm Limited +// and labelled as such in comments in the individual source files. All +// have been licensed under extremely permissive terms. +// +// The ARM memcpy code (src/string/arm/memcpy.S) is Copyright © 2008 +// The Android Open Source Project and is licensed under a two-clause BSD +// license. It was taken from Bionic libc, used on Android. +// +// The AArch64 memcpy and memset code (src/string/aarch64/*) are +// Copyright © 1999-2019, Arm Limited. +// +// The implementation of DES for crypt (src/crypt/crypt_des.c) is +// Copyright © 1994 David Burren. It is licensed under a BSD license. +// +// The implementation of blowfish crypt (src/crypt/crypt_blowfish.c) was +// originally written by Solar Designer and placed into the public +// domain. The code also comes with a fallback permissive license for use +// in jurisdictions that may not recognize the public domain. +// +// The smoothsort implementation (src/stdlib/qsort.c) is Copyright © 2011 +// Valentin Ochs and is licensed under an MIT-style license. +// +// The x86_64 port was written by Nicholas J. Kain and is licensed under +// the standard MIT terms. +// +// The mips and microblaze ports were originally written by Richard +// Pennington for use in the ellcc project. The original code was adapted +// by Rich Felker for build system and code conventions during upstream +// integration. It is licensed under the standard MIT terms. +// +// The mips64 port was contributed by Imagination Technologies and is +// licensed under the standard MIT terms. +// +// The powerpc port was also originally written by Richard Pennington, +// and later supplemented and integrated by John Spencer. It is licensed +// under the standard MIT terms. +// +// All other files which have no copyright comments are original works +// produced specifically for use as part of this library, written either +// by Rich Felker, the main author of the library, or by one or more +// contibutors listed above. Details on authorship of individual files +// can be found in the git version control history of the project. The +// omission of copyright and license comments in each file is in the +// interest of source tree size. +// +// In addition, permission is hereby granted for all public header files +// (include/* and arch/* /bits/* ) and crt files intended to be linked into +// applications (crt/*, ldso/dlstart.c, and arch/* /crt_arch.h) to omit +// the copyright notice and permission notice otherwise required by the +// license, and to use these files without any requirement of +// attribution. These files include substantial contributions from: +// +// Bobby Bingham +// John Spencer +// Nicholas J. Kain +// Rich Felker +// Richard Pennington +// Stefan Kristiansson +// Szabolcs Nagy +// +// all of whom have explicitly granted such permission. +// +// This file previously contained text expressing a belief that most of +// the files covered by the above exception were sufficiently trivial not +// to be subject to copyright, resulting in confusion over whether it +// negated the permissions granted in the license. In the spirit of +// permissive licensing, and of not having licensing issues being an +// obstacle to adoption, that text has been removed. + .text + .file "memset.c" + .globl memset # -- Begin function memset + .p2align 2 + .type memset,@function + .set nomicromips + .set nomips16 + .ent memset +memset: # @memset + .frame $fp,8,$ra + .mask 0xc0000000,-4 + .fmask 0x00000000,0 + .set noreorder + .set nomacro + .set noat +# %bb.0: + addiu $sp, $sp, -8 + sw $ra, 4($sp) # 4-byte Folded Spill + sw $fp, 0($sp) # 4-byte Folded Spill + move $fp, $sp + beqz $6, $BBmemset0_9 + nop +# %bb.1: + addu $2, $6, $4 + sltiu $1, $6, 3 + sb $5, 0($4) + bnez $1, $BBmemset0_9 + sb $5, -1($2) +# %bb.2: + sltiu $1, $6, 7 + sb $5, 2($4) + sb $5, 1($4) + sb $5, -3($2) + bnez $1, $BBmemset0_9 + sb $5, -2($2) +# %bb.3: + sltiu $1, $6, 9 + sb $5, 3($4) + bnez $1, $BBmemset0_9 + sb $5, -4($2) +# %bb.4: + andi $2, $5, 255 + negu $1, $4 + sll $5, $2, 8 + sll $7, $2, 16 + andi $1, $1, 3 + or $5, $5, $2 + sll $2, $2, 24 + addu $3, $4, $1 + subu $1, $6, $1 + or $5, $7, $5 + or $2, $2, $5 + addiu $5, $zero, -4 + and $5, $1, $5 + sw $2, 0($3) + addu $6, $3, $5 + sltiu $1, $5, 9 + bnez $1, $BBmemset0_9 + sw $2, -4($6) +# %bb.5: + sltiu $1, $5, 25 + sw $2, 8($3) + sw $2, 4($3) + sw $2, -8($6) + bnez $1, $BBmemset0_9 + sw $2, -12($6) +# %bb.6: + andi $1, $3, 4 + sw $2, 24($3) + sw $2, 20($3) + sw $2, 16($3) + sw $2, 12($3) + sw $2, -16($6) + sw $2, -20($6) + sw $2, -24($6) + sw $2, -28($6) + ori $6, $1, 24 + subu $5, $5, $6 + sltiu $1, $5, 32 + bnez $1, $BBmemset0_9 + nop +# %bb.7: + addu $3, $3, $6 +$BBmemset0_8: # =>This Inner Loop Header: Depth=1 + addiu $5, $5, -32 + sw $2, 24($3) + sw $2, 16($3) + sw $2, 8($3) + sw $2, 0($3) + sw $2, 28($3) + sw $2, 20($3) + sw $2, 12($3) + sw $2, 4($3) + sltiu $1, $5, 32 + beqz $1, $BBmemset0_8 + addiu $3, $3, 32 +$BBmemset0_9: + move $2, $4 + move $sp, $fp + lw $fp, 0($sp) # 4-byte Folded Reload + lw $ra, 4($sp) # 4-byte Folded Reload + jr $ra + addiu $sp, $sp, 8 + .set at + .set macro + .set reorder + .end memset +$func_end0: + .size memset, ($func_end0)-memset + # -- End function + .ident "clang version 10.0.0-4ubuntu1 " + .section ".note.GNU-stack","",@progbits + .addrsig \ No newline at end of file diff --git a/zkvm/entrypoint/src/syscalls/halt.rs b/zkvm/entrypoint/src/syscalls/halt.rs new file mode 100644 index 00000000..4ad43f42 --- /dev/null +++ b/zkvm/entrypoint/src/syscalls/halt.rs @@ -0,0 +1,27 @@ +use cfg_if::cfg_if; + +cfg_if! { + if #[cfg(target_os = "zkvm")] { + use core::arch::asm; + use sha2::Digest; + use crate::zkvm; + use crate::{PV_DIGEST_NUM_WORDS, POSEIDON_NUM_WORDS}; + } +} + +/// Halts the program. +#[allow(unused_variables)] +pub extern "C" fn syscall_halt(exit_code: u8) -> ! { + #[cfg(target_os = "zkvm")] + unsafe { + asm!( + "syscall", + in("v0") crate::syscalls::HALT, + in("a0") exit_code + ); + unreachable!() + } + + #[cfg(not(target_os = "zkvm"))] + unreachable!() +} diff --git a/zkvm/entrypoint/src/syscalls/io.rs b/zkvm/entrypoint/src/syscalls/io.rs new file mode 100644 index 00000000..a61fbfcf --- /dev/null +++ b/zkvm/entrypoint/src/syscalls/io.rs @@ -0,0 +1,72 @@ +cfg_if::cfg_if! { + if #[cfg(target_os = "zkvm")] { + use core::arch::asm; + use crate::zkvm; + use sha2::digest::Update; + use zkm_precompiles::io::FD_PUBLIC_VALUES; + } +} + +/// Write data to the prover. +#[allow(unused_variables)] +#[no_mangle] +pub extern "C" fn syscall_write(fd: u32, write_buf: *const u8, nbytes: usize) { + cfg_if::cfg_if! { + if #[cfg(target_os = "zkvm")] { + unsafe { + asm!( + "syscall", + in("v0") crate::syscalls::WRITE, + in("a0") fd, + in("a1") write_buf, + in("a2") nbytes, + ); + } + + // For writes to the public values fd, we update a global program hasher with the bytes + // being written. At the end of the program, we call the COMMIT ecall with the finalized + // version of this hash. + if fd == FD_PUBLIC_VALUES { + let pi_slice: &[u8] = unsafe { core::slice::from_raw_parts(write_buf, nbytes) }; + unsafe { zkvm::PUBLIC_VALUES_HASHER.as_mut().unwrap().update(pi_slice) }; + } + } else { + unreachable!() + } + } +} + +#[allow(unused_variables)] +#[no_mangle] +pub extern "C" fn syscall_hint_len() -> usize { + #[cfg(target_os = "zkvm")] + unsafe { + let len; + asm!( + "syscall", + in("v0") crate::syscalls::HINT_LEN, + lateout("v0") len, + ); + len + } + + #[cfg(not(target_os = "zkvm"))] + unreachable!() +} + +#[allow(unused_variables)] +#[no_mangle] +pub extern "C" fn syscall_hint_read(ptr: *mut u8, len: usize) { + #[cfg(target_os = "zkvm")] + unsafe { + asm!( + "syscall", + in("v0") crate::syscalls::HINT_READ, + in("a0") ptr, + in("a1") len, + ); + } + + #[cfg(not(target_os = "zkvm"))] + unreachable!() +} diff --git a/zkvm/entrypoint/src/syscalls/memory.rs b/zkvm/entrypoint/src/syscalls/memory.rs new file mode 100644 index 00000000..b4c967ea --- /dev/null +++ b/zkvm/entrypoint/src/syscalls/memory.rs @@ -0,0 +1,51 @@ +// Copyright 2023 RISC Zero, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +const SYSTEM_START: usize = 0x0C00_0000; + +#[allow(clippy::missing_safety_doc)] +#[no_mangle] +pub unsafe extern "C" fn sys_alloc_aligned(bytes: usize, align: usize) -> *mut u8 { + extern "C" { + // https://lld.llvm.org/ELF/linker_script.html#sections-command + static _end: u8; + } + + // Pointer to next heap address to use, or 0 if the heap has not yet been + // initialized. + static mut HEAP_POS: usize = 0; + + // SAFETY: Single threaded, so nothing else can touch this while we're working. + let mut heap_pos = unsafe { HEAP_POS }; + + if heap_pos == 0 { + heap_pos = unsafe { (&_end) as *const u8 as usize }; + } + + let offset = heap_pos & (align - 1); + if offset != 0 { + heap_pos += align - offset; + } + + let ptr = heap_pos as *mut u8; + heap_pos += bytes; + + // Check to make sure heap doesn't collide with SYSTEM memory. + if SYSTEM_START < heap_pos { + panic!(); + } + + unsafe { HEAP_POS = heap_pos }; + ptr +} diff --git a/zkvm/entrypoint/src/syscalls/mod.rs b/zkvm/entrypoint/src/syscalls/mod.rs new file mode 100644 index 00000000..ba3f51c3 --- /dev/null +++ b/zkvm/entrypoint/src/syscalls/mod.rs @@ -0,0 +1,28 @@ + +mod halt; +mod io; +mod memory; +mod sys; + +pub use halt::*; +pub use io::*; +pub use memory::*; +pub use sys::*; + +/// These codes MUST match the codes in `core/src/runtime/syscall.rs`. There is a derived test +/// that checks that the enum is consistent with the syscalls. + +/// Halts the program. +pub const HALT: u32 = 4246u32; + +/// Writes to a file descriptor. Currently only used for `STDOUT/STDERR`. +pub const WRITE: u32 = 4004u32; + +/// Executes the `COMMIT` precompile. +pub const COMMIT: u32 = 0x00_00_00_10; + +/// Executes `HINT_LEN`. +pub const HINT_LEN: u32 = 0x00_00_00_F0; + +/// Executes `HINT_READ`. +pub const HINT_READ: u32 = 0x00_00_00_F1; diff --git a/zkvm/entrypoint/src/syscalls/sys.rs b/zkvm/entrypoint/src/syscalls/sys.rs new file mode 100644 index 00000000..520d58ef --- /dev/null +++ b/zkvm/entrypoint/src/syscalls/sys.rs @@ -0,0 +1,68 @@ +use std::sync::Mutex; + +use lazy_static::lazy_static; +use rand::{rngs::StdRng, Rng, SeedableRng}; + +use crate::syscalls::{syscall_halt, syscall_write}; + +/// The random number generator seed for the zkVM. +/// +/// In the future, we can pass in this seed from the host or have the verifier generate it. +const PRNG_SEED: u64 = 0x123456789abcdef0; + +lazy_static! { + /// A lazy static to generate a global random number generator. + static ref RNG: Mutex = Mutex::new(StdRng::seed_from_u64(PRNG_SEED)); +} + +/// A lazy static to print a warning once for using the `sys_rand` system call. +static SYS_RAND_WARNING: std::sync::Once = std::sync::Once::new(); + +/// Generates random bytes. +/// +/// # Safety +/// +/// Make sure that `buf` has at least `nwords` words. +#[no_mangle] +pub unsafe extern "C" fn sys_rand(recv_buf: *mut u8, words: usize) { + SYS_RAND_WARNING.call_once(|| { + println!("WARNING: Using insecure random number generator."); + }); + let mut rng = RNG.lock().unwrap(); + for i in 0..words { + let element = recv_buf.add(i); + *element = rng.gen(); + } +} + +#[allow(clippy::missing_safety_doc)] +#[no_mangle] +pub unsafe extern "C" fn sys_panic(msg_ptr: *const u8, len: usize) -> ! { + sys_write(2, msg_ptr, len); + syscall_halt(1); +} + +#[allow(unused_variables)] +#[no_mangle] +pub const fn sys_getenv( + recv_buf: *mut u32, + words: usize, + varname: *const u8, + varname_len: usize, +) -> usize { + 0 +} + +#[allow(unused_variables)] +#[no_mangle] +pub const fn sys_alloc_words(nwords: usize) -> *mut u32 { + core::ptr::null_mut() +} + +#[allow(unused_unsafe)] +#[no_mangle] +pub fn sys_write(fd: u32, write_buf: *const u8, nbytes: usize) { + unsafe { + syscall_write(fd, write_buf, nbytes); + } +} diff --git a/zkvm/precompiles/Cargo.toml b/zkvm/precompiles/Cargo.toml new file mode 100644 index 00000000..a017d35e --- /dev/null +++ b/zkvm/precompiles/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "zkm-precompiles" +version = "0.1.0" +edition = "2021" + +[dependencies] +anyhow = "1.0.83" +bincode = "1.3.3" +cfg-if = "1.0.0" +getrandom = { version = "0.2.14", features = ["custom"] } +hex = "0.4.3" +rand = "0.8.5" +serde = { version = "1.0.201", features = ["derive"] } +num = { version = "0.4.3" } diff --git a/zkvm/precompiles/src/io.rs b/zkvm/precompiles/src/io.rs new file mode 100644 index 00000000..cc1be96e --- /dev/null +++ b/zkvm/precompiles/src/io.rs @@ -0,0 +1,90 @@ +#![allow(unused_unsafe)] +use crate::syscall_write; +use crate::{syscall_hint_len, syscall_hint_read}; +use serde::de::DeserializeOwned; +use serde::Serialize; +use std::alloc::Layout; +use std::io::Write; + +const FD_HINT: u32 = 4; +pub const FD_PUBLIC_VALUES: u32 = 3; +// Runtime hook file descriptors. Make sure these match the FDs in the HookRegistry. +// The default hooks can be found in `core/src/runtime/hooks.rs`. +pub const FD_ECRECOVER_HOOK: u32 = 5; + +pub struct SyscallWriter { + fd: u32, +} + +impl std::io::Write for SyscallWriter { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + let nbytes = buf.len(); + let write_buf = buf.as_ptr(); + unsafe { + syscall_write(self.fd, write_buf, nbytes); + } + Ok(nbytes) + } + + fn flush(&mut self) -> std::io::Result<()> { + Ok(()) + } +} + +pub fn read_vec() -> Vec { + let len = unsafe { syscall_hint_len() }; + // Round up to the nearest multiple of 4 so that the memory allocated is in whole words + let capacity = (len + 3) / 4 * 4; + + // Allocate a buffer of the required length that is 4 byte aligned + let layout = Layout::from_size_align(capacity, 4).expect("vec is too large"); + let ptr = unsafe { std::alloc::alloc(layout) }; + // SAFETY: + // 1. `ptr` was allocated using alloc + // 2. We assuume that the VM global allocator doesn't dealloc + // 3/6. Size is correct from above + // 4/5. Length is 0 + // 7. Layout::from_size_align already checks this + let mut vec = unsafe { Vec::from_raw_parts(ptr, 0, capacity) }; + // Read the vec into uninitialized memory. The syscall assumes the memory is uninitialized, + // which should be true because the allocator does not dealloc, so a new alloc should be fresh. + unsafe { + syscall_hint_read(ptr, len); + vec.set_len(len); + } + vec +} + +pub fn read() -> T { + let vec = read_vec(); + bincode::deserialize(&vec).expect("deserialization failed") +} + +pub fn commit(value: &T) { + let writer = SyscallWriter { + fd: FD_PUBLIC_VALUES, + }; + bincode::serialize_into(writer, value).expect("serialization failed"); +} + +pub fn commit_slice(buf: &[u8]) { + let mut my_writer = SyscallWriter { + fd: FD_PUBLIC_VALUES, + }; + my_writer.write_all(buf).unwrap(); +} + +pub fn hint(value: &T) { + let writer = SyscallWriter { fd: FD_HINT }; + bincode::serialize_into(writer, value).expect("serialization failed"); +} + +pub fn hint_slice(buf: &[u8]) { + let mut my_reader = SyscallWriter { fd: FD_HINT }; + my_reader.write_all(buf).unwrap(); +} + +/// Write the data `buf` to the file descriptor `fd` using `Write::write_all` . +pub fn write(fd: u32, buf: &[u8]) { + SyscallWriter { fd }.write_all(buf).unwrap(); +} diff --git a/zkvm/precompiles/src/lib.rs b/zkvm/precompiles/src/lib.rs new file mode 100644 index 00000000..0b9215af --- /dev/null +++ b/zkvm/precompiles/src/lib.rs @@ -0,0 +1,25 @@ +//! Precompiles for SP1 zkVM. +//! +//! Specifically, this crate contains user-friendly functions that call SP1 syscalls. Syscalls are +//! also declared here for convenience. In order to avoid duplicate symbol errors, the syscall +//! function impls must live in sp1-zkvm, which is only imported into the end user program crate. +//! In contrast, sp1-precompiles can be imported into any crate in the dependency tree. + +pub mod bls12381; +pub mod bn254; +pub mod io; +pub mod secp256k1; +pub mod unconstrained; +pub mod utils; +#[cfg(feature = "verify")] +pub mod verify; + +pub const BIGINT_WIDTH_WORDS: usize = 8; + +extern "C" { + pub fn syscall_halt(exit_code: u8) -> !; + pub fn syscall_write(fd: u32, write_buf: *const u8, nbytes: usize); + pub fn syscall_hint_len() -> usize; + pub fn syscall_hint_read(ptr: *mut u8, len: usize); + pub fn sys_alloc_aligned(bytes: usize, align: usize) -> *mut u8; +} diff --git a/zkvm/precompiles/src/utils.rs b/zkvm/precompiles/src/utils.rs new file mode 100644 index 00000000..c2cf1a0d --- /dev/null +++ b/zkvm/precompiles/src/utils.rs @@ -0,0 +1,109 @@ +pub trait CurveOperations { + const GENERATOR: [u32; NUM_WORDS]; + + fn add_assign(limbs: &mut [u32; NUM_WORDS], other: &[u32; NUM_WORDS]); + fn double(limbs: &mut [u32; NUM_WORDS]); +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct AffinePoint, const NUM_WORDS: usize> { + pub(crate) limbs: [u32; NUM_WORDS], + _marker: std::marker::PhantomData, +} + +impl + Copy, const NUM_WORDS: usize> AffinePoint { + const GENERATOR: [u32; NUM_WORDS] = C::GENERATOR; + + pub const fn generator_in_affine() -> Self { + Self { + limbs: Self::GENERATOR, + _marker: std::marker::PhantomData, + } + } + + pub const fn new(limbs: [u32; NUM_WORDS]) -> Self { + Self { + limbs, + _marker: std::marker::PhantomData, + } + } + + /// x_bytes and y_bytes are the concatenated little endian representations of the x and y coordinates. + /// The length of x_bytes and y_bytes must each be NUM_WORDS * 2. + pub fn from(x_bytes: &[u8], y_bytes: &[u8]) -> Self { + debug_assert!(x_bytes.len() == NUM_WORDS * 2); + debug_assert!(y_bytes.len() == NUM_WORDS * 2); + + let mut limbs = [0u32; NUM_WORDS]; + let x = bytes_to_words_le(x_bytes); + let y = bytes_to_words_le(y_bytes); + debug_assert!(x.len() == NUM_WORDS / 2); + debug_assert!(y.len() == NUM_WORDS / 2); + + limbs[..(NUM_WORDS / 2)].copy_from_slice(&x); + limbs[(NUM_WORDS / 2)..].copy_from_slice(&y); + Self::new(limbs) + } + + pub fn add_assign(&mut self, other: &AffinePoint) { + C::add_assign(&mut self.limbs, &other.limbs); + } + + pub fn double(&mut self) { + C::double(&mut self.limbs); + } + + pub fn mul_assign(&mut self, scalar: &[u32]) { + debug_assert!(scalar.len() == NUM_WORDS / 2); + + let mut res: Option = None; + let mut temp = *self; + + for &words in scalar.iter() { + for i in 0..32 { + if (words >> i) & 1 == 1 { + match res.as_mut() { + Some(res) => res.add_assign(&temp), + None => res = Some(temp), + }; + } + + temp.double(); + } + } + + *self = res.unwrap(); + } + + pub fn from_le_bytes(limbs: &[u8]) -> Self { + let u32_limbs = bytes_to_words_le(limbs); + debug_assert!(u32_limbs.len() == NUM_WORDS); + + Self { + limbs: u32_limbs.try_into().unwrap(), + _marker: std::marker::PhantomData, + } + } + + pub fn to_le_bytes(&self) -> Vec { + let le_bytes = words_to_bytes_le(&self.limbs); + debug_assert!(le_bytes.len() == NUM_WORDS * 4); + le_bytes + } +} + +/// Converts a slice of words to a byte array in little endian. +pub fn words_to_bytes_le(words: &[u32]) -> Vec { + words + .iter() + .flat_map(|word| word.to_le_bytes().to_vec()) + .collect::>() +} + +/// Converts a byte array in little endian to a slice of words. +pub fn bytes_to_words_le(bytes: &[u8]) -> Vec { + bytes + .chunks_exact(4) + .map(|chunk| u32::from_le_bytes(chunk.try_into().unwrap())) + .collect::>() +} From 0a6f202646c43dcf8531718e7abe0ff953532ae6 Mon Sep 17 00:00:00 2001 From: Angell Li Date: Wed, 19 Jun 2024 22:54:48 +0800 Subject: [PATCH 02/13] remove unused mod --- zkvm/precompiles/src/lib.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/zkvm/precompiles/src/lib.rs b/zkvm/precompiles/src/lib.rs index 0b9215af..b1c9743e 100644 --- a/zkvm/precompiles/src/lib.rs +++ b/zkvm/precompiles/src/lib.rs @@ -5,14 +5,8 @@ //! function impls must live in sp1-zkvm, which is only imported into the end user program crate. //! In contrast, sp1-precompiles can be imported into any crate in the dependency tree. -pub mod bls12381; -pub mod bn254; pub mod io; -pub mod secp256k1; -pub mod unconstrained; pub mod utils; -#[cfg(feature = "verify")] -pub mod verify; pub const BIGINT_WIDTH_WORDS: usize = 8; From 9070890132652bfeb883d9f9a3b41faf1dff4e70 Mon Sep 17 00:00:00 2001 From: Angell Li Date: Wed, 19 Jun 2024 23:48:30 +0800 Subject: [PATCH 03/13] fix mips disas problem --- zkvm/entrypoint/src/lib.rs | 12 ++++++------ zkvm/entrypoint/src/memcpy.s | 4 ++-- zkvm/entrypoint/src/memset.s | 4 ++-- zkvm/entrypoint/src/syscalls/halt.rs | 7 ++----- zkvm/entrypoint/src/syscalls/io.rs | 18 +++++++++--------- 5 files changed, 21 insertions(+), 24 deletions(-) diff --git a/zkvm/entrypoint/src/lib.rs b/zkvm/entrypoint/src/lib.rs index 848fb03c..02443df0 100644 --- a/zkvm/entrypoint/src/lib.rs +++ b/zkvm/entrypoint/src/lib.rs @@ -1,3 +1,5 @@ +#![feature(asm_experimental_arch)] + pub mod heap; pub mod syscalls; pub mod io { @@ -29,7 +31,6 @@ macro_rules! entrypoint { }; } -#[cfg(all(target_os = "zkvm", feature = "libm"))] mod libm; /// The number of 32 bit words that the public values digest is composed of. @@ -40,7 +41,6 @@ pub const POSEIDON_NUM_WORDS: usize = 8; mod zkvm { use crate::syscalls::syscall_halt; - use cfg_if::cfg_if; use getrandom::{register_custom_getrandom, Error}; use sha2::{Digest, Sha256}; @@ -71,10 +71,10 @@ mod zkvm { .section .text._start; .globl _start; _start: - la gp, __global_pointer$; - la sp, {0} - lw sp, 0(sp) - call __start; + la $28, __global_pointer$; + la $29, {0}; + lw $29, 0($29); + jal __start; "#, sym STACK_TOP ); diff --git a/zkvm/entrypoint/src/memcpy.s b/zkvm/entrypoint/src/memcpy.s index cea37dce..f983a45a 100644 --- a/zkvm/entrypoint/src/memcpy.s +++ b/zkvm/entrypoint/src/memcpy.s @@ -327,8 +327,8 @@ $BBmemcpy0_22: .set macro .set reorder .end memccpy -$func_end0: - .size memccpy, ($func_end0)-memccpy +$memcpy_func_end0: + .size memccpy, ($memcpy_func_end0)-memccpy # -- End function .ident "clang version 10.0.0-4ubuntu1 " .section ".note.GNU-stack","",@progbits diff --git a/zkvm/entrypoint/src/memset.s b/zkvm/entrypoint/src/memset.s index 35765659..a4840ec4 100644 --- a/zkvm/entrypoint/src/memset.s +++ b/zkvm/entrypoint/src/memset.s @@ -308,8 +308,8 @@ $BBmemset0_9: .set macro .set reorder .end memset -$func_end0: - .size memset, ($func_end0)-memset +$memset_func_end0: + .size memset, ($memset_func_end0)-memset # -- End function .ident "clang version 10.0.0-4ubuntu1 " .section ".note.GNU-stack","",@progbits diff --git a/zkvm/entrypoint/src/syscalls/halt.rs b/zkvm/entrypoint/src/syscalls/halt.rs index 4ad43f42..fb38b589 100644 --- a/zkvm/entrypoint/src/syscalls/halt.rs +++ b/zkvm/entrypoint/src/syscalls/halt.rs @@ -3,9 +3,6 @@ use cfg_if::cfg_if; cfg_if! { if #[cfg(target_os = "zkvm")] { use core::arch::asm; - use sha2::Digest; - use crate::zkvm; - use crate::{PV_DIGEST_NUM_WORDS, POSEIDON_NUM_WORDS}; } } @@ -16,8 +13,8 @@ pub extern "C" fn syscall_halt(exit_code: u8) -> ! { unsafe { asm!( "syscall", - in("v0") crate::syscalls::HALT, - in("a0") exit_code + in("$2") crate::syscalls::HALT, + in("$4") exit_code ); unreachable!() } diff --git a/zkvm/entrypoint/src/syscalls/io.rs b/zkvm/entrypoint/src/syscalls/io.rs index a61fbfcf..c9d9da30 100644 --- a/zkvm/entrypoint/src/syscalls/io.rs +++ b/zkvm/entrypoint/src/syscalls/io.rs @@ -16,10 +16,10 @@ pub extern "C" fn syscall_write(fd: u32, write_buf: *const u8, nbytes: usize) { unsafe { asm!( "syscall", - in("v0") crate::syscalls::WRITE, - in("a0") fd, - in("a1") write_buf, - in("a2") nbytes, + in("$2") crate::syscalls::WRITE, + in("$4") fd, + in("$5") write_buf, + in("$6") nbytes, ); } @@ -44,8 +44,8 @@ pub extern "C" fn syscall_hint_len() -> usize { let len; asm!( "syscall", - in("v0") crate::syscalls::HINT_LEN, - lateout("v0") len, + in("$2") crate::syscalls::HINT_LEN, + lateout("$2") len, ); len } @@ -61,9 +61,9 @@ pub extern "C" fn syscall_hint_read(ptr: *mut u8, len: usize) { unsafe { asm!( "syscall", - in("v0") crate::syscalls::HINT_READ, - in("a0") ptr, - in("a1") len, + in("$2") crate::syscalls::HINT_READ, + in("$4") ptr, + in("$5") len, ); } From abcc808284e37f2859c594e43d3fcd44093bcf6b Mon Sep 17 00:00:00 2001 From: Angell Li Date: Fri, 21 Jun 2024 09:17:00 +0800 Subject: [PATCH 04/13] add benchmark test(tofix) --- benchmark/bench.rs | 75 +++++++ benchmark/sha2/Cargo.lock | 350 +++++++++++++++++++++++++++++ benchmark/sha2/Cargo.toml | 9 + benchmark/sha2/rust-toolchain.toml | 4 + benchmark/sha2/src/main.rs | 18 ++ src/mips_emulator/state.rs | 37 ++- zkvm/entrypoint/src/lib.rs | 24 +- 7 files changed, 497 insertions(+), 20 deletions(-) create mode 100644 benchmark/bench.rs create mode 100644 benchmark/sha2/Cargo.lock create mode 100644 benchmark/sha2/Cargo.toml create mode 100644 benchmark/sha2/rust-toolchain.toml create mode 100644 benchmark/sha2/src/main.rs diff --git a/benchmark/bench.rs b/benchmark/bench.rs new file mode 100644 index 00000000..b84b75e5 --- /dev/null +++ b/benchmark/bench.rs @@ -0,0 +1,75 @@ +use elf::{endian::AnyEndian, ElfBytes}; +use std::env; +use std::fs::{self, File}; +use std::io::BufReader; +use std::ops::Range; +use std::time::Duration; + +use plonky2::field::goldilocks_field::GoldilocksField; +use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; +use plonky2::util::timing::TimingTree; +use plonky2x::backend::circuit::Groth16WrapperParameters; +use plonky2x::backend::wrapper::wrap::WrappedCircuit; +use plonky2x::frontend::builder::CircuitBuilder as WrapperBuilder; +use plonky2x::prelude::DefaultParameters; +use zkm::all_stark::AllStark; +use zkm::config::StarkConfig; +use zkm::cpu::kernel::assembler::segment_kernel; +use zkm::fixed_recursive_verifier::AllRecursiveCircuits; +use zkm::mips_emulator::state::{InstrumentedState, State, SEGMENT_STEPS}; +use zkm::mips_emulator::utils::get_block_path; +use zkm::proof; +use zkm::proof::PublicValues; +use zkm::prover::prove; +use zkm::verifier::verify_proof; + +fn main() { + // 1. split ELF into segs + let basedir = env::var("BASEDIR").unwrap_or("/tmp/cannon".to_string()); + let elf_path = env::var("ELF_PATH").expect("ELF file is missing"); + let block_no = env::var("BLOCK_NO"); + let blockfile = env::var("BLOCK_FILE").unwrap_or(String::from("")); + let seg_path = env::var("SEG_OUTPUT").expect("Segment output path is missing"); + let seg_size = env::var("SEG_SIZE").unwrap_or(format!("{SEGMENT_STEPS}")); + let seg_size = seg_size.parse::<_>().unwrap_or(SEGMENT_STEPS); + let args = env::var("ARGS").unwrap_or("".to_string()); + let args = args.split_whitespace().collect(); + + let data = fs::read(elf_path).expect("could not read file"); + let file = + ElfBytes::::minimal_parse(data.as_slice()).expect("opening elf file failed"); + let (mut state, _) = State::load_elf(&file); + state.patch_go(&file); + state.patch_stack(args); + let input = [5u8; 32]; + state.add_input_stream(&input); + + let block_path = match block_no { + Ok(no) => { + let block_path = get_block_path(&basedir, &no, ""); + state.load_input(&block_path); + block_path + } + _ => "".to_string(), + }; + + let mut instrumented_state = InstrumentedState::new(state, block_path); + std::fs::create_dir_all(&seg_path).unwrap(); + let new_writer = |_: &str| -> Option { None }; + instrumented_state.split_segment(false, &seg_path, new_writer); + let mut segment_step: usize = seg_size; + let new_writer = |name: &str| -> Option { File::create(name).ok() }; + loop { + if instrumented_state.state.exited { + break; + } + instrumented_state.step(); + segment_step -= 1; + if segment_step == 0 { + segment_step = seg_size; + instrumented_state.split_segment(true, &seg_path, new_writer); + } + } + instrumented_state.split_segment(true, &seg_path, new_writer); + log::info!("Split done {}", instrumented_state.state.step); +} diff --git a/benchmark/sha2/Cargo.lock b/benchmark/sha2/Cargo.lock new file mode 100644 index 00000000..126136ae --- /dev/null +++ b/benchmark/sha2/Cargo.lock @@ -0,0 +1,350 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "serde" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2-bench" +version = "0.1.0" +dependencies = [ + "sha2", + "zkm-zkvm", +] + +[[package]] +name = "syn" +version = "2.0.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "zkm-precompiles" +version = "0.1.0" +dependencies = [ + "anyhow", + "bincode", + "cfg-if", + "getrandom", + "hex", + "num", + "rand", + "serde", +] + +[[package]] +name = "zkm-zkvm" +version = "0.1.0" +dependencies = [ + "bincode", + "cfg-if", + "getrandom", + "lazy_static", + "libm", + "once_cell", + "rand", + "serde", + "sha2", + "zkm-precompiles", +] diff --git a/benchmark/sha2/Cargo.toml b/benchmark/sha2/Cargo.toml new file mode 100644 index 00000000..eed83245 --- /dev/null +++ b/benchmark/sha2/Cargo.toml @@ -0,0 +1,9 @@ +[workspace] +[package] +version = "0.1.0" +name = "sha2-bench" +edition = "2021" + +[dependencies] +zkm-zkvm = { path = "../../zkvm/entrypoint" } +sha2 = { version = "0.10.8", default-features = false } diff --git a/benchmark/sha2/rust-toolchain.toml b/benchmark/sha2/rust-toolchain.toml new file mode 100644 index 00000000..6650ae6e --- /dev/null +++ b/benchmark/sha2/rust-toolchain.toml @@ -0,0 +1,4 @@ +[toolchain] +channel = "nightly-2023-03-06-x86_64-unknown-linux-gnu" +targets = ["mips-unknown-linux-musl"] +profile = "minimal" diff --git a/benchmark/sha2/src/main.rs b/benchmark/sha2/src/main.rs new file mode 100644 index 00000000..e0ae5002 --- /dev/null +++ b/benchmark/sha2/src/main.rs @@ -0,0 +1,18 @@ +#![no_std] +#![no_main] + +use sha2::{Digest, Sha256}; +extern crate alloc; +use alloc::vec::Vec; + +zkm_zkvm::entrypoint!(main); + +pub fn main() { + let input: Vec = zkm_zkvm::io::read(); + + let mut hasher = Sha256::new(); + hasher.update(input); + let result = hasher.finalize(); + + zkm_zkvm::io::commit::<[u8; 32]>(&result.into()); +} diff --git a/src/mips_emulator/state.rs b/src/mips_emulator/state.rs index 165cf4eb..048f54e7 100644 --- a/src/mips_emulator/state.rs +++ b/src/mips_emulator/state.rs @@ -54,12 +54,18 @@ pub struct State { /// brk handles the brk syscall brk: u32, - // tlb addr + /// tlb addr local_user: u32, /// step tracks the total step has been executed. pub step: u64, + /// A stream of input values (global to the entire program). + pub input_stream: Vec>, + + /// A ptr to the current position in the input stream incremented by HINT_READ opcode. + pub input_stream_ptr: usize, + pub exited: bool, pub exit_code: u8, dump_info: bool, @@ -90,6 +96,8 @@ impl State { local_user: 0, step: 0, brk: 0, + input_stream: Vec::new(), + input_stream_ptr: 0, exited: false, exit_code: 0, dump_info: false, @@ -110,6 +118,8 @@ impl State { local_user: 0, step: 0, brk: 0, + input_stream: Vec::new(), + input_stream_ptr: 0, exited: false, exit_code: 0, dump_info: false, @@ -338,6 +348,10 @@ impl State { } } + pub fn add_input_stream(&mut self, input: &[u8]) { + self.input_stream.push(input.to_vec()); + } + pub fn load_preimage(&mut self, blockpath: String) { let mut hash_bytes = [0u8; 32]; for i in 0..8 { @@ -462,6 +476,27 @@ impl InstrumentedState { log::debug!("syscall {}", syscall_num); match syscall_num { + 0xF0 => { + if self.state.input_stream_ptr >= self.state.input_stream.len() { + panic!("not enough vecs in hint input stream"); + } + v0 = self.state.input_stream[self.state.input_stream_ptr].len() as u32 + } + 0xF1 => { + if self.state.input_stream_ptr >= self.state.input_stream.len() { + panic!("not enough vecs in hint input stream"); + } + + let data = &self.state.input_stream[self.state.input_stream_ptr]; + assert_eq!( + data.len() as u32, + a2, + "hint input stream read length mismatch" + ); + let data= Box::new(data.as_slice()); + self.state.memory.set_memory_range(a1, data).expect("hint read failed"); + v0 = a2 + } 4020 => { // read preimage (getpid) self.state.load_preimage(self.block_path.clone()) diff --git a/zkvm/entrypoint/src/lib.rs b/zkvm/entrypoint/src/lib.rs index 02443df0..d9c6d42a 100644 --- a/zkvm/entrypoint/src/lib.rs +++ b/zkvm/entrypoint/src/lib.rs @@ -1,5 +1,4 @@ #![feature(asm_experimental_arch)] - pub mod heap; pub mod syscalls; pub mod io { @@ -24,7 +23,7 @@ macro_rules! entrypoint { mod zkvm_generated_main { #[no_mangle] - fn main() { + fn start() { super::ZKVM_ENTRY() } } @@ -48,14 +47,14 @@ mod zkvm { #[cfg(not(feature = "interface"))] #[no_mangle] - unsafe extern "C" fn __start() { - { + fn main() { + unsafe { PUBLIC_VALUES_HASHER = Some(Sha256::new()); extern "C" { - fn main(); + fn start(); } - main() + start() } syscall_halt(0); @@ -66,19 +65,6 @@ mod zkvm { core::arch::global_asm!(include_str!("memset.s")); core::arch::global_asm!(include_str!("memcpy.s")); - core::arch::global_asm!( - r#" - .section .text._start; - .globl _start; - _start: - la $28, __global_pointer$; - la $29, {0}; - lw $29, 0($29); - jal __start; - "#, - sym STACK_TOP - ); - fn zkvm_getrandom(s: &mut [u8]) -> Result<(), Error> { unsafe { crate::syscalls::sys_rand(s.as_mut_ptr(), s.len()); From 838a3bcbd073d92d3666c3e552429cb464cdc93a Mon Sep 17 00:00:00 2001 From: Angell Li Date: Sun, 30 Jun 2024 11:09:52 +0800 Subject: [PATCH 05/13] fix input and fmt --- Cargo.toml | 2 + benchmark/bench.rs | 75 -------------------------------------- examples/zkmips.rs | 54 ++++++++++++++++++++++++++- src/mips_emulator/state.rs | 37 +++++++++++++++---- 4 files changed, 84 insertions(+), 84 deletions(-) delete mode 100644 benchmark/bench.rs diff --git a/Cargo.toml b/Cargo.toml index cc01e722..1e1bbd35 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,8 @@ edition = "2021" #plonky2_util = { path = "../plonky2/util" } #plonky2_maybe_rayon = { path = "../plonky2/maybe_rayon" } +bincode = "1.3.3" + plonky2 = { git = "https://github.com/zkMIPS/plonky2.git", branch = "zkm_dev" } #starky = { git = "https://github.com/zkMIPS/plonky2.git", branch = "zkm_dev" } plonky2_util = { git = "https://github.com/zkMIPS/plonky2.git", branch = "zkm_dev" } diff --git a/benchmark/bench.rs b/benchmark/bench.rs deleted file mode 100644 index b84b75e5..00000000 --- a/benchmark/bench.rs +++ /dev/null @@ -1,75 +0,0 @@ -use elf::{endian::AnyEndian, ElfBytes}; -use std::env; -use std::fs::{self, File}; -use std::io::BufReader; -use std::ops::Range; -use std::time::Duration; - -use plonky2::field::goldilocks_field::GoldilocksField; -use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; -use plonky2::util::timing::TimingTree; -use plonky2x::backend::circuit::Groth16WrapperParameters; -use plonky2x::backend::wrapper::wrap::WrappedCircuit; -use plonky2x::frontend::builder::CircuitBuilder as WrapperBuilder; -use plonky2x::prelude::DefaultParameters; -use zkm::all_stark::AllStark; -use zkm::config::StarkConfig; -use zkm::cpu::kernel::assembler::segment_kernel; -use zkm::fixed_recursive_verifier::AllRecursiveCircuits; -use zkm::mips_emulator::state::{InstrumentedState, State, SEGMENT_STEPS}; -use zkm::mips_emulator::utils::get_block_path; -use zkm::proof; -use zkm::proof::PublicValues; -use zkm::prover::prove; -use zkm::verifier::verify_proof; - -fn main() { - // 1. split ELF into segs - let basedir = env::var("BASEDIR").unwrap_or("/tmp/cannon".to_string()); - let elf_path = env::var("ELF_PATH").expect("ELF file is missing"); - let block_no = env::var("BLOCK_NO"); - let blockfile = env::var("BLOCK_FILE").unwrap_or(String::from("")); - let seg_path = env::var("SEG_OUTPUT").expect("Segment output path is missing"); - let seg_size = env::var("SEG_SIZE").unwrap_or(format!("{SEGMENT_STEPS}")); - let seg_size = seg_size.parse::<_>().unwrap_or(SEGMENT_STEPS); - let args = env::var("ARGS").unwrap_or("".to_string()); - let args = args.split_whitespace().collect(); - - let data = fs::read(elf_path).expect("could not read file"); - let file = - ElfBytes::::minimal_parse(data.as_slice()).expect("opening elf file failed"); - let (mut state, _) = State::load_elf(&file); - state.patch_go(&file); - state.patch_stack(args); - let input = [5u8; 32]; - state.add_input_stream(&input); - - let block_path = match block_no { - Ok(no) => { - let block_path = get_block_path(&basedir, &no, ""); - state.load_input(&block_path); - block_path - } - _ => "".to_string(), - }; - - let mut instrumented_state = InstrumentedState::new(state, block_path); - std::fs::create_dir_all(&seg_path).unwrap(); - let new_writer = |_: &str| -> Option { None }; - instrumented_state.split_segment(false, &seg_path, new_writer); - let mut segment_step: usize = seg_size; - let new_writer = |name: &str| -> Option { File::create(name).ok() }; - loop { - if instrumented_state.state.exited { - break; - } - instrumented_state.step(); - segment_step -= 1; - if segment_step == 0 { - segment_step = seg_size; - instrumented_state.split_segment(true, &seg_path, new_writer); - } - } - instrumented_state.split_segment(true, &seg_path, new_writer); - log::info!("Split done {}", instrumented_state.state.step); -} diff --git a/examples/zkmips.rs b/examples/zkmips.rs index 6ad4cee9..220ff4d3 100644 --- a/examples/zkmips.rs +++ b/examples/zkmips.rs @@ -75,6 +75,57 @@ fn split_elf_into_segs() { instrumented_state.dump_memory(); } +fn prove_sha2_bench() { + // 1. split ELF into segs + let basedir = env::var("BASEDIR").unwrap_or("/tmp/cannon".to_string()); + let elf_path = env::var("ELF_PATH").expect("ELF file is missing"); + let block_no = env::var("BLOCK_NO"); + let seg_path = env::var("SEG_OUTPUT").expect("Segment output path is missing"); + let seg_size = env::var("SEG_SIZE").unwrap_or(format!("{SEGMENT_STEPS}")); + let seg_size = seg_size.parse::<_>().unwrap_or(SEGMENT_STEPS); + let args = env::var("ARGS").unwrap_or("".to_string()); + let args = args.split_whitespace().collect(); + + let data = fs::read(elf_path).expect("could not read file"); + let file = + ElfBytes::::minimal_parse(data.as_slice()).expect("opening elf file failed"); + let (mut state, _) = State::load_elf(&file); + state.patch_go(&file); + state.patch_stack(args); + + let input = [5u8; 32]; + state.add_input_stream(&input.to_vec()); + + let block_path = match block_no { + Ok(no) => { + let block_path = get_block_path(&basedir, &no, ""); + state.load_input(&block_path); + block_path + } + _ => "".to_string(), + }; + + let mut instrumented_state: Box = InstrumentedState::new(state, block_path); + std::fs::create_dir_all(&seg_path).unwrap(); + let new_writer = |_: &str| -> Option { None }; + instrumented_state.split_segment(false, &seg_path, new_writer); + let mut segment_step: usize = seg_size; + let new_writer = |name: &str| -> Option { File::create(name).ok() }; + loop { + if instrumented_state.state.exited { + break; + } + instrumented_state.step(); + segment_step -= 1; + if segment_step == 0 { + segment_step = seg_size; + instrumented_state.split_segment(true, &seg_path, new_writer); + } + } + instrumented_state.split_segment(true, &seg_path, new_writer); + log::info!("Split done {}", instrumented_state.state.step); +} + fn prove_single_seg() { let basedir = env::var("BASEDIR").unwrap_or("/tmp/cannon".to_string()); let block = env::var("BLOCK_NO").unwrap_or("".to_string()); @@ -115,7 +166,7 @@ fn main() { let args: Vec = env::args().collect(); let helper = || { log::info!( - "Help: {} split | prove | aggregate_proof | aggregate_proof_all | prove_groth16", + "Help: {} split | prove | aggregate_proof | aggregate_proof_all | prove_groth16 | bench", args[0] ); std::process::exit(-1); @@ -129,6 +180,7 @@ fn main() { "aggregate_proof" => aggregate_proof().unwrap(), "aggregate_proof_all" => aggregate_proof_all().unwrap(), "prove_groth16" => prove_groth16(), + "bench" => prove_sha2_bench(), _ => helper(), }; } diff --git a/src/mips_emulator/state.rs b/src/mips_emulator/state.rs index 048f54e7..3a979c68 100644 --- a/src/mips_emulator/state.rs +++ b/src/mips_emulator/state.rs @@ -348,8 +348,10 @@ impl State { } } - pub fn add_input_stream(&mut self, input: &[u8]) { - self.input_stream.push(input.to_vec()); + pub fn add_input_stream(&mut self, input: &T) { + let mut buf = Vec::new(); + bincode::serialize_into(&mut buf, input).expect("serialization failed"); + self.input_stream.push(buf); } pub fn load_preimage(&mut self, blockpath: String) { @@ -480,21 +482,40 @@ impl InstrumentedState { if self.state.input_stream_ptr >= self.state.input_stream.len() { panic!("not enough vecs in hint input stream"); } + log::debug!( + "hint len {:X}", + self.state.input_stream[self.state.input_stream_ptr].len() + ); v0 = self.state.input_stream[self.state.input_stream_ptr].len() as u32 } 0xF1 => { + log::debug!("{:X} {:X} {:X}", a0, a1, a2); if self.state.input_stream_ptr >= self.state.input_stream.len() { - panic!("not enough vecs in hint input stream"); + warn!("not enough vecs in hint input stream"); } - let data = &self.state.input_stream[self.state.input_stream_ptr]; + let vec = &self.state.input_stream[self.state.input_stream_ptr]; + self.state.input_stream_ptr += 1; assert_eq!( - data.len() as u32, - a2, + vec.len() as u32, + a1, "hint input stream read length mismatch" ); - let data= Box::new(data.as_slice()); - self.state.memory.set_memory_range(a1, data).expect("hint read failed"); + assert_eq!(a0 % 4, 0, "hint read address not aligned to 4 bytes"); + for i in (0..a1).step_by(4) { + // Get each byte in the chunk + let b1 = vec[i as usize]; + // In case the vec is not a multiple of 4, right-pad with 0s. This is fine because we + // are assuming the word is uninitialized, so filling it with 0s makes sense. + let b2 = vec.get(i as usize + 1).copied().unwrap_or(0); + let b3 = vec.get(i as usize + 2).copied().unwrap_or(0); + let b4 = vec.get(i as usize + 3).copied().unwrap_or(0); + let word = u32::from_le_bytes([b1, b2, b3, b4]); + + // Save the data into runtime state so the runtime will use the desired data instead of + // 0 when first reading/writing from this address. + self.state.memory.set_memory(a0 + i, word); + } v0 = a2 } 4020 => { From ae9d3d897b84fd670dab385dc6a47fdefdd9bf25 Mon Sep 17 00:00:00 2001 From: Angell Li Date: Sun, 30 Jun 2024 12:26:15 +0800 Subject: [PATCH 06/13] add trace support for hint ops --- examples/zkmips.rs | 51 ++++++++++++++-------------- src/cpu/kernel/elf.rs | 6 ++++ src/generation/state.rs | 5 +++ src/mips_emulator/state.rs | 4 +++ src/witness/operation.rs | 68 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 110 insertions(+), 24 deletions(-) diff --git a/examples/zkmips.rs b/examples/zkmips.rs index 220ff4d3..0ab14ba0 100644 --- a/examples/zkmips.rs +++ b/examples/zkmips.rs @@ -77,53 +77,56 @@ fn split_elf_into_segs() { fn prove_sha2_bench() { // 1. split ELF into segs - let basedir = env::var("BASEDIR").unwrap_or("/tmp/cannon".to_string()); let elf_path = env::var("ELF_PATH").expect("ELF file is missing"); - let block_no = env::var("BLOCK_NO"); let seg_path = env::var("SEG_OUTPUT").expect("Segment output path is missing"); - let seg_size = env::var("SEG_SIZE").unwrap_or(format!("{SEGMENT_STEPS}")); - let seg_size = seg_size.parse::<_>().unwrap_or(SEGMENT_STEPS); - let args = env::var("ARGS").unwrap_or("".to_string()); - let args = args.split_whitespace().collect(); let data = fs::read(elf_path).expect("could not read file"); let file = ElfBytes::::minimal_parse(data.as_slice()).expect("opening elf file failed"); let (mut state, _) = State::load_elf(&file); state.patch_go(&file); - state.patch_stack(args); - + state.patch_stack(vec![]); + + // load input let input = [5u8; 32]; state.add_input_stream(&input.to_vec()); - let block_path = match block_no { - Ok(no) => { - let block_path = get_block_path(&basedir, &no, ""); - state.load_input(&block_path); - block_path - } - _ => "".to_string(), - }; - - let mut instrumented_state: Box = InstrumentedState::new(state, block_path); + let mut instrumented_state: Box = InstrumentedState::new(state, "".to_string()); std::fs::create_dir_all(&seg_path).unwrap(); let new_writer = |_: &str| -> Option { None }; instrumented_state.split_segment(false, &seg_path, new_writer); - let mut segment_step: usize = seg_size; let new_writer = |name: &str| -> Option { File::create(name).ok() }; loop { if instrumented_state.state.exited { break; } instrumented_state.step(); - segment_step -= 1; - if segment_step == 0 { - segment_step = seg_size; - instrumented_state.split_segment(true, &seg_path, new_writer); - } } instrumented_state.split_segment(true, &seg_path, new_writer); log::info!("Split done {}", instrumented_state.state.step); + + let seg_file = format!("{seg_path}/{}", 0); + let seg_reader = BufReader::new(File::open(seg_file).unwrap()); + let kernel = segment_kernel("", "", "", seg_reader, instrumented_state.state.step as usize); + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + type F = >::F; + + let allstark: AllStark = AllStark::default(); + let config = StarkConfig::standard_fast_config(); + let mut timing = TimingTree::new("prove", log::Level::Info); + let allproof: proof::AllProof = + prove(&allstark, &kernel, &config, &mut timing).unwrap(); + let mut count_bytes = 0; + for (row, proof) in allproof.stark_proofs.clone().iter().enumerate() { + let proof_str = serde_json::to_string(&proof.proof).unwrap(); + log::info!("row:{} proof bytes:{}", row, proof_str.len()); + count_bytes += proof_str.len(); + } + timing.filter(Duration::from_millis(100)).print(); + log::info!("total proof bytes:{}KB", count_bytes / 1024); + verify_proof(&allstark, allproof, &config).unwrap(); + log::info!("Prove done"); } fn prove_single_seg() { diff --git a/src/cpu/kernel/elf.rs b/src/cpu/kernel/elf.rs index 1f943a7e..92c1bd04 100644 --- a/src/cpu/kernel/elf.rs +++ b/src/cpu/kernel/elf.rs @@ -32,6 +32,8 @@ pub struct Program { pub pre_image_id: [u8; 32], pub pre_hash_root: [u8; 32], pub page_hash_root: [u8; 32], + pub input_stream: Vec>, + pub input_stream_ptr: usize, } impl Program { @@ -252,6 +254,8 @@ impl Program { pre_image_id: pre_image_id.try_into().unwrap(), pre_hash_root, page_hash_root, + input_stream: Vec::new(), + input_stream_ptr: 0, }) } @@ -330,6 +334,8 @@ impl Program { pre_image_id: segment.pre_image_id, pre_hash_root: segment.pre_hash_root, page_hash_root, + input_stream: segment.input_stream, + input_stream_ptr: segment.input_stream_ptr, }) } } diff --git a/src/generation/state.rs b/src/generation/state.rs index 6f720370..b4090070 100644 --- a/src/generation/state.rs +++ b/src/generation/state.rs @@ -16,8 +16,11 @@ pub(crate) struct GenerationStateCheckpoint { pub(crate) struct GenerationState { pub(crate) registers: RegistersState, pub(crate) memory: MemoryState, + pub(crate) input_stream: Vec>, + pub(crate) input_stream_ptr: usize, pub(crate) traces: Traces, pub(crate) step: usize, + } impl GenerationState { @@ -26,6 +29,8 @@ impl GenerationState { registers: RegistersState::new(kernel), memory: MemoryState::new(&[]), // FIXME traces: Traces::default(), + input_stream: kernel.program.input_stream.clone(), + input_stream_ptr: kernel.program.input_stream_ptr, step, }) } diff --git a/src/mips_emulator/state.rs b/src/mips_emulator/state.rs index 3a979c68..81400120 100644 --- a/src/mips_emulator/state.rs +++ b/src/mips_emulator/state.rs @@ -32,6 +32,8 @@ pub struct Segment { pub image_id: [u8; 32], pub page_hash_root: [u8; 32], pub end_pc: u32, + pub input_stream: Vec>, + pub input_stream_ptr: usize, } pub struct State { @@ -1197,6 +1199,8 @@ impl InstrumentedState { image_id, end_pc: self.state.pc, page_hash_root, + input_stream: self.state.input_stream.clone(), + input_stream_ptr: self.state.input_stream_ptr }; let name = format!("{output}/{}", self.pre_segment_id); log::debug!("split: file {}", name); diff --git a/src/witness/operation.rs b/src/witness/operation.rs index 2449b87d..cfaaa8e2 100644 --- a/src/witness/operation.rs +++ b/src/witness/operation.rs @@ -76,6 +76,9 @@ pub(crate) const SYSWRITE: usize = 4004; pub(crate) const SYSFCNTL: usize = 4055; pub(crate) const SYSSETTHREADAREA: usize = 4283; +pub(crate) const SYSHINTLEN: usize = 240; +pub(crate) const SYSHINTREAD: usize = 241; + pub(crate) const FD_STDIN: usize = 0; pub(crate) const FD_STDOUT: usize = 1; pub(crate) const FD_STDERR: usize = 2; @@ -852,6 +855,52 @@ pub(crate) fn load_preimage( Ok(()) } +pub(crate) fn load_input( + state: &mut GenerationState, + addr: usize, + size: usize, +) -> Result<()> { + let mut map_addr = addr; + let vec = state.input_stream[state.input_stream_ptr].clone(); + state.input_stream_ptr += 1; + assert_eq!( + vec.len(), + size, + "hint input stream read length mismatch" + ); + assert_eq!(addr % 4, 0, "hint read address not aligned to 4 bytes"); + + let mut cpu_row = CpuColumnsView::default(); + cpu_row.clock = F::from_canonical_usize(state.traces.clock()); + let mut j = 0; + for i in (0..size).step_by(4) { + // Get each byte in the chunk + let b1 = vec[i as usize]; + // In case the vec is not a multiple of 4, right-pad with 0s. This is fine because we + // are assuming the word is uninitialized, so filling it with 0s makes sense. + let b2 = vec.get(i as usize + 1).copied().unwrap_or(0); + let b3 = vec.get(i as usize + 2).copied().unwrap_or(0); + let b4 = vec.get(i as usize + 3).copied().unwrap_or(0); + let word = u32::from_le_bytes([b1, b2, b3, b4]); + + if j == 8 { + state.traces.push_cpu(cpu_row); + cpu_row = CpuColumnsView::default(); + cpu_row.clock = F::from_canonical_usize(state.traces.clock()); + j = 0; + } + let addr = MemoryAddress::new(0, Segment::Code, map_addr); + let mem_op = mem_write_gp_log_and_fill(j, addr, state, &mut cpu_row, word.to_be()); + state.traces.push_memory(mem_op); + map_addr += 4; + j += 1; + } + + state.traces.push_cpu(cpu_row); + + Ok(()) +} + pub(crate) fn generate_syscall( state: &mut GenerationState, mut row: CpuColumnsView, @@ -864,6 +913,7 @@ pub(crate) fn generate_syscall( let mut v0 = 0usize; let mut v1 = 0usize; let mut is_load_preimage = false; + let mut is_load_input = false; let result = match sys_num { SYSGETPID => { row.general.syscall_mut().sysnum[0] = F::ONE; @@ -992,6 +1042,20 @@ pub(crate) fn generate_syscall( state.traces.push_memory(localop); Ok(()) } + SYSHINTLEN => { + if state.input_stream_ptr >= state.input_stream.len() { + log::warn!("not enough vecs in hint input stream"); + } + v0 = state.input_stream[state.input_stream_ptr].len(); + Ok(()) + } + SYSHINTREAD => { + if state.input_stream_ptr >= state.input_stream.len() { + log::warn!("not enough vecs in hint input stream"); + } + is_load_input = true; + Ok(()) + } _ => { row.general.syscall_mut().sysnum[11] = F::ONE; Ok(()) @@ -1009,6 +1073,10 @@ pub(crate) fn generate_syscall( if is_load_preimage { let _ = load_preimage(state, kernel); } + + if is_load_input { + let _ = load_input(state, a0, a1); + } result } From 7b58cffc8826fbaa17516d26bee455093bd0a980 Mon Sep 17 00:00:00 2001 From: Angell Li Date: Sun, 30 Jun 2024 15:15:56 +0800 Subject: [PATCH 07/13] fix input ptr in segment files --- src/mips_emulator/state.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/mips_emulator/state.rs b/src/mips_emulator/state.rs index 81400120..336a9b34 100644 --- a/src/mips_emulator/state.rs +++ b/src/mips_emulator/state.rs @@ -444,6 +444,7 @@ pub struct InstrumentedState { pre_image_id: [u8; 32], pre_hash_root: [u8; 32], block_path: String, + pre_input_ptr: usize, } impl Display for InstrumentedState { @@ -463,6 +464,7 @@ impl InstrumentedState { pre_image_id: [0u8; 32], pre_hash_root: [0u8; 32], pre_segment_id: 0u32, + pre_input_ptr: 0, }) } @@ -1200,7 +1202,7 @@ impl InstrumentedState { end_pc: self.state.pc, page_hash_root, input_stream: self.state.input_stream.clone(), - input_stream_ptr: self.state.input_stream_ptr + input_stream_ptr: self.pre_input_ptr, }; let name = format!("{output}/{}", self.pre_segment_id); log::debug!("split: file {}", name); @@ -1210,6 +1212,7 @@ impl InstrumentedState { self.pre_segment_id += 1; } + self.pre_input_ptr = self.state.input_stream_ptr; self.pre_pc = self.state.pc; self.pre_image_id = image_id; self.pre_hash_root = page_hash_root; From b3771f117f6f588be6bb483f45e447e0f5dcb585 Mon Sep 17 00:00:00 2001 From: Angell Li Date: Tue, 2 Jul 2024 09:12:10 +0800 Subject: [PATCH 08/13] fix hint read syscall and rebase --- examples/zkmips.rs | 17 ++++++++++++----- src/generation/state.rs | 1 - src/witness/operation.rs | 15 +++++---------- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/examples/zkmips.rs b/examples/zkmips.rs index 0ab14ba0..40f92e7e 100644 --- a/examples/zkmips.rs +++ b/examples/zkmips.rs @@ -84,14 +84,15 @@ fn prove_sha2_bench() { let file = ElfBytes::::minimal_parse(data.as_slice()).expect("opening elf file failed"); let (mut state, _) = State::load_elf(&file); - state.patch_go(&file); + state.patch_elf(&file); state.patch_stack(vec![]); - - // load input + + // load input let input = [5u8; 32]; state.add_input_stream(&input.to_vec()); - let mut instrumented_state: Box = InstrumentedState::new(state, "".to_string()); + let mut instrumented_state: Box = + InstrumentedState::new(state, "".to_string()); std::fs::create_dir_all(&seg_path).unwrap(); let new_writer = |_: &str| -> Option { None }; instrumented_state.split_segment(false, &seg_path, new_writer); @@ -107,7 +108,13 @@ fn prove_sha2_bench() { let seg_file = format!("{seg_path}/{}", 0); let seg_reader = BufReader::new(File::open(seg_file).unwrap()); - let kernel = segment_kernel("", "", "", seg_reader, instrumented_state.state.step as usize); + let kernel = segment_kernel( + "", + "", + "", + seg_reader, + instrumented_state.state.step as usize, + ); const D: usize = 2; type C = PoseidonGoldilocksConfig; type F = >::F; diff --git a/src/generation/state.rs b/src/generation/state.rs index b4090070..6cc7606e 100644 --- a/src/generation/state.rs +++ b/src/generation/state.rs @@ -20,7 +20,6 @@ pub(crate) struct GenerationState { pub(crate) input_stream_ptr: usize, pub(crate) traces: Traces, pub(crate) step: usize, - } impl GenerationState { diff --git a/src/witness/operation.rs b/src/witness/operation.rs index cfaaa8e2..e0df9197 100644 --- a/src/witness/operation.rs +++ b/src/witness/operation.rs @@ -860,16 +860,12 @@ pub(crate) fn load_input( addr: usize, size: usize, ) -> Result<()> { - let mut map_addr = addr; + let map_addr = addr; let vec = state.input_stream[state.input_stream_ptr].clone(); state.input_stream_ptr += 1; - assert_eq!( - vec.len(), - size, - "hint input stream read length mismatch" - ); + assert_eq!(vec.len(), size, "hint input stream read length mismatch"); assert_eq!(addr % 4, 0, "hint read address not aligned to 4 bytes"); - + let mut cpu_row = CpuColumnsView::default(); cpu_row.clock = F::from_canonical_usize(state.traces.clock()); let mut j = 0; @@ -889,10 +885,9 @@ pub(crate) fn load_input( cpu_row.clock = F::from_canonical_usize(state.traces.clock()); j = 0; } - let addr = MemoryAddress::new(0, Segment::Code, map_addr); - let mem_op = mem_write_gp_log_and_fill(j, addr, state, &mut cpu_row, word.to_be()); + let addr = MemoryAddress::new(0, Segment::Code, map_addr + i); + let mem_op = mem_write_gp_log_and_fill(j, addr, state, &mut cpu_row, word); state.traces.push_memory(mem_op); - map_addr += 4; j += 1; } From 09fd5dae9e72308ab53791087712176f8a5a128f Mon Sep 17 00:00:00 2001 From: Angell Li Date: Wed, 3 Jul 2024 12:59:12 +0800 Subject: [PATCH 09/13] add port header and update sha2 bench test --- {benchmark => examples}/sha2/Cargo.lock | 24 +- {benchmark => examples}/sha2/Cargo.toml | 2 +- .../sha2/rust-toolchain.toml | 0 {benchmark => examples}/sha2/src/main.rs | 6 +- zkvm/entrypoint/Cargo.toml | 20 - zkvm/entrypoint/src/heap.rs | 16 - zkvm/entrypoint/src/lib.rs | 77 --- zkvm/entrypoint/src/libm.rs | 559 ------------------ zkvm/entrypoint/src/memcpy.s | 335 ----------- zkvm/entrypoint/src/memory.rs | 51 -- zkvm/entrypoint/src/memset.s | 316 ---------- zkvm/entrypoint/src/syscalls/halt.rs | 24 - zkvm/entrypoint/src/syscalls/io.rs | 72 --- zkvm/entrypoint/src/syscalls/memory.rs | 51 -- zkvm/entrypoint/src/syscalls/mod.rs | 28 - zkvm/entrypoint/src/syscalls/sys.rs | 68 --- zkvm/precompiles/Cargo.toml | 14 - zkvm/precompiles/src/io.rs | 90 --- zkvm/precompiles/src/lib.rs | 19 - zkvm/precompiles/src/utils.rs | 109 ---- 20 files changed, 16 insertions(+), 1865 deletions(-) rename {benchmark => examples}/sha2/Cargo.lock (93%) rename {benchmark => examples}/sha2/Cargo.toml (74%) rename {benchmark => examples}/sha2/rust-toolchain.toml (100%) rename {benchmark => examples}/sha2/src/main.rs (60%) delete mode 100644 zkvm/entrypoint/Cargo.toml delete mode 100644 zkvm/entrypoint/src/heap.rs delete mode 100644 zkvm/entrypoint/src/lib.rs delete mode 100644 zkvm/entrypoint/src/libm.rs delete mode 100644 zkvm/entrypoint/src/memcpy.s delete mode 100644 zkvm/entrypoint/src/memory.rs delete mode 100644 zkvm/entrypoint/src/memset.s delete mode 100644 zkvm/entrypoint/src/syscalls/halt.rs delete mode 100644 zkvm/entrypoint/src/syscalls/io.rs delete mode 100644 zkvm/entrypoint/src/syscalls/memory.rs delete mode 100644 zkvm/entrypoint/src/syscalls/mod.rs delete mode 100644 zkvm/entrypoint/src/syscalls/sys.rs delete mode 100644 zkvm/precompiles/Cargo.toml delete mode 100644 zkvm/precompiles/src/io.rs delete mode 100644 zkvm/precompiles/src/lib.rs delete mode 100644 zkvm/precompiles/src/utils.rs diff --git a/benchmark/sha2/Cargo.lock b/examples/sha2/Cargo.lock similarity index 93% rename from benchmark/sha2/Cargo.lock rename to examples/sha2/Cargo.lock index 126136ae..10dd144c 100644 --- a/benchmark/sha2/Cargo.lock +++ b/examples/sha2/Cargo.lock @@ -96,9 +96,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" @@ -128,9 +128,9 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", @@ -199,18 +199,18 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.79" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.35" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -281,14 +281,14 @@ name = "sha2-bench" version = "0.1.0" dependencies = [ "sha2", - "zkm-zkvm", + "zkm-runtime", ] [[package]] name = "syn" -version = "2.0.53" +version = "2.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" +checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9" dependencies = [ "proc-macro2", "quote", @@ -334,7 +334,7 @@ dependencies = [ ] [[package]] -name = "zkm-zkvm" +name = "zkm-runtime" version = "0.1.0" dependencies = [ "bincode", diff --git a/benchmark/sha2/Cargo.toml b/examples/sha2/Cargo.toml similarity index 74% rename from benchmark/sha2/Cargo.toml rename to examples/sha2/Cargo.toml index eed83245..cc8c6751 100644 --- a/benchmark/sha2/Cargo.toml +++ b/examples/sha2/Cargo.toml @@ -5,5 +5,5 @@ name = "sha2-bench" edition = "2021" [dependencies] -zkm-zkvm = { path = "../../zkvm/entrypoint" } +zkm-runtime = { path = "../../runtime/entrypoint" } sha2 = { version = "0.10.8", default-features = false } diff --git a/benchmark/sha2/rust-toolchain.toml b/examples/sha2/rust-toolchain.toml similarity index 100% rename from benchmark/sha2/rust-toolchain.toml rename to examples/sha2/rust-toolchain.toml diff --git a/benchmark/sha2/src/main.rs b/examples/sha2/src/main.rs similarity index 60% rename from benchmark/sha2/src/main.rs rename to examples/sha2/src/main.rs index e0ae5002..68e64b39 100644 --- a/benchmark/sha2/src/main.rs +++ b/examples/sha2/src/main.rs @@ -5,14 +5,14 @@ use sha2::{Digest, Sha256}; extern crate alloc; use alloc::vec::Vec; -zkm_zkvm::entrypoint!(main); +zkm_runtime::entrypoint!(main); pub fn main() { - let input: Vec = zkm_zkvm::io::read(); + let input: Vec = zkm_runtime::io::read(); let mut hasher = Sha256::new(); hasher.update(input); let result = hasher.finalize(); - zkm_zkvm::io::commit::<[u8; 32]>(&result.into()); + zkm_runtime::io::commit::<[u8; 32]>(&result.into()); } diff --git a/zkvm/entrypoint/Cargo.toml b/zkvm/entrypoint/Cargo.toml deleted file mode 100644 index 303100a0..00000000 --- a/zkvm/entrypoint/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "zkm-zkvm" -version = "0.1.0" -edition = "2021" - -[dependencies] -zkm-precompiles = { path = "../precompiles" } -bincode = "1.3.3" -cfg-if = "1.0.0" -getrandom = { version = "0.2.14", features = ["custom"] } -once_cell = "1.19.0" -rand = "0.8.5" -serde = { version = "1.0.201", features = ["derive"] } -libm = { version = "0.2.8", optional = true } -sha2 = { version = "0.10.8" } -lazy_static = "1.4.0" - -[features] -default = ["libm"] -libm = ["dep:libm"] diff --git a/zkvm/entrypoint/src/heap.rs b/zkvm/entrypoint/src/heap.rs deleted file mode 100644 index 86b3c0e1..00000000 --- a/zkvm/entrypoint/src/heap.rs +++ /dev/null @@ -1,16 +0,0 @@ -use core::alloc::{GlobalAlloc, Layout}; - -use crate::syscalls::sys_alloc_aligned; - -/// A simple heap allocator. -/// -/// Allocates memory from left to right, without any deallocation. -pub struct SimpleAlloc; - -unsafe impl GlobalAlloc for SimpleAlloc { - unsafe fn alloc(&self, layout: Layout) -> *mut u8 { - sys_alloc_aligned(layout.size(), layout.align()) - } - - unsafe fn dealloc(&self, _: *mut u8, _: Layout) {} -} diff --git a/zkvm/entrypoint/src/lib.rs b/zkvm/entrypoint/src/lib.rs deleted file mode 100644 index d9c6d42a..00000000 --- a/zkvm/entrypoint/src/lib.rs +++ /dev/null @@ -1,77 +0,0 @@ -#![feature(asm_experimental_arch)] -pub mod heap; -pub mod syscalls; -pub mod io { - pub use zkm_precompiles::io::*; -} -pub mod precompiles { - pub use zkm_precompiles::*; -} - -extern crate alloc; - -#[macro_export] -macro_rules! entrypoint { - ($path:path) => { - const ZKVM_ENTRY: fn() = $path; - - use $crate::heap::SimpleAlloc; - - #[global_allocator] - static HEAP: SimpleAlloc = SimpleAlloc; - - mod zkvm_generated_main { - - #[no_mangle] - fn start() { - super::ZKVM_ENTRY() - } - } - }; -} - -mod libm; - -/// The number of 32 bit words that the public values digest is composed of. -pub const PV_DIGEST_NUM_WORDS: usize = 8; -pub const POSEIDON_NUM_WORDS: usize = 8; - -#[cfg(target_os = "zkvm")] -mod zkvm { - use crate::syscalls::syscall_halt; - - use getrandom::{register_custom_getrandom, Error}; - use sha2::{Digest, Sha256}; - - pub static mut PUBLIC_VALUES_HASHER: Option = None; - - #[cfg(not(feature = "interface"))] - #[no_mangle] - fn main() { - unsafe { - PUBLIC_VALUES_HASHER = Some(Sha256::new()); - - extern "C" { - fn start(); - } - start() - } - - syscall_halt(0); - } - - static STACK_TOP: u32 = 0x0020_0400; - - core::arch::global_asm!(include_str!("memset.s")); - core::arch::global_asm!(include_str!("memcpy.s")); - - fn zkvm_getrandom(s: &mut [u8]) -> Result<(), Error> { - unsafe { - crate::syscalls::sys_rand(s.as_mut_ptr(), s.len()); - } - - Ok(()) - } - - register_custom_getrandom!(zkvm_getrandom); -} diff --git a/zkvm/entrypoint/src/libm.rs b/zkvm/entrypoint/src/libm.rs deleted file mode 100644 index 304624d0..00000000 --- a/zkvm/entrypoint/src/libm.rs +++ /dev/null @@ -1,559 +0,0 @@ -#[no_mangle] -pub extern "C" fn acos(x: f64) -> f64 { - libm::acos(x) -} - -#[no_mangle] -pub extern "C" fn acosf(x: f32) -> f32 { - libm::acosf(x) -} - -#[no_mangle] -pub extern "C" fn acosh(x: f64) -> f64 { - libm::acosh(x) -} - -#[no_mangle] -pub extern "C" fn acoshf(x: f32) -> f32 { - libm::acoshf(x) -} - -#[no_mangle] -pub extern "C" fn asin(x: f64) -> f64 { - libm::asin(x) -} - -#[no_mangle] -pub extern "C" fn asinf(x: f32) -> f32 { - libm::asinf(x) -} - -#[no_mangle] -pub extern "C" fn asinh(x: f64) -> f64 { - libm::asinh(x) -} - -#[no_mangle] -pub extern "C" fn asinhf(x: f32) -> f32 { - libm::asinhf(x) -} - -#[no_mangle] -pub extern "C" fn atan(x: f64) -> f64 { - libm::atan(x) -} - -#[no_mangle] -pub extern "C" fn atan2(y: f64, x: f64) -> f64 { - libm::atan2(y, x) -} - -#[no_mangle] -pub extern "C" fn atan2f(y: f32, x: f32) -> f32 { - libm::atan2f(y, x) -} - -#[no_mangle] -pub extern "C" fn atanf(x: f32) -> f32 { - libm::atanf(x) -} - -#[no_mangle] -pub extern "C" fn atanh(x: f64) -> f64 { - libm::atanh(x) -} - -#[no_mangle] -pub extern "C" fn atanhf(x: f32) -> f32 { - libm::atanhf(x) -} - -#[no_mangle] -pub extern "C" fn cbrt(x: f64) -> f64 { - libm::cbrt(x) -} - -#[no_mangle] -pub extern "C" fn cbrtf(x: f32) -> f32 { - libm::cbrtf(x) -} - -#[no_mangle] -pub extern "C" fn ceil(x: f64) -> f64 { - libm::ceil(x) -} - -#[no_mangle] -pub extern "C" fn ceilf(x: f32) -> f32 { - libm::ceilf(x) -} - -#[no_mangle] -pub extern "C" fn copysign(x: f64, y: f64) -> f64 { - libm::copysign(x, y) -} - -#[no_mangle] -pub extern "C" fn copysignf(x: f32, y: f32) -> f32 { - libm::copysignf(x, y) -} - -#[no_mangle] -pub extern "C" fn cos(x: f64) -> f64 { - libm::cos(x) -} - -#[no_mangle] -pub extern "C" fn cosf(x: f32) -> f32 { - libm::cosf(x) -} - -#[no_mangle] -pub extern "C" fn cosh(x: f64) -> f64 { - libm::cosh(x) -} - -#[no_mangle] -pub extern "C" fn coshf(x: f32) -> f32 { - libm::coshf(x) -} - -#[no_mangle] -pub extern "C" fn erf(x: f64) -> f64 { - libm::erf(x) -} - -#[no_mangle] -pub extern "C" fn erfc(x: f64) -> f64 { - libm::erfc(x) -} - -#[no_mangle] -pub extern "C" fn erfcf(x: f32) -> f32 { - libm::erfcf(x) -} - -#[no_mangle] -pub extern "C" fn erff(x: f32) -> f32 { - libm::erff(x) -} - -#[no_mangle] -pub extern "C" fn exp(x: f64) -> f64 { - libm::exp(x) -} - -#[no_mangle] -pub extern "C" fn exp2(x: f64) -> f64 { - libm::exp2(x) -} - -#[no_mangle] -pub extern "C" fn exp2f(x: f32) -> f32 { - libm::exp2f(x) -} - -#[no_mangle] -pub extern "C" fn exp10(x: f64) -> f64 { - libm::exp10(x) -} - -#[no_mangle] -pub extern "C" fn exp10f(x: f32) -> f32 { - libm::exp10f(x) -} - -#[no_mangle] -pub extern "C" fn expf(x: f32) -> f32 { - libm::expf(x) -} - -#[no_mangle] -pub extern "C" fn expm1(x: f64) -> f64 { - libm::expm1(x) -} - -#[no_mangle] -pub extern "C" fn expm1f(x: f32) -> f32 { - libm::expm1f(x) -} - -#[no_mangle] -pub extern "C" fn fabs(x: f64) -> f64 { - libm::fabs(x) -} - -#[no_mangle] -pub extern "C" fn fabsf(x: f32) -> f32 { - libm::fabsf(x) -} - -#[no_mangle] -pub extern "C" fn fdim(x: f64, y: f64) -> f64 { - libm::fdim(x, y) -} - -#[no_mangle] -pub extern "C" fn fdimf(x: f32, y: f32) -> f32 { - libm::fdimf(x, y) -} - -#[no_mangle] -pub extern "C" fn floor(x: f64) -> f64 { - libm::floor(x) -} - -#[no_mangle] -pub extern "C" fn floorf(x: f32) -> f32 { - libm::floorf(x) -} - -#[no_mangle] -pub extern "C" fn fma(x: f64, y: f64, z: f64) -> f64 { - libm::fma(x, y, z) -} - -#[no_mangle] -pub extern "C" fn fmaf(x: f32, y: f32, z: f32) -> f32 { - libm::fmaf(x, y, z) -} - -#[no_mangle] -pub extern "C" fn fmax(x: f64, y: f64) -> f64 { - libm::fmax(x, y) -} - -#[no_mangle] -pub extern "C" fn fmaxf(x: f32, y: f32) -> f32 { - libm::fmaxf(x, y) -} - -#[no_mangle] -pub extern "C" fn fmin(x: f64, y: f64) -> f64 { - libm::fmin(x, y) -} - -#[no_mangle] -pub extern "C" fn fminf(x: f32, y: f32) -> f32 { - libm::fminf(x, y) -} - -#[no_mangle] -pub extern "C" fn fmod(x: f64, y: f64) -> f64 { - libm::fmod(x, y) -} - -#[no_mangle] -pub extern "C" fn fmodf(x: f32, y: f32) -> f32 { - libm::fmodf(x, y) -} - -#[no_mangle] -pub fn frexp(x: f64) -> (f64, i32) { - libm::frexp(x) -} - -#[no_mangle] -pub fn frexpf(x: f32) -> (f32, i32) { - libm::frexpf(x) -} - -#[no_mangle] -pub extern "C" fn hypot(x: f64, y: f64) -> f64 { - libm::hypot(x, y) -} - -#[no_mangle] -pub extern "C" fn hypotf(x: f32, y: f32) -> f32 { - libm::hypotf(x, y) -} - -#[no_mangle] -pub extern "C" fn ilogb(x: f64) -> i32 { - libm::ilogb(x) -} - -#[no_mangle] -pub extern "C" fn ilogbf(x: f32) -> i32 { - libm::ilogbf(x) -} - -#[no_mangle] -pub extern "C" fn j0(x: f64) -> f64 { - libm::j0(x) -} - -#[no_mangle] -pub extern "C" fn j0f(x: f32) -> f32 { - libm::j0f(x) -} - -#[no_mangle] -pub extern "C" fn j1(x: f64) -> f64 { - libm::j1(x) -} - -#[no_mangle] -pub extern "C" fn j1f(x: f32) -> f32 { - libm::j1f(x) -} - -#[no_mangle] -pub extern "C" fn jn(n: i32, x: f64) -> f64 { - libm::jn(n, x) -} - -#[no_mangle] -pub extern "C" fn jnf(n: i32, x: f32) -> f32 { - libm::jnf(n, x) -} - -#[no_mangle] -pub extern "C" fn ldexp(x: f64, n: i32) -> f64 { - libm::ldexp(x, n) -} - -#[no_mangle] -pub extern "C" fn ldexpf(x: f32, n: i32) -> f32 { - libm::ldexpf(x, n) -} - -#[no_mangle] -pub extern "C" fn lgamma(x: f64) -> f64 { - libm::lgamma(x) -} - -#[no_mangle] -pub fn lgamma_r(x: f64) -> (f64, i32) { - libm::lgamma_r(x) -} - -#[no_mangle] -pub fn lgammaf(x: f32) -> f32 { - libm::lgammaf(x) -} - -#[no_mangle] -pub fn lgammaf_r(x: f32) -> (f32, i32) { - libm::lgammaf_r(x) -} - -#[no_mangle] -pub extern "C" fn log(x: f64) -> f64 { - libm::log(x) -} - -#[no_mangle] -pub extern "C" fn log1p(x: f64) -> f64 { - libm::log1p(x) -} - -#[no_mangle] -pub extern "C" fn log1pf(x: f32) -> f32 { - libm::log1pf(x) -} - -#[no_mangle] -pub extern "C" fn log2(x: f64) -> f64 { - libm::log2(x) -} - -#[no_mangle] -pub extern "C" fn log2f(x: f32) -> f32 { - libm::log2f(x) -} - -#[no_mangle] -pub extern "C" fn log10(x: f64) -> f64 { - libm::log10(x) -} - -#[no_mangle] -pub extern "C" fn log10f(x: f32) -> f32 { - libm::log10f(x) -} - -#[no_mangle] -pub extern "C" fn logf(x: f32) -> f32 { - libm::logf(x) -} - -#[no_mangle] -pub fn modf(x: f64) -> (f64, f64) { - libm::modf(x) -} - -#[no_mangle] -pub fn modff(x: f32) -> (f32, f32) { - libm::modff(x) -} - -#[no_mangle] -pub extern "C" fn nextafter(x: f64, y: f64) -> f64 { - libm::nextafter(x, y) -} - -#[no_mangle] -pub extern "C" fn nextafterf(x: f32, y: f32) -> f32 { - libm::nextafterf(x, y) -} - -#[no_mangle] -pub extern "C" fn pow(x: f64, y: f64) -> f64 { - libm::pow(x, y) -} - -#[no_mangle] -pub extern "C" fn powf(x: f32, y: f32) -> f32 { - libm::powf(x, y) -} - -#[no_mangle] -pub extern "C" fn remainder(x: f64, y: f64) -> f64 { - libm::remainder(x, y) -} - -#[no_mangle] -pub extern "C" fn remainderf(x: f32, y: f32) -> f32 { - libm::remainderf(x, y) -} - -#[no_mangle] -pub fn remquo(x: f64, y: f64) -> (f64, i32) { - libm::remquo(x, y) -} - -#[no_mangle] -pub fn remquof(x: f32, y: f32) -> (f32, i32) { - libm::remquof(x, y) -} - -#[no_mangle] -pub extern "C" fn round(x: f64) -> f64 { - libm::round(x) -} - -#[no_mangle] -pub extern "C" fn roundf(x: f32) -> f32 { - libm::roundf(x) -} - -#[no_mangle] -pub extern "C" fn scalbn(x: f64, n: i32) -> f64 { - libm::scalbn(x, n) -} - -#[no_mangle] -pub extern "C" fn scalbnf(x: f32, n: i32) -> f32 { - libm::scalbnf(x, n) -} - -#[no_mangle] -pub extern "C" fn sin(x: f64) -> f64 { - libm::sin(x) -} - -#[no_mangle] -pub fn sincos(x: f64) -> (f64, f64) { - libm::sincos(x) -} - -#[no_mangle] -pub fn sincosf(x: f32) -> (f32, f32) { - libm::sincosf(x) -} - -#[no_mangle] -pub extern "C" fn sinf(x: f32) -> f32 { - libm::sinf(x) -} - -#[no_mangle] -pub extern "C" fn sinh(x: f64) -> f64 { - libm::sinh(x) -} - -#[no_mangle] -pub extern "C" fn sinhf(x: f32) -> f32 { - libm::sinhf(x) -} - -#[no_mangle] -pub extern "C" fn sqrt(x: f64) -> f64 { - libm::sqrt(x) -} - -#[no_mangle] -pub extern "C" fn sqrtf(x: f32) -> f32 { - libm::sqrtf(x) -} - -#[no_mangle] -pub extern "C" fn tan(x: f64) -> f64 { - libm::tan(x) -} - -#[no_mangle] -pub extern "C" fn tanf(x: f32) -> f32 { - libm::tanf(x) -} - -#[no_mangle] -pub extern "C" fn tanh(x: f64) -> f64 { - libm::tanh(x) -} - -#[no_mangle] -pub extern "C" fn tanhf(x: f32) -> f32 { - libm::tanhf(x) -} - -#[no_mangle] -pub extern "C" fn tgamma(x: f64) -> f64 { - libm::tgamma(x) -} - -#[no_mangle] -pub extern "C" fn tgammaf(x: f32) -> f32 { - libm::tgammaf(x) -} - -#[no_mangle] -pub extern "C" fn trunc(x: f64) -> f64 { - libm::trunc(x) -} - -#[no_mangle] -pub extern "C" fn truncf(x: f32) -> f32 { - libm::truncf(x) -} - -#[no_mangle] -pub extern "C" fn y0(x: f64) -> f64 { - libm::y0(x) -} - -#[no_mangle] -pub extern "C" fn y0f(x: f32) -> f32 { - libm::y0f(x) -} - -#[no_mangle] -pub extern "C" fn y1(x: f64) -> f64 { - libm::y1(x) -} - -#[no_mangle] -pub extern "C" fn y1f(x: f32) -> f32 { - libm::y1f(x) -} - -#[no_mangle] -pub extern "C" fn yn(n: i32, x: f64) -> f64 { - libm::yn(n, x) -} - -#[no_mangle] -pub extern "C" fn ynf(n: i32, x: f32) -> f32 { - libm::ynf(n, x) -} diff --git a/zkvm/entrypoint/src/memcpy.s b/zkvm/entrypoint/src/memcpy.s deleted file mode 100644 index f983a45a..00000000 --- a/zkvm/entrypoint/src/memcpy.s +++ /dev/null @@ -1,335 +0,0 @@ -// This is musl-libc commit 3b0a370020c4d5b80ff32a609e5322b7760f0dc4: -// -// src/string/memcpy.c -// -// This was compiled into assembly with: -// -// clang-10 -target mips -O3 -S memcpy.c -nostdlib -fno-builtin -funroll-loops -// -// and labels manually updated to not conflict. -// -// musl as a whole is licensed under the following standard MIT license: -// -// ---------------------------------------------------------------------- -// Copyright © 2005-2020 Rich Felker, et al. -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// ---------------------------------------------------------------------- -// -// Authors/contributors include: -// -// A. Wilcox -// Ada Worcester -// Alex Dowad -// Alex Suykov -// Alexander Monakov -// Andre McCurdy -// Andrew Kelley -// Anthony G. Basile -// Aric Belsito -// Arvid Picciani -// Bartosz Brachaczek -// Benjamin Peterson -// Bobby Bingham -// Boris Brezillon -// Brent Cook -// Chris Spiegel -// Clément Vasseur -// Daniel Micay -// Daniel Sabogal -// Daurnimator -// David Carlier -// David Edelsohn -// Denys Vlasenko -// Dmitry Ivanov -// Dmitry V. Levin -// Drew DeVault -// Emil Renner Berthing -// Fangrui Song -// Felix Fietkau -// Felix Janda -// Gianluca Anzolin -// Hauke Mehrtens -// He X -// Hiltjo Posthuma -// Isaac Dunham -// Jaydeep Patil -// Jens Gustedt -// Jeremy Huntwork -// Jo-Philipp Wich -// Joakim Sindholt -// John Spencer -// Julien Ramseier -// Justin Cormack -// Kaarle Ritvanen -// Khem Raj -// Kylie McClain -// Leah Neukirchen -// Luca Barbato -// Luka Perkov -// M Farkas-Dyck (Strake) -// Mahesh Bodapati -// Markus Wichmann -// Masanori Ogino -// Michael Clark -// Michael Forney -// Mikhail Kremnyov -// Natanael Copa -// Nicholas J. Kain -// orc -// Pascal Cuoq -// Patrick Oppenlander -// Petr Hosek -// Petr Skocik -// Pierre Carrier -// Reini Urban -// Rich Felker -// Richard Pennington -// Ryan Fairfax -// Samuel Holland -// Segev Finer -// Shiz -// sin -// Solar Designer -// Stefan Kristiansson -// Stefan O'Rear -// Szabolcs Nagy -// Timo Teräs -// Trutz Behn -// Valentin Ochs -// Will Dietz -// William Haddon -// William Pitcock -// -// Portions of this software are derived from third-party works licensed -// under terms compatible with the above MIT license: -// -// The TRE regular expression implementation (src/regex/reg* and -// src/regex/tre*) is Copyright © 2001-2008 Ville Laurikari and licensed -// under a 2-clause BSD license (license text in the source files). The -// included version has been heavily modified by Rich Felker in 2012, in -// the interests of size, simplicity, and namespace cleanliness. -// -// Much of the math library code (src/math/* and src/complex/*) is -// Copyright © 1993,2004 Sun Microsystems or -// Copyright © 2003-2011 David Schultz or -// Copyright © 2003-2009 Steven G. Kargl or -// Copyright © 2003-2009 Bruce D. Evans or -// Copyright © 2008 Stephen L. Moshier or -// Copyright © 2017-2018 Arm Limited -// and labelled as such in comments in the individual source files. All -// have been licensed under extremely permissive terms. -// -// The ARM memcpy code (src/string/arm/memcpy.S) is Copyright © 2008 -// The Android Open Source Project and is licensed under a two-clause BSD -// license. It was taken from Bionic libc, used on Android. -// -// The AArch64 memcpy and memset code (src/string/aarch64/*) are -// Copyright © 1999-2019, Arm Limited. -// -// The implementation of DES for crypt (src/crypt/crypt_des.c) is -// Copyright © 1994 David Burren. It is licensed under a BSD license. -// -// The implementation of blowfish crypt (src/crypt/crypt_blowfish.c) was -// originally written by Solar Designer and placed into the public -// domain. The code also comes with a fallback permissive license for use -// in jurisdictions that may not recognize the public domain. -// -// The smoothsort implementation (src/stdlib/qsort.c) is Copyright © 2011 -// Valentin Ochs and is licensed under an MIT-style license. -// -// The x86_64 port was written by Nicholas J. Kain and is licensed under -// the standard MIT terms. -// -// The mips and microblaze ports were originally written by Richard -// Pennington for use in the ellcc project. The original code was adapted -// by Rich Felker for build system and code conventions during upstream -// integration. It is licensed under the standard MIT terms. -// -// The mips64 port was contributed by Imagination Technologies and is -// licensed under the standard MIT terms. -// -// The powerpc port was also originally written by Richard Pennington, -// and later supplemented and integrated by John Spencer. It is licensed -// under the standard MIT terms. -// -// All other files which have no copyright comments are original works -// produced specifically for use as part of this library, written either -// by Rich Felker, the main author of the library, or by one or more -// contibutors listed above. Details on authorship of individual files -// can be found in the git version control history of the project. The -// omission of copyright and license comments in each file is in the -// interest of source tree size. -// -// In addition, permission is hereby granted for all public header files -// (include/* and arch/* /bits/* ) and crt files intended to be linked into -// applications (crt/*, ldso/dlstart.c, and arch/* /crt_arch.h) to omit -// the copyright notice and permission notice otherwise required by the -// license, and to use these files without any requirement of -// attribution. These files include substantial contributions from: -// -// Bobby Bingham -// John Spencer -// Nicholas J. Kain -// Rich Felker -// Richard Pennington -// Stefan Kristiansson -// Szabolcs Nagy -// -// all of whom have explicitly granted such permission. -// -// This file previously contained text expressing a belief that most of -// the files covered by the above exception were sufficiently trivial not -// to be subject to copyright, resulting in confusion over whether it -// negated the permissions granted in the license. In the spirit of -// permissive licensing, and of not having licensing issues being an -// obstacle to adoption, that text has been removed. - .text - .file "memcpy.c" - .globl memccpy # -- Begin function memccpy - .p2align 2 - .type memccpy,@function - .set nomicromips - .set nomips16 - .ent memccpy -memccpy: # @memccpy - .frame $fp,8,$ra - .mask 0xc0000000,-4 - .fmask 0x00000000,0 - .set noreorder - .set nomacro - .set noat -# %bb.0: - addiu $sp, $sp, -8 - sw $ra, 4($sp) # 4-byte Folded Spill - sw $fp, 0($sp) # 4-byte Folded Spill - move $fp, $sp - xor $1, $5, $4 - andi $1, $1, 3 - beqz $1, $BBmemcpy0_7 - andi $3, $6, 255 -$BBmemcpy0_1: - beqz $7, $BBmemcpy0_5 - nop -# %bb.2: - addiu $2, $4, 1 -$BBmemcpy0_3: # =>This Inner Loop Header: Depth=1 - lbu $1, 0($5) - beq $1, $3, $BBmemcpy0_6 - sb $1, -1($2) -# %bb.4: # in Loop: Header=BBmemcpy0_3 Depth=1 - addiu $2, $2, 1 - addiu $7, $7, -1 - bnez $7, $BBmemcpy0_3 - addiu $5, $5, 1 -$BBmemcpy0_5: - addiu $2, $zero, 0 -$BBmemcpy0_6: - move $sp, $fp - lw $fp, 0($sp) # 4-byte Folded Reload - lw $ra, 4($sp) # 4-byte Folded Reload - jr $ra - addiu $sp, $sp, 8 -$BBmemcpy0_7: - andi $6, $5, 3 - beqz $7, $BBmemcpy0_14 - sltu $2, $zero, $6 -# %bb.8: - beqz $6, $BBmemcpy0_14 - nop -# %bb.9: - addiu $2, $7, -1 - addiu $6, $zero, 0 -$BBmemcpy0_10: # =>This Inner Loop Header: Depth=1 - addu $9, $5, $6 - addu $8, $4, $6 - lbu $1, 0($9) - beq $1, $3, $BBmemcpy0_22 - sb $1, 0($8) -# %bb.11: # in Loop: Header=BBmemcpy0_10 Depth=1 - addiu $1, $9, 1 - addiu $8, $6, 1 - beq $2, $6, $BBmemcpy0_13 - andi $9, $1, 3 -# %bb.12: # in Loop: Header=BBmemcpy0_10 Depth=1 - bnez $9, $BBmemcpy0_10 - move $6, $8 -$BBmemcpy0_13: - sltu $2, $zero, $9 - subu $7, $7, $8 - addu $4, $4, $8 - addu $5, $5, $8 -$BBmemcpy0_14: - beqz $2, $BBmemcpy0_17 - nop -# %bb.15: - bnez $7, $BBmemcpy0_6 - addiu $2, $4, 1 -# %bb.16: - j $BBmemcpy0_5 - nop -$BBmemcpy0_17: - sltiu $1, $7, 4 - bnez $1, $BBmemcpy0_1 - nop -# %bb.18: - sll $1, $3, 8 - sll $2, $3, 16 - or $1, $1, $3 - or $1, $2, $1 - sll $2, $3, 24 - or $6, $2, $1 - lui $1, 65278 - andi $2, $7, 3 - ori $8, $1, 65279 - lui $1, 32896 - ori $9, $1, 32896 -$BBmemcpy0_19: # =>This Inner Loop Header: Depth=1 - lw $10, 0($5) - xor $1, $10, $6 - addu $11, $1, $8 - not $1, $1 - and $1, $1, $11 - and $1, $1, $9 - bnez $1, $BBmemcpy0_1 - nop -# %bb.20: # in Loop: Header=BBmemcpy0_19 Depth=1 - addiu $7, $7, -4 - sw $10, 0($4) - addiu $4, $4, 4 - sltiu $1, $7, 4 - beqz $1, $BBmemcpy0_19 - addiu $5, $5, 4 -# %bb.21: - j $BBmemcpy0_1 - move $7, $2 -$BBmemcpy0_22: - j $BBmemcpy0_6 - addiu $2, $8, 1 - .set at - .set macro - .set reorder - .end memccpy -$memcpy_func_end0: - .size memccpy, ($memcpy_func_end0)-memccpy - # -- End function - .ident "clang version 10.0.0-4ubuntu1 " - .section ".note.GNU-stack","",@progbits - .addrsig \ No newline at end of file diff --git a/zkvm/entrypoint/src/memory.rs b/zkvm/entrypoint/src/memory.rs deleted file mode 100644 index b4c967ea..00000000 --- a/zkvm/entrypoint/src/memory.rs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2023 RISC Zero, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -const SYSTEM_START: usize = 0x0C00_0000; - -#[allow(clippy::missing_safety_doc)] -#[no_mangle] -pub unsafe extern "C" fn sys_alloc_aligned(bytes: usize, align: usize) -> *mut u8 { - extern "C" { - // https://lld.llvm.org/ELF/linker_script.html#sections-command - static _end: u8; - } - - // Pointer to next heap address to use, or 0 if the heap has not yet been - // initialized. - static mut HEAP_POS: usize = 0; - - // SAFETY: Single threaded, so nothing else can touch this while we're working. - let mut heap_pos = unsafe { HEAP_POS }; - - if heap_pos == 0 { - heap_pos = unsafe { (&_end) as *const u8 as usize }; - } - - let offset = heap_pos & (align - 1); - if offset != 0 { - heap_pos += align - offset; - } - - let ptr = heap_pos as *mut u8; - heap_pos += bytes; - - // Check to make sure heap doesn't collide with SYSTEM memory. - if SYSTEM_START < heap_pos { - panic!(); - } - - unsafe { HEAP_POS = heap_pos }; - ptr -} diff --git a/zkvm/entrypoint/src/memset.s b/zkvm/entrypoint/src/memset.s deleted file mode 100644 index a4840ec4..00000000 --- a/zkvm/entrypoint/src/memset.s +++ /dev/null @@ -1,316 +0,0 @@ -// This is musl-libc memset commit 5613a1486e6a6fc3988be6561f41b07b2647d80f: -// -// src/string/memset.c -// -// This was compiled into assembly with: -// -// clang10 -target mips -O3 -S memset.c -nostdlib -fno-builtin -funroll-loops -// -// and labels manually updated to not conflict. -// -// musl as a whole is licensed under the following standard MIT license: -// -// ---------------------------------------------------------------------- -// Copyright © 2005-2020 Rich Felker, et al. -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// ---------------------------------------------------------------------- -// -// Authors/contributors include: -// -// A. Wilcox -// Ada Worcester -// Alex Dowad -// Alex Suykov -// Alexander Monakov -// Andre McCurdy -// Andrew Kelley -// Anthony G. Basile -// Aric Belsito -// Arvid Picciani -// Bartosz Brachaczek -// Benjamin Peterson -// Bobby Bingham -// Boris Brezillon -// Brent Cook -// Chris Spiegel -// Clément Vasseur -// Daniel Micay -// Daniel Sabogal -// Daurnimator -// David Carlier -// David Edelsohn -// Denys Vlasenko -// Dmitry Ivanov -// Dmitry V. Levin -// Drew DeVault -// Emil Renner Berthing -// Fangrui Song -// Felix Fietkau -// Felix Janda -// Gianluca Anzolin -// Hauke Mehrtens -// He X -// Hiltjo Posthuma -// Isaac Dunham -// Jaydeep Patil -// Jens Gustedt -// Jeremy Huntwork -// Jo-Philipp Wich -// Joakim Sindholt -// John Spencer -// Julien Ramseier -// Justin Cormack -// Kaarle Ritvanen -// Khem Raj -// Kylie McClain -// Leah Neukirchen -// Luca Barbato -// Luka Perkov -// M Farkas-Dyck (Strake) -// Mahesh Bodapati -// Markus Wichmann -// Masanori Ogino -// Michael Clark -// Michael Forney -// Mikhail Kremnyov -// Natanael Copa -// Nicholas J. Kain -// orc -// Pascal Cuoq -// Patrick Oppenlander -// Petr Hosek -// Petr Skocik -// Pierre Carrier -// Reini Urban -// Rich Felker -// Richard Pennington -// Ryan Fairfax -// Samuel Holland -// Segev Finer -// Shiz -// sin -// Solar Designer -// Stefan Kristiansson -// Stefan O'Rear -// Szabolcs Nagy -// Timo Teräs -// Trutz Behn -// Valentin Ochs -// Will Dietz -// William Haddon -// William Pitcock -// -// Portions of this software are derived from third-party works licensed -// under terms compatible with the above MIT license: -// -// The TRE regular expression implementation (src/regex/reg* and -// src/regex/tre*) is Copyright © 2001-2008 Ville Laurikari and licensed -// under a 2-clause BSD license (license text in the source files). The -// included version has been heavily modified by Rich Felker in 2012, in -// the interests of size, simplicity, and namespace cleanliness. -// -// Much of the math library code (src/math/* and src/complex/*) is -// Copyright © 1993,2004 Sun Microsystems or -// Copyright © 2003-2011 David Schultz or -// Copyright © 2003-2009 Steven G. Kargl or -// Copyright © 2003-2009 Bruce D. Evans or -// Copyright © 2008 Stephen L. Moshier or -// Copyright © 2017-2018 Arm Limited -// and labelled as such in comments in the individual source files. All -// have been licensed under extremely permissive terms. -// -// The ARM memcpy code (src/string/arm/memcpy.S) is Copyright © 2008 -// The Android Open Source Project and is licensed under a two-clause BSD -// license. It was taken from Bionic libc, used on Android. -// -// The AArch64 memcpy and memset code (src/string/aarch64/*) are -// Copyright © 1999-2019, Arm Limited. -// -// The implementation of DES for crypt (src/crypt/crypt_des.c) is -// Copyright © 1994 David Burren. It is licensed under a BSD license. -// -// The implementation of blowfish crypt (src/crypt/crypt_blowfish.c) was -// originally written by Solar Designer and placed into the public -// domain. The code also comes with a fallback permissive license for use -// in jurisdictions that may not recognize the public domain. -// -// The smoothsort implementation (src/stdlib/qsort.c) is Copyright © 2011 -// Valentin Ochs and is licensed under an MIT-style license. -// -// The x86_64 port was written by Nicholas J. Kain and is licensed under -// the standard MIT terms. -// -// The mips and microblaze ports were originally written by Richard -// Pennington for use in the ellcc project. The original code was adapted -// by Rich Felker for build system and code conventions during upstream -// integration. It is licensed under the standard MIT terms. -// -// The mips64 port was contributed by Imagination Technologies and is -// licensed under the standard MIT terms. -// -// The powerpc port was also originally written by Richard Pennington, -// and later supplemented and integrated by John Spencer. It is licensed -// under the standard MIT terms. -// -// All other files which have no copyright comments are original works -// produced specifically for use as part of this library, written either -// by Rich Felker, the main author of the library, or by one or more -// contibutors listed above. Details on authorship of individual files -// can be found in the git version control history of the project. The -// omission of copyright and license comments in each file is in the -// interest of source tree size. -// -// In addition, permission is hereby granted for all public header files -// (include/* and arch/* /bits/* ) and crt files intended to be linked into -// applications (crt/*, ldso/dlstart.c, and arch/* /crt_arch.h) to omit -// the copyright notice and permission notice otherwise required by the -// license, and to use these files without any requirement of -// attribution. These files include substantial contributions from: -// -// Bobby Bingham -// John Spencer -// Nicholas J. Kain -// Rich Felker -// Richard Pennington -// Stefan Kristiansson -// Szabolcs Nagy -// -// all of whom have explicitly granted such permission. -// -// This file previously contained text expressing a belief that most of -// the files covered by the above exception were sufficiently trivial not -// to be subject to copyright, resulting in confusion over whether it -// negated the permissions granted in the license. In the spirit of -// permissive licensing, and of not having licensing issues being an -// obstacle to adoption, that text has been removed. - .text - .file "memset.c" - .globl memset # -- Begin function memset - .p2align 2 - .type memset,@function - .set nomicromips - .set nomips16 - .ent memset -memset: # @memset - .frame $fp,8,$ra - .mask 0xc0000000,-4 - .fmask 0x00000000,0 - .set noreorder - .set nomacro - .set noat -# %bb.0: - addiu $sp, $sp, -8 - sw $ra, 4($sp) # 4-byte Folded Spill - sw $fp, 0($sp) # 4-byte Folded Spill - move $fp, $sp - beqz $6, $BBmemset0_9 - nop -# %bb.1: - addu $2, $6, $4 - sltiu $1, $6, 3 - sb $5, 0($4) - bnez $1, $BBmemset0_9 - sb $5, -1($2) -# %bb.2: - sltiu $1, $6, 7 - sb $5, 2($4) - sb $5, 1($4) - sb $5, -3($2) - bnez $1, $BBmemset0_9 - sb $5, -2($2) -# %bb.3: - sltiu $1, $6, 9 - sb $5, 3($4) - bnez $1, $BBmemset0_9 - sb $5, -4($2) -# %bb.4: - andi $2, $5, 255 - negu $1, $4 - sll $5, $2, 8 - sll $7, $2, 16 - andi $1, $1, 3 - or $5, $5, $2 - sll $2, $2, 24 - addu $3, $4, $1 - subu $1, $6, $1 - or $5, $7, $5 - or $2, $2, $5 - addiu $5, $zero, -4 - and $5, $1, $5 - sw $2, 0($3) - addu $6, $3, $5 - sltiu $1, $5, 9 - bnez $1, $BBmemset0_9 - sw $2, -4($6) -# %bb.5: - sltiu $1, $5, 25 - sw $2, 8($3) - sw $2, 4($3) - sw $2, -8($6) - bnez $1, $BBmemset0_9 - sw $2, -12($6) -# %bb.6: - andi $1, $3, 4 - sw $2, 24($3) - sw $2, 20($3) - sw $2, 16($3) - sw $2, 12($3) - sw $2, -16($6) - sw $2, -20($6) - sw $2, -24($6) - sw $2, -28($6) - ori $6, $1, 24 - subu $5, $5, $6 - sltiu $1, $5, 32 - bnez $1, $BBmemset0_9 - nop -# %bb.7: - addu $3, $3, $6 -$BBmemset0_8: # =>This Inner Loop Header: Depth=1 - addiu $5, $5, -32 - sw $2, 24($3) - sw $2, 16($3) - sw $2, 8($3) - sw $2, 0($3) - sw $2, 28($3) - sw $2, 20($3) - sw $2, 12($3) - sw $2, 4($3) - sltiu $1, $5, 32 - beqz $1, $BBmemset0_8 - addiu $3, $3, 32 -$BBmemset0_9: - move $2, $4 - move $sp, $fp - lw $fp, 0($sp) # 4-byte Folded Reload - lw $ra, 4($sp) # 4-byte Folded Reload - jr $ra - addiu $sp, $sp, 8 - .set at - .set macro - .set reorder - .end memset -$memset_func_end0: - .size memset, ($memset_func_end0)-memset - # -- End function - .ident "clang version 10.0.0-4ubuntu1 " - .section ".note.GNU-stack","",@progbits - .addrsig \ No newline at end of file diff --git a/zkvm/entrypoint/src/syscalls/halt.rs b/zkvm/entrypoint/src/syscalls/halt.rs deleted file mode 100644 index fb38b589..00000000 --- a/zkvm/entrypoint/src/syscalls/halt.rs +++ /dev/null @@ -1,24 +0,0 @@ -use cfg_if::cfg_if; - -cfg_if! { - if #[cfg(target_os = "zkvm")] { - use core::arch::asm; - } -} - -/// Halts the program. -#[allow(unused_variables)] -pub extern "C" fn syscall_halt(exit_code: u8) -> ! { - #[cfg(target_os = "zkvm")] - unsafe { - asm!( - "syscall", - in("$2") crate::syscalls::HALT, - in("$4") exit_code - ); - unreachable!() - } - - #[cfg(not(target_os = "zkvm"))] - unreachable!() -} diff --git a/zkvm/entrypoint/src/syscalls/io.rs b/zkvm/entrypoint/src/syscalls/io.rs deleted file mode 100644 index c9d9da30..00000000 --- a/zkvm/entrypoint/src/syscalls/io.rs +++ /dev/null @@ -1,72 +0,0 @@ -cfg_if::cfg_if! { - if #[cfg(target_os = "zkvm")] { - use core::arch::asm; - use crate::zkvm; - use sha2::digest::Update; - use zkm_precompiles::io::FD_PUBLIC_VALUES; - } -} - -/// Write data to the prover. -#[allow(unused_variables)] -#[no_mangle] -pub extern "C" fn syscall_write(fd: u32, write_buf: *const u8, nbytes: usize) { - cfg_if::cfg_if! { - if #[cfg(target_os = "zkvm")] { - unsafe { - asm!( - "syscall", - in("$2") crate::syscalls::WRITE, - in("$4") fd, - in("$5") write_buf, - in("$6") nbytes, - ); - } - - // For writes to the public values fd, we update a global program hasher with the bytes - // being written. At the end of the program, we call the COMMIT ecall with the finalized - // version of this hash. - if fd == FD_PUBLIC_VALUES { - let pi_slice: &[u8] = unsafe { core::slice::from_raw_parts(write_buf, nbytes) }; - unsafe { zkvm::PUBLIC_VALUES_HASHER.as_mut().unwrap().update(pi_slice) }; - } - } else { - unreachable!() - } - } -} - -#[allow(unused_variables)] -#[no_mangle] -pub extern "C" fn syscall_hint_len() -> usize { - #[cfg(target_os = "zkvm")] - unsafe { - let len; - asm!( - "syscall", - in("$2") crate::syscalls::HINT_LEN, - lateout("$2") len, - ); - len - } - - #[cfg(not(target_os = "zkvm"))] - unreachable!() -} - -#[allow(unused_variables)] -#[no_mangle] -pub extern "C" fn syscall_hint_read(ptr: *mut u8, len: usize) { - #[cfg(target_os = "zkvm")] - unsafe { - asm!( - "syscall", - in("$2") crate::syscalls::HINT_READ, - in("$4") ptr, - in("$5") len, - ); - } - - #[cfg(not(target_os = "zkvm"))] - unreachable!() -} diff --git a/zkvm/entrypoint/src/syscalls/memory.rs b/zkvm/entrypoint/src/syscalls/memory.rs deleted file mode 100644 index b4c967ea..00000000 --- a/zkvm/entrypoint/src/syscalls/memory.rs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2023 RISC Zero, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -const SYSTEM_START: usize = 0x0C00_0000; - -#[allow(clippy::missing_safety_doc)] -#[no_mangle] -pub unsafe extern "C" fn sys_alloc_aligned(bytes: usize, align: usize) -> *mut u8 { - extern "C" { - // https://lld.llvm.org/ELF/linker_script.html#sections-command - static _end: u8; - } - - // Pointer to next heap address to use, or 0 if the heap has not yet been - // initialized. - static mut HEAP_POS: usize = 0; - - // SAFETY: Single threaded, so nothing else can touch this while we're working. - let mut heap_pos = unsafe { HEAP_POS }; - - if heap_pos == 0 { - heap_pos = unsafe { (&_end) as *const u8 as usize }; - } - - let offset = heap_pos & (align - 1); - if offset != 0 { - heap_pos += align - offset; - } - - let ptr = heap_pos as *mut u8; - heap_pos += bytes; - - // Check to make sure heap doesn't collide with SYSTEM memory. - if SYSTEM_START < heap_pos { - panic!(); - } - - unsafe { HEAP_POS = heap_pos }; - ptr -} diff --git a/zkvm/entrypoint/src/syscalls/mod.rs b/zkvm/entrypoint/src/syscalls/mod.rs deleted file mode 100644 index ba3f51c3..00000000 --- a/zkvm/entrypoint/src/syscalls/mod.rs +++ /dev/null @@ -1,28 +0,0 @@ - -mod halt; -mod io; -mod memory; -mod sys; - -pub use halt::*; -pub use io::*; -pub use memory::*; -pub use sys::*; - -/// These codes MUST match the codes in `core/src/runtime/syscall.rs`. There is a derived test -/// that checks that the enum is consistent with the syscalls. - -/// Halts the program. -pub const HALT: u32 = 4246u32; - -/// Writes to a file descriptor. Currently only used for `STDOUT/STDERR`. -pub const WRITE: u32 = 4004u32; - -/// Executes the `COMMIT` precompile. -pub const COMMIT: u32 = 0x00_00_00_10; - -/// Executes `HINT_LEN`. -pub const HINT_LEN: u32 = 0x00_00_00_F0; - -/// Executes `HINT_READ`. -pub const HINT_READ: u32 = 0x00_00_00_F1; diff --git a/zkvm/entrypoint/src/syscalls/sys.rs b/zkvm/entrypoint/src/syscalls/sys.rs deleted file mode 100644 index 520d58ef..00000000 --- a/zkvm/entrypoint/src/syscalls/sys.rs +++ /dev/null @@ -1,68 +0,0 @@ -use std::sync::Mutex; - -use lazy_static::lazy_static; -use rand::{rngs::StdRng, Rng, SeedableRng}; - -use crate::syscalls::{syscall_halt, syscall_write}; - -/// The random number generator seed for the zkVM. -/// -/// In the future, we can pass in this seed from the host or have the verifier generate it. -const PRNG_SEED: u64 = 0x123456789abcdef0; - -lazy_static! { - /// A lazy static to generate a global random number generator. - static ref RNG: Mutex = Mutex::new(StdRng::seed_from_u64(PRNG_SEED)); -} - -/// A lazy static to print a warning once for using the `sys_rand` system call. -static SYS_RAND_WARNING: std::sync::Once = std::sync::Once::new(); - -/// Generates random bytes. -/// -/// # Safety -/// -/// Make sure that `buf` has at least `nwords` words. -#[no_mangle] -pub unsafe extern "C" fn sys_rand(recv_buf: *mut u8, words: usize) { - SYS_RAND_WARNING.call_once(|| { - println!("WARNING: Using insecure random number generator."); - }); - let mut rng = RNG.lock().unwrap(); - for i in 0..words { - let element = recv_buf.add(i); - *element = rng.gen(); - } -} - -#[allow(clippy::missing_safety_doc)] -#[no_mangle] -pub unsafe extern "C" fn sys_panic(msg_ptr: *const u8, len: usize) -> ! { - sys_write(2, msg_ptr, len); - syscall_halt(1); -} - -#[allow(unused_variables)] -#[no_mangle] -pub const fn sys_getenv( - recv_buf: *mut u32, - words: usize, - varname: *const u8, - varname_len: usize, -) -> usize { - 0 -} - -#[allow(unused_variables)] -#[no_mangle] -pub const fn sys_alloc_words(nwords: usize) -> *mut u32 { - core::ptr::null_mut() -} - -#[allow(unused_unsafe)] -#[no_mangle] -pub fn sys_write(fd: u32, write_buf: *const u8, nbytes: usize) { - unsafe { - syscall_write(fd, write_buf, nbytes); - } -} diff --git a/zkvm/precompiles/Cargo.toml b/zkvm/precompiles/Cargo.toml deleted file mode 100644 index a017d35e..00000000 --- a/zkvm/precompiles/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "zkm-precompiles" -version = "0.1.0" -edition = "2021" - -[dependencies] -anyhow = "1.0.83" -bincode = "1.3.3" -cfg-if = "1.0.0" -getrandom = { version = "0.2.14", features = ["custom"] } -hex = "0.4.3" -rand = "0.8.5" -serde = { version = "1.0.201", features = ["derive"] } -num = { version = "0.4.3" } diff --git a/zkvm/precompiles/src/io.rs b/zkvm/precompiles/src/io.rs deleted file mode 100644 index cc1be96e..00000000 --- a/zkvm/precompiles/src/io.rs +++ /dev/null @@ -1,90 +0,0 @@ -#![allow(unused_unsafe)] -use crate::syscall_write; -use crate::{syscall_hint_len, syscall_hint_read}; -use serde::de::DeserializeOwned; -use serde::Serialize; -use std::alloc::Layout; -use std::io::Write; - -const FD_HINT: u32 = 4; -pub const FD_PUBLIC_VALUES: u32 = 3; -// Runtime hook file descriptors. Make sure these match the FDs in the HookRegistry. -// The default hooks can be found in `core/src/runtime/hooks.rs`. -pub const FD_ECRECOVER_HOOK: u32 = 5; - -pub struct SyscallWriter { - fd: u32, -} - -impl std::io::Write for SyscallWriter { - fn write(&mut self, buf: &[u8]) -> std::io::Result { - let nbytes = buf.len(); - let write_buf = buf.as_ptr(); - unsafe { - syscall_write(self.fd, write_buf, nbytes); - } - Ok(nbytes) - } - - fn flush(&mut self) -> std::io::Result<()> { - Ok(()) - } -} - -pub fn read_vec() -> Vec { - let len = unsafe { syscall_hint_len() }; - // Round up to the nearest multiple of 4 so that the memory allocated is in whole words - let capacity = (len + 3) / 4 * 4; - - // Allocate a buffer of the required length that is 4 byte aligned - let layout = Layout::from_size_align(capacity, 4).expect("vec is too large"); - let ptr = unsafe { std::alloc::alloc(layout) }; - // SAFETY: - // 1. `ptr` was allocated using alloc - // 2. We assuume that the VM global allocator doesn't dealloc - // 3/6. Size is correct from above - // 4/5. Length is 0 - // 7. Layout::from_size_align already checks this - let mut vec = unsafe { Vec::from_raw_parts(ptr, 0, capacity) }; - // Read the vec into uninitialized memory. The syscall assumes the memory is uninitialized, - // which should be true because the allocator does not dealloc, so a new alloc should be fresh. - unsafe { - syscall_hint_read(ptr, len); - vec.set_len(len); - } - vec -} - -pub fn read() -> T { - let vec = read_vec(); - bincode::deserialize(&vec).expect("deserialization failed") -} - -pub fn commit(value: &T) { - let writer = SyscallWriter { - fd: FD_PUBLIC_VALUES, - }; - bincode::serialize_into(writer, value).expect("serialization failed"); -} - -pub fn commit_slice(buf: &[u8]) { - let mut my_writer = SyscallWriter { - fd: FD_PUBLIC_VALUES, - }; - my_writer.write_all(buf).unwrap(); -} - -pub fn hint(value: &T) { - let writer = SyscallWriter { fd: FD_HINT }; - bincode::serialize_into(writer, value).expect("serialization failed"); -} - -pub fn hint_slice(buf: &[u8]) { - let mut my_reader = SyscallWriter { fd: FD_HINT }; - my_reader.write_all(buf).unwrap(); -} - -/// Write the data `buf` to the file descriptor `fd` using `Write::write_all` . -pub fn write(fd: u32, buf: &[u8]) { - SyscallWriter { fd }.write_all(buf).unwrap(); -} diff --git a/zkvm/precompiles/src/lib.rs b/zkvm/precompiles/src/lib.rs deleted file mode 100644 index b1c9743e..00000000 --- a/zkvm/precompiles/src/lib.rs +++ /dev/null @@ -1,19 +0,0 @@ -//! Precompiles for SP1 zkVM. -//! -//! Specifically, this crate contains user-friendly functions that call SP1 syscalls. Syscalls are -//! also declared here for convenience. In order to avoid duplicate symbol errors, the syscall -//! function impls must live in sp1-zkvm, which is only imported into the end user program crate. -//! In contrast, sp1-precompiles can be imported into any crate in the dependency tree. - -pub mod io; -pub mod utils; - -pub const BIGINT_WIDTH_WORDS: usize = 8; - -extern "C" { - pub fn syscall_halt(exit_code: u8) -> !; - pub fn syscall_write(fd: u32, write_buf: *const u8, nbytes: usize); - pub fn syscall_hint_len() -> usize; - pub fn syscall_hint_read(ptr: *mut u8, len: usize); - pub fn sys_alloc_aligned(bytes: usize, align: usize) -> *mut u8; -} diff --git a/zkvm/precompiles/src/utils.rs b/zkvm/precompiles/src/utils.rs deleted file mode 100644 index c2cf1a0d..00000000 --- a/zkvm/precompiles/src/utils.rs +++ /dev/null @@ -1,109 +0,0 @@ -pub trait CurveOperations { - const GENERATOR: [u32; NUM_WORDS]; - - fn add_assign(limbs: &mut [u32; NUM_WORDS], other: &[u32; NUM_WORDS]); - fn double(limbs: &mut [u32; NUM_WORDS]); -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub struct AffinePoint, const NUM_WORDS: usize> { - pub(crate) limbs: [u32; NUM_WORDS], - _marker: std::marker::PhantomData, -} - -impl + Copy, const NUM_WORDS: usize> AffinePoint { - const GENERATOR: [u32; NUM_WORDS] = C::GENERATOR; - - pub const fn generator_in_affine() -> Self { - Self { - limbs: Self::GENERATOR, - _marker: std::marker::PhantomData, - } - } - - pub const fn new(limbs: [u32; NUM_WORDS]) -> Self { - Self { - limbs, - _marker: std::marker::PhantomData, - } - } - - /// x_bytes and y_bytes are the concatenated little endian representations of the x and y coordinates. - /// The length of x_bytes and y_bytes must each be NUM_WORDS * 2. - pub fn from(x_bytes: &[u8], y_bytes: &[u8]) -> Self { - debug_assert!(x_bytes.len() == NUM_WORDS * 2); - debug_assert!(y_bytes.len() == NUM_WORDS * 2); - - let mut limbs = [0u32; NUM_WORDS]; - let x = bytes_to_words_le(x_bytes); - let y = bytes_to_words_le(y_bytes); - debug_assert!(x.len() == NUM_WORDS / 2); - debug_assert!(y.len() == NUM_WORDS / 2); - - limbs[..(NUM_WORDS / 2)].copy_from_slice(&x); - limbs[(NUM_WORDS / 2)..].copy_from_slice(&y); - Self::new(limbs) - } - - pub fn add_assign(&mut self, other: &AffinePoint) { - C::add_assign(&mut self.limbs, &other.limbs); - } - - pub fn double(&mut self) { - C::double(&mut self.limbs); - } - - pub fn mul_assign(&mut self, scalar: &[u32]) { - debug_assert!(scalar.len() == NUM_WORDS / 2); - - let mut res: Option = None; - let mut temp = *self; - - for &words in scalar.iter() { - for i in 0..32 { - if (words >> i) & 1 == 1 { - match res.as_mut() { - Some(res) => res.add_assign(&temp), - None => res = Some(temp), - }; - } - - temp.double(); - } - } - - *self = res.unwrap(); - } - - pub fn from_le_bytes(limbs: &[u8]) -> Self { - let u32_limbs = bytes_to_words_le(limbs); - debug_assert!(u32_limbs.len() == NUM_WORDS); - - Self { - limbs: u32_limbs.try_into().unwrap(), - _marker: std::marker::PhantomData, - } - } - - pub fn to_le_bytes(&self) -> Vec { - let le_bytes = words_to_bytes_le(&self.limbs); - debug_assert!(le_bytes.len() == NUM_WORDS * 4); - le_bytes - } -} - -/// Converts a slice of words to a byte array in little endian. -pub fn words_to_bytes_le(words: &[u32]) -> Vec { - words - .iter() - .flat_map(|word| word.to_le_bytes().to_vec()) - .collect::>() -} - -/// Converts a byte array in little endian to a slice of words. -pub fn bytes_to_words_le(bytes: &[u8]) -> Vec { - bytes - .chunks_exact(4) - .map(|chunk| u32::from_le_bytes(chunk.try_into().unwrap())) - .collect::>() -} From 97365b0b8d00bd652c3d97c71fd5769fdd5aadb5 Mon Sep 17 00:00:00 2001 From: Angell Li Date: Wed, 3 Jul 2024 13:03:38 +0800 Subject: [PATCH 10/13] add missed files --- runtime/entrypoint/Cargo.toml | 20 + runtime/entrypoint/src/heap.rs | 18 + runtime/entrypoint/src/lib.rs | 77 +++ runtime/entrypoint/src/libm.rs | 561 ++++++++++++++++++++++ runtime/entrypoint/src/memcpy.s | 335 +++++++++++++ runtime/entrypoint/src/memory.rs | 51 ++ runtime/entrypoint/src/memset.s | 316 ++++++++++++ runtime/entrypoint/src/syscalls/halt.rs | 26 + runtime/entrypoint/src/syscalls/io.rs | 74 +++ runtime/entrypoint/src/syscalls/memory.rs | 51 ++ runtime/entrypoint/src/syscalls/mod.rs | 29 ++ runtime/entrypoint/src/syscalls/sys.rs | 70 +++ runtime/precompiles/Cargo.toml | 14 + runtime/precompiles/src/io.rs | 92 ++++ runtime/precompiles/src/lib.rs | 19 + runtime/precompiles/src/utils.rs | 111 +++++ 16 files changed, 1864 insertions(+) create mode 100644 runtime/entrypoint/Cargo.toml create mode 100644 runtime/entrypoint/src/heap.rs create mode 100644 runtime/entrypoint/src/lib.rs create mode 100644 runtime/entrypoint/src/libm.rs create mode 100644 runtime/entrypoint/src/memcpy.s create mode 100644 runtime/entrypoint/src/memory.rs create mode 100644 runtime/entrypoint/src/memset.s create mode 100644 runtime/entrypoint/src/syscalls/halt.rs create mode 100644 runtime/entrypoint/src/syscalls/io.rs create mode 100644 runtime/entrypoint/src/syscalls/memory.rs create mode 100644 runtime/entrypoint/src/syscalls/mod.rs create mode 100644 runtime/entrypoint/src/syscalls/sys.rs create mode 100644 runtime/precompiles/Cargo.toml create mode 100644 runtime/precompiles/src/io.rs create mode 100644 runtime/precompiles/src/lib.rs create mode 100644 runtime/precompiles/src/utils.rs diff --git a/runtime/entrypoint/Cargo.toml b/runtime/entrypoint/Cargo.toml new file mode 100644 index 00000000..b7ae47ff --- /dev/null +++ b/runtime/entrypoint/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "zkm-runtime" +version = "0.1.0" +edition = "2021" + +[dependencies] +zkm-precompiles = { path = "../precompiles" } +bincode = "1.3.3" +cfg-if = "1.0.0" +getrandom = { version = "0.2.14", features = ["custom"] } +once_cell = "1.19.0" +rand = "0.8.5" +serde = { version = "1.0.201", features = ["derive"] } +libm = { version = "0.2.8", optional = true } +sha2 = { version = "0.10.8" } +lazy_static = "1.4.0" + +[features] +default = ["libm"] +libm = ["dep:libm"] diff --git a/runtime/entrypoint/src/heap.rs b/runtime/entrypoint/src/heap.rs new file mode 100644 index 00000000..345c5276 --- /dev/null +++ b/runtime/entrypoint/src/heap.rs @@ -0,0 +1,18 @@ +//! Ported from Entrypoint for SP1 zkVM. + +use core::alloc::{GlobalAlloc, Layout}; + +use crate::syscalls::sys_alloc_aligned; + +/// A simple heap allocator. +/// +/// Allocates memory from left to right, without any deallocation. +pub struct SimpleAlloc; + +unsafe impl GlobalAlloc for SimpleAlloc { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + sys_alloc_aligned(layout.size(), layout.align()) + } + + unsafe fn dealloc(&self, _: *mut u8, _: Layout) {} +} diff --git a/runtime/entrypoint/src/lib.rs b/runtime/entrypoint/src/lib.rs new file mode 100644 index 00000000..a367a91c --- /dev/null +++ b/runtime/entrypoint/src/lib.rs @@ -0,0 +1,77 @@ +//! Ported from Entrypoint for SP1 zkVM. + +#![feature(asm_experimental_arch)] +pub mod heap; +pub mod syscalls; +pub mod io { + pub use zkm_precompiles::io::*; +} +pub mod precompiles { + pub use zkm_precompiles::*; +} + +extern crate alloc; + +#[macro_export] +macro_rules! entrypoint { + ($path:path) => { + const ZKVM_ENTRY: fn() = $path; + + use $crate::heap::SimpleAlloc; + + #[global_allocator] + static HEAP: SimpleAlloc = SimpleAlloc; + + mod zkvm_generated_main { + + #[no_mangle] + fn start() { + super::ZKVM_ENTRY() + } + } + }; +} + +mod libm; + +/// The number of 32 bit words that the public values digest is composed of. +pub const PV_DIGEST_NUM_WORDS: usize = 8; +pub const POSEIDON_NUM_WORDS: usize = 8; + +#[cfg(target_os = "zkvm")] +mod zkvm { + use crate::syscalls::syscall_halt; + + use getrandom::{register_custom_getrandom, Error}; + use sha2::{Digest, Sha256}; + + pub static mut PUBLIC_VALUES_HASHER: Option = None; + + #[cfg(not(feature = "interface"))] + #[no_mangle] + fn main() { + unsafe { + PUBLIC_VALUES_HASHER = Some(Sha256::new()); + + extern "C" { + fn start(); + } + start() + } + + syscall_halt(0); + } + + core::arch::global_asm!(include_str!("memset.s")); + core::arch::global_asm!(include_str!("memcpy.s")); + + fn zkvm_getrandom(s: &mut [u8]) -> Result<(), Error> { + unsafe { + crate::syscalls::sys_rand(s.as_mut_ptr(), s.len()); + } + + Ok(()) + } + + register_custom_getrandom!(zkvm_getrandom); +} diff --git a/runtime/entrypoint/src/libm.rs b/runtime/entrypoint/src/libm.rs new file mode 100644 index 00000000..ceb7be4d --- /dev/null +++ b/runtime/entrypoint/src/libm.rs @@ -0,0 +1,561 @@ +//! Ported from Entrypoint for SP1 zkVM. +//! +#[no_mangle] +pub extern "C" fn acos(x: f64) -> f64 { + libm::acos(x) +} + +#[no_mangle] +pub extern "C" fn acosf(x: f32) -> f32 { + libm::acosf(x) +} + +#[no_mangle] +pub extern "C" fn acosh(x: f64) -> f64 { + libm::acosh(x) +} + +#[no_mangle] +pub extern "C" fn acoshf(x: f32) -> f32 { + libm::acoshf(x) +} + +#[no_mangle] +pub extern "C" fn asin(x: f64) -> f64 { + libm::asin(x) +} + +#[no_mangle] +pub extern "C" fn asinf(x: f32) -> f32 { + libm::asinf(x) +} + +#[no_mangle] +pub extern "C" fn asinh(x: f64) -> f64 { + libm::asinh(x) +} + +#[no_mangle] +pub extern "C" fn asinhf(x: f32) -> f32 { + libm::asinhf(x) +} + +#[no_mangle] +pub extern "C" fn atan(x: f64) -> f64 { + libm::atan(x) +} + +#[no_mangle] +pub extern "C" fn atan2(y: f64, x: f64) -> f64 { + libm::atan2(y, x) +} + +#[no_mangle] +pub extern "C" fn atan2f(y: f32, x: f32) -> f32 { + libm::atan2f(y, x) +} + +#[no_mangle] +pub extern "C" fn atanf(x: f32) -> f32 { + libm::atanf(x) +} + +#[no_mangle] +pub extern "C" fn atanh(x: f64) -> f64 { + libm::atanh(x) +} + +#[no_mangle] +pub extern "C" fn atanhf(x: f32) -> f32 { + libm::atanhf(x) +} + +#[no_mangle] +pub extern "C" fn cbrt(x: f64) -> f64 { + libm::cbrt(x) +} + +#[no_mangle] +pub extern "C" fn cbrtf(x: f32) -> f32 { + libm::cbrtf(x) +} + +#[no_mangle] +pub extern "C" fn ceil(x: f64) -> f64 { + libm::ceil(x) +} + +#[no_mangle] +pub extern "C" fn ceilf(x: f32) -> f32 { + libm::ceilf(x) +} + +#[no_mangle] +pub extern "C" fn copysign(x: f64, y: f64) -> f64 { + libm::copysign(x, y) +} + +#[no_mangle] +pub extern "C" fn copysignf(x: f32, y: f32) -> f32 { + libm::copysignf(x, y) +} + +#[no_mangle] +pub extern "C" fn cos(x: f64) -> f64 { + libm::cos(x) +} + +#[no_mangle] +pub extern "C" fn cosf(x: f32) -> f32 { + libm::cosf(x) +} + +#[no_mangle] +pub extern "C" fn cosh(x: f64) -> f64 { + libm::cosh(x) +} + +#[no_mangle] +pub extern "C" fn coshf(x: f32) -> f32 { + libm::coshf(x) +} + +#[no_mangle] +pub extern "C" fn erf(x: f64) -> f64 { + libm::erf(x) +} + +#[no_mangle] +pub extern "C" fn erfc(x: f64) -> f64 { + libm::erfc(x) +} + +#[no_mangle] +pub extern "C" fn erfcf(x: f32) -> f32 { + libm::erfcf(x) +} + +#[no_mangle] +pub extern "C" fn erff(x: f32) -> f32 { + libm::erff(x) +} + +#[no_mangle] +pub extern "C" fn exp(x: f64) -> f64 { + libm::exp(x) +} + +#[no_mangle] +pub extern "C" fn exp2(x: f64) -> f64 { + libm::exp2(x) +} + +#[no_mangle] +pub extern "C" fn exp2f(x: f32) -> f32 { + libm::exp2f(x) +} + +#[no_mangle] +pub extern "C" fn exp10(x: f64) -> f64 { + libm::exp10(x) +} + +#[no_mangle] +pub extern "C" fn exp10f(x: f32) -> f32 { + libm::exp10f(x) +} + +#[no_mangle] +pub extern "C" fn expf(x: f32) -> f32 { + libm::expf(x) +} + +#[no_mangle] +pub extern "C" fn expm1(x: f64) -> f64 { + libm::expm1(x) +} + +#[no_mangle] +pub extern "C" fn expm1f(x: f32) -> f32 { + libm::expm1f(x) +} + +#[no_mangle] +pub extern "C" fn fabs(x: f64) -> f64 { + libm::fabs(x) +} + +#[no_mangle] +pub extern "C" fn fabsf(x: f32) -> f32 { + libm::fabsf(x) +} + +#[no_mangle] +pub extern "C" fn fdim(x: f64, y: f64) -> f64 { + libm::fdim(x, y) +} + +#[no_mangle] +pub extern "C" fn fdimf(x: f32, y: f32) -> f32 { + libm::fdimf(x, y) +} + +#[no_mangle] +pub extern "C" fn floor(x: f64) -> f64 { + libm::floor(x) +} + +#[no_mangle] +pub extern "C" fn floorf(x: f32) -> f32 { + libm::floorf(x) +} + +#[no_mangle] +pub extern "C" fn fma(x: f64, y: f64, z: f64) -> f64 { + libm::fma(x, y, z) +} + +#[no_mangle] +pub extern "C" fn fmaf(x: f32, y: f32, z: f32) -> f32 { + libm::fmaf(x, y, z) +} + +#[no_mangle] +pub extern "C" fn fmax(x: f64, y: f64) -> f64 { + libm::fmax(x, y) +} + +#[no_mangle] +pub extern "C" fn fmaxf(x: f32, y: f32) -> f32 { + libm::fmaxf(x, y) +} + +#[no_mangle] +pub extern "C" fn fmin(x: f64, y: f64) -> f64 { + libm::fmin(x, y) +} + +#[no_mangle] +pub extern "C" fn fminf(x: f32, y: f32) -> f32 { + libm::fminf(x, y) +} + +#[no_mangle] +pub extern "C" fn fmod(x: f64, y: f64) -> f64 { + libm::fmod(x, y) +} + +#[no_mangle] +pub extern "C" fn fmodf(x: f32, y: f32) -> f32 { + libm::fmodf(x, y) +} + +#[no_mangle] +pub fn frexp(x: f64) -> (f64, i32) { + libm::frexp(x) +} + +#[no_mangle] +pub fn frexpf(x: f32) -> (f32, i32) { + libm::frexpf(x) +} + +#[no_mangle] +pub extern "C" fn hypot(x: f64, y: f64) -> f64 { + libm::hypot(x, y) +} + +#[no_mangle] +pub extern "C" fn hypotf(x: f32, y: f32) -> f32 { + libm::hypotf(x, y) +} + +#[no_mangle] +pub extern "C" fn ilogb(x: f64) -> i32 { + libm::ilogb(x) +} + +#[no_mangle] +pub extern "C" fn ilogbf(x: f32) -> i32 { + libm::ilogbf(x) +} + +#[no_mangle] +pub extern "C" fn j0(x: f64) -> f64 { + libm::j0(x) +} + +#[no_mangle] +pub extern "C" fn j0f(x: f32) -> f32 { + libm::j0f(x) +} + +#[no_mangle] +pub extern "C" fn j1(x: f64) -> f64 { + libm::j1(x) +} + +#[no_mangle] +pub extern "C" fn j1f(x: f32) -> f32 { + libm::j1f(x) +} + +#[no_mangle] +pub extern "C" fn jn(n: i32, x: f64) -> f64 { + libm::jn(n, x) +} + +#[no_mangle] +pub extern "C" fn jnf(n: i32, x: f32) -> f32 { + libm::jnf(n, x) +} + +#[no_mangle] +pub extern "C" fn ldexp(x: f64, n: i32) -> f64 { + libm::ldexp(x, n) +} + +#[no_mangle] +pub extern "C" fn ldexpf(x: f32, n: i32) -> f32 { + libm::ldexpf(x, n) +} + +#[no_mangle] +pub extern "C" fn lgamma(x: f64) -> f64 { + libm::lgamma(x) +} + +#[no_mangle] +pub fn lgamma_r(x: f64) -> (f64, i32) { + libm::lgamma_r(x) +} + +#[no_mangle] +pub fn lgammaf(x: f32) -> f32 { + libm::lgammaf(x) +} + +#[no_mangle] +pub fn lgammaf_r(x: f32) -> (f32, i32) { + libm::lgammaf_r(x) +} + +#[no_mangle] +pub extern "C" fn log(x: f64) -> f64 { + libm::log(x) +} + +#[no_mangle] +pub extern "C" fn log1p(x: f64) -> f64 { + libm::log1p(x) +} + +#[no_mangle] +pub extern "C" fn log1pf(x: f32) -> f32 { + libm::log1pf(x) +} + +#[no_mangle] +pub extern "C" fn log2(x: f64) -> f64 { + libm::log2(x) +} + +#[no_mangle] +pub extern "C" fn log2f(x: f32) -> f32 { + libm::log2f(x) +} + +#[no_mangle] +pub extern "C" fn log10(x: f64) -> f64 { + libm::log10(x) +} + +#[no_mangle] +pub extern "C" fn log10f(x: f32) -> f32 { + libm::log10f(x) +} + +#[no_mangle] +pub extern "C" fn logf(x: f32) -> f32 { + libm::logf(x) +} + +#[no_mangle] +pub fn modf(x: f64) -> (f64, f64) { + libm::modf(x) +} + +#[no_mangle] +pub fn modff(x: f32) -> (f32, f32) { + libm::modff(x) +} + +#[no_mangle] +pub extern "C" fn nextafter(x: f64, y: f64) -> f64 { + libm::nextafter(x, y) +} + +#[no_mangle] +pub extern "C" fn nextafterf(x: f32, y: f32) -> f32 { + libm::nextafterf(x, y) +} + +#[no_mangle] +pub extern "C" fn pow(x: f64, y: f64) -> f64 { + libm::pow(x, y) +} + +#[no_mangle] +pub extern "C" fn powf(x: f32, y: f32) -> f32 { + libm::powf(x, y) +} + +#[no_mangle] +pub extern "C" fn remainder(x: f64, y: f64) -> f64 { + libm::remainder(x, y) +} + +#[no_mangle] +pub extern "C" fn remainderf(x: f32, y: f32) -> f32 { + libm::remainderf(x, y) +} + +#[no_mangle] +pub fn remquo(x: f64, y: f64) -> (f64, i32) { + libm::remquo(x, y) +} + +#[no_mangle] +pub fn remquof(x: f32, y: f32) -> (f32, i32) { + libm::remquof(x, y) +} + +#[no_mangle] +pub extern "C" fn round(x: f64) -> f64 { + libm::round(x) +} + +#[no_mangle] +pub extern "C" fn roundf(x: f32) -> f32 { + libm::roundf(x) +} + +#[no_mangle] +pub extern "C" fn scalbn(x: f64, n: i32) -> f64 { + libm::scalbn(x, n) +} + +#[no_mangle] +pub extern "C" fn scalbnf(x: f32, n: i32) -> f32 { + libm::scalbnf(x, n) +} + +#[no_mangle] +pub extern "C" fn sin(x: f64) -> f64 { + libm::sin(x) +} + +#[no_mangle] +pub fn sincos(x: f64) -> (f64, f64) { + libm::sincos(x) +} + +#[no_mangle] +pub fn sincosf(x: f32) -> (f32, f32) { + libm::sincosf(x) +} + +#[no_mangle] +pub extern "C" fn sinf(x: f32) -> f32 { + libm::sinf(x) +} + +#[no_mangle] +pub extern "C" fn sinh(x: f64) -> f64 { + libm::sinh(x) +} + +#[no_mangle] +pub extern "C" fn sinhf(x: f32) -> f32 { + libm::sinhf(x) +} + +#[no_mangle] +pub extern "C" fn sqrt(x: f64) -> f64 { + libm::sqrt(x) +} + +#[no_mangle] +pub extern "C" fn sqrtf(x: f32) -> f32 { + libm::sqrtf(x) +} + +#[no_mangle] +pub extern "C" fn tan(x: f64) -> f64 { + libm::tan(x) +} + +#[no_mangle] +pub extern "C" fn tanf(x: f32) -> f32 { + libm::tanf(x) +} + +#[no_mangle] +pub extern "C" fn tanh(x: f64) -> f64 { + libm::tanh(x) +} + +#[no_mangle] +pub extern "C" fn tanhf(x: f32) -> f32 { + libm::tanhf(x) +} + +#[no_mangle] +pub extern "C" fn tgamma(x: f64) -> f64 { + libm::tgamma(x) +} + +#[no_mangle] +pub extern "C" fn tgammaf(x: f32) -> f32 { + libm::tgammaf(x) +} + +#[no_mangle] +pub extern "C" fn trunc(x: f64) -> f64 { + libm::trunc(x) +} + +#[no_mangle] +pub extern "C" fn truncf(x: f32) -> f32 { + libm::truncf(x) +} + +#[no_mangle] +pub extern "C" fn y0(x: f64) -> f64 { + libm::y0(x) +} + +#[no_mangle] +pub extern "C" fn y0f(x: f32) -> f32 { + libm::y0f(x) +} + +#[no_mangle] +pub extern "C" fn y1(x: f64) -> f64 { + libm::y1(x) +} + +#[no_mangle] +pub extern "C" fn y1f(x: f32) -> f32 { + libm::y1f(x) +} + +#[no_mangle] +pub extern "C" fn yn(n: i32, x: f64) -> f64 { + libm::yn(n, x) +} + +#[no_mangle] +pub extern "C" fn ynf(n: i32, x: f32) -> f32 { + libm::ynf(n, x) +} diff --git a/runtime/entrypoint/src/memcpy.s b/runtime/entrypoint/src/memcpy.s new file mode 100644 index 00000000..f983a45a --- /dev/null +++ b/runtime/entrypoint/src/memcpy.s @@ -0,0 +1,335 @@ +// This is musl-libc commit 3b0a370020c4d5b80ff32a609e5322b7760f0dc4: +// +// src/string/memcpy.c +// +// This was compiled into assembly with: +// +// clang-10 -target mips -O3 -S memcpy.c -nostdlib -fno-builtin -funroll-loops +// +// and labels manually updated to not conflict. +// +// musl as a whole is licensed under the following standard MIT license: +// +// ---------------------------------------------------------------------- +// Copyright © 2005-2020 Rich Felker, et al. +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// ---------------------------------------------------------------------- +// +// Authors/contributors include: +// +// A. Wilcox +// Ada Worcester +// Alex Dowad +// Alex Suykov +// Alexander Monakov +// Andre McCurdy +// Andrew Kelley +// Anthony G. Basile +// Aric Belsito +// Arvid Picciani +// Bartosz Brachaczek +// Benjamin Peterson +// Bobby Bingham +// Boris Brezillon +// Brent Cook +// Chris Spiegel +// Clément Vasseur +// Daniel Micay +// Daniel Sabogal +// Daurnimator +// David Carlier +// David Edelsohn +// Denys Vlasenko +// Dmitry Ivanov +// Dmitry V. Levin +// Drew DeVault +// Emil Renner Berthing +// Fangrui Song +// Felix Fietkau +// Felix Janda +// Gianluca Anzolin +// Hauke Mehrtens +// He X +// Hiltjo Posthuma +// Isaac Dunham +// Jaydeep Patil +// Jens Gustedt +// Jeremy Huntwork +// Jo-Philipp Wich +// Joakim Sindholt +// John Spencer +// Julien Ramseier +// Justin Cormack +// Kaarle Ritvanen +// Khem Raj +// Kylie McClain +// Leah Neukirchen +// Luca Barbato +// Luka Perkov +// M Farkas-Dyck (Strake) +// Mahesh Bodapati +// Markus Wichmann +// Masanori Ogino +// Michael Clark +// Michael Forney +// Mikhail Kremnyov +// Natanael Copa +// Nicholas J. Kain +// orc +// Pascal Cuoq +// Patrick Oppenlander +// Petr Hosek +// Petr Skocik +// Pierre Carrier +// Reini Urban +// Rich Felker +// Richard Pennington +// Ryan Fairfax +// Samuel Holland +// Segev Finer +// Shiz +// sin +// Solar Designer +// Stefan Kristiansson +// Stefan O'Rear +// Szabolcs Nagy +// Timo Teräs +// Trutz Behn +// Valentin Ochs +// Will Dietz +// William Haddon +// William Pitcock +// +// Portions of this software are derived from third-party works licensed +// under terms compatible with the above MIT license: +// +// The TRE regular expression implementation (src/regex/reg* and +// src/regex/tre*) is Copyright © 2001-2008 Ville Laurikari and licensed +// under a 2-clause BSD license (license text in the source files). The +// included version has been heavily modified by Rich Felker in 2012, in +// the interests of size, simplicity, and namespace cleanliness. +// +// Much of the math library code (src/math/* and src/complex/*) is +// Copyright © 1993,2004 Sun Microsystems or +// Copyright © 2003-2011 David Schultz or +// Copyright © 2003-2009 Steven G. Kargl or +// Copyright © 2003-2009 Bruce D. Evans or +// Copyright © 2008 Stephen L. Moshier or +// Copyright © 2017-2018 Arm Limited +// and labelled as such in comments in the individual source files. All +// have been licensed under extremely permissive terms. +// +// The ARM memcpy code (src/string/arm/memcpy.S) is Copyright © 2008 +// The Android Open Source Project and is licensed under a two-clause BSD +// license. It was taken from Bionic libc, used on Android. +// +// The AArch64 memcpy and memset code (src/string/aarch64/*) are +// Copyright © 1999-2019, Arm Limited. +// +// The implementation of DES for crypt (src/crypt/crypt_des.c) is +// Copyright © 1994 David Burren. It is licensed under a BSD license. +// +// The implementation of blowfish crypt (src/crypt/crypt_blowfish.c) was +// originally written by Solar Designer and placed into the public +// domain. The code also comes with a fallback permissive license for use +// in jurisdictions that may not recognize the public domain. +// +// The smoothsort implementation (src/stdlib/qsort.c) is Copyright © 2011 +// Valentin Ochs and is licensed under an MIT-style license. +// +// The x86_64 port was written by Nicholas J. Kain and is licensed under +// the standard MIT terms. +// +// The mips and microblaze ports were originally written by Richard +// Pennington for use in the ellcc project. The original code was adapted +// by Rich Felker for build system and code conventions during upstream +// integration. It is licensed under the standard MIT terms. +// +// The mips64 port was contributed by Imagination Technologies and is +// licensed under the standard MIT terms. +// +// The powerpc port was also originally written by Richard Pennington, +// and later supplemented and integrated by John Spencer. It is licensed +// under the standard MIT terms. +// +// All other files which have no copyright comments are original works +// produced specifically for use as part of this library, written either +// by Rich Felker, the main author of the library, or by one or more +// contibutors listed above. Details on authorship of individual files +// can be found in the git version control history of the project. The +// omission of copyright and license comments in each file is in the +// interest of source tree size. +// +// In addition, permission is hereby granted for all public header files +// (include/* and arch/* /bits/* ) and crt files intended to be linked into +// applications (crt/*, ldso/dlstart.c, and arch/* /crt_arch.h) to omit +// the copyright notice and permission notice otherwise required by the +// license, and to use these files without any requirement of +// attribution. These files include substantial contributions from: +// +// Bobby Bingham +// John Spencer +// Nicholas J. Kain +// Rich Felker +// Richard Pennington +// Stefan Kristiansson +// Szabolcs Nagy +// +// all of whom have explicitly granted such permission. +// +// This file previously contained text expressing a belief that most of +// the files covered by the above exception were sufficiently trivial not +// to be subject to copyright, resulting in confusion over whether it +// negated the permissions granted in the license. In the spirit of +// permissive licensing, and of not having licensing issues being an +// obstacle to adoption, that text has been removed. + .text + .file "memcpy.c" + .globl memccpy # -- Begin function memccpy + .p2align 2 + .type memccpy,@function + .set nomicromips + .set nomips16 + .ent memccpy +memccpy: # @memccpy + .frame $fp,8,$ra + .mask 0xc0000000,-4 + .fmask 0x00000000,0 + .set noreorder + .set nomacro + .set noat +# %bb.0: + addiu $sp, $sp, -8 + sw $ra, 4($sp) # 4-byte Folded Spill + sw $fp, 0($sp) # 4-byte Folded Spill + move $fp, $sp + xor $1, $5, $4 + andi $1, $1, 3 + beqz $1, $BBmemcpy0_7 + andi $3, $6, 255 +$BBmemcpy0_1: + beqz $7, $BBmemcpy0_5 + nop +# %bb.2: + addiu $2, $4, 1 +$BBmemcpy0_3: # =>This Inner Loop Header: Depth=1 + lbu $1, 0($5) + beq $1, $3, $BBmemcpy0_6 + sb $1, -1($2) +# %bb.4: # in Loop: Header=BBmemcpy0_3 Depth=1 + addiu $2, $2, 1 + addiu $7, $7, -1 + bnez $7, $BBmemcpy0_3 + addiu $5, $5, 1 +$BBmemcpy0_5: + addiu $2, $zero, 0 +$BBmemcpy0_6: + move $sp, $fp + lw $fp, 0($sp) # 4-byte Folded Reload + lw $ra, 4($sp) # 4-byte Folded Reload + jr $ra + addiu $sp, $sp, 8 +$BBmemcpy0_7: + andi $6, $5, 3 + beqz $7, $BBmemcpy0_14 + sltu $2, $zero, $6 +# %bb.8: + beqz $6, $BBmemcpy0_14 + nop +# %bb.9: + addiu $2, $7, -1 + addiu $6, $zero, 0 +$BBmemcpy0_10: # =>This Inner Loop Header: Depth=1 + addu $9, $5, $6 + addu $8, $4, $6 + lbu $1, 0($9) + beq $1, $3, $BBmemcpy0_22 + sb $1, 0($8) +# %bb.11: # in Loop: Header=BBmemcpy0_10 Depth=1 + addiu $1, $9, 1 + addiu $8, $6, 1 + beq $2, $6, $BBmemcpy0_13 + andi $9, $1, 3 +# %bb.12: # in Loop: Header=BBmemcpy0_10 Depth=1 + bnez $9, $BBmemcpy0_10 + move $6, $8 +$BBmemcpy0_13: + sltu $2, $zero, $9 + subu $7, $7, $8 + addu $4, $4, $8 + addu $5, $5, $8 +$BBmemcpy0_14: + beqz $2, $BBmemcpy0_17 + nop +# %bb.15: + bnez $7, $BBmemcpy0_6 + addiu $2, $4, 1 +# %bb.16: + j $BBmemcpy0_5 + nop +$BBmemcpy0_17: + sltiu $1, $7, 4 + bnez $1, $BBmemcpy0_1 + nop +# %bb.18: + sll $1, $3, 8 + sll $2, $3, 16 + or $1, $1, $3 + or $1, $2, $1 + sll $2, $3, 24 + or $6, $2, $1 + lui $1, 65278 + andi $2, $7, 3 + ori $8, $1, 65279 + lui $1, 32896 + ori $9, $1, 32896 +$BBmemcpy0_19: # =>This Inner Loop Header: Depth=1 + lw $10, 0($5) + xor $1, $10, $6 + addu $11, $1, $8 + not $1, $1 + and $1, $1, $11 + and $1, $1, $9 + bnez $1, $BBmemcpy0_1 + nop +# %bb.20: # in Loop: Header=BBmemcpy0_19 Depth=1 + addiu $7, $7, -4 + sw $10, 0($4) + addiu $4, $4, 4 + sltiu $1, $7, 4 + beqz $1, $BBmemcpy0_19 + addiu $5, $5, 4 +# %bb.21: + j $BBmemcpy0_1 + move $7, $2 +$BBmemcpy0_22: + j $BBmemcpy0_6 + addiu $2, $8, 1 + .set at + .set macro + .set reorder + .end memccpy +$memcpy_func_end0: + .size memccpy, ($memcpy_func_end0)-memccpy + # -- End function + .ident "clang version 10.0.0-4ubuntu1 " + .section ".note.GNU-stack","",@progbits + .addrsig \ No newline at end of file diff --git a/runtime/entrypoint/src/memory.rs b/runtime/entrypoint/src/memory.rs new file mode 100644 index 00000000..b4c967ea --- /dev/null +++ b/runtime/entrypoint/src/memory.rs @@ -0,0 +1,51 @@ +// Copyright 2023 RISC Zero, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +const SYSTEM_START: usize = 0x0C00_0000; + +#[allow(clippy::missing_safety_doc)] +#[no_mangle] +pub unsafe extern "C" fn sys_alloc_aligned(bytes: usize, align: usize) -> *mut u8 { + extern "C" { + // https://lld.llvm.org/ELF/linker_script.html#sections-command + static _end: u8; + } + + // Pointer to next heap address to use, or 0 if the heap has not yet been + // initialized. + static mut HEAP_POS: usize = 0; + + // SAFETY: Single threaded, so nothing else can touch this while we're working. + let mut heap_pos = unsafe { HEAP_POS }; + + if heap_pos == 0 { + heap_pos = unsafe { (&_end) as *const u8 as usize }; + } + + let offset = heap_pos & (align - 1); + if offset != 0 { + heap_pos += align - offset; + } + + let ptr = heap_pos as *mut u8; + heap_pos += bytes; + + // Check to make sure heap doesn't collide with SYSTEM memory. + if SYSTEM_START < heap_pos { + panic!(); + } + + unsafe { HEAP_POS = heap_pos }; + ptr +} diff --git a/runtime/entrypoint/src/memset.s b/runtime/entrypoint/src/memset.s new file mode 100644 index 00000000..a4840ec4 --- /dev/null +++ b/runtime/entrypoint/src/memset.s @@ -0,0 +1,316 @@ +// This is musl-libc memset commit 5613a1486e6a6fc3988be6561f41b07b2647d80f: +// +// src/string/memset.c +// +// This was compiled into assembly with: +// +// clang10 -target mips -O3 -S memset.c -nostdlib -fno-builtin -funroll-loops +// +// and labels manually updated to not conflict. +// +// musl as a whole is licensed under the following standard MIT license: +// +// ---------------------------------------------------------------------- +// Copyright © 2005-2020 Rich Felker, et al. +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// ---------------------------------------------------------------------- +// +// Authors/contributors include: +// +// A. Wilcox +// Ada Worcester +// Alex Dowad +// Alex Suykov +// Alexander Monakov +// Andre McCurdy +// Andrew Kelley +// Anthony G. Basile +// Aric Belsito +// Arvid Picciani +// Bartosz Brachaczek +// Benjamin Peterson +// Bobby Bingham +// Boris Brezillon +// Brent Cook +// Chris Spiegel +// Clément Vasseur +// Daniel Micay +// Daniel Sabogal +// Daurnimator +// David Carlier +// David Edelsohn +// Denys Vlasenko +// Dmitry Ivanov +// Dmitry V. Levin +// Drew DeVault +// Emil Renner Berthing +// Fangrui Song +// Felix Fietkau +// Felix Janda +// Gianluca Anzolin +// Hauke Mehrtens +// He X +// Hiltjo Posthuma +// Isaac Dunham +// Jaydeep Patil +// Jens Gustedt +// Jeremy Huntwork +// Jo-Philipp Wich +// Joakim Sindholt +// John Spencer +// Julien Ramseier +// Justin Cormack +// Kaarle Ritvanen +// Khem Raj +// Kylie McClain +// Leah Neukirchen +// Luca Barbato +// Luka Perkov +// M Farkas-Dyck (Strake) +// Mahesh Bodapati +// Markus Wichmann +// Masanori Ogino +// Michael Clark +// Michael Forney +// Mikhail Kremnyov +// Natanael Copa +// Nicholas J. Kain +// orc +// Pascal Cuoq +// Patrick Oppenlander +// Petr Hosek +// Petr Skocik +// Pierre Carrier +// Reini Urban +// Rich Felker +// Richard Pennington +// Ryan Fairfax +// Samuel Holland +// Segev Finer +// Shiz +// sin +// Solar Designer +// Stefan Kristiansson +// Stefan O'Rear +// Szabolcs Nagy +// Timo Teräs +// Trutz Behn +// Valentin Ochs +// Will Dietz +// William Haddon +// William Pitcock +// +// Portions of this software are derived from third-party works licensed +// under terms compatible with the above MIT license: +// +// The TRE regular expression implementation (src/regex/reg* and +// src/regex/tre*) is Copyright © 2001-2008 Ville Laurikari and licensed +// under a 2-clause BSD license (license text in the source files). The +// included version has been heavily modified by Rich Felker in 2012, in +// the interests of size, simplicity, and namespace cleanliness. +// +// Much of the math library code (src/math/* and src/complex/*) is +// Copyright © 1993,2004 Sun Microsystems or +// Copyright © 2003-2011 David Schultz or +// Copyright © 2003-2009 Steven G. Kargl or +// Copyright © 2003-2009 Bruce D. Evans or +// Copyright © 2008 Stephen L. Moshier or +// Copyright © 2017-2018 Arm Limited +// and labelled as such in comments in the individual source files. All +// have been licensed under extremely permissive terms. +// +// The ARM memcpy code (src/string/arm/memcpy.S) is Copyright © 2008 +// The Android Open Source Project and is licensed under a two-clause BSD +// license. It was taken from Bionic libc, used on Android. +// +// The AArch64 memcpy and memset code (src/string/aarch64/*) are +// Copyright © 1999-2019, Arm Limited. +// +// The implementation of DES for crypt (src/crypt/crypt_des.c) is +// Copyright © 1994 David Burren. It is licensed under a BSD license. +// +// The implementation of blowfish crypt (src/crypt/crypt_blowfish.c) was +// originally written by Solar Designer and placed into the public +// domain. The code also comes with a fallback permissive license for use +// in jurisdictions that may not recognize the public domain. +// +// The smoothsort implementation (src/stdlib/qsort.c) is Copyright © 2011 +// Valentin Ochs and is licensed under an MIT-style license. +// +// The x86_64 port was written by Nicholas J. Kain and is licensed under +// the standard MIT terms. +// +// The mips and microblaze ports were originally written by Richard +// Pennington for use in the ellcc project. The original code was adapted +// by Rich Felker for build system and code conventions during upstream +// integration. It is licensed under the standard MIT terms. +// +// The mips64 port was contributed by Imagination Technologies and is +// licensed under the standard MIT terms. +// +// The powerpc port was also originally written by Richard Pennington, +// and later supplemented and integrated by John Spencer. It is licensed +// under the standard MIT terms. +// +// All other files which have no copyright comments are original works +// produced specifically for use as part of this library, written either +// by Rich Felker, the main author of the library, or by one or more +// contibutors listed above. Details on authorship of individual files +// can be found in the git version control history of the project. The +// omission of copyright and license comments in each file is in the +// interest of source tree size. +// +// In addition, permission is hereby granted for all public header files +// (include/* and arch/* /bits/* ) and crt files intended to be linked into +// applications (crt/*, ldso/dlstart.c, and arch/* /crt_arch.h) to omit +// the copyright notice and permission notice otherwise required by the +// license, and to use these files without any requirement of +// attribution. These files include substantial contributions from: +// +// Bobby Bingham +// John Spencer +// Nicholas J. Kain +// Rich Felker +// Richard Pennington +// Stefan Kristiansson +// Szabolcs Nagy +// +// all of whom have explicitly granted such permission. +// +// This file previously contained text expressing a belief that most of +// the files covered by the above exception were sufficiently trivial not +// to be subject to copyright, resulting in confusion over whether it +// negated the permissions granted in the license. In the spirit of +// permissive licensing, and of not having licensing issues being an +// obstacle to adoption, that text has been removed. + .text + .file "memset.c" + .globl memset # -- Begin function memset + .p2align 2 + .type memset,@function + .set nomicromips + .set nomips16 + .ent memset +memset: # @memset + .frame $fp,8,$ra + .mask 0xc0000000,-4 + .fmask 0x00000000,0 + .set noreorder + .set nomacro + .set noat +# %bb.0: + addiu $sp, $sp, -8 + sw $ra, 4($sp) # 4-byte Folded Spill + sw $fp, 0($sp) # 4-byte Folded Spill + move $fp, $sp + beqz $6, $BBmemset0_9 + nop +# %bb.1: + addu $2, $6, $4 + sltiu $1, $6, 3 + sb $5, 0($4) + bnez $1, $BBmemset0_9 + sb $5, -1($2) +# %bb.2: + sltiu $1, $6, 7 + sb $5, 2($4) + sb $5, 1($4) + sb $5, -3($2) + bnez $1, $BBmemset0_9 + sb $5, -2($2) +# %bb.3: + sltiu $1, $6, 9 + sb $5, 3($4) + bnez $1, $BBmemset0_9 + sb $5, -4($2) +# %bb.4: + andi $2, $5, 255 + negu $1, $4 + sll $5, $2, 8 + sll $7, $2, 16 + andi $1, $1, 3 + or $5, $5, $2 + sll $2, $2, 24 + addu $3, $4, $1 + subu $1, $6, $1 + or $5, $7, $5 + or $2, $2, $5 + addiu $5, $zero, -4 + and $5, $1, $5 + sw $2, 0($3) + addu $6, $3, $5 + sltiu $1, $5, 9 + bnez $1, $BBmemset0_9 + sw $2, -4($6) +# %bb.5: + sltiu $1, $5, 25 + sw $2, 8($3) + sw $2, 4($3) + sw $2, -8($6) + bnez $1, $BBmemset0_9 + sw $2, -12($6) +# %bb.6: + andi $1, $3, 4 + sw $2, 24($3) + sw $2, 20($3) + sw $2, 16($3) + sw $2, 12($3) + sw $2, -16($6) + sw $2, -20($6) + sw $2, -24($6) + sw $2, -28($6) + ori $6, $1, 24 + subu $5, $5, $6 + sltiu $1, $5, 32 + bnez $1, $BBmemset0_9 + nop +# %bb.7: + addu $3, $3, $6 +$BBmemset0_8: # =>This Inner Loop Header: Depth=1 + addiu $5, $5, -32 + sw $2, 24($3) + sw $2, 16($3) + sw $2, 8($3) + sw $2, 0($3) + sw $2, 28($3) + sw $2, 20($3) + sw $2, 12($3) + sw $2, 4($3) + sltiu $1, $5, 32 + beqz $1, $BBmemset0_8 + addiu $3, $3, 32 +$BBmemset0_9: + move $2, $4 + move $sp, $fp + lw $fp, 0($sp) # 4-byte Folded Reload + lw $ra, 4($sp) # 4-byte Folded Reload + jr $ra + addiu $sp, $sp, 8 + .set at + .set macro + .set reorder + .end memset +$memset_func_end0: + .size memset, ($memset_func_end0)-memset + # -- End function + .ident "clang version 10.0.0-4ubuntu1 " + .section ".note.GNU-stack","",@progbits + .addrsig \ No newline at end of file diff --git a/runtime/entrypoint/src/syscalls/halt.rs b/runtime/entrypoint/src/syscalls/halt.rs new file mode 100644 index 00000000..83d791bb --- /dev/null +++ b/runtime/entrypoint/src/syscalls/halt.rs @@ -0,0 +1,26 @@ +//! Ported from Entrypoint for SP1 zkVM. + +use cfg_if::cfg_if; + +cfg_if! { + if #[cfg(target_os = "zkvm")] { + use core::arch::asm; + } +} + +/// Halts the program. +#[allow(unused_variables)] +pub extern "C" fn syscall_halt(exit_code: u8) -> ! { + #[cfg(target_os = "zkvm")] + unsafe { + asm!( + "syscall", + in("$2") crate::syscalls::HALT, + in("$4") exit_code + ); + unreachable!() + } + + #[cfg(not(target_os = "zkvm"))] + unreachable!() +} diff --git a/runtime/entrypoint/src/syscalls/io.rs b/runtime/entrypoint/src/syscalls/io.rs new file mode 100644 index 00000000..6d511c58 --- /dev/null +++ b/runtime/entrypoint/src/syscalls/io.rs @@ -0,0 +1,74 @@ +//! Ported from Entrypoint for SP1 zkVM. + +cfg_if::cfg_if! { + if #[cfg(target_os = "zkvm")] { + use core::arch::asm; + use crate::zkvm; + use sha2::digest::Update; + use zkm_precompiles::io::FD_PUBLIC_VALUES; + } +} + +/// Write data to the prover. +#[allow(unused_variables)] +#[no_mangle] +pub extern "C" fn syscall_write(fd: u32, write_buf: *const u8, nbytes: usize) { + cfg_if::cfg_if! { + if #[cfg(target_os = "zkvm")] { + unsafe { + asm!( + "syscall", + in("$2") crate::syscalls::WRITE, + in("$4") fd, + in("$5") write_buf, + in("$6") nbytes, + ); + } + + // For writes to the public values fd, we update a global program hasher with the bytes + // being written. At the end of the program, we call the COMMIT ecall with the finalized + // version of this hash. + if fd == FD_PUBLIC_VALUES { + let pi_slice: &[u8] = unsafe { core::slice::from_raw_parts(write_buf, nbytes) }; + unsafe { zkvm::PUBLIC_VALUES_HASHER.as_mut().unwrap().update(pi_slice) }; + } + } else { + unreachable!() + } + } +} + +#[allow(unused_variables)] +#[no_mangle] +pub extern "C" fn syscall_hint_len() -> usize { + #[cfg(target_os = "zkvm")] + unsafe { + let len; + asm!( + "syscall", + in("$2") crate::syscalls::HINT_LEN, + lateout("$2") len, + ); + len + } + + #[cfg(not(target_os = "zkvm"))] + unreachable!() +} + +#[allow(unused_variables)] +#[no_mangle] +pub extern "C" fn syscall_hint_read(ptr: *mut u8, len: usize) { + #[cfg(target_os = "zkvm")] + unsafe { + asm!( + "syscall", + in("$2") crate::syscalls::HINT_READ, + in("$4") ptr, + in("$5") len, + ); + } + + #[cfg(not(target_os = "zkvm"))] + unreachable!() +} diff --git a/runtime/entrypoint/src/syscalls/memory.rs b/runtime/entrypoint/src/syscalls/memory.rs new file mode 100644 index 00000000..b4c967ea --- /dev/null +++ b/runtime/entrypoint/src/syscalls/memory.rs @@ -0,0 +1,51 @@ +// Copyright 2023 RISC Zero, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +const SYSTEM_START: usize = 0x0C00_0000; + +#[allow(clippy::missing_safety_doc)] +#[no_mangle] +pub unsafe extern "C" fn sys_alloc_aligned(bytes: usize, align: usize) -> *mut u8 { + extern "C" { + // https://lld.llvm.org/ELF/linker_script.html#sections-command + static _end: u8; + } + + // Pointer to next heap address to use, or 0 if the heap has not yet been + // initialized. + static mut HEAP_POS: usize = 0; + + // SAFETY: Single threaded, so nothing else can touch this while we're working. + let mut heap_pos = unsafe { HEAP_POS }; + + if heap_pos == 0 { + heap_pos = unsafe { (&_end) as *const u8 as usize }; + } + + let offset = heap_pos & (align - 1); + if offset != 0 { + heap_pos += align - offset; + } + + let ptr = heap_pos as *mut u8; + heap_pos += bytes; + + // Check to make sure heap doesn't collide with SYSTEM memory. + if SYSTEM_START < heap_pos { + panic!(); + } + + unsafe { HEAP_POS = heap_pos }; + ptr +} diff --git a/runtime/entrypoint/src/syscalls/mod.rs b/runtime/entrypoint/src/syscalls/mod.rs new file mode 100644 index 00000000..40bc14da --- /dev/null +++ b/runtime/entrypoint/src/syscalls/mod.rs @@ -0,0 +1,29 @@ +//! Ported from Entrypoint for SP1 zkVM. + +mod halt; +mod io; +mod memory; +mod sys; + +pub use halt::*; +pub use io::*; +pub use memory::*; +pub use sys::*; + +/// These codes MUST match the codes in `core/src/runtime/syscall.rs`. There is a derived test +/// that checks that the enum is consistent with the syscalls. + +/// Halts the program. +pub const HALT: u32 = 4246u32; + +/// Writes to a file descriptor. Currently only used for `STDOUT/STDERR`. +pub const WRITE: u32 = 4004u32; + +/// Executes the `COMMIT` precompile. +pub const COMMIT: u32 = 0x00_00_00_10; + +/// Executes `HINT_LEN`. +pub const HINT_LEN: u32 = 0x00_00_00_F0; + +/// Executes `HINT_READ`. +pub const HINT_READ: u32 = 0x00_00_00_F1; diff --git a/runtime/entrypoint/src/syscalls/sys.rs b/runtime/entrypoint/src/syscalls/sys.rs new file mode 100644 index 00000000..5fc1a3e6 --- /dev/null +++ b/runtime/entrypoint/src/syscalls/sys.rs @@ -0,0 +1,70 @@ +//! Ported from Entrypoint for SP1 zkVM. + +use std::sync::Mutex; + +use lazy_static::lazy_static; +use rand::{rngs::StdRng, Rng, SeedableRng}; + +use crate::syscalls::{syscall_halt, syscall_write}; + +/// The random number generator seed for the zkVM. +/// +/// In the future, we can pass in this seed from the host or have the verifier generate it. +const PRNG_SEED: u64 = 0x123456789abcdef0; + +lazy_static! { + /// A lazy static to generate a global random number generator. + static ref RNG: Mutex = Mutex::new(StdRng::seed_from_u64(PRNG_SEED)); +} + +/// A lazy static to print a warning once for using the `sys_rand` system call. +static SYS_RAND_WARNING: std::sync::Once = std::sync::Once::new(); + +/// Generates random bytes. +/// +/// # Safety +/// +/// Make sure that `buf` has at least `nwords` words. +#[no_mangle] +pub unsafe extern "C" fn sys_rand(recv_buf: *mut u8, words: usize) { + SYS_RAND_WARNING.call_once(|| { + println!("WARNING: Using insecure random number generator."); + }); + let mut rng = RNG.lock().unwrap(); + for i in 0..words { + let element = recv_buf.add(i); + *element = rng.gen(); + } +} + +#[allow(clippy::missing_safety_doc)] +#[no_mangle] +pub unsafe extern "C" fn sys_panic(msg_ptr: *const u8, len: usize) -> ! { + sys_write(2, msg_ptr, len); + syscall_halt(1); +} + +#[allow(unused_variables)] +#[no_mangle] +pub const fn sys_getenv( + recv_buf: *mut u32, + words: usize, + varname: *const u8, + varname_len: usize, +) -> usize { + 0 +} + +#[allow(unused_variables)] +#[no_mangle] +pub const fn sys_alloc_words(nwords: usize) -> *mut u32 { + core::ptr::null_mut() +} + +#[allow(unused_unsafe)] +#[no_mangle] +pub fn sys_write(fd: u32, write_buf: *const u8, nbytes: usize) { + unsafe { + syscall_write(fd, write_buf, nbytes); + } +} diff --git a/runtime/precompiles/Cargo.toml b/runtime/precompiles/Cargo.toml new file mode 100644 index 00000000..a017d35e --- /dev/null +++ b/runtime/precompiles/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "zkm-precompiles" +version = "0.1.0" +edition = "2021" + +[dependencies] +anyhow = "1.0.83" +bincode = "1.3.3" +cfg-if = "1.0.0" +getrandom = { version = "0.2.14", features = ["custom"] } +hex = "0.4.3" +rand = "0.8.5" +serde = { version = "1.0.201", features = ["derive"] } +num = { version = "0.4.3" } diff --git a/runtime/precompiles/src/io.rs b/runtime/precompiles/src/io.rs new file mode 100644 index 00000000..a46a1def --- /dev/null +++ b/runtime/precompiles/src/io.rs @@ -0,0 +1,92 @@ +//! Ported from Precompiles for SP1 zkVM. + +#![allow(unused_unsafe)] +use crate::syscall_write; +use crate::{syscall_hint_len, syscall_hint_read}; +use serde::de::DeserializeOwned; +use serde::Serialize; +use std::alloc::Layout; +use std::io::Write; + +const FD_HINT: u32 = 4; +pub const FD_PUBLIC_VALUES: u32 = 3; +// Runtime hook file descriptors. Make sure these match the FDs in the HookRegistry. +// The default hooks can be found in `core/src/runtime/hooks.rs`. +pub const FD_ECRECOVER_HOOK: u32 = 5; + +pub struct SyscallWriter { + fd: u32, +} + +impl std::io::Write for SyscallWriter { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + let nbytes = buf.len(); + let write_buf = buf.as_ptr(); + unsafe { + syscall_write(self.fd, write_buf, nbytes); + } + Ok(nbytes) + } + + fn flush(&mut self) -> std::io::Result<()> { + Ok(()) + } +} + +pub fn read_vec() -> Vec { + let len = unsafe { syscall_hint_len() }; + // Round up to the nearest multiple of 4 so that the memory allocated is in whole words + let capacity = (len + 3) / 4 * 4; + + // Allocate a buffer of the required length that is 4 byte aligned + let layout = Layout::from_size_align(capacity, 4).expect("vec is too large"); + let ptr = unsafe { std::alloc::alloc(layout) }; + // SAFETY: + // 1. `ptr` was allocated using alloc + // 2. We assuume that the VM global allocator doesn't dealloc + // 3/6. Size is correct from above + // 4/5. Length is 0 + // 7. Layout::from_size_align already checks this + let mut vec = unsafe { Vec::from_raw_parts(ptr, 0, capacity) }; + // Read the vec into uninitialized memory. The syscall assumes the memory is uninitialized, + // which should be true because the allocator does not dealloc, so a new alloc should be fresh. + unsafe { + syscall_hint_read(ptr, len); + vec.set_len(len); + } + vec +} + +pub fn read() -> T { + let vec = read_vec(); + bincode::deserialize(&vec).expect("deserialization failed") +} + +pub fn commit(value: &T) { + let writer = SyscallWriter { + fd: FD_PUBLIC_VALUES, + }; + bincode::serialize_into(writer, value).expect("serialization failed"); +} + +pub fn commit_slice(buf: &[u8]) { + let mut my_writer = SyscallWriter { + fd: FD_PUBLIC_VALUES, + }; + my_writer.write_all(buf).unwrap(); +} + +pub fn hint(value: &T) { + let writer = SyscallWriter { fd: FD_HINT }; + bincode::serialize_into(writer, value).expect("serialization failed"); +} + +pub fn hint_slice(buf: &[u8]) { + let mut my_reader = SyscallWriter { fd: FD_HINT }; + my_reader.write_all(buf).unwrap(); +} + +/// Write the data `buf` to the file descriptor `fd` using `Write::write_all` . +pub fn write(fd: u32, buf: &[u8]) { + SyscallWriter { fd }.write_all(buf).unwrap(); +} diff --git a/runtime/precompiles/src/lib.rs b/runtime/precompiles/src/lib.rs new file mode 100644 index 00000000..070485c7 --- /dev/null +++ b/runtime/precompiles/src/lib.rs @@ -0,0 +1,19 @@ +//! Ported from Precompiles for SP1 zkVM. +//! +//! Specifically, this crate contains user-friendly functions that call SP1 syscalls. Syscalls are +//! also declared here for convenience. In order to avoid duplicate symbol errors, the syscall +//! function impls must live in sp1-zkvm, which is only imported into the end user program crate. +//! In contrast, sp1-precompiles can be imported into any crate in the dependency tree. + +pub mod io; +pub mod utils; + +pub const BIGINT_WIDTH_WORDS: usize = 8; + +extern "C" { + pub fn syscall_halt(exit_code: u8) -> !; + pub fn syscall_write(fd: u32, write_buf: *const u8, nbytes: usize); + pub fn syscall_hint_len() -> usize; + pub fn syscall_hint_read(ptr: *mut u8, len: usize); + pub fn sys_alloc_aligned(bytes: usize, align: usize) -> *mut u8; +} diff --git a/runtime/precompiles/src/utils.rs b/runtime/precompiles/src/utils.rs new file mode 100644 index 00000000..3bc2676c --- /dev/null +++ b/runtime/precompiles/src/utils.rs @@ -0,0 +1,111 @@ +//! Ported from Precompiles for SP1 zkVM. + +pub trait CurveOperations { + const GENERATOR: [u32; NUM_WORDS]; + + fn add_assign(limbs: &mut [u32; NUM_WORDS], other: &[u32; NUM_WORDS]); + fn double(limbs: &mut [u32; NUM_WORDS]); +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct AffinePoint, const NUM_WORDS: usize> { + pub(crate) limbs: [u32; NUM_WORDS], + _marker: std::marker::PhantomData, +} + +impl + Copy, const NUM_WORDS: usize> AffinePoint { + const GENERATOR: [u32; NUM_WORDS] = C::GENERATOR; + + pub const fn generator_in_affine() -> Self { + Self { + limbs: Self::GENERATOR, + _marker: std::marker::PhantomData, + } + } + + pub const fn new(limbs: [u32; NUM_WORDS]) -> Self { + Self { + limbs, + _marker: std::marker::PhantomData, + } + } + + /// x_bytes and y_bytes are the concatenated little endian representations of the x and y coordinates. + /// The length of x_bytes and y_bytes must each be NUM_WORDS * 2. + pub fn from(x_bytes: &[u8], y_bytes: &[u8]) -> Self { + debug_assert!(x_bytes.len() == NUM_WORDS * 2); + debug_assert!(y_bytes.len() == NUM_WORDS * 2); + + let mut limbs = [0u32; NUM_WORDS]; + let x = bytes_to_words_le(x_bytes); + let y = bytes_to_words_le(y_bytes); + debug_assert!(x.len() == NUM_WORDS / 2); + debug_assert!(y.len() == NUM_WORDS / 2); + + limbs[..(NUM_WORDS / 2)].copy_from_slice(&x); + limbs[(NUM_WORDS / 2)..].copy_from_slice(&y); + Self::new(limbs) + } + + pub fn add_assign(&mut self, other: &AffinePoint) { + C::add_assign(&mut self.limbs, &other.limbs); + } + + pub fn double(&mut self) { + C::double(&mut self.limbs); + } + + pub fn mul_assign(&mut self, scalar: &[u32]) { + debug_assert!(scalar.len() == NUM_WORDS / 2); + + let mut res: Option = None; + let mut temp = *self; + + for &words in scalar.iter() { + for i in 0..32 { + if (words >> i) & 1 == 1 { + match res.as_mut() { + Some(res) => res.add_assign(&temp), + None => res = Some(temp), + }; + } + + temp.double(); + } + } + + *self = res.unwrap(); + } + + pub fn from_le_bytes(limbs: &[u8]) -> Self { + let u32_limbs = bytes_to_words_le(limbs); + debug_assert!(u32_limbs.len() == NUM_WORDS); + + Self { + limbs: u32_limbs.try_into().unwrap(), + _marker: std::marker::PhantomData, + } + } + + pub fn to_le_bytes(&self) -> Vec { + let le_bytes = words_to_bytes_le(&self.limbs); + debug_assert!(le_bytes.len() == NUM_WORDS * 4); + le_bytes + } +} + +/// Converts a slice of words to a byte array in little endian. +pub fn words_to_bytes_le(words: &[u32]) -> Vec { + words + .iter() + .flat_map(|word| word.to_le_bytes().to_vec()) + .collect::>() +} + +/// Converts a byte array in little endian to a slice of words. +pub fn bytes_to_words_le(bytes: &[u8]) -> Vec { + bytes + .chunks_exact(4) + .map(|chunk| u32::from_le_bytes(chunk.try_into().unwrap())) + .collect::>() +} From eee6fbb680c0946f470d2ce6950e1d790010ea69 Mon Sep 17 00:00:00 2001 From: Angell Li Date: Wed, 3 Jul 2024 23:29:07 +0800 Subject: [PATCH 11/13] fix clippy --- src/witness/operation.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/witness/operation.rs b/src/witness/operation.rs index e0df9197..a5e9fa72 100644 --- a/src/witness/operation.rs +++ b/src/witness/operation.rs @@ -871,12 +871,12 @@ pub(crate) fn load_input( let mut j = 0; for i in (0..size).step_by(4) { // Get each byte in the chunk - let b1 = vec[i as usize]; + let b1 = vec[i]; // In case the vec is not a multiple of 4, right-pad with 0s. This is fine because we // are assuming the word is uninitialized, so filling it with 0s makes sense. - let b2 = vec.get(i as usize + 1).copied().unwrap_or(0); - let b3 = vec.get(i as usize + 2).copied().unwrap_or(0); - let b4 = vec.get(i as usize + 3).copied().unwrap_or(0); + let b2 = vec.get(i + 1).copied().unwrap_or(0); + let b3 = vec.get(i + 2).copied().unwrap_or(0); + let b4 = vec.get(i + 3).copied().unwrap_or(0); let word = u32::from_le_bytes([b1, b2, b3, b4]); if j == 8 { From 29835d82a7b40d4dbcc9e2a8b5ed55a3e3297344 Mon Sep 17 00:00:00 2001 From: Angell Li Date: Thu, 4 Jul 2024 23:06:36 +0800 Subject: [PATCH 12/13] remove unused commit func --- examples/sha2/src/main.rs | 4 +-- runtime/entrypoint/src/syscalls/io.rs | 11 -------- runtime/entrypoint/src/syscalls/mod.rs | 3 -- runtime/precompiles/src/io.rs | 39 +------------------------- 4 files changed, 2 insertions(+), 55 deletions(-) diff --git a/examples/sha2/src/main.rs b/examples/sha2/src/main.rs index 68e64b39..891a530f 100644 --- a/examples/sha2/src/main.rs +++ b/examples/sha2/src/main.rs @@ -12,7 +12,5 @@ pub fn main() { let mut hasher = Sha256::new(); hasher.update(input); - let result = hasher.finalize(); - - zkm_runtime::io::commit::<[u8; 32]>(&result.into()); + let _result = hasher.finalize(); } diff --git a/runtime/entrypoint/src/syscalls/io.rs b/runtime/entrypoint/src/syscalls/io.rs index 6d511c58..173074bb 100644 --- a/runtime/entrypoint/src/syscalls/io.rs +++ b/runtime/entrypoint/src/syscalls/io.rs @@ -3,9 +3,6 @@ cfg_if::cfg_if! { if #[cfg(target_os = "zkvm")] { use core::arch::asm; - use crate::zkvm; - use sha2::digest::Update; - use zkm_precompiles::io::FD_PUBLIC_VALUES; } } @@ -24,14 +21,6 @@ pub extern "C" fn syscall_write(fd: u32, write_buf: *const u8, nbytes: usize) { in("$6") nbytes, ); } - - // For writes to the public values fd, we update a global program hasher with the bytes - // being written. At the end of the program, we call the COMMIT ecall with the finalized - // version of this hash. - if fd == FD_PUBLIC_VALUES { - let pi_slice: &[u8] = unsafe { core::slice::from_raw_parts(write_buf, nbytes) }; - unsafe { zkvm::PUBLIC_VALUES_HASHER.as_mut().unwrap().update(pi_slice) }; - } } else { unreachable!() } diff --git a/runtime/entrypoint/src/syscalls/mod.rs b/runtime/entrypoint/src/syscalls/mod.rs index 40bc14da..4e4020f7 100644 --- a/runtime/entrypoint/src/syscalls/mod.rs +++ b/runtime/entrypoint/src/syscalls/mod.rs @@ -19,9 +19,6 @@ pub const HALT: u32 = 4246u32; /// Writes to a file descriptor. Currently only used for `STDOUT/STDERR`. pub const WRITE: u32 = 4004u32; -/// Executes the `COMMIT` precompile. -pub const COMMIT: u32 = 0x00_00_00_10; - /// Executes `HINT_LEN`. pub const HINT_LEN: u32 = 0x00_00_00_F0; diff --git a/runtime/precompiles/src/io.rs b/runtime/precompiles/src/io.rs index a46a1def..01c8b4ab 100644 --- a/runtime/precompiles/src/io.rs +++ b/runtime/precompiles/src/io.rs @@ -4,15 +4,7 @@ use crate::syscall_write; use crate::{syscall_hint_len, syscall_hint_read}; use serde::de::DeserializeOwned; -use serde::Serialize; use std::alloc::Layout; -use std::io::Write; - -const FD_HINT: u32 = 4; -pub const FD_PUBLIC_VALUES: u32 = 3; -// Runtime hook file descriptors. Make sure these match the FDs in the HookRegistry. -// The default hooks can be found in `core/src/runtime/hooks.rs`. -pub const FD_ECRECOVER_HOOK: u32 = 5; pub struct SyscallWriter { fd: u32, @@ -60,33 +52,4 @@ pub fn read_vec() -> Vec { pub fn read() -> T { let vec = read_vec(); bincode::deserialize(&vec).expect("deserialization failed") -} - -pub fn commit(value: &T) { - let writer = SyscallWriter { - fd: FD_PUBLIC_VALUES, - }; - bincode::serialize_into(writer, value).expect("serialization failed"); -} - -pub fn commit_slice(buf: &[u8]) { - let mut my_writer = SyscallWriter { - fd: FD_PUBLIC_VALUES, - }; - my_writer.write_all(buf).unwrap(); -} - -pub fn hint(value: &T) { - let writer = SyscallWriter { fd: FD_HINT }; - bincode::serialize_into(writer, value).expect("serialization failed"); -} - -pub fn hint_slice(buf: &[u8]) { - let mut my_reader = SyscallWriter { fd: FD_HINT }; - my_reader.write_all(buf).unwrap(); -} - -/// Write the data `buf` to the file descriptor `fd` using `Write::write_all` . -pub fn write(fd: u32, buf: &[u8]) { - SyscallWriter { fd }.write_all(buf).unwrap(); -} +} \ No newline at end of file From 17340fed09e56b99e41b4b7cda4ddd472abe0994 Mon Sep 17 00:00:00 2001 From: Angell Li Date: Fri, 5 Jul 2024 16:48:53 +0800 Subject: [PATCH 13/13] update readme --- examples/README.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/examples/README.md b/examples/README.md index a0fcfb34..0752d4a9 100644 --- a/examples/README.md +++ b/examples/README.md @@ -38,4 +38,36 @@ BASEDIR=test-vectors RUST_LOG=info BLOCK_NO=13284491 SEG_FILE_DIR="/tmp/output" cargo run --release --example zkmips aggregate_proof_all ``` +- run bench + + - download/install toolchain for mips + + ``` + wget http://musl.cc/mips-linux-muslsf-cross.tgz + tar -zxvf mips-linux-muslsf-cross.tgz + ``` + + - modify ~/.cargo/config: + + ``` + [target.mips-unknown-linux-musl] + linker = /mips-linux-muslsf-gcc" + rustflags = ["--cfg", 'target_os="zkvm"',"-C", "target-feature=+crt-static", "-C", "link-arg=-g"] + ``` + + - build sha2 + + ``` + cd examples/sha2 + cargo build --target=mips-unknown-linux-musl + cd ../../ + ``` + + - run bench + + ``` + RUST_LOG=info ELF_PATH=examples/sha2/target/mips-unknown-linux-musl/debug/sha2-bench SEG_OUTPUT=/tmp/output cargo run --release --example zkmips bench + ``` + Basically, you can run the example on a 32G RAM machine, if you get OOM error, please read https://github.com/zkMIPS/zkm/issues/97. +