diff --git a/Cargo.lock b/Cargo.lock index bc5bd1a1..1b12f863 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1531,6 +1531,16 @@ dependencies = [ "typenum", ] +[[package]] +name = "ctor" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" +dependencies = [ + "quote", + "syn 2.0.89", +] + [[package]] name = "darling" version = "0.20.10" @@ -2954,6 +2964,18 @@ dependencies = [ "linked-hash-map", ] +[[package]] +name = "macros" +version = "0.1.0" +dependencies = [ + "ctor", + "macros-core", + "once_cell", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "macros" version = "0.1.0" @@ -2965,6 +2987,14 @@ dependencies = [ "syn 2.0.89", ] +[[package]] +name = "macros-core" +version = "0.1.0" +dependencies = [ + "once_cell", + "serde_json", +] + [[package]] name = "match_cfg" version = "0.1.0" @@ -3618,9 +3648,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.92" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" dependencies = [ "unicode-ident", ] @@ -3720,9 +3750,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] @@ -4592,7 +4622,7 @@ dependencies = [ "halo2_poseidon", "halo2_proofs", "human_bytes", - "macros", + "macros 0.1.0 (git+ssh://git@github.com/Cardinal-Cryptography/zkOS-circuits?rev=7743b2f)", "once_cell", "rand", "rand_chacha", @@ -4697,14 +4727,23 @@ name = "shielder_bindings" version = "0.1.0" dependencies = [ "alloy-primitives", + "axum", + "ctor", "getrandom", "halo2_proofs", + "macros 0.1.0", + "macros-core", + "once_cell", "powers-of-tau", "rand", "rayon", + "serde", + "serde_json", "shielder-account", "shielder-circuits", "thiserror 2.0.11", + "tokio", + "tower-http", "type-conversions", "uniffi", "wasm-bindgen", diff --git a/Cargo.toml b/Cargo.toml index 1bdd34b6..daf620d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ axum = { version = "0.7.7" } byteorder = { version = "1.4.3" } chacha20poly1305 = { version = "0.10.1", default-features = false } clap = { version = "4.5.8" } +ctor = { version = "0.2.9" } getrandom = { version = "0.2" } halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2", tag = "v0.3.0", default-features = false } halo2curves = { version = "0.6.0", default-features = false } @@ -38,7 +39,10 @@ itertools = { version = "0.13.0" } metrics = { version = "0.24.1", default-features = false } metrics-exporter-prometheus = { version = "0.16.0", default-features = false } num-bigint = { version = "0.4.3" } +once_cell = { version = "1.20.2" } openssl = { version = "0.10.59" } +quote = { version = "1.0.38" } +proc-macro2 = { version = "1.0.93" } rand = { version = "0.8.5" } rayon = { version = "1.8" } reqwest = { version = "0.12.5" } @@ -67,9 +71,12 @@ wasm-bindgen-rayon = { version = "1.2.1" } content-encryption = { path = "crates/content-encryption", default-features = false } evm-utils = { path = "crates/evm-utils" } halo2_solidity_verifier = { path = "crates/halo2-verifier" } +macros-core = { path = "crates/macros-core" } +macros = { path = "crates/macros" } powers-of-tau = { path = "crates/powers-of-tau" } shielder-account = { path = "crates/shielder-account" } shielder-contract = { path = "crates/shielder-contract" } shielder-relayer = { path = "crates/shielder-relayer" } shielder-setup = { path = "crates/shielder-setup" } type-conversions = { path = "crates/type-conversions" } +shielder_bindings = { path = "crates/shielder_bindings" } diff --git a/crates/macros-core/Cargo.toml b/crates/macros-core/Cargo.toml new file mode 100644 index 00000000..2bb9c458 --- /dev/null +++ b/crates/macros-core/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "macros-core" +version = "0.1.0" +edition = "2021" + +[dependencies] +once_cell = { workspace = true } +serde_json = { workspace = true } diff --git a/crates/macros-core/src/lib.rs b/crates/macros-core/src/lib.rs new file mode 100644 index 00000000..642f9476 --- /dev/null +++ b/crates/macros-core/src/lib.rs @@ -0,0 +1,22 @@ +use std::sync::Mutex; + +use once_cell::sync::Lazy; +use serde_json::Value; + +pub type JsonFnPointer = fn(Value) -> Value; + +/// A simple struct to hold info about an "exported" function. +#[derive(Debug, Clone)] +pub struct JsonizedFunction { + /// The function name as a string. + pub name: &'static str, + /// Pointer to the bridging function. + pub func: JsonFnPointer, +} + +/// A global registry of exported functions. +/// +/// By using `Lazy>`, we can push to this vector at compile time +/// (technically, it's “init-time” for each static), and read it later. +pub static EXPORTED_FUNCTIONS: Lazy>> = + Lazy::new(|| Mutex::new(Vec::new())); diff --git a/crates/macros/Cargo.toml b/crates/macros/Cargo.toml new file mode 100644 index 00000000..e1e06529 --- /dev/null +++ b/crates/macros/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "macros" +version = "0.1.0" +edition = "2021" + +[lib] +proc-macro = true + +[dependencies] +ctor = { workspace = true } +macros-core = { workspace = true } +once_cell = { workspace = true } +proc-macro2 = { workspace = true } +quote = { workspace = true } +syn = { version = "1", features = ["full"] } diff --git a/crates/macros/src/args.rs b/crates/macros/src/args.rs new file mode 100644 index 00000000..09551a8e --- /dev/null +++ b/crates/macros/src/args.rs @@ -0,0 +1,54 @@ +use proc_macro2::Ident; +use quote::{format_ident, quote}; +use syn::{FnArg, Pat, Type}; + +/// Helper struct to store parsed argument information +pub struct ArgumentInfo { + pub name: Ident, + pub ty: Box, +} + +/// Parse function arguments into a vector of ArgumentInfo +pub fn parse_arguments( + inputs: &syn::punctuated::Punctuated, +) -> Vec { + let mut args = Vec::new(); + + for (i, arg) in inputs.iter().enumerate() { + if let FnArg::Typed(pat_type) = arg { + let arg_name = match &*pat_type.pat { + Pat::Ident(ident) => ident.ident.clone(), + _ => format_ident!("arg{}", i), + }; + args.push(ArgumentInfo { + name: arg_name, + ty: pat_type.ty.clone(), + }); + } + } + + args +} + +/// Generate Deserealizable struct definition for function arguments +pub fn generate_args_struct( + struct_name: &Ident, + args: &[ArgumentInfo], +) -> proc_macro2::TokenStream { + let fields = args.iter().map(|arg| { + let name = &arg.name; + let ty = &arg.ty; + quote! { pub #name: #ty } + }); + let fields_ts = quote! { + #(#fields),* + }; + + quote! { + #[allow(non_camel_case_types)] + #[derive(::serde::Deserialize)] + struct #struct_name { + #fields_ts + } + } +} diff --git a/crates/macros/src/bridging.rs b/crates/macros/src/bridging.rs new file mode 100644 index 00000000..42c992f8 --- /dev/null +++ b/crates/macros/src/bridging.rs @@ -0,0 +1,39 @@ +use proc_macro2::Ident; +use quote::quote; + +use crate::args::ArgumentInfo; + +/// Generate bridging function that converts between JSON and native types +/// JSON is parsed into a Deserealizable struct, then the function is called +/// with the struct fields as arguments. The result is then serialized back +/// into JSON. +pub fn generate_bridging_fn( + fn_name: &Ident, + struct_name: &Ident, + args: &[ArgumentInfo], + ret_type: &proc_macro2::TokenStream, + call_path: proc_macro2::TokenStream, +) -> (proc_macro2::TokenStream, Ident) { + let arg_names: Vec<_> = args.iter().map(|arg| &arg.name).collect(); + let bridging_name = quote::format_ident!("{}_json", fn_name); + + ( + quote! { + #[allow(non_snake_case)] + fn #bridging_name(input: ::serde_json::Value) -> ::serde_json::Value { + let args: #struct_name = match ::serde_json::from_value(input) { + Ok(val) => val, + Err(e) => { + return ::serde_json::json!({ + "error": format!("Invalid input JSON: {}", e) + }); + } + }; + + let result: #ret_type = #call_path(#( args.#arg_names ),*); + ::serde_json::json!(result) + } + }, + bridging_name, + ) +} diff --git a/crates/macros/src/lib.rs b/crates/macros/src/lib.rs new file mode 100644 index 00000000..15b6bf31 --- /dev/null +++ b/crates/macros/src/lib.rs @@ -0,0 +1,134 @@ +use meta_utils::find_constructor; +use proc_macro::TokenStream; +use quote::quote; +use syn::{parse_macro_input, AttributeArgs, ImplItem, ItemFn, ItemImpl, ReturnType, Signature}; + +mod args; +mod bridging; +mod meta_utils; +mod registration; +mod utils; + +use args::parse_arguments; +use bridging::generate_bridging_fn; +use registration::generate_registration; +use utils::{get_type_name, is_valid_constructor, should_export_method}; + +/// Generate exported function code +fn gen_jsonized_fn( + signature: &Signature, + call_path: proc_macro2::TokenStream, + type_name: Option<&str>, +) -> proc_macro2::TokenStream { + let fn_name = &signature.ident; + let args = parse_arguments(&signature.inputs); + + let struct_ident = quote::format_ident!("{}_{}_Args", type_name.unwrap_or(""), fn_name); + let register_ident = + quote::format_ident!("__register_method_{}_{}", type_name.unwrap_or(""), fn_name); + + let ret_type = match &signature.output { + ReturnType::Default => quote! { () }, + ReturnType::Type(_, ty) => quote! { #ty }, + }; + + let args_struct = args::generate_args_struct(&struct_ident, &args); + let (bridging_fn, bridging_fn_ident) = + generate_bridging_fn(fn_name, &struct_ident, &args, &ret_type, call_path); + + let route_name = format!( + "{}{}", + type_name.map_or(String::from(""), |t| format!("{}.", t)), + fn_name + ); + let registration = generate_registration(®ister_ident, &route_name, &bridging_fn_ident); + quote! { + #args_struct + #bridging_fn + #registration + } +} + +/// The attribute macro: `#[jsonize]` +/// Derive a function that takes a JSON object as input and returns a JSON object as output, +/// mirroring the original function's signature. +/// The derived function is registered in a global static vector `EXPORTED_FUNCTIONS`. +#[proc_macro_attribute] +pub fn jsonize(_attr: TokenStream, item: TokenStream) -> TokenStream { + let parsed_fn = parse_macro_input!(item as ItemFn); + let fn_name = &parsed_fn.sig.ident; + let jsonized_fn = gen_jsonized_fn(&parsed_fn.sig, quote! { #fn_name }, None); + + let expanded = quote! { + #parsed_fn + #jsonized_fn + }; + + expanded.into() +} + +/// The attribute macro for exporting methods of a singleton struct: `#[jsonize_singleton]` +/// Derive a function that takes a JSON object as input and returns a JSON object as output, +/// mirroring the original method's signature. +/// The derived function is registered in a global static vector `EXPORTED_FUNCTIONS`. +/// The singleton instance is also registered as a global static variable. +#[proc_macro_attribute] +pub fn jsonize_singleton(attr: TokenStream, item: TokenStream) -> TokenStream { + let attr_args = parse_macro_input!(attr as AttributeArgs); + let constructor_name = find_constructor(attr_args) + .expect("Missing `constructor` argument for `jsonize_singleton`"); + let impl_block = parse_macro_input!(item as ItemImpl); + let self_ty = &impl_block.self_ty; + let type_name = get_type_name(self_ty); + let instance_ident = quote::format_ident!("GLOBAL_{}_INSTANCE", type_name.to_uppercase()); + + let mut methods = Vec::new(); + let mut has_constructor = false; + + for item in &impl_block.items { + if let ImplItem::Method(method) = item { + if is_valid_constructor(&constructor_name, method) { + has_constructor = true; + continue; + } + + if !should_export_method(method) { + continue; + } + + let method_name = &method.sig.ident; + let jsonized_fn = gen_jsonized_fn( + &method.sig, + quote! { #instance_ident.#method_name }, + Some(&type_name), + ); + + methods.push(jsonized_fn); + } + } + + if !has_constructor { + panic!( + "No zero-arg `{}` found for type {}", + constructor_name, type_name + ); + } + + let constructor_ident = quote::format_ident!("{}", constructor_name); + let instance_code = quote! { + ::once_cell::sync::Lazy::new(|| { + #self_ty::#constructor_ident() + }) + }; + + let expanded = quote! { + #impl_block + + #[allow(non_upper_case_globals)] + pub static #instance_ident: ::once_cell::sync::Lazy<#self_ty> = #instance_code; + + #( #methods )* + }; + + expanded.into() +} diff --git a/crates/macros/src/meta_utils.rs b/crates/macros/src/meta_utils.rs new file mode 100644 index 00000000..5780ab45 --- /dev/null +++ b/crates/macros/src/meta_utils.rs @@ -0,0 +1,26 @@ +use syn::{AttributeArgs, Lit, Meta, NestedMeta}; + +pub fn find_constructor(attr_args: AttributeArgs) -> Option { + // We'll extract the user-provided constructor name if present + let mut constructor_name: Option = None; + + for nested in attr_args { + match nested { + NestedMeta::Meta(Meta::NameValue(name_value)) => { + if name_value.path.is_ident("constructor") { + // e.g. constructor = "my_constructor" + if let Lit::Str(lit_str) = &name_value.lit { + constructor_name = Some(lit_str.value()); + } else { + panic!("Expected string literal for `constructor = \"...\"`"); + } + } + } + _ => { + panic!("Unsupported attribute argument format"); + } + } + } + + constructor_name +} diff --git a/crates/macros/src/registration.rs b/crates/macros/src/registration.rs new file mode 100644 index 00000000..15d43d0c --- /dev/null +++ b/crates/macros/src/registration.rs @@ -0,0 +1,24 @@ +use proc_macro2::Ident; +use quote::quote; + +/// Generate registration code for exported functions +/// function is registered in a global static vector +pub fn generate_registration( + register_name: &Ident, + fn_name: &str, + bridging_name: &Ident, +) -> proc_macro2::TokenStream { + quote! { + #[doc(hidden)] + #[allow(non_snake_case)] + #[ctor::ctor] + fn #register_name() { + macros_core::EXPORTED_FUNCTIONS.lock().unwrap().push( + macros_core::JsonizedFunction { + name: #fn_name, + func: #bridging_name, + } + ); + } + } +} diff --git a/crates/macros/src/utils.rs b/crates/macros/src/utils.rs new file mode 100644 index 00000000..1c11a443 --- /dev/null +++ b/crates/macros/src/utils.rs @@ -0,0 +1,37 @@ +use syn::{ImplItemMethod, ReturnType, Type, Visibility}; + +/// Extract the type name from a Type +pub fn get_type_name(ty: &Type) -> String { + if let Type::Path(type_path) = ty { + type_path + .path + .segments + .last() + .map(|seg| seg.ident.to_string()) + .unwrap_or_else(|| "UnknownType".to_string()) + } else { + "UnknownType".to_string() + } +} + +/// Helper to check if a method is a valid constructor +pub fn is_valid_constructor(expected_sig: &str, method: &ImplItemMethod) -> bool { + method.sig.ident == expected_sig + && method.sig.inputs.is_empty() + && matches!(method.vis, Visibility::Public(_)) + && matches!(method.sig.output, ReturnType::Type(_, _)) +} + +/// Helper to check if a method should be exported +pub fn should_export_method(method: &ImplItemMethod) -> bool { + if !matches!(method.vis, Visibility::Public(_)) { + return false; + } + + method + .sig + .inputs + .iter() + .next() + .map_or(false, |arg| matches!(arg, syn::FnArg::Receiver(_))) +} diff --git a/crates/shielder_bindings/Cargo.toml b/crates/shielder_bindings/Cargo.toml index f3a338d1..8c0cbcf9 100644 --- a/crates/shielder_bindings/Cargo.toml +++ b/crates/shielder_bindings/Cargo.toml @@ -11,21 +11,30 @@ categories.workspace = true repository.workspace = true [lib] -crate-type = ["cdylib", "staticlib"] +crate-type = ["lib", "cdylib", "staticlib"] [dependencies] alloy-primitives = { workspace = true } +axum = { workspace = true, optional = true } +ctor = { workspace = true, optional = true } getrandom = { workspace = true, optional = true } halo2_proofs = { workspace = true } rand = { workspace = true, features = ["small_rng"] } rayon = { workspace = true, optional = true } +serde_json = { workspace = true, optional = true } +serde = { workspace = true, features = ["derive"], optional = true } shielder-account = { workspace = true } shielder-circuits = { workspace = true } thiserror = { workspace = true } +tokio = { workspace = true, features = ["full"], optional = true } +tower-http = { workspace = true, features = ["cors"], optional = true } type-conversions = { workspace = true } uniffi = { workspace = true, features = ["cli"], optional = true } wasm-bindgen-rayon = { workspace = true, optional = true } wasm-bindgen = { workspace = true, optional = true } +macros-core = { workspace = true, optional = true } +macros = { workspace = true, optional = true } +once_cell = { workspace = true, optional = true } [build-dependencies] powers-of-tau = { workspace = true } @@ -37,6 +46,20 @@ default = ["std"] std = [] build-wasm = ["wasm-bindgen", "getrandom/js"] build-uniffi = ["uniffi", "rayon", "shielder-circuits/multithreading"] +build-server = [ + "dep:axum", + "dep:ctor", + "dep:macros-core", + "dep:macros", + "dep:tokio", + "dep:tower-http", + "dep:once_cell", + "dep:serde", + "dep:serde_json", + "rayon", + "shielder-circuits/multithreading", + "std", +] multithreading-wasm = [ "rayon", "wasm-bindgen-rayon", @@ -51,3 +74,8 @@ wasm-opt = ['-O4', '-g'] name = "uniffi-bindgen" path = "src/bin/uniffi-bindgen.rs" required-features = ["build-uniffi"] + +[[bin]] +name = "server" +path = "src/bin/server.rs" +required-features = ["build-server"] diff --git a/crates/shielder_bindings/Makefile b/crates/shielder_bindings/Makefile index 278162c6..ab830b37 100644 --- a/crates/shielder_bindings/Makefile +++ b/crates/shielder_bindings/Makefile @@ -10,6 +10,10 @@ endif help: # Show help for each of the Makefile recipes. @grep -E '^[a-zA-Z0-9 -]+:.*#' Makefile | sort | while read -r l; do printf "\033[1;32m$$(echo $$l | cut -f 1 -d':')\033[00m:$$(echo $$l | cut -f 2- -d'#')\n"; done +.PHONY: server +server: # Build and run HTTP server + cargo run --release --features build-server --bin server + .PHONY: wasm wasm: # Build wasm bindings wasm: clean-wasm build-pkg-wasm update-package-web remove-unused-files-wasm diff --git a/crates/shielder_bindings/src/bin/server.rs b/crates/shielder_bindings/src/bin/server.rs new file mode 100644 index 00000000..44820d4e --- /dev/null +++ b/crates/shielder_bindings/src/bin/server.rs @@ -0,0 +1,37 @@ +//! This is a simple server that exposes the functions defined in the `shielder_bindings` crate. +//! It uses `axum` to create a REST API that can be called to execute the functions. +//! Functions are exposed through the `EXPORTED_FUNCTIONS` static vector, which is lazily populated +//! with the functions and singletons that are annotated with the `#[jsonize]` or `#[jsonize_singleton]` macro. +use axum::{extract::Json, routing::post, Router}; +use serde_json::Value; +use shielder_bindings::EXPORTED_FUNCTIONS; + +#[tokio::main] +async fn main() { + let registry = { + let registry = EXPORTED_FUNCTIONS.lock().unwrap(); + registry.clone() + }; + for func in registry.iter() { + println!("Exported function: {}", func.name); + } + + let mut app = Router::new(); + for func_info in registry.iter() { + let path = format!("/{}", func_info.name); + let func_ptr = func_info.func; + + // Each route calls the bridging function + let route = post(move |Json(payload): Json| async move { + let output = (func_ptr)(payload); + Json(output) + }); + app = app.route(&path, route); + } + let addr = std::net::SocketAddr::from(([0, 0, 0, 0], 43312)); + println!("Server running on http://{}", addr); + + axum::serve(tokio::net::TcpListener::bind(addr).await.unwrap(), app) + .await + .unwrap(); +} diff --git a/crates/shielder_bindings/src/circuits/deposit.rs b/crates/shielder_bindings/src/circuits/deposit.rs index 0d38d655..35b71d98 100644 --- a/crates/shielder_bindings/src/circuits/deposit.rs +++ b/crates/shielder_bindings/src/circuits/deposit.rs @@ -14,6 +14,10 @@ pub struct DepositCircuit(super::DepositCircuit); #[cfg_attr(feature = "build-uniffi", uniffi::export)] #[cfg_attr(feature = "build-wasm", wasm_bindgen)] +#[cfg_attr( + feature = "build-server", + macros::jsonize_singleton(constructor = "new_pronto") +)] impl DepositCircuit { #[cfg_attr(feature = "build-uniffi", uniffi::constructor)] #[cfg_attr(feature = "build-wasm", wasm_bindgen(constructor))] diff --git a/crates/shielder_bindings/src/circuits/error.rs b/crates/shielder_bindings/src/circuits/error.rs index e1c097f4..83525814 100644 --- a/crates/shielder_bindings/src/circuits/error.rs +++ b/crates/shielder_bindings/src/circuits/error.rs @@ -4,6 +4,7 @@ use alloc::{format, string::String}; use wasm_bindgen::JsValue; #[cfg_attr(feature = "build-uniffi", derive(uniffi::Error))] +#[cfg_attr(feature = "build-server", derive(serde::Serialize))] #[derive(Debug, thiserror::Error)] pub enum VerificationError { #[error("Verification failed: {message}")] diff --git a/crates/shielder_bindings/src/circuits/new_account.rs b/crates/shielder_bindings/src/circuits/new_account.rs index e946b275..e81f904b 100644 --- a/crates/shielder_bindings/src/circuits/new_account.rs +++ b/crates/shielder_bindings/src/circuits/new_account.rs @@ -14,6 +14,10 @@ pub struct NewAccountCircuit(super::NewAccountCircuit); #[cfg_attr(feature = "build-uniffi", uniffi::export)] #[cfg_attr(feature = "build-wasm", wasm_bindgen)] +#[cfg_attr( + feature = "build-server", + macros::jsonize_singleton(constructor = "new_pronto") +)] impl NewAccountCircuit { #[cfg_attr(feature = "build-uniffi", uniffi::constructor)] #[cfg_attr(feature = "build-wasm", wasm_bindgen(constructor))] diff --git a/crates/shielder_bindings/src/circuits/withdraw.rs b/crates/shielder_bindings/src/circuits/withdraw.rs index 7fc68695..b732c84a 100644 --- a/crates/shielder_bindings/src/circuits/withdraw.rs +++ b/crates/shielder_bindings/src/circuits/withdraw.rs @@ -14,6 +14,10 @@ pub struct WithdrawCircuit(super::WithdrawCircuit); #[cfg_attr(feature = "build-uniffi", uniffi::export)] #[cfg_attr(feature = "build-wasm", wasm_bindgen)] +#[cfg_attr( + feature = "build-server", + macros::jsonize_singleton(constructor = "new_pronto") +)] impl WithdrawCircuit { #[cfg_attr(feature = "build-uniffi", uniffi::constructor)] #[cfg_attr(feature = "build-wasm", wasm_bindgen(constructor))] diff --git a/crates/shielder_bindings/src/conversions.rs b/crates/shielder_bindings/src/conversions.rs index 50957f31..4efd9d24 100644 --- a/crates/shielder_bindings/src/conversions.rs +++ b/crates/shielder_bindings/src/conversions.rs @@ -1,4 +1,4 @@ -use alloc::vec::Vec; +use alloc::{string::String, vec::Vec}; use halo2_proofs::halo2curves::bn256::Fr; use type_conversions::private_key_to_field; @@ -7,8 +7,9 @@ use wasm_bindgen::prelude::wasm_bindgen; #[cfg_attr(feature = "build-wasm", wasm_bindgen)] #[cfg_attr(feature = "build-uniffi", uniffi::export)] -pub fn private_key_to_f(hex: &str) -> Vec { - private_key_to_field::(hex) +#[cfg_attr(feature = "build-server", macros::jsonize)] +pub fn private_key_to_f(hex: String) -> Vec { + private_key_to_field::(&hex) .unwrap() .to_bytes() .as_slice() diff --git a/crates/shielder_bindings/src/hash.rs b/crates/shielder_bindings/src/hash.rs index 98647e3f..4ece106b 100644 --- a/crates/shielder_bindings/src/hash.rs +++ b/crates/shielder_bindings/src/hash.rs @@ -8,12 +8,14 @@ use crate::utils::{hash_variable_length, vec_to_f}; #[cfg_attr(feature = "build-wasm", wasm_bindgen)] #[cfg_attr(feature = "build-uniffi", uniffi::export)] +#[cfg_attr(feature = "build-server", macros::jsonize)] pub fn poseidon_rate() -> u32 { POSEIDON_RATE.try_into().unwrap() } #[cfg_attr(feature = "build-wasm", wasm_bindgen)] #[cfg_attr(feature = "build-uniffi", uniffi::export)] +#[cfg_attr(feature = "build-server", macros::jsonize)] pub fn poseidon_hash(inputs: Vec) -> Vec { if inputs.len() % F::size() != 0 { panic!("Input length must be divisible by F::size()"); diff --git a/crates/shielder_bindings/src/lib.rs b/crates/shielder_bindings/src/lib.rs index d192a2c9..44b1004f 100644 --- a/crates/shielder_bindings/src/lib.rs +++ b/crates/shielder_bindings/src/lib.rs @@ -1,8 +1,10 @@ -#![cfg_attr(not(feature = "build-uniffi"), no_std)] +#![cfg_attr(not(any(feature = "build-uniffi", feature = "build-server")), no_std)] #[cfg(feature = "build-uniffi")] uniffi::setup_scaffolding!(); +#[cfg(feature = "build-server")] +pub use macros_core::EXPORTED_FUNCTIONS; #[cfg(feature = "multithreading-wasm")] pub use wasm_bindgen_rayon::init_thread_pool; diff --git a/crates/shielder_bindings/src/note_config.rs b/crates/shielder_bindings/src/note_config.rs index ba9c9b1b..623e0b5e 100644 --- a/crates/shielder_bindings/src/note_config.rs +++ b/crates/shielder_bindings/src/note_config.rs @@ -4,12 +4,14 @@ use wasm_bindgen::prelude::wasm_bindgen; #[cfg_attr(feature = "build-wasm", wasm_bindgen)] #[cfg_attr(feature = "build-uniffi", uniffi::export)] +#[cfg_attr(feature = "build-server", macros::jsonize)] pub fn note_tree_arity() -> u32 { ARITY.try_into().unwrap() } #[cfg_attr(feature = "build-wasm", wasm_bindgen)] #[cfg_attr(feature = "build-uniffi", uniffi::export)] +#[cfg_attr(feature = "build-server", macros::jsonize)] pub fn note_tree_height() -> u32 { NOTE_TREE_HEIGHT.try_into().unwrap() } diff --git a/crates/shielder_bindings/src/secrets.rs b/crates/shielder_bindings/src/secrets.rs index 97d65736..28a5300d 100644 --- a/crates/shielder_bindings/src/secrets.rs +++ b/crates/shielder_bindings/src/secrets.rs @@ -9,6 +9,7 @@ use wasm_bindgen::prelude::wasm_bindgen; #[cfg_attr(feature = "build-uniffi", derive(uniffi::Record))] // `getter_with_clone` is required for `Vec` struct fields #[cfg_attr(feature = "build-wasm", wasm_bindgen(getter_with_clone))] +#[cfg_attr(feature = "build-server", derive(serde::Serialize))] #[derive(Clone, Debug, Default)] pub struct ShielderActionSecrets { pub nullifier: Vec, @@ -19,6 +20,7 @@ pub struct ShielderActionSecrets { /// All returned values are field elements. #[cfg_attr(feature = "build-uniffi", uniffi::export)] #[cfg_attr(feature = "build-wasm", wasm_bindgen)] +#[cfg_attr(feature = "build-server", macros::jsonize)] pub fn get_action_secrets(id: Vec, nonce: u32) -> ShielderActionSecrets { let id: U256 = bytes_to_u256(id).expect("Expecting a 32-byte vector");