From 59a7bd3e8417aff255cd5ad7d38e3fc11254b07d Mon Sep 17 00:00:00 2001 From: Alexander Golovanov Date: Tue, 29 Oct 2024 18:34:54 +0100 Subject: [PATCH 01/14] Add custom insn macros --- toolchain/riscv/platform/src/intrinsics.rs | 30 ++++++++++++++++++++++ toolchain/riscv/platform/src/lib.rs | 2 ++ toolchain/riscv/platform/src/rust_rt.rs | 8 +++--- 3 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 toolchain/riscv/platform/src/intrinsics.rs diff --git a/toolchain/riscv/platform/src/intrinsics.rs b/toolchain/riscv/platform/src/intrinsics.rs new file mode 100644 index 0000000000..ad34105d72 --- /dev/null +++ b/toolchain/riscv/platform/src/intrinsics.rs @@ -0,0 +1,30 @@ +#[macro_export] +macro_rules! custom_insn_i { + ($opcode:expr, $funct3:expr, $rd:literal, $rs1:literal, $imm:expr) => { + unsafe { + asm!(concat!( + ".insn i {opcode}, {funct3}, ", + $rd, + ", ", + $rs1, + ", {imm}", + ), opcode = const $opcode, funct3 = const $funct3, imm = const $imm) + } + }; +} + +#[macro_export] +macro_rules! custom_insn_r { + ($opcode:expr, $funct3:expr, $rd:literal, $rs1:literal, $rs2:literal) => { + unsafe { + asm!(concat!( + ".insn i {opcode}, {funct3}, ", + $rd, + ", ", + $rs1, + ", ", + $rs2, + ), opcode = const $opcode, funct3 = const $funct3) + } + }; +} diff --git a/toolchain/riscv/platform/src/lib.rs b/toolchain/riscv/platform/src/lib.rs index 1267dc3e7b..a21f65f152 100644 --- a/toolchain/riscv/platform/src/lib.rs +++ b/toolchain/riscv/platform/src/lib.rs @@ -31,6 +31,8 @@ mod libm_extern; #[cfg(feature = "rust-runtime")] pub mod rust_rt; +pub mod intrinsics; + /// Size of a zkVM machine word in bytes. /// 4 bytes (i.e. 32 bits) as the zkVM is an implementation of the rv32im ISA. pub const WORD_SIZE: usize = core::mem::size_of::(); diff --git a/toolchain/riscv/platform/src/rust_rt.rs b/toolchain/riscv/platform/src/rust_rt.rs index 3b6f90ab9e..19065c2861 100644 --- a/toolchain/riscv/platform/src/rust_rt.rs +++ b/toolchain/riscv/platform/src/rust_rt.rs @@ -23,17 +23,17 @@ #[cfg(target_os = "zkvm")] use core::arch::asm; +#[cfg(target_os = "zkvm")] +use crate::intrinsics::{custom_insn_i, custom_insn_r}; + extern crate alloc; #[inline(always)] pub fn terminate() { #[cfg(target_os = "zkvm")] - unsafe { - asm!(".insn i 0x0b, 0, x0, x0, {ec}", ec = const EXIT_CODE) - }; + custom_insn_i!(0x0b, 0, "x0", "x0", EXIT_CODE); #[cfg(not(target_os = "zkvm"))] { - core::hint::black_box(()); unimplemented!() } } From ac5ad9467baa39f1fa3c8f1b1798ab9554580a09 Mon Sep 17 00:00:00 2001 From: Alexander Golovanov Date: Wed, 30 Oct 2024 00:07:13 +0100 Subject: [PATCH 02/14] Wip --- toolchain/riscv/axvm/src/intrinsics/io.rs | 9 +++++ toolchain/riscv/axvm/src/intrinsics/mod.rs | 1 + .../examples/hint/program/.cargo/config.toml | 5 +++ .../riscv/examples/hint/program/Cargo.toml | 8 ++++ .../riscv/examples/hint/program/src/main.rs | 11 ++++++ .../src/{intrinsics.rs => intrinsics/mod.rs} | 5 ++- toolchain/riscv/platform/src/lib.rs | 4 +- toolchain/riscv/platform/src/rust_rt.rs | 4 +- toolchain/riscv/transpiler/src/rrs.rs | 37 ++++++++++--------- 9 files changed, 62 insertions(+), 22 deletions(-) create mode 100644 toolchain/riscv/axvm/src/intrinsics/io.rs create mode 100644 toolchain/riscv/examples/hint/program/.cargo/config.toml create mode 100644 toolchain/riscv/examples/hint/program/Cargo.toml create mode 100644 toolchain/riscv/examples/hint/program/src/main.rs rename toolchain/riscv/platform/src/{intrinsics.rs => intrinsics/mod.rs} (87%) diff --git a/toolchain/riscv/axvm/src/intrinsics/io.rs b/toolchain/riscv/axvm/src/intrinsics/io.rs new file mode 100644 index 0000000000..fd3cd1de20 --- /dev/null +++ b/toolchain/riscv/axvm/src/intrinsics/io.rs @@ -0,0 +1,9 @@ +// use crate::custom_insn_i; + +/// Store the next 4 bytes from the hint stream to [[rd] + imm]_2. +#[macro_export] +macro_rules! hint_store_u32 { + ($rd:literal, $imm:expr) => { + unsafe { custom_insn_i!(CUSTOM_0, 0b001, $rd, "x0", $imm) } + }; +} diff --git a/toolchain/riscv/axvm/src/intrinsics/mod.rs b/toolchain/riscv/axvm/src/intrinsics/mod.rs index d6c4f0426a..587c6b1ab6 100644 --- a/toolchain/riscv/axvm/src/intrinsics/mod.rs +++ b/toolchain/riscv/axvm/src/intrinsics/mod.rs @@ -1,5 +1,6 @@ //! Functions that call custom instructions that use axVM intrinsic instructions. mod hash; +mod io; pub use hash::*; diff --git a/toolchain/riscv/examples/hint/program/.cargo/config.toml b/toolchain/riscv/examples/hint/program/.cargo/config.toml new file mode 100644 index 0000000000..bb18f45366 --- /dev/null +++ b/toolchain/riscv/examples/hint/program/.cargo/config.toml @@ -0,0 +1,5 @@ +[build] +target = "riscv32im-risc0-zkvm-elf" + +[unstable] +build-std = ["core", "alloc", "proc_macro", "panic_abort"] diff --git a/toolchain/riscv/examples/hint/program/Cargo.toml b/toolchain/riscv/examples/hint/program/Cargo.toml new file mode 100644 index 0000000000..a04e080de9 --- /dev/null +++ b/toolchain/riscv/examples/hint/program/Cargo.toml @@ -0,0 +1,8 @@ +[workspace] +[package] +version = "0.1.0" +name = "axvm-hint-program" +edition = "2021" + +[dependencies] +axvm = { path = "../../../axvm" } diff --git a/toolchain/riscv/examples/hint/program/src/main.rs b/toolchain/riscv/examples/hint/program/src/main.rs new file mode 100644 index 0000000000..8cb7de34fb --- /dev/null +++ b/toolchain/riscv/examples/hint/program/src/main.rs @@ -0,0 +1,11 @@ +#![no_main] +#![no_std] +#![recursion_limit = "10"] + +use axvm::*; + +axvm::entry!(main); + +pub fn main() { + hint_store_u32!("a0", 0); +} diff --git a/toolchain/riscv/platform/src/intrinsics.rs b/toolchain/riscv/platform/src/intrinsics/mod.rs similarity index 87% rename from toolchain/riscv/platform/src/intrinsics.rs rename to toolchain/riscv/platform/src/intrinsics/mod.rs index ad34105d72..b84d3bcd63 100644 --- a/toolchain/riscv/platform/src/intrinsics.rs +++ b/toolchain/riscv/platform/src/intrinsics/mod.rs @@ -1,3 +1,6 @@ +pub const CUSTOM_0: u32 = 0x0b; +pub const CUSTOM_1: u32 = 0x2b; + #[macro_export] macro_rules! custom_insn_i { ($opcode:expr, $funct3:expr, $rd:literal, $rs1:literal, $imm:expr) => { @@ -18,7 +21,7 @@ macro_rules! custom_insn_r { ($opcode:expr, $funct3:expr, $rd:literal, $rs1:literal, $rs2:literal) => { unsafe { asm!(concat!( - ".insn i {opcode}, {funct3}, ", + ".insn r {opcode}, {funct3}, ", $rd, ", ", $rs1, diff --git a/toolchain/riscv/platform/src/lib.rs b/toolchain/riscv/platform/src/lib.rs index a21f65f152..d26829665c 100644 --- a/toolchain/riscv/platform/src/lib.rs +++ b/toolchain/riscv/platform/src/lib.rs @@ -26,13 +26,13 @@ pub mod memory; // mod getrandom; #[cfg(all(feature = "rust-runtime", target_os = "zkvm"))] pub mod heap; +#[cfg(feature = "rust-runtime")] +pub mod intrinsics; #[cfg(all(feature = "export-libm", target_os = "zkvm"))] mod libm_extern; #[cfg(feature = "rust-runtime")] pub mod rust_rt; -pub mod intrinsics; - /// Size of a zkVM machine word in bytes. /// 4 bytes (i.e. 32 bits) as the zkVM is an implementation of the rv32im ISA. pub const WORD_SIZE: usize = core::mem::size_of::(); diff --git a/toolchain/riscv/platform/src/rust_rt.rs b/toolchain/riscv/platform/src/rust_rt.rs index 19065c2861..de4ea56b00 100644 --- a/toolchain/riscv/platform/src/rust_rt.rs +++ b/toolchain/riscv/platform/src/rust_rt.rs @@ -24,14 +24,14 @@ use core::arch::asm; #[cfg(target_os = "zkvm")] -use crate::intrinsics::{custom_insn_i, custom_insn_r}; +use crate::{custom_insn_i, custom_insn_r, intrinsics::CUSTOM_0}; extern crate alloc; #[inline(always)] pub fn terminate() { #[cfg(target_os = "zkvm")] - custom_insn_i!(0x0b, 0, "x0", "x0", EXIT_CODE); + custom_insn_i!(CUSTOM_0, 0, "x0", "x0", EXIT_CODE); #[cfg(not(target_os = "zkvm"))] { unimplemented!() diff --git a/toolchain/riscv/transpiler/src/rrs.rs b/toolchain/riscv/transpiler/src/rrs.rs index ca3deb354f..1c6622986d 100644 --- a/toolchain/riscv/transpiler/src/rrs.rs +++ b/toolchain/riscv/transpiler/src/rrs.rs @@ -9,7 +9,8 @@ use axvm_circuit::{ rv32im::adapters::RV32_REGISTER_NUM_LIMBS, }; use axvm_instructions::{ - instruction::Instruction, riscv::RvIntrinsic, EccOpcode, Rv32ModularArithmeticOpcode, + instruction::Instruction, riscv::RvIntrinsic, EccOpcode, Rv32HintStoreOpcode, + Rv32ModularArithmeticOpcode, }; use p3_field::PrimeField32; use rrs_lib::{ @@ -247,23 +248,25 @@ fn process_custom_instruction(instruction_u32: u32) -> Instruct let funct3 = ((instruction_u32 >> 12) & 0b111) as u8; // All our instructions are R- or I-type match opcode { - 0x0b => { - match funct3 { - 0b000 => { - let imm = (instruction_u32 >> 20) & 0xfff; - Some(terminate(imm.try_into().expect("exit code must be byte"))) - } - 0b001 => { - // keccak or poseidon - None - } - 0b010 => { - // u256 - todo!("Implement u256 transpiler"); - } - _ => None, + 0x0b => match funct3 { + 0b000 => { + let imm = (instruction_u32 >> 20) & 0xfff; + Some(terminate(imm.try_into().expect("exit code must be byte"))) } - } + 0b001 => { + let rd = (instruction_u32 >> 7) & 0x1f; + let imm = (instruction_u32 >> 20) & 0xfff; + Some(Instruction::from_isize( + Rv32HintStoreOpcode::HINT_STOREW.with_default_offset(), + (RV32_REGISTER_NUM_LIMBS * rd as usize) as isize, + 0, + imm as isize, + 0, + 0, + )) + } + _ => unimplemented!(), + }, 0x2b => { match funct3 { Rv32ModularArithmeticOpcode::FUNCT3 => { From c961df2927cc8433aef54f89392a5414c766d51f Mon Sep 17 00:00:00 2001 From: Alexander Golovanov Date: Wed, 30 Oct 2024 03:12:55 +0100 Subject: [PATCH 03/14] Wip --- toolchain/riscv/axvm/src/intrinsics/io.rs | 9 +++++++++ toolchain/riscv/axvm/src/intrinsics/mod.rs | 4 +++- toolchain/riscv/axvm/src/lib.rs | 1 + toolchain/riscv/examples/hint/program/src/main.rs | 8 ++++---- toolchain/riscv/platform/src/intrinsics/mod.rs | 13 +++++++++++-- 5 files changed, 28 insertions(+), 7 deletions(-) diff --git a/toolchain/riscv/axvm/src/intrinsics/io.rs b/toolchain/riscv/axvm/src/intrinsics/io.rs index fd3cd1de20..7e2b4fa40e 100644 --- a/toolchain/riscv/axvm/src/intrinsics/io.rs +++ b/toolchain/riscv/axvm/src/intrinsics/io.rs @@ -1,5 +1,7 @@ // use crate::custom_insn_i; +use axvm_platform::{custom_insn_i, intrinsics::CUSTOM_0}; + /// Store the next 4 bytes from the hint stream to [[rd] + imm]_2. #[macro_export] macro_rules! hint_store_u32 { @@ -7,3 +9,10 @@ macro_rules! hint_store_u32 { unsafe { custom_insn_i!(CUSTOM_0, 0b001, $rd, "x0", $imm) } }; } + +/// Read the next byte from the hint stream. +pub fn read_byte() -> u8 { + let mut x: u8; + custom_insn_i!(CUSTOM_0, 0b001, x, "x0", 0); + x +} diff --git a/toolchain/riscv/axvm/src/intrinsics/mod.rs b/toolchain/riscv/axvm/src/intrinsics/mod.rs index 587c6b1ab6..cd49b5dba4 100644 --- a/toolchain/riscv/axvm/src/intrinsics/mod.rs +++ b/toolchain/riscv/axvm/src/intrinsics/mod.rs @@ -1,6 +1,8 @@ //! Functions that call custom instructions that use axVM intrinsic instructions. mod hash; -mod io; +/// Utilities to work with the hint stream. +pub mod io; pub use hash::*; +pub use io::*; diff --git a/toolchain/riscv/axvm/src/lib.rs b/toolchain/riscv/axvm/src/lib.rs index e2913b8a5d..3f1d66e032 100644 --- a/toolchain/riscv/axvm/src/lib.rs +++ b/toolchain/riscv/axvm/src/lib.rs @@ -79,6 +79,7 @@ #![deny(rustdoc::broken_intra_doc_links)] #![deny(missing_docs)] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +#![feature(asm_const)] extern crate alloc; diff --git a/toolchain/riscv/examples/hint/program/src/main.rs b/toolchain/riscv/examples/hint/program/src/main.rs index 8cb7de34fb..b5817e2f7e 100644 --- a/toolchain/riscv/examples/hint/program/src/main.rs +++ b/toolchain/riscv/examples/hint/program/src/main.rs @@ -1,11 +1,11 @@ #![no_main] #![no_std] -#![recursion_limit = "10"] - -use axvm::*; axvm::entry!(main); pub fn main() { - hint_store_u32!("a0", 0); + let x = axvm::intrinsics::io::read_byte(); + if x == 0 { + loop {} + } } diff --git a/toolchain/riscv/platform/src/intrinsics/mod.rs b/toolchain/riscv/platform/src/intrinsics/mod.rs index b84d3bcd63..9a8c44b8f4 100644 --- a/toolchain/riscv/platform/src/intrinsics/mod.rs +++ b/toolchain/riscv/platform/src/intrinsics/mod.rs @@ -5,7 +5,7 @@ pub const CUSTOM_1: u32 = 0x2b; macro_rules! custom_insn_i { ($opcode:expr, $funct3:expr, $rd:literal, $rs1:literal, $imm:expr) => { unsafe { - asm!(concat!( + core::arch::asm!(concat!( ".insn i {opcode}, {funct3}, ", $rd, ", ", @@ -14,13 +14,22 @@ macro_rules! custom_insn_i { ), opcode = const $opcode, funct3 = const $funct3, imm = const $imm) } }; + ($opcode:expr, $funct3:expr, $x:ident, $rs1:literal, $imm:expr) => { + unsafe { + core::arch::asm!(concat!( + ".insn i {opcode}, {funct3}, {rd}, ", + $rs1, + ", {imm}", + ), opcode = const $opcode, funct3 = const $funct3, rd = out(reg) $x, imm = const $imm) + } + }; } #[macro_export] macro_rules! custom_insn_r { ($opcode:expr, $funct3:expr, $rd:literal, $rs1:literal, $rs2:literal) => { unsafe { - asm!(concat!( + core::arch::asm!(concat!( ".insn r {opcode}, {funct3}, ", $rd, ", ", From fed98b8f11b5f0a45251af447830b468a00c2b71 Mon Sep 17 00:00:00 2001 From: Alexander Golovanov Date: Wed, 30 Oct 2024 14:17:39 +0100 Subject: [PATCH 04/14] Add "read-vec" function --- toolchain/riscv/axvm/src/intrinsics/io.rs | 25 +++++++++++++++++++ .../riscv/examples/hint/program/src/main.rs | 4 +++ .../riscv/platform/src/intrinsics/mod.rs | 11 ++++++++ 3 files changed, 40 insertions(+) diff --git a/toolchain/riscv/axvm/src/intrinsics/io.rs b/toolchain/riscv/axvm/src/intrinsics/io.rs index 7e2b4fa40e..9c4ca21fe8 100644 --- a/toolchain/riscv/axvm/src/intrinsics/io.rs +++ b/toolchain/riscv/axvm/src/intrinsics/io.rs @@ -1,5 +1,7 @@ // use crate::custom_insn_i; +use alloc::vec::Vec; + use axvm_platform::{custom_insn_i, intrinsics::CUSTOM_0}; /// Store the next 4 bytes from the hint stream to [[rd] + imm]_2. @@ -16,3 +18,26 @@ pub fn read_byte() -> u8 { custom_insn_i!(CUSTOM_0, 0b001, x, "x0", 0); x } + +/// Read the next 4 bytes from the hint stream. +pub fn read_u32() -> u32 { + let mut x = 0; + for i in 0..4 { + x |= (read_byte() as u32) << (i * 8); + } + x +} + +/// Read the next `len` bytes from the hint stream into a vector. +pub fn read_vec(len: usize) -> Vec { + let mut vec = Vec::with_capacity(len); + for _ in 0..len { + vec.push(read_byte()); + } + vec +} + +/// Read `size: u32` and then `size` bytes from the hint stream into a vector. +pub fn read_size_and_vec() -> Vec { + read_vec(read_u32() as usize) +} diff --git a/toolchain/riscv/examples/hint/program/src/main.rs b/toolchain/riscv/examples/hint/program/src/main.rs index b5817e2f7e..74a556a9f4 100644 --- a/toolchain/riscv/examples/hint/program/src/main.rs +++ b/toolchain/riscv/examples/hint/program/src/main.rs @@ -8,4 +8,8 @@ pub fn main() { if x == 0 { loop {} } + let vec = axvm::intrinsics::io::read_size_and_vec(); + if vec.iter().sum::() == 0 { + loop {} + } } diff --git a/toolchain/riscv/platform/src/intrinsics/mod.rs b/toolchain/riscv/platform/src/intrinsics/mod.rs index 9a8c44b8f4..3b54568b9f 100644 --- a/toolchain/riscv/platform/src/intrinsics/mod.rs +++ b/toolchain/riscv/platform/src/intrinsics/mod.rs @@ -39,4 +39,15 @@ macro_rules! custom_insn_r { ), opcode = const $opcode, funct3 = const $funct3) } }; + ($opcode:expr, $funct3:expr, $x:ident, $rs1:literal, $rs2:literal) => { + unsafe { + core::arch::asm!(concat!( + ".insn r {opcode}, {funct3}, {rd}, ", + $rs1, + ", ", + $rs2, + ), opcode = const $opcode, funct3 = const $funct3, rd = out(reg) $x) + } + }; + // TODO: implement more variants with like rs1 = in(reg) $y etc } From 8fb16f0c675a1a696d1d00542ca936384d68c650 Mon Sep 17 00:00:00 2001 From: Alexander Golovanov Date: Wed, 30 Oct 2024 14:51:53 +0100 Subject: [PATCH 05/14] Add the new HintInputRv32 phantom instruction, add the corresponding intrinsic, support transpiling it --- toolchain/instructions/src/phantom.rs | 2 ++ toolchain/riscv/axvm/src/intrinsics/io.rs | 27 +++++++++---------- .../riscv/examples/hint/program/src/main.rs | 3 ++- toolchain/riscv/transpiler/src/rrs.rs | 10 +++++-- vm/src/system/phantom/mod.rs | 17 +++++++++--- 5 files changed, 37 insertions(+), 22 deletions(-) diff --git a/toolchain/instructions/src/phantom.rs b/toolchain/instructions/src/phantom.rs index eb4ecf0127..dda16e42e2 100644 --- a/toolchain/instructions/src/phantom.rs +++ b/toolchain/instructions/src/phantom.rs @@ -13,6 +13,8 @@ pub enum PhantomInstruction { PrintF, /// Prepare the next input vector for hinting. HintInput, + /// Prepare the next input vector for hinting, but prepend it with a 4-byte decomposition of its length instead of one field element. + HintInputRv32, /// Prepare the little-endian bit decomposition of a variable for hinting. HintBits, /// Start tracing diff --git a/toolchain/riscv/axvm/src/intrinsics/io.rs b/toolchain/riscv/axvm/src/intrinsics/io.rs index 9c4ca21fe8..996ff7bbbf 100644 --- a/toolchain/riscv/axvm/src/intrinsics/io.rs +++ b/toolchain/riscv/axvm/src/intrinsics/io.rs @@ -7,32 +7,24 @@ use axvm_platform::{custom_insn_i, intrinsics::CUSTOM_0}; /// Store the next 4 bytes from the hint stream to [[rd] + imm]_2. #[macro_export] macro_rules! hint_store_u32 { - ($rd:literal, $imm:expr) => { - unsafe { custom_insn_i!(CUSTOM_0, 0b001, $rd, "x0", $imm) } + ($x:ident, $imm:expr) => { + custom_insn_i!(CUSTOM_0, 0b001, $x, "x0", $imm) }; } -/// Read the next byte from the hint stream. -pub fn read_byte() -> u8 { - let mut x: u8; - custom_insn_i!(CUSTOM_0, 0b001, x, "x0", 0); - x -} - /// Read the next 4 bytes from the hint stream. pub fn read_u32() -> u32 { - let mut x = 0; - for i in 0..4 { - x |= (read_byte() as u32) << (i * 8); - } + let mut x: u32; + custom_insn_i!(CUSTOM_0, 0b001, x, "x0", 0); x } /// Read the next `len` bytes from the hint stream into a vector. pub fn read_vec(len: usize) -> Vec { let mut vec = Vec::with_capacity(len); - for _ in 0..len { - vec.push(read_byte()); + // we probably need to enforce len % 4 == 0 somewhere + for _ in 0..len / 4 { + vec.extend(read_u32().to_le_bytes()); } vec } @@ -41,3 +33,8 @@ pub fn read_vec(len: usize) -> Vec { pub fn read_size_and_vec() -> Vec { read_vec(read_u32() as usize) } + +/// Reset the hint stream with the next hint. +pub fn hint_input() { + custom_insn_i!(CUSTOM_0, 0b011, "x0", "x0", 0); +} diff --git a/toolchain/riscv/examples/hint/program/src/main.rs b/toolchain/riscv/examples/hint/program/src/main.rs index 74a556a9f4..4119a955ba 100644 --- a/toolchain/riscv/examples/hint/program/src/main.rs +++ b/toolchain/riscv/examples/hint/program/src/main.rs @@ -4,7 +4,8 @@ axvm::entry!(main); pub fn main() { - let x = axvm::intrinsics::io::read_byte(); + axvm::intrinsics::io::hint_input(); + let x = axvm::intrinsics::io::read_u32(); if x == 0 { loop {} } diff --git a/toolchain/riscv/transpiler/src/rrs.rs b/toolchain/riscv/transpiler/src/rrs.rs index 1c6622986d..c5e1876a8b 100644 --- a/toolchain/riscv/transpiler/src/rrs.rs +++ b/toolchain/riscv/transpiler/src/rrs.rs @@ -9,8 +9,8 @@ use axvm_circuit::{ rv32im::adapters::RV32_REGISTER_NUM_LIMBS, }; use axvm_instructions::{ - instruction::Instruction, riscv::RvIntrinsic, EccOpcode, Rv32HintStoreOpcode, - Rv32ModularArithmeticOpcode, + instruction::Instruction, riscv::RvIntrinsic, EccOpcode, PhantomInstruction, + Rv32HintStoreOpcode, Rv32ModularArithmeticOpcode, }; use p3_field::PrimeField32; use rrs_lib::{ @@ -265,6 +265,12 @@ fn process_custom_instruction(instruction_u32: u32) -> Instruct 0, )) } + 0b011 => Some(Instruction::phantom( + PhantomInstruction::HintInputRv32, + F::zero(), + F::zero(), + 0, + )), _ => unimplemented!(), }, 0x2b => { diff --git a/vm/src/system/phantom/mod.rs b/vm/src/system/phantom/mod.rs index fcb440ffb0..fe7c12bebc 100644 --- a/vm/src/system/phantom/mod.rs +++ b/vm/src/system/phantom/mod.rs @@ -137,7 +137,7 @@ impl InstructionExecutor for PhantomChip { let value = RefCell::borrow(&self.memory).unsafe_read_cell(addr_space, a); println!("{}", value); } - PhantomInstruction::HintInput => { + PhantomInstruction::HintInput | PhantomInstruction::HintInputRv32 => { let mut streams = self.streams.get().unwrap().lock(); let hint = match streams.input_stream.pop_front() { Some(hint) => hint, @@ -146,9 +146,18 @@ impl InstructionExecutor for PhantomChip { } }; streams.hint_stream.clear(); - streams - .hint_stream - .push_back(F::from_canonical_usize(hint.len())); + if phantom == PhantomInstruction::HintInputRv32 { + streams.hint_stream.extend( + hint.len() + .to_le_bytes() + .iter() + .map(|b| F::from_canonical_u8(*b)), + ); + } else { + streams + .hint_stream + .push_back(F::from_canonical_usize(hint.len())); + } streams.hint_stream.extend(hint); drop(streams); } From f6e132c120b05db01439641aae0562add4fc2d6a Mon Sep 17 00:00:00 2001 From: Alexander Golovanov Date: Wed, 30 Oct 2024 15:05:31 +0100 Subject: [PATCH 06/14] Add a test --- .../data/rv32im-hint-program-elf-release | Bin 0 -> 15200 bytes toolchain/riscv/transpiler/src/tests.rs | 1 + 2 files changed, 1 insertion(+) create mode 100755 toolchain/riscv/transpiler/data/rv32im-hint-program-elf-release diff --git a/toolchain/riscv/transpiler/data/rv32im-hint-program-elf-release b/toolchain/riscv/transpiler/data/rv32im-hint-program-elf-release new file mode 100755 index 0000000000000000000000000000000000000000..46823247746c07d2c9b23dc4acbd5b7e43c74294 GIT binary patch literal 15200 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 Mj?;&hjmxL|zuvwq&j0`b literal 0 HcmV?d00001 diff --git a/toolchain/riscv/transpiler/src/tests.rs b/toolchain/riscv/transpiler/src/tests.rs index 756f57baa6..44e6379f2c 100644 --- a/toolchain/riscv/transpiler/src/tests.rs +++ b/toolchain/riscv/transpiler/src/tests.rs @@ -53,6 +53,7 @@ fn test_decode_elf() -> Result<()> { // riscv64-unknown-elf-gcc supports rv32im if you set -march target #[test_case("data/rv32im-fib-from-as")] #[test_case("data/rv32im-intrin-from-as")] +#[test_case("data/rv32im-hint-program-elf-release")] fn test_generate_program(elf_path: &str) -> Result<()> { let dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); let data = read(dir.join(elf_path))?; From 45826019a533cbb0022f33e74806daf06d41c793 Mon Sep 17 00:00:00 2001 From: Alexander Golovanov Date: Wed, 30 Oct 2024 21:15:39 +0100 Subject: [PATCH 07/14] Optimize reading a vector --- toolchain/riscv/axvm/src/intrinsics/io.rs | 20 +++++++++++++----- .../data/rv32im-hint-program-elf-release | Bin 15200 -> 10904 bytes 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/toolchain/riscv/axvm/src/intrinsics/io.rs b/toolchain/riscv/axvm/src/intrinsics/io.rs index 996ff7bbbf..e85ba9e086 100644 --- a/toolchain/riscv/axvm/src/intrinsics/io.rs +++ b/toolchain/riscv/axvm/src/intrinsics/io.rs @@ -1,6 +1,6 @@ // use crate::custom_insn_i; -use alloc::vec::Vec; +use alloc::{alloc::Layout, vec::Vec}; use axvm_platform::{custom_insn_i, intrinsics::CUSTOM_0}; @@ -21,11 +21,21 @@ pub fn read_u32() -> u32 { /// Read the next `len` bytes from the hint stream into a vector. pub fn read_vec(len: usize) -> Vec { - let mut vec = Vec::with_capacity(len); - // we probably need to enforce len % 4 == 0 somewhere - for _ in 0..len / 4 { - vec.extend(read_u32().to_le_bytes()); + let layout = Layout::from_size_align(len, 4).expect("vec is too large"); + let ptr = unsafe { alloc::alloc::alloc(layout) }; + let mut vec = unsafe { Vec::from_raw_parts(ptr, 0, len) }; + let mut x: u32 = 0; + // Note: if len % 4 != 0, this will discard some last bytes + for i in 0..len { + if i % 4 == 0 { + x = read_u32(); + } + unsafe { + ptr.add(i).write_volatile((x & 255) as u8); + } + x >>= 8; } + unsafe { vec.set_len(len) }; vec } diff --git a/toolchain/riscv/transpiler/data/rv32im-hint-program-elf-release b/toolchain/riscv/transpiler/data/rv32im-hint-program-elf-release index 46823247746c07d2c9b23dc4acbd5b7e43c74294..4dfc72c84edf642dd5c547b8e52630404b1fed84 100755 GIT binary patch literal 10904 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 Mj?;&hjmxL|zuvwq&j0`b From a3785d030bbc369a7360bdcb3deb76334b5def5d Mon Sep 17 00:00:00 2001 From: Alexander Golovanov Date: Thu, 31 Oct 2024 03:05:40 +0100 Subject: [PATCH 08/14] Address comments, add a test, fix transpiler --- toolchain/build/src/lib.rs | 2 +- toolchain/riscv/axvm/src/intrinsics/io.rs | 27 ++++++++++++------- toolchain/riscv/axvm/src/intrinsics/mod.rs | 12 ++++++++- .../riscv/examples/hint/program/src/main.rs | 6 +---- .../riscv/platform/src/intrinsics/mod.rs | 6 ++--- toolchain/riscv/platform/src/lib.rs | 1 - toolchain/riscv/transpiler/src/rrs.rs | 12 ++++----- toolchain/riscv/transpiler/src/tests.rs | 26 +++++++++++++++++- vm/src/system/phantom/mod.rs | 2 +- 9 files changed, 65 insertions(+), 29 deletions(-) diff --git a/toolchain/build/src/lib.rs b/toolchain/build/src/lib.rs index e78531172d..f4c21070c2 100644 --- a/toolchain/build/src/lib.rs +++ b/toolchain/build/src/lib.rs @@ -257,11 +257,11 @@ pub fn build_guest_package

( "--target-dir", target_dir.as_ref().to_str().unwrap(), ]); - tty_println(&format!("cargo command: {:?}", cmd)); if !is_debug() { cmd.args(["--release"]); } + tty_println(&format!("cargo command: {:?}", cmd)); let mut child = cmd .stderr(Stdio::piped()) diff --git a/toolchain/riscv/axvm/src/intrinsics/io.rs b/toolchain/riscv/axvm/src/intrinsics/io.rs index e85ba9e086..fac878e79e 100644 --- a/toolchain/riscv/axvm/src/intrinsics/io.rs +++ b/toolchain/riscv/axvm/src/intrinsics/io.rs @@ -13,21 +13,29 @@ macro_rules! hint_store_u32 { } /// Read the next 4 bytes from the hint stream. +#[allow(asm_sub_register)] pub fn read_u32() -> u32 { - let mut x: u32; - custom_insn_i!(CUSTOM_0, 0b001, x, "x0", 0); - x + let ptr = unsafe { alloc::alloc::alloc(Layout::from_size_align(4, 4).unwrap()) }; + let addr = ptr as u32; + hint_store_u32!(addr, 0); + let result: u32; + unsafe { + core::arch::asm!("lw {rd}, ({rs1})", rd = out(reg) result, rs1 = in(reg) addr); + } + result } /// Read the next `len` bytes from the hint stream into a vector. -pub fn read_vec(len: usize) -> Vec { - let layout = Layout::from_size_align(len, 4).expect("vec is too large"); +fn read_vec_by_len(len: usize) -> Vec { + // Note: this expect message doesn't matter until our panic handler actually cares about it + let layout = Layout::from_size_align((len + 3) / 4 * 4, 4).expect("vec is too large"); let ptr = unsafe { alloc::alloc::alloc(layout) }; - let mut vec = unsafe { Vec::from_raw_parts(ptr, 0, len) }; let mut x: u32 = 0; // Note: if len % 4 != 0, this will discard some last bytes for i in 0..len { if i % 4 == 0 { + // TODO: it probably makes sense not to juggle the data between registers and memory here. + // On the other hand, maybe it's not a big deal. x = read_u32(); } unsafe { @@ -35,13 +43,12 @@ pub fn read_vec(len: usize) -> Vec { } x >>= 8; } - unsafe { vec.set_len(len) }; - vec + unsafe { Vec::from_raw_parts(ptr, len, len) } } /// Read `size: u32` and then `size` bytes from the hint stream into a vector. -pub fn read_size_and_vec() -> Vec { - read_vec(read_u32() as usize) +pub fn read_vec() -> Vec { + read_vec_by_len(read_u32() as usize) } /// Reset the hint stream with the next hint. diff --git a/toolchain/riscv/axvm/src/intrinsics/mod.rs b/toolchain/riscv/axvm/src/intrinsics/mod.rs index cd49b5dba4..3021e4721b 100644 --- a/toolchain/riscv/axvm/src/intrinsics/mod.rs +++ b/toolchain/riscv/axvm/src/intrinsics/mod.rs @@ -1,8 +1,18 @@ //! Functions that call custom instructions that use axVM intrinsic instructions. mod hash; -/// Utilities to work with the hint stream. +/// Library functions for user input/output. pub mod io; pub use hash::*; pub use io::*; + +/// Exit the program with exit code 0. +pub fn exit() { + axvm_platform::rust_rt::terminate::<0>(); +} + +/// Exit the program with exit code 1. +pub fn panic() { + axvm_platform::rust_rt::terminate::<1>(); +} diff --git a/toolchain/riscv/examples/hint/program/src/main.rs b/toolchain/riscv/examples/hint/program/src/main.rs index 4119a955ba..7c20067bfc 100644 --- a/toolchain/riscv/examples/hint/program/src/main.rs +++ b/toolchain/riscv/examples/hint/program/src/main.rs @@ -5,12 +5,8 @@ axvm::entry!(main); pub fn main() { axvm::intrinsics::io::hint_input(); - let x = axvm::intrinsics::io::read_u32(); - if x == 0 { - loop {} - } let vec = axvm::intrinsics::io::read_size_and_vec(); if vec.iter().sum::() == 0 { - loop {} + axvm::intrinsics::panic(); } } diff --git a/toolchain/riscv/platform/src/intrinsics/mod.rs b/toolchain/riscv/platform/src/intrinsics/mod.rs index 3b54568b9f..b264654605 100644 --- a/toolchain/riscv/platform/src/intrinsics/mod.rs +++ b/toolchain/riscv/platform/src/intrinsics/mod.rs @@ -1,5 +1,5 @@ -pub const CUSTOM_0: u32 = 0x0b; -pub const CUSTOM_1: u32 = 0x2b; +pub const CUSTOM_0: u8 = 0x0b; +pub const CUSTOM_1: u8 = 0x2b; #[macro_export] macro_rules! custom_insn_i { @@ -20,7 +20,7 @@ macro_rules! custom_insn_i { ".insn i {opcode}, {funct3}, {rd}, ", $rs1, ", {imm}", - ), opcode = const $opcode, funct3 = const $funct3, rd = out(reg) $x, imm = const $imm) + ), opcode = const $opcode, funct3 = const $funct3, rd = in(reg) $x, imm = const $imm) } }; } diff --git a/toolchain/riscv/platform/src/lib.rs b/toolchain/riscv/platform/src/lib.rs index d26829665c..9f001cf9fe 100644 --- a/toolchain/riscv/platform/src/lib.rs +++ b/toolchain/riscv/platform/src/lib.rs @@ -26,7 +26,6 @@ pub mod memory; // mod getrandom; #[cfg(all(feature = "rust-runtime", target_os = "zkvm"))] pub mod heap; -#[cfg(feature = "rust-runtime")] pub mod intrinsics; #[cfg(all(feature = "export-libm", target_os = "zkvm"))] mod libm_extern; diff --git a/toolchain/riscv/transpiler/src/rrs.rs b/toolchain/riscv/transpiler/src/rrs.rs index 7074e1a972..04e3646bdb 100644 --- a/toolchain/riscv/transpiler/src/rrs.rs +++ b/toolchain/riscv/transpiler/src/rrs.rs @@ -12,6 +12,7 @@ use axvm_instructions::{ instruction::Instruction, riscv::RvIntrinsic, EccOpcode, PhantomInstruction, Rv32HintStoreOpcode, Rv32ModularArithmeticOpcode, }; +use axvm_platform::intrinsics::{CUSTOM_0, CUSTOM_1}; use p3_field::PrimeField32; use rrs_lib::{ instruction_formats::{BType, IType, ITypeShamt, JType, RType, SType, UType}, @@ -246,7 +247,7 @@ fn process_custom_instruction(instruction_u32: u32) -> Instruct let funct3 = ((instruction_u32 >> 12) & 0b111) as u8; // All our instructions are R- or I-type match opcode { - 0x0b => match funct3 { + CUSTOM_0 => match funct3 { 0b000 => { let imm = (instruction_u32 >> 20) & 0xfff; Some(terminate(imm.try_into().expect("exit code must be byte"))) @@ -256,11 +257,11 @@ fn process_custom_instruction(instruction_u32: u32) -> Instruct let imm = (instruction_u32 >> 20) & 0xfff; Some(Instruction::from_isize( Rv32HintStoreOpcode::HINT_STOREW.with_default_offset(), - (RV32_REGISTER_NUM_LIMBS * rd as usize) as isize, 0, + (RV32_REGISTER_NUM_LIMBS * rd as usize) as isize, imm as isize, - 0, - 0, + 1, + 2, )) } 0b011 => Some(Instruction::phantom( @@ -271,7 +272,7 @@ fn process_custom_instruction(instruction_u32: u32) -> Instruct )), _ => unimplemented!(), }, - 0x2b => { + CUSTOM_1 => { match funct3 { Rv32ModularArithmeticOpcode::FUNCT3 => { // mod operations @@ -324,7 +325,6 @@ pub(crate) fn transpile(instructions_u32: &[u32]) -> Vec(PhantomData); for instruction_u32 in instructions_u32 { - // TODO: we probably want to forbid such instructions, but for now we just skip them assert!(*instruction_u32 != 115, "ecall is not supported"); let instruction = process_instruction(&mut transpiler, *instruction_u32) .unwrap_or_else(|| process_custom_instruction(*instruction_u32)); diff --git a/toolchain/riscv/transpiler/src/tests.rs b/toolchain/riscv/transpiler/src/tests.rs index 44e6379f2c..52f3dcd675 100644 --- a/toolchain/riscv/transpiler/src/tests.rs +++ b/toolchain/riscv/transpiler/src/tests.rs @@ -12,6 +12,7 @@ use axvm_circuit::{ use axvm_platform::memory::MEM_SIZE; use eyre::Result; use p3_baby_bear::BabyBear; +use p3_field::AbstractField; use tempfile::tempdir; use test_case::test_case; @@ -53,7 +54,6 @@ fn test_decode_elf() -> Result<()> { // riscv64-unknown-elf-gcc supports rv32im if you set -march target #[test_case("data/rv32im-fib-from-as")] #[test_case("data/rv32im-intrin-from-as")] -#[test_case("data/rv32im-hint-program-elf-release")] fn test_generate_program(elf_path: &str) -> Result<()> { let dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); let data = read(dir.join(elf_path))?; @@ -92,6 +92,30 @@ fn test_rv32i_prove(examples_path: &str, min_segments: usize) -> Result<()> { Ok(()) } +#[test] +fn test_rv32i_prove_with_hint() -> Result<()> { + let pkg = get_package(get_examples_dir().join("hint/program")); + let target_dir = tempdir()?; + let guest_opts = GuestOptions::default().into(); + build_guest_package(&pkg, &target_dir, &guest_opts, None); + let elf_path = guest_methods(&pkg, &target_dir, &[]).pop().unwrap(); + let config = VmConfig { + max_segment_len: (1 << 18) - 1, + ..VmConfig::rv32i() + }; + let (_, exe) = setup_executor_from_elf(elf_path, config.clone())?; + air_test_with_min_segments( + config, + exe, + vec![[1, 0, 0, 0] + .iter() + .map(|x| F::from_canonical_u32(*x)) + .collect()], + 1, + ); + Ok(()) +} + #[test_case("data/rv32im-intrin-from-as")] fn test_intrinsic_runtime(elf_path: &str) -> Result<()> { setup_tracing(); diff --git a/vm/src/system/phantom/mod.rs b/vm/src/system/phantom/mod.rs index fe7c12bebc..462a433cf7 100644 --- a/vm/src/system/phantom/mod.rs +++ b/vm/src/system/phantom/mod.rs @@ -148,7 +148,7 @@ impl InstructionExecutor for PhantomChip { streams.hint_stream.clear(); if phantom == PhantomInstruction::HintInputRv32 { streams.hint_stream.extend( - hint.len() + (hint.len() as u32) .to_le_bytes() .iter() .map(|b| F::from_canonical_u8(*b)), From 2b448236a1520593de99efa83a4e3347243e5803 Mon Sep 17 00:00:00 2001 From: Alexander Golovanov Date: Thu, 31 Oct 2024 03:11:40 +0100 Subject: [PATCH 09/14] Fix rust-v hint program --- .../riscv/examples/hint/program/src/main.rs | 2 +- .../data/rv32im-hint-program-elf-release | Bin 10904 -> 0 bytes 2 files changed, 1 insertion(+), 1 deletion(-) delete mode 100755 toolchain/riscv/transpiler/data/rv32im-hint-program-elf-release diff --git a/toolchain/riscv/examples/hint/program/src/main.rs b/toolchain/riscv/examples/hint/program/src/main.rs index 7c20067bfc..a4fc14da55 100644 --- a/toolchain/riscv/examples/hint/program/src/main.rs +++ b/toolchain/riscv/examples/hint/program/src/main.rs @@ -5,7 +5,7 @@ axvm::entry!(main); pub fn main() { axvm::intrinsics::io::hint_input(); - let vec = axvm::intrinsics::io::read_size_and_vec(); + let vec = axvm::intrinsics::io::read_vec(); if vec.iter().sum::() == 0 { axvm::intrinsics::panic(); } diff --git a/toolchain/riscv/transpiler/data/rv32im-hint-program-elf-release b/toolchain/riscv/transpiler/data/rv32im-hint-program-elf-release deleted file mode 100755 index 4dfc72c84edf642dd5c547b8e52630404b1fed84..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10904 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 Date: Wed, 30 Oct 2024 20:17:59 -0700 Subject: [PATCH 10/14] chore: mv exit,panic to process --- toolchain/riscv/axvm/src/intrinsics/mod.rs | 10 ---------- toolchain/riscv/axvm/src/lib.rs | 1 + toolchain/riscv/axvm/src/process.rs | 11 +++++++++++ toolchain/riscv/examples/hint/program/src/main.rs | 2 +- 4 files changed, 13 insertions(+), 11 deletions(-) create mode 100644 toolchain/riscv/axvm/src/process.rs diff --git a/toolchain/riscv/axvm/src/intrinsics/mod.rs b/toolchain/riscv/axvm/src/intrinsics/mod.rs index 3021e4721b..0dabfe4216 100644 --- a/toolchain/riscv/axvm/src/intrinsics/mod.rs +++ b/toolchain/riscv/axvm/src/intrinsics/mod.rs @@ -6,13 +6,3 @@ pub mod io; pub use hash::*; pub use io::*; - -/// Exit the program with exit code 0. -pub fn exit() { - axvm_platform::rust_rt::terminate::<0>(); -} - -/// Exit the program with exit code 1. -pub fn panic() { - axvm_platform::rust_rt::terminate::<1>(); -} diff --git a/toolchain/riscv/axvm/src/lib.rs b/toolchain/riscv/axvm/src/lib.rs index 3f1d66e032..29785ac39f 100644 --- a/toolchain/riscv/axvm/src/lib.rs +++ b/toolchain/riscv/axvm/src/lib.rs @@ -85,6 +85,7 @@ extern crate alloc; pub mod env; pub mod intrinsics; +pub mod process; pub mod serde; #[cfg(target_os = "zkvm")] diff --git a/toolchain/riscv/axvm/src/process.rs b/toolchain/riscv/axvm/src/process.rs new file mode 100644 index 0000000000..bb98b32ca4 --- /dev/null +++ b/toolchain/riscv/axvm/src/process.rs @@ -0,0 +1,11 @@ +//! System exit and panic functions. + +/// Exit the program with exit code 0. +pub fn exit() { + axvm_platform::rust_rt::terminate::<0>(); +} + +/// Exit the program with exit code 1. +pub fn panic() { + axvm_platform::rust_rt::terminate::<1>(); +} diff --git a/toolchain/riscv/examples/hint/program/src/main.rs b/toolchain/riscv/examples/hint/program/src/main.rs index a4fc14da55..1e4a03bcba 100644 --- a/toolchain/riscv/examples/hint/program/src/main.rs +++ b/toolchain/riscv/examples/hint/program/src/main.rs @@ -7,6 +7,6 @@ pub fn main() { axvm::intrinsics::io::hint_input(); let vec = axvm::intrinsics::io::read_vec(); if vec.iter().sum::() == 0 { - axvm::intrinsics::panic(); + axvm::process::panic(); } } From 895ace551e52ed4b019cacc4ed5eb35dfd557026 Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Wed, 30 Oct 2024 21:41:21 -0700 Subject: [PATCH 11/14] feat: make `read_vec` more optimal --- toolchain/riscv/axvm/src/env/mod.rs | 83 ------------------- toolchain/riscv/axvm/src/intrinsics/io.rs | 44 +--------- toolchain/riscv/axvm/src/io.rs | 46 ++++++++++ toolchain/riscv/axvm/src/lib.rs | 81 +----------------- .../riscv/examples/hint/program/src/main.rs | 9 +- toolchain/riscv/transpiler/src/tests.rs | 5 +- 6 files changed, 57 insertions(+), 211 deletions(-) delete mode 100644 toolchain/riscv/axvm/src/env/mod.rs create mode 100644 toolchain/riscv/axvm/src/io.rs diff --git a/toolchain/riscv/axvm/src/env/mod.rs b/toolchain/riscv/axvm/src/env/mod.rs deleted file mode 100644 index 96a2206a22..0000000000 --- a/toolchain/riscv/axvm/src/env/mod.rs +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2024 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. - -//! Functions for interacting with the host environment. -//! -//! The zkVM provides a set of functions to perform operations that manage -//! execution, I/O, and proof composition. The set of functions related to each -//! of these operations are described below. -//! -//! ## System State -//! -//! The guest has some control over the execution of the zkVM by pausing or -//! exiting the program explicitly. This can be achieved using the [pause] and -//! [exit] functions. -//! -//! ## Proof Verification -//! -//! The zkVM supports verification of RISC Zero [receipts] in a guest program, -//! enabling [proof composition]. This can be achieved using the [verify()] and -//! [verify_integrity] functions. -//! -//! ## Input and Output -//! -//! The zkVM provides a set of functions for handling input, public output, and -//! private output. This is useful when interacting with the host and committing -//! to some data publicly. -//! -//! The zkVM provides functions that automatically perform (de)serialization on -//! types and, for performance reasons, there is also a `_slice` variant that -//! works with raw slices of plain old data. Performing operations on slices is -//! more efficient, saving cycles during execution and consequently producing -//! smaller proofs that are faster to produce. However, the `_slice` variants -//! can be less ergonomic, so consider trade-offs when choosing between the two. -//! For more information about guest optimization, see RISC Zero's [instruction -//! on guest optimization][guest-optimization] -//! -//! Convenience functions to read and write to default file descriptors are -//! provided. See [read()], [write()], [self::commit] (and their `_slice` -//! variants) for more information. -//! -//! In order to access default file descriptors directly, see [stdin], [stdout], -//! [stderr] and [journal]. These file descriptors are either [FdReader] or -//! [FdWriter] instances, which can be used to read from or write to the host. -//! To read from or write into them, use the [Read] and [Write] traits. -//! -//! WARNING: Specifying a file descriptor with the same value of a default file -//! descriptor is not recommended and may lead to unexpected behavior. A list of -//! default file descriptors can be found in the [fileno] module. -//! -//! ## Utility -//! -//! The zkVM provides utility functions to log messages to the debug console and -//! to measure the number of processor cycles that have occurred since the guest -//! began. These can be achieved using the [log] and [cycle_count] functions. -//! -//! [receipts]: crate::Receipt -//! [proof composition]:https://www.risczero.com/blog/proof-composition -//! [guest-optimization]: -//! https://dev.risczero.com/api/zkvm/optimization#when-reading-data-as-raw-bytes-use-envread_slice - -extern crate alloc; - -use axvm_platform; - -/// Terminate execution of the zkVM. -/// -/// Use an exit code of 0 to indicate success, and non-zero to indicate an error. -#[inline(always)] -pub fn exit() -> ! { - axvm_platform::rust_rt::terminate::(); - unreachable!(); -} diff --git a/toolchain/riscv/axvm/src/intrinsics/io.rs b/toolchain/riscv/axvm/src/intrinsics/io.rs index fac878e79e..bc22275a8d 100644 --- a/toolchain/riscv/axvm/src/intrinsics/io.rs +++ b/toolchain/riscv/axvm/src/intrinsics/io.rs @@ -1,57 +1,17 @@ // use crate::custom_insn_i; -use alloc::{alloc::Layout, vec::Vec}; - use axvm_platform::{custom_insn_i, intrinsics::CUSTOM_0}; /// Store the next 4 bytes from the hint stream to [[rd] + imm]_2. #[macro_export] macro_rules! hint_store_u32 { ($x:ident, $imm:expr) => { - custom_insn_i!(CUSTOM_0, 0b001, $x, "x0", $imm) + axvm_platform::custom_insn_i!(axvm_platform::intrinsics::CUSTOM_0, 0b001, $x, "x0", $imm) }; } -/// Read the next 4 bytes from the hint stream. -#[allow(asm_sub_register)] -pub fn read_u32() -> u32 { - let ptr = unsafe { alloc::alloc::alloc(Layout::from_size_align(4, 4).unwrap()) }; - let addr = ptr as u32; - hint_store_u32!(addr, 0); - let result: u32; - unsafe { - core::arch::asm!("lw {rd}, ({rs1})", rd = out(reg) result, rs1 = in(reg) addr); - } - result -} - -/// Read the next `len` bytes from the hint stream into a vector. -fn read_vec_by_len(len: usize) -> Vec { - // Note: this expect message doesn't matter until our panic handler actually cares about it - let layout = Layout::from_size_align((len + 3) / 4 * 4, 4).expect("vec is too large"); - let ptr = unsafe { alloc::alloc::alloc(layout) }; - let mut x: u32 = 0; - // Note: if len % 4 != 0, this will discard some last bytes - for i in 0..len { - if i % 4 == 0 { - // TODO: it probably makes sense not to juggle the data between registers and memory here. - // On the other hand, maybe it's not a big deal. - x = read_u32(); - } - unsafe { - ptr.add(i).write_volatile((x & 255) as u8); - } - x >>= 8; - } - unsafe { Vec::from_raw_parts(ptr, len, len) } -} - -/// Read `size: u32` and then `size` bytes from the hint stream into a vector. -pub fn read_vec() -> Vec { - read_vec_by_len(read_u32() as usize) -} - /// Reset the hint stream with the next hint. +#[inline(always)] pub fn hint_input() { custom_insn_i!(CUSTOM_0, 0b011, "x0", "x0", 0); } diff --git a/toolchain/riscv/axvm/src/io.rs b/toolchain/riscv/axvm/src/io.rs new file mode 100644 index 0000000000..be3f0812df --- /dev/null +++ b/toolchain/riscv/axvm/src/io.rs @@ -0,0 +1,46 @@ +//! User IO functions + +use alloc::vec::Vec; +use core::alloc::Layout; + +use crate::{hint_store_u32, intrinsics::hint_input}; + +/// Read `size: u32` and then `size` bytes from the hint stream into a vector. +pub fn read_vec() -> Vec { + hint_input(); + read_vec_by_len(read_u32() as usize) +} + +/// Read the next 4 bytes from the hint stream into a register. +/// Because [hint_store_u32] stores a word to memory, this function first reads to memory and then +/// loads from memory to register. +#[inline(always)] +#[allow(asm_sub_register)] +pub fn read_u32() -> u32 { + let ptr = unsafe { alloc::alloc::alloc(Layout::from_size_align(4, 4).unwrap()) }; + let addr = ptr as u32; + hint_store_u32!(addr, 0); + let result: u32; + unsafe { + core::arch::asm!("lw {rd}, ({rs1})", rd = out(reg) result, rs1 = in(reg) addr); + } + result +} + +/// Read the next `len` bytes from the hint stream into a vector. +fn read_vec_by_len(len: usize) -> Vec { + let num_words = (len + 3) / 4; + let capacity = num_words * 4; + // Allocate a buffer of the required length that is 4 byte aligned + // Note: this expect message doesn't matter until our panic handler actually cares about it + let layout = Layout::from_size_align(capacity, 4).expect("vec is too large"); + // SAFETY: We populate a `Vec` by hintstore-ing `num_words` 4 byte words. We set the length to `len` and don't care about the extra `capacity - len` bytes stored. + let mut ptr = unsafe { alloc::alloc::alloc(layout) }; + + // Note: if len % 4 != 0, this will discard some last bytes + for _ in 0..num_words { + hint_store_u32!(ptr, 0); + ptr = unsafe { ptr.add(4) }; + } + unsafe { Vec::from_raw_parts(ptr, len, capacity) } +} diff --git a/toolchain/riscv/axvm/src/lib.rs b/toolchain/riscv/axvm/src/lib.rs index 29785ac39f..cc1f3ae578 100644 --- a/toolchain/riscv/axvm/src/lib.rs +++ b/toolchain/riscv/axvm/src/lib.rs @@ -1,79 +1,4 @@ -// Copyright 2024 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. - -//! The RISC Zero zkVM's guest-side RISC-V API. -//! -//! Code that is validated by the [RISC Zero zkVM](crate) is run inside the guest. In almost all -//! practical cases, the guest will want to read private input data from the host and write public -//! data to the journal. This can be done with [env::read] and [env::commit], respectively; -//! additional I/O functionality is also available in [mod@env]. -//! -//! ## Installation -//! -//! To build and run RISC Zero zkVM code, you will need to install the RISC Zero -//! toolchain, which can be done using the rzup utility: -//! -//! ```sh -//! curl -L https://risczero.com/install | bash -//! rzup install -//! ``` -//! -//! ## Example -//! -//! The following guest code[^starter-ex] proves a number is -//! composite by multiplying two unsigned integers, and panicking if either is -//! `1` or if the multiplication overflows: -//! -//! ```ignore -//! #![no_main] -//! #![no_std] -//! -//! use risc0_zkvm::guest::env; -//! -//! risc0_zkvm::guest::entry!(main); -//! -//! fn main() { -//! // Load the first number from the host -//! let a: u64 = env::read(); -//! // Load the second number from the host -//! let b: u64 = env::read(); -//! // Verify that neither of them are 1 (i.e. nontrivial factors) -//! if a == 1 || b == 1 { -//! panic!("Trivial factors") -//! } -//! // Compute the product while being careful with integer overflow -//! let product = a.checked_mul(b).expect("Integer overflow"); -//! env::commit(&product); -//! } -//! ``` -//! -//! Notice how [env::read] is used to load the two factors, and [env::commit] is used to make their -//! composite product publicly available. All input an output of your guest is private except for -//! what is written to the journal with [env::commit]. -//! -//! By default, the guest only has the Rust `core` libraries and not `std`. A partial -//! implementation of the Rust standard libraries can be enabled with the `std` feature on this [crate]. -//! When this feature is not enabled, the lines including `#![no_std]` and `#![no_main]` are -//! required, as well as the use of the [crate::guest::entry] macro. When `std` is enabled, these -//! three lines can be omitted and many features of `std` can be used. -//! -//! If you encounter problems building zkVM guest code, you can see if we have a -//! known workaround for your issue by looking in our -//! [rust guest workarounds](https://github.com/risc0/risc0/issues?q=is%3Aissue+is%3Aopen+label%3A%22rust+guest+workarounds%22) -//! tag on GitHub. -//! -//! [^starter-ex]: The example is based on the [Factors example](https://github.com/risc0/risc0/tree/main/examples/factors). +//! # axVM #![cfg_attr(not(feature = "std"), no_std)] #![deny(rustdoc::broken_intra_doc_links)] @@ -83,8 +8,8 @@ extern crate alloc; -pub mod env; pub mod intrinsics; +pub mod io; pub mod process; pub mod serde; @@ -167,7 +92,7 @@ unsafe extern "C" fn __start() -> ! { main() } - env::exit::<0>(); + process::exit(); } #[cfg(target_os = "zkvm")] diff --git a/toolchain/riscv/examples/hint/program/src/main.rs b/toolchain/riscv/examples/hint/program/src/main.rs index 1e4a03bcba..2d81520fd1 100644 --- a/toolchain/riscv/examples/hint/program/src/main.rs +++ b/toolchain/riscv/examples/hint/program/src/main.rs @@ -1,12 +1,13 @@ #![no_main] #![no_std] +use axvm::intrinsics::io::read_vec; axvm::entry!(main); pub fn main() { - axvm::intrinsics::io::hint_input(); - let vec = axvm::intrinsics::io::read_vec(); - if vec.iter().sum::() == 0 { - axvm::process::panic(); + let vec = read_vec(); + assert_eq!(vec.len(), 4); + for i in 0..4 { + assert_eq!(vec[i], i as u8); } } diff --git a/toolchain/riscv/transpiler/src/tests.rs b/toolchain/riscv/transpiler/src/tests.rs index 52f3dcd675..88e4c59856 100644 --- a/toolchain/riscv/transpiler/src/tests.rs +++ b/toolchain/riscv/transpiler/src/tests.rs @@ -107,10 +107,7 @@ fn test_rv32i_prove_with_hint() -> Result<()> { air_test_with_min_segments( config, exe, - vec![[1, 0, 0, 0] - .iter() - .map(|x| F::from_canonical_u32(*x)) - .collect()], + vec![[0, 1, 2, 3].map(F::from_canonical_u32).to_vec()], 1, ); Ok(()) From 963dee7b4146c70f7bc07e506a68817517b2a2b7 Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Wed, 30 Oct 2024 21:48:00 -0700 Subject: [PATCH 12/14] fix: () vs ! --- toolchain/riscv/axvm/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/toolchain/riscv/axvm/src/lib.rs b/toolchain/riscv/axvm/src/lib.rs index cc1f3ae578..b6f92504d9 100644 --- a/toolchain/riscv/axvm/src/lib.rs +++ b/toolchain/riscv/axvm/src/lib.rs @@ -93,6 +93,7 @@ unsafe extern "C" fn __start() -> ! { } process::exit(); + unreachable!() } #[cfg(target_os = "zkvm")] From a47f3c920ec2e8ffec459b0566bcbd5aa58ea79c Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Wed, 30 Oct 2024 21:58:50 -0700 Subject: [PATCH 13/14] fix import --- toolchain/riscv/examples/hint/program/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolchain/riscv/examples/hint/program/src/main.rs b/toolchain/riscv/examples/hint/program/src/main.rs index 2d81520fd1..b2ca6ac68e 100644 --- a/toolchain/riscv/examples/hint/program/src/main.rs +++ b/toolchain/riscv/examples/hint/program/src/main.rs @@ -1,6 +1,6 @@ #![no_main] #![no_std] -use axvm::intrinsics::io::read_vec; +use axvm::io::read_vec; axvm::entry!(main); From 869aa21a583c79242a6c1d46e4d9b8ae09b9c2ff Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Wed, 30 Oct 2024 22:16:48 -0700 Subject: [PATCH 14/14] fix: ptr was not ptr_start --- toolchain/riscv/axvm/src/io.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/toolchain/riscv/axvm/src/io.rs b/toolchain/riscv/axvm/src/io.rs index be3f0812df..24d33485f6 100644 --- a/toolchain/riscv/axvm/src/io.rs +++ b/toolchain/riscv/axvm/src/io.rs @@ -35,12 +35,13 @@ fn read_vec_by_len(len: usize) -> Vec { // Note: this expect message doesn't matter until our panic handler actually cares about it let layout = Layout::from_size_align(capacity, 4).expect("vec is too large"); // SAFETY: We populate a `Vec` by hintstore-ing `num_words` 4 byte words. We set the length to `len` and don't care about the extra `capacity - len` bytes stored. - let mut ptr = unsafe { alloc::alloc::alloc(layout) }; + let ptr_start = unsafe { alloc::alloc::alloc(layout) }; + let mut ptr = ptr_start; // Note: if len % 4 != 0, this will discard some last bytes for _ in 0..num_words { hint_store_u32!(ptr, 0); ptr = unsafe { ptr.add(4) }; } - unsafe { Vec::from_raw_parts(ptr, len, capacity) } + unsafe { Vec::from_raw_parts(ptr_start, len, capacity) } }