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