use crate::circom::error::CircomError;
use ark_std::{boxed::Box, string::ToString};
use wasmer::{Function, Instance, Store, Value};
#[derive(Clone, Debug)]
pub struct Wasm(Instance);
impl Wasm {
pub fn new(instance: Instance) -> Self {
Self(instance)
}
pub fn init(&self, store: &mut Store, sanity_check: bool) -> Result<(), CircomError> {
self.call_func(store, "init", &[Value::I32(sanity_check as i32)])?;
Ok(())
}
pub fn get_version(&self, store: &mut Store) -> Result<u32, CircomError> {
match self.0.exports.get_function("getVersion") {
Ok(func) => Ok(func
.call(store, &[])
.map_err(|_| CircomError::WasmFunctionCallFailed("getVersion".to_string()))?[0]
.unwrap_i32() as u32),
Err(_) => Ok(1),
}
}
pub fn get_field_num_len32(&self, store: &mut Store) -> Result<u32, CircomError> {
self.get_u32(store, "getFieldNumLen32", &[])
}
pub fn get_raw_prime(&self, store: &mut Store) -> Result<(), CircomError> {
self.call_func(store, "getRawPrime", &[])?;
Ok(())
}
pub fn read_shared_rw_memory(&self, store: &mut Store, i: u32) -> Result<u32, CircomError> {
self.get_u32(store, "readSharedRWMemory", &[i.into()])
}
pub fn write_shared_rw_memory(
&self,
store: &mut Store,
i: u32,
v: u32,
) -> Result<(), CircomError> {
self.call_func(store, "writeSharedRWMemory", &[i.into(), v.into()])?;
Ok(())
}
pub fn set_input_signal(
&self,
store: &mut Store,
hmsb: u32,
hlsb: u32,
pos: u32,
) -> Result<(), CircomError> {
self.call_func(
store,
"setInputSignal",
&[hmsb.into(), hlsb.into(), pos.into()],
)?;
Ok(())
}
pub fn get_witness(&self, store: &mut Store, i: u32) -> Result<(), CircomError> {
self.call_func(store, "getWitness", &[i.into()])?;
Ok(())
}
pub fn get_witness_count(&self, store: &mut Store) -> Result<u32, CircomError> {
self.get_u32(store, "getWitnessSize", &[])
}
pub fn get_input_count(&self, store: &mut Store) -> Result<u32, CircomError> {
self.get_u32(store, "getInputSize", &[])
}
pub fn get_signal_count(
&self,
store: &mut Store,
hmsb: u32,
hlsb: u32,
) -> Result<u32, CircomError> {
self.get_u32(store, "getInputSignalSize", &[hmsb.into(), hlsb.into()])
}
pub fn get_u32(
&self,
store: &mut Store,
name: &str,
args: &[Value],
) -> Result<u32, CircomError> {
let result = self.call_func(store, name, args)?;
if result.is_empty() {
return Err(CircomError::WasmFunctionResultEmpty(name.to_string()));
}
result[0]
.i32()
.ok_or_else(|| CircomError::WasmFunctionResultEmpty(name.to_string()))
.map(|i| i as u32)
}
fn call_func(
&self,
store: &mut Store,
name: &str,
args: &[Value],
) -> Result<Box<[Value]>, CircomError> {
let func = self.func(name)?;
func.call(store, args)
.map_err(|_| CircomError::WasmFunctionCallFailed(name.to_string()))
}
fn func(&self, name: &str) -> Result<&Function, CircomError> {
self.0
.exports
.get_function(name)
.map_err(|_| CircomError::UnknownWasmFunction(name.to_string()))
}
}