Skip to content

Commit

Permalink
wip: initial compiling version
Browse files Browse the repository at this point in the history
  • Loading branch information
jonathanpwang committed Oct 16, 2024
1 parent 4a5ab42 commit 9537e59
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 45 deletions.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[build]
target = "riscv32im-risc0-zkvm-elf"

[unstable]
build-std = ["core", "alloc", "proc_macro", "panic_abort"]
9 changes: 9 additions & 0 deletions toolchain/riscv/examples/prime_field/program/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[workspace]
[package]
version = "0.1.0"
name = "axvm-fibonacci-program"
edition = "2021"

[dependencies]
axvm = { path = "../../../zkvm/lib" }
axvm-macros = { path = "../../../zkvm/macros" }
17 changes: 17 additions & 0 deletions toolchain/riscv/examples/prime_field/program/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#![no_main]
#![no_std]

use axvm_macros::axvm;

axvm::entry!(main);

pub fn main() {
let x = [1u8; 32];
let y = [2u8; 32];
// Currently must alloc z first; not ideal
let mut z = [0u8; 32];

// the generic is a placeholder; real primes are bigints - what's the best way to specify? probably the proc macro should provide a list of constants from the axiom.toml
// z will be auto converted to the pointer &mut z
axvm!(z = addmod::<777>(&x, &y););
}
97 changes: 55 additions & 42 deletions toolchain/riscv/zkvm/macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,46 +2,48 @@ extern crate proc_macro;

use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, Expr, GenericArgument, Ident, Pat, PathArguments, Stmt};
use syn::{parse_macro_input, Expr, ExprReference, GenericArgument, Ident, PathArguments, Stmt};

#[proc_macro_attribute]
pub fn axvm(_attr: TokenStream, item: TokenStream) -> TokenStream {
#[proc_macro]
pub fn axvm(item: TokenStream) -> TokenStream {
// Parse the input tokens into a syntax tree
let stmt = parse_macro_input!(item as Stmt);

// Variables to hold the extracted identifiers
let mut rd_name: Option<Ident> = None;
// The return path, not pointer
let mut dest_name: Option<Ident> = None;
let mut func_name: Option<Ident> = None;
let mut generic_param: Option<Expr> = None;
let mut rs1_name: Option<Ident> = None;
let mut rs2_name: Option<Ident> = None;
// Pointer to first argument
let mut rs1_name: Option<ExprReference> = None;
// Pointer to second argument
let mut rs2_name: Option<ExprReference> = None;

if let Stmt::Local(local) = stmt {
// Extract the variable name from the pattern
if let Pat::Ident(pat_ident) = &local.pat {
rd_name = Some(pat_ident.ident.clone());
}
if let Stmt::Semi(expr, _) = stmt {
if let Expr::Assign(expr_assign) = expr {
// Parse the left-hand side (lhs)
if let Expr::Path(rd_path) = *expr_assign.left {
if let Some(segment) = rd_path.path.segments.last() {
dest_name = Some(segment.ident.clone());
}
}

// Extract the initialization expression
if let Some((_eq_token, init_expr)) = &local.init {
// Check if the expression is a function call
if let Expr::Call(expr_call) = &**init_expr {
// Extract the function being called
if let Expr::Path(expr_path) = &*expr_call.func {
// Extract the function name and generic parameters
// Parse the right-hand side (rhs)
if let Expr::Call(expr_call) = *expr_assign.right {
if let Expr::Path(expr_path) = *expr_call.func {
let path = &expr_path.path;
if let Some(segment) = path.segments.last() {
func_name = Some(segment.ident.clone());

// Extract generic parameters if any
if let PathArguments::AngleBracketed(angle_bracketed) = &segment.arguments {
let generic_arg = angle_bracketed.args.first().unwrap();
match generic_arg {
GenericArgument::Const(const_expr) => {
generic_param = Some(const_expr.clone());
}
_ => panic!("Must provide constant generic"),
if let Some(GenericArgument::Const(expr)) = angle_bracketed.args.first()
{
generic_param = Some(expr.clone());
} else {
panic!("Must provide constant generic");
}
} else {
panic!("No generic arguments");
}
}
}
Expand All @@ -50,31 +52,42 @@ pub fn axvm(_attr: TokenStream, item: TokenStream) -> TokenStream {
let args = &expr_call.args;
let mut args_iter = args.iter();

if let Some(Expr::Path(rs1_path)) = args_iter.next() {
if let Some(rs1_segment) = rs1_path.path.segments.last() {
rs1_name = Some(rs1_segment.ident.clone());
}
if let Some(Expr::Reference(rs1_ref)) = args_iter.next() {
rs1_name = Some(rs1_ref.clone());
} else {
panic!("Must provide reference as first argument");
}

if let Some(Expr::Path(rs2_path)) = args_iter.next() {
if let Some(rs2_segment) = rs2_path.path.segments.last() {
rs2_name = Some(rs2_segment.ident.clone());
}
if let Some(Expr::Reference(rs2_ref)) = args_iter.next() {
rs2_name = Some(rs2_ref.clone());
} else {
panic!("Must provide reference as second argument");
}
}
} else {
return syn::Error::new_spanned(expr, "Expected an assignment expression")
.to_compile_error()
.into();
}
} else {
return syn::Error::new_spanned(stmt, "Expected a statement")
.to_compile_error()
.into();
}

let rd_name = quote! {
&mut #dest_name
};
let output = quote! {
// #[cfg(target_os = "zkvm")]
// unsafe {
// core::arch::asm!(
// ".insn r 0b0101011 0b000 0x00 {rd} {rs1} {rs2}",
// rd = in(reg) #rd_name,
// rs1 = in(reg) #rs1_name,
// rs2 = in(reg) #rs2_name,
// )
// }
#[cfg(target_os = "zkvm")]
unsafe {
core::arch::asm!(
".insn r 0b0101011, 0x00, 0x00, {rd}, {rs1}, {rs2}",
rd = in(reg) #rd_name,
rs1 = in(reg) #rs1_name,
rs2 = in(reg) #rs2_name,
)
}
#[cfg(not(target_os = "zkvm"))]
{
// Debug output
Expand Down
4 changes: 1 addition & 3 deletions toolchain/riscv/zkvm/macros/tests/intrinsic.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
#![feature(proc_macro_hygiene)]
use axvm_macros::axvm;

#[test]
fn main() {
#[axvm]
let z = addmod::<777>(x, y);
axvm!(z = addmod::<777>(&x, &y););
}

0 comments on commit 9537e59

Please sign in to comment.