Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: intrinsic for reveal #745

Merged
merged 7 commits into from
Nov 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions docs/specs/vm/ISA.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,9 +185,9 @@ All load/store instructions always do block accesses of block size `4`, even for
| LOADW_RV32 | `a,b,c,1,e` | `[a:4]_1 = [r32{c}(b):4]_e` |
| LOADBU_RV32 | `a,b,c,1,e` | `[a:4]_1 = zero_extend([r32{c}(b):1]_e)` Must zero-extend the number read from memory. |
| LOADHU_RV32 | `a,b,c,1,e` | `[a:4]_1 = zero_extend([r32{c}(b):2]_e)` Must zero-extend the number read from memory. |
| STOREB_RV32 | `a,b,c,1,e` | `[r32{c}(b):1]_e <- [b:1]_1` |
| STOREH_RV32 | `a,b,c,1,e` | `[r32{c}(b):2]_e <- [b:2]_1` |
| STOREW_RV32 | `a,b,c,1,e` | `[r32{c}(b):4]_e <- [b:4]_1` |
| STOREB_RV32 | `a,b,c,1,e` | `[r32{c}(b):1]_e <- [a:1]_1` |
| STOREH_RV32 | `a,b,c,1,e` | `[r32{c}(b):2]_e <- [a:2]_1` |
| STOREW_RV32 | `a,b,c,1,e` | `[r32{c}(b):4]_e <- [a:4]_1` |

### Branch/Jump/Upper Immediate

Expand Down
62 changes: 31 additions & 31 deletions docs/specs/vm/RISCV.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,34 +153,34 @@ The transpilation will only be valid for programs where:

## Custom Instruction Transpilation

| RISC-V Inst | axVM Instruction |
| -------------- | ------------------------------------------------------------- |
| terminate | TERMINATE `_, _, utof(imm)` |
| hintstorew | HINTSTOREW_RV32 `0, ind(rd), utof(sign_extend_16(imm)), 1, 2` |
| reveal | REVEAL_RV32 `0, ind(rd), utof(sign_extend_16(imm)), 1, 3` |
| hintinput | PHANTOM `_, _, HintInput as u16` |
| keccak256 | KECCAK256_RV32 `ind(rd), ind(rs1), ind(rs2), 1, 2` |
| add256 | ADD256_RV32 `ind(rd), ind(rs1), ind(rs2), 1, 2` |
| sub256 | SUB256_RV32 `ind(rd), ind(rs1), ind(rs2), 1, 2` |
| xor256 | XOR256_RV32 `ind(rd), ind(rs1), ind(rs2), 1, 2` |
| or256 | OR256_RV32 `ind(rd), ind(rs1), ind(rs2), 1, 2` |
| and256 | AND256_RV32 `ind(rd), ind(rs1), ind(rs2), 1, 2` |
| sll256 | SLL256_RV32 `ind(rd), ind(rs1), ind(rs2), 1, 2` |
| srl256 | SRL256_RV32 `ind(rd), ind(rs1), ind(rs2), 1, 2` |
| sra256 | SRA256_RV32 `ind(rd), ind(rs1), ind(rs2), 1, 2` |
| slt256 | SLT256_RV32 `ind(rd), ind(rs1), ind(rs2), 1, 2` |
| sltu256 | SLTU256_RV32 `ind(rd), ind(rs1), ind(rs2), 1, 2` |
| beq256 | BEQ256_RV32 `ind(rs1), ind(rs2), itof(imm), 1, 2` |
| bne256 | BNE256_RV32 `ind(rs1), ind(rs2), itof(imm), 1, 2` |
| blt256 | BLT256_RV32 `ind(rs1), ind(rs2), itof(imm), 1, 2` |
| bge256 | BGE256_RV32 `ind(rs1), ind(rs2), itof(imm), 1, 2` |
| bltu256 | BLTU256_RV32 `ind(rs1), ind(rs2), itof(imm), 1, 2` |
| bgeu256 | BGEU256_RV32 `ind(rs1), ind(rs2), itof(imm), 1, 2` |
| mul256 | MUL256_RV32 `ind(rd), ind(rs1), ind(rs2), 1, 2` |
| addmod\<N\> | ADDMOD_RV32\<N\> `ind(rd), ind(rs1), ind(rs2), 1, 2` |
| submod\<N\> | SUBMOD_RV32\<N\> `ind(rd), ind(rs1), ind(rs2), 1, 2` |
| mulmod\<N\> | MULMOD_RV32\<N\> `ind(rd), ind(rs1), ind(rs2), 1, 2` |
| divmod\<N\> | DIVMOD_RV32\<N\> `ind(rd), ind(rs1), ind(rs2), 1, 2` |
| iseqmod\<N\> | ISEQMOD_RV32\<N\> `ind(rd), ind(rs1), ind(rs2), 1, 2` |
| sw_add_ne\<C\> | SW_ADD_NE_RV32\<C\> `ind(rd), ind(rs1), ind(rs2), 1, 2` |
| sw_double\<C\> | SW_DOUBLE_RV32\<C\> `ind(rd), ind(rs1), 0, 1, 2` |
| RISC-V Inst | axVM Instruction |
| -------------- | ---------------------------------------------------------------- |
| terminate | TERMINATE `_, _, utof(imm)` |
| hintstorew | HINTSTOREW_RV32 `0, ind(rd), utof(sign_extend_16(imm)), 1, 2` |
| reveal | REVEAL_RV32 `ind(rs1), ind(rd), utof(sign_extend_16(imm)), 1, 3` |
| hintinput | PHANTOM `_, _, HintInput as u16` |
| keccak256 | KECCAK256_RV32 `ind(rd), ind(rs1), ind(rs2), 1, 2` |
| add256 | ADD256_RV32 `ind(rd), ind(rs1), ind(rs2), 1, 2` |
| sub256 | SUB256_RV32 `ind(rd), ind(rs1), ind(rs2), 1, 2` |
| xor256 | XOR256_RV32 `ind(rd), ind(rs1), ind(rs2), 1, 2` |
| or256 | OR256_RV32 `ind(rd), ind(rs1), ind(rs2), 1, 2` |
| and256 | AND256_RV32 `ind(rd), ind(rs1), ind(rs2), 1, 2` |
| sll256 | SLL256_RV32 `ind(rd), ind(rs1), ind(rs2), 1, 2` |
| srl256 | SRL256_RV32 `ind(rd), ind(rs1), ind(rs2), 1, 2` |
| sra256 | SRA256_RV32 `ind(rd), ind(rs1), ind(rs2), 1, 2` |
| slt256 | SLT256_RV32 `ind(rd), ind(rs1), ind(rs2), 1, 2` |
| sltu256 | SLTU256_RV32 `ind(rd), ind(rs1), ind(rs2), 1, 2` |
| beq256 | BEQ256_RV32 `ind(rs1), ind(rs2), itof(imm), 1, 2` |
| bne256 | BNE256_RV32 `ind(rs1), ind(rs2), itof(imm), 1, 2` |
| blt256 | BLT256_RV32 `ind(rs1), ind(rs2), itof(imm), 1, 2` |
| bge256 | BGE256_RV32 `ind(rs1), ind(rs2), itof(imm), 1, 2` |
| bltu256 | BLTU256_RV32 `ind(rs1), ind(rs2), itof(imm), 1, 2` |
| bgeu256 | BGEU256_RV32 `ind(rs1), ind(rs2), itof(imm), 1, 2` |
| mul256 | MUL256_RV32 `ind(rd), ind(rs1), ind(rs2), 1, 2` |
| addmod\<N\> | ADDMOD_RV32\<N\> `ind(rd), ind(rs1), ind(rs2), 1, 2` |
| submod\<N\> | SUBMOD_RV32\<N\> `ind(rd), ind(rs1), ind(rs2), 1, 2` |
| mulmod\<N\> | MULMOD_RV32\<N\> `ind(rd), ind(rs1), ind(rs2), 1, 2` |
| divmod\<N\> | DIVMOD_RV32\<N\> `ind(rd), ind(rs1), ind(rs2), 1, 2` |
| iseqmod\<N\> | ISEQMOD_RV32\<N\> `ind(rd), ind(rs1), ind(rs2), 1, 2` |
| sw_add_ne\<C\> | SW_ADD_NE_RV32\<C\> `ind(rd), ind(rs1), ind(rs2), 1, 2` |
| sw_double\<C\> | SW_DOUBLE_RV32\<C\> `ind(rd), ind(rs1), 0, 1, 2` |
23 changes: 0 additions & 23 deletions toolchain/instructions/src/riscv.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,3 @@
use crate::{EccOpcode, Rv32ModularArithmeticOpcode};

/// 32-bit register stored as 4 bytes (4 limbs of 8-bits) in axVM memory.
pub const RV32_REGISTER_NUM_LIMBS: usize = 4;
pub const RV32_CELL_BITS: usize = 8;

/// The 7-bit opcode prefix for a 32-bit RISC-V instruction.
#[repr(u8)]
pub enum RvOpcodePrefix {
Custom0 = 0b0001011,
Custom1 = 0b0101011,
}

/// Trait to implement on opcode class enum to specify custom 32-bit RISC-V instruction definition.
pub trait RvIntrinsic {
/// The 3-bit funct3 field to use in custom intrinsic 32-bit RISC-V instructions.
const FUNCT3: u8;
}

impl RvIntrinsic for Rv32ModularArithmeticOpcode {
const FUNCT3: u8 = 0b000;
}

impl RvIntrinsic for EccOpcode {
const FUNCT3: u8 = 0b001;
}
15 changes: 15 additions & 0 deletions toolchain/riscv/axvm/src/intrinsics/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,18 @@ pub fn hint_input() {
#[cfg(not(target_os = "zkvm"))]
todo!()
}

/// Store rs1 to [[rd] + imm]_2.
#[cfg(target_os = "zkvm")]
#[macro_export]
macro_rules! reveal {
($rd:ident, $rs1:ident, $imm:expr) => {
axvm_platform::custom_insn_i!(
axvm_platform::constants::CUSTOM_0,
axvm_platform::constants::Custom0Funct3::Reveal as u8,
$rd,
$rs1,
$imm
)
};
}
2 changes: 1 addition & 1 deletion toolchain/riscv/axvm/src/intrinsics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

mod hash;
/// Library functions for user input/output.
pub mod io;
mod io;

pub use hash::*;
pub use io::*;
9 changes: 9 additions & 0 deletions toolchain/riscv/axvm/src/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,12 @@ fn read_vec_by_len(len: usize) -> Vec<u8> {
}
unsafe { Vec::from_raw_parts(ptr_start, len, capacity) }
}

/// Publish `x` as the `index`-th u32 output.
pub fn reveal(x: u32, index: usize) {
let byte_index = (index * 4) as u32;
#[cfg(target_os = "zkvm")]
crate::reveal!(byte_index, x, 0);
#[cfg(not(target_os = "zkvm"))]
todo!()
}
8 changes: 8 additions & 0 deletions toolchain/riscv/examples/reveal/program/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[workspace]
[package]
version = "0.1.0"
name = "axvm-hint-program"
edition = "2021"

[dependencies]
axvm = { path = "../../../axvm" }
12 changes: 12 additions & 0 deletions toolchain/riscv/examples/reveal/program/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#![no_main]
#![no_std]
use axvm::io::reveal;

axvm::entry!(main);

pub fn main() {
let x: u32 = core::hint::black_box(123);
let y: u32 = core::hint::black_box(456);
reveal(x, 0);
reveal(y, 2);
}
1 change: 1 addition & 0 deletions toolchain/riscv/platform/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ repository = { workspace = true }

[dependencies]
stability = "0.2"
strum_macros.workspace = true

# This crate should have as few dependencies as possible so it can be
# used as many places as possible to share the platform definitions.
Expand Down
4 changes: 2 additions & 2 deletions toolchain/riscv/platform/README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
Platform definitions for the RISC Zero zkVM, including IO port addresses,
memory regions, and low-level runtime functions.
Platform definitions for axVM, including memory regions, low-level runtime functions, custom instruction constants, and assembly macros.
This crate is intended to be lightweight and imported both when the target is axVM and when it is a normal host machine.
12 changes: 7 additions & 5 deletions toolchain/riscv/platform/src/constants.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use strum_macros::FromRepr;

pub const CUSTOM_0: u8 = 0x0b;
pub const CUSTOM_1: u8 = 0x2b;

/// Different funct3 for custom RISC-V instructions using the [CUSTOM_0] 7-bit opcode prefix.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, FromRepr)]
#[repr(u8)]
pub enum Custom0Funct3 {
Terminate = 0,
Expand All @@ -14,15 +16,15 @@ pub enum Custom0Funct3 {
}

/// Different funct3 for custom RISC-V instructions using the [CUSTOM_1] 7-bit opcode prefix.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, FromRepr)]
#[repr(u8)]
pub enum Custom1Funct3 {
ModularArithmetic = 0,
ShortWeierstrass,
}

/// funct7 options for 256-bit integer instructions.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, FromRepr)]
#[repr(u8)]
pub enum Int256Funct7 {
Add = 0,
Expand All @@ -47,7 +49,7 @@ pub enum Int256Funct7 {
pub const MODULAR_ARITHMETIC_MAX_KINDS: u8 = 8;

/// Modular arithmetic is configurable. The funct7 field equals `mod_idx * MODULAR_ARITHMETIC_MAX_KINDS + base_funct7`.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, FromRepr)]
#[repr(u8)]
pub enum ModArithBaseFunct7 {
AddMod = 0,
Expand All @@ -60,7 +62,7 @@ pub enum ModArithBaseFunct7 {
pub const SHORT_WEIERSTRASS_MAX_KINDS: u8 = 8;

/// Short Weierstrass curves are configurable. The funct7 field equals `curve_idx * SHORT_WEIERSTRASS_MAX_KINDS + base_funct7`.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, FromRepr)]
#[repr(u8)]
pub enum SwBaseFunct7 {
SwAddNe = 0,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! Macros for adding custom RISC-V instructions in assembly using .insn directives.

#[macro_export]
macro_rules! custom_insn_i {
($opcode:expr, $funct3:expr, $rd:literal, $rs1:literal, $imm:expr) => {
Expand All @@ -20,6 +22,13 @@ macro_rules! custom_insn_i {
), opcode = const $opcode, funct3 = const $funct3, rd = in(reg) $x, imm = const $imm)
}
};
($opcode:expr, $funct3:expr, $x:ident, $y:ident, $imm:expr) => {
unsafe {
core::arch::asm!(
".insn i {opcode}, {funct3}, {rd}, {rs1}, {imm}",
opcode = const $opcode, funct3 = const $funct3, rd = in(reg) $x, rs1 = in(reg) $y, imm = const $imm)
}
};
}

#[macro_export]
Expand Down
59 changes: 36 additions & 23 deletions toolchain/riscv/transpiler/src/rrs.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
use std::marker::PhantomData;

use axvm_instructions::{
instruction::Instruction,
riscv::{RvIntrinsic, RV32_REGISTER_NUM_LIMBS},
BaseAluOpcode, BranchEqualOpcode, BranchLessThanOpcode, DivRemOpcode, EccOpcode,
LessThanOpcode, MulHOpcode, MulOpcode, PhantomInstruction, Rv32AuipcOpcode,
Rv32HintStoreOpcode, Rv32JalLuiOpcode, Rv32JalrOpcode, Rv32LoadStoreOpcode,
Rv32ModularArithmeticOpcode, ShiftOpcode, UsizeOpcode,
instruction::Instruction, riscv::RV32_REGISTER_NUM_LIMBS, BaseAluOpcode, BranchEqualOpcode,
BranchLessThanOpcode, DivRemOpcode, EccOpcode, LessThanOpcode, MulHOpcode, MulOpcode,
PhantomInstruction, Rv32AuipcOpcode, Rv32HintStoreOpcode, Rv32JalLuiOpcode, Rv32JalrOpcode,
Rv32LoadStoreOpcode, Rv32ModularArithmeticOpcode, ShiftOpcode, UsizeOpcode,
};
use axvm_platform::constants::{
Custom0Funct3, Custom1Funct3, CUSTOM_0, CUSTOM_1, MODULAR_ARITHMETIC_MAX_KINDS,
SHORT_WEIERSTRASS_MAX_KINDS,
};
use axvm_platform::constants::{CUSTOM_0, CUSTOM_1};
use p3_field::PrimeField32;
use rrs_lib::{
instruction_formats::{BType, IType, ITypeShamt, JType, RType, SType, UType},
process_instruction, InstructionProcessor,
};
use strum::EnumCount;

use crate::util::*;

Expand Down Expand Up @@ -243,24 +243,37 @@ fn process_custom_instruction<F: PrimeField32>(instruction_u32: u32) -> Instruct
let funct3 = ((instruction_u32 >> 12) & 0b111) as u8; // All our instructions are R- or I-type

match opcode {
CUSTOM_0 => match funct3 {
0b000 => {
CUSTOM_0 => match Custom0Funct3::from_repr(funct3) {
Some(Custom0Funct3::Terminate) => {
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(Custom0Funct3::HintStoreW) => {
let dec_insn = IType::new(instruction_u32);
let imm_u16 = (dec_insn.imm as u32) & 0xffff;
Some(Instruction::from_isize(
Rv32HintStoreOpcode::HINT_STOREW.with_default_offset(),
0,
(RV32_REGISTER_NUM_LIMBS * rd as usize) as isize,
imm as isize,
(RV32_REGISTER_NUM_LIMBS * dec_insn.rd) as isize,
imm_u16 as isize,
1,
2,
))
}
0b011 => Some(Instruction::phantom(
Some(Custom0Funct3::Reveal) => {
let dec_insn = IType::new(instruction_u32);
let imm_u16 = (dec_insn.imm as u32) & 0xffff;
// REVEAL_RV32 is a pseudo-instruction for STOREW_RV32 a,b,c,1,3
Some(Instruction::from_isize(
Rv32LoadStoreOpcode::STOREW.with_default_offset(),
(RV32_REGISTER_NUM_LIMBS * dec_insn.rs1) as isize,
(RV32_REGISTER_NUM_LIMBS * dec_insn.rd) as isize,
imm_u16 as isize,
1,
3,
))
}
Some(Custom0Funct3::HintInput) => Some(Instruction::phantom(
PhantomInstruction::HintInputRv32,
F::zero(),
F::zero(),
Expand All @@ -269,11 +282,11 @@ fn process_custom_instruction<F: PrimeField32>(instruction_u32: u32) -> Instruct
_ => unimplemented!(),
},
CUSTOM_1 => {
match funct3 {
Rv32ModularArithmeticOpcode::FUNCT3 => {
match Custom1Funct3::from_repr(funct3) {
Some(Custom1Funct3::ModularArithmetic) => {
// mod operations
let funct7 = (instruction_u32 >> 25) & 0x7f;
let size = Rv32ModularArithmeticOpcode::COUNT as u32;
let size = MODULAR_ARITHMETIC_MAX_KINDS as u32;
let prime_idx = funct7 / size;
let local_opcode_idx = funct7 % size;
let global_opcode_idx = (local_opcode_idx + prime_idx * size) as usize
Expand All @@ -284,13 +297,13 @@ fn process_custom_instruction<F: PrimeField32>(instruction_u32: u32) -> Instruct
&RType::new(instruction_u32),
))
}
EccOpcode::FUNCT3 => {
Some(Custom1Funct3::ShortWeierstrass) => {
// short weierstrass ec
let funct7 = (instruction_u32 >> 25) & 0x7f;
let size = EccOpcode::COUNT as u32;
let prime_idx = funct7 / size;
let size = SHORT_WEIERSTRASS_MAX_KINDS as u32;
let curve_idx = funct7 / size;
let local_opcode_idx = funct7 % size;
let global_opcode_idx = (local_opcode_idx + prime_idx * size) as usize
let global_opcode_idx = (local_opcode_idx + curve_idx * size) as usize
+ EccOpcode::default_offset();
Some(from_r_type(
global_opcode_idx,
Expand Down
Loading
Loading