use std::str::FromStr;
use rings_snark::prelude::ff;
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsError;
use wasm_bindgen::JsValue;
use wasm_bindgen_futures::future_to_promise;
use super::*;
use crate::backend::types::snark::SNARKProofTask;
use crate::backend::types::snark::SNARKVerifyTask;
use crate::backend::BackendMessageHandlerDynObj;
use crate::prelude::rings_core::utils::js_value;
use crate::provider::browser::ProviderRef;
#[wasm_bindgen]
#[derive(Deserialize, Serialize)]
pub struct SNARKProofTaskRef {
inner: Arc<SNARKProofTask>,
}
#[wasm_bindgen]
impl SNARKProofTaskRef {
pub fn split(&self, n: usize) -> Vec<SNARKProofTaskRef> {
self.inner.split(n).into_iter().map(|t| t.into()).collect()
}
pub fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(self)?)
}
pub fn from_json(s: String) -> Result<SNARKProofTaskRef> {
Ok(serde_json::from_str(&s)?)
}
}
impl AsRef<SNARKProofTask> for SNARKProofTaskRef {
fn as_ref(&self) -> &SNARKProofTask {
self.inner.as_ref()
}
}
impl std::ops::Deref for SNARKProofTaskRef {
type Target = Arc<SNARKProofTask>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl From<SNARKProofTask> for SNARKProofTaskRef {
fn from(t: SNARKProofTask) -> SNARKProofTaskRef {
SNARKProofTaskRef { inner: Arc::new(t) }
}
}
#[wasm_bindgen]
#[derive(Deserialize, Serialize)]
pub struct SNARKVerifyTaskRef {
inner: Arc<SNARKVerifyTask>,
}
#[wasm_bindgen]
impl SNARKVerifyTaskRef {
pub fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(self)?)
}
pub fn from_json(s: String) -> Result<SNARKVerifyTaskRef> {
Ok(serde_json::from_str(&s)?)
}
}
impl AsRef<SNARKVerifyTask> for SNARKVerifyTaskRef {
fn as_ref(&self) -> &SNARKVerifyTask {
self.inner.as_ref()
}
}
impl std::ops::Deref for SNARKVerifyTaskRef {
type Target = Arc<SNARKVerifyTask>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl From<SNARKVerifyTask> for SNARKVerifyTaskRef {
fn from(t: SNARKVerifyTask) -> SNARKVerifyTaskRef {
SNARKVerifyTaskRef { inner: Arc::new(t) }
}
}
#[wasm_bindgen]
impl SNARKVerifyTaskRef {
#[allow(clippy::should_implement_trait)]
pub fn clone(&self) -> SNARKVerifyTaskRef {
SNARKVerifyTaskRef {
inner: self.inner.clone(),
}
}
}
#[wasm_bindgen]
impl SNARKProofTaskRef {
#[allow(clippy::should_implement_trait)]
pub fn clone(&self) -> SNARKProofTaskRef {
SNARKProofTaskRef {
inner: self.inner.clone(),
}
}
}
#[wasm_bindgen]
impl SNARKBehaviour {
pub fn as_dyn_obj(self) -> BackendMessageHandlerDynObj {
BackendMessageHandlerDynObj::new(self.into())
}
pub fn handle_snark_task_message(
self,
provider: ProviderRef,
ctx: JsValue,
msg: JsValue,
) -> js_sys::Promise {
let ins = self.clone();
future_to_promise(async move {
let ctx = js_value::deserialize::<MessagePayload>(ctx)?;
let msg = js_value::deserialize::<SNARKTaskMessage>(msg)?;
ins.handle_message(provider.inner(), &ctx, &msg)
.await
.map_err(|e| Error::BackendError(e.to_string()))?;
Ok(JsValue::NULL)
})
}
pub fn gen_proof_task_ref(circuits: Vec<Circuit>) -> Result<SNARKProofTaskRef> {
SNARKBehaviour::gen_proof_task(circuits).map(|t| t.into())
}
pub fn handle_snark_proof_task_ref(data: SNARKProofTaskRef) -> Result<SNARKVerifyTaskRef> {
Self::handle_snark_proof_task(data).map(|x| x.into())
}
pub fn handle_snark_verify_task_ref(
data: SNARKVerifyTaskRef,
snark: SNARKProofTaskRef,
) -> Result<bool> {
Self::handle_snark_verify_task(data, snark)
}
pub fn send_proof_task_to(
&self,
provider: ProviderRef,
task: SNARKProofTaskRef,
did: String,
) -> js_sys::Promise {
let ins = self.clone();
future_to_promise(async move {
let ret = ins
.send_proof_task(
provider.inner().clone(),
task.as_ref(),
Did::from_str(&did)?,
)
.await
.map_err(JsError::from)?;
Ok(JsValue::from(ret))
})
}
pub fn gen_and_send_proof_task_to(
&self,
provider: ProviderRef,
circuits: Vec<Circuit>,
did: String,
) -> js_sys::Promise {
let ins = self.clone();
future_to_promise(async move {
let ret = ins
.gen_and_send_proof_task(provider.inner().clone(), circuits, Did::from_str(&did)?)
.await
.map_err(JsError::from)?;
Ok(JsValue::from(ret))
})
}
#[wasm_bindgen(constructor)]
pub fn new_instance() -> SNARKBehaviour {
SNARKBehaviour::default()
}
#[allow(clippy::should_implement_trait)]
pub fn clone(&self) -> SNARKBehaviour {
SNARKBehaviour {
inner: self.inner.clone(),
}
}
}
#[wasm_bindgen]
impl SNARKTaskBuilder {
#[wasm_bindgen(constructor)]
pub fn new_instance(
r1cs_path: String,
witness_wasm_path: String,
field: SupportedPrimeField,
) -> js_sys::Promise {
future_to_promise(async move {
let ret = SNARKTaskBuilder::from_remote(r1cs_path, witness_wasm_path, field)
.await
.map_err(JsError::from)?;
Ok(JsValue::from(ret))
})
}
}
pub(crate) fn bigint2ff<F: ff::PrimeField>(v: js_sys::BigInt) -> Result<F> {
let repr = v
.to_string(10)
.map_err(|e| Error::SNARKFFRangeError(format!("{:?}", e)))?
.as_string();
if let Some(v) = &repr {
Ok(F::from_str_vartime(v).ok_or(Error::FailedToLoadFF())?)
} else {
Err(Error::SNARKBigIntValueEmpty())
}
}
#[wasm_bindgen]
pub fn bigint_to_field(v: js_sys::BigInt, field: SupportedPrimeField) -> Result<Field> {
let ret = match field {
SupportedPrimeField::Vesta => {
type F = <provider::VestaEngine as Engine>::Scalar;
Field {
value: FieldEnum::Vesta(bigint2ff::<F>(v)?),
}
}
SupportedPrimeField::Pallas => {
type F = <provider::PallasEngine as Engine>::Scalar;
Field {
value: FieldEnum::Pallas(bigint2ff::<F>(v)?),
}
}
SupportedPrimeField::Bn256KZG => {
type F = <provider::Bn256EngineKZG as Engine>::Scalar;
Field {
value: FieldEnum::Bn256KZG(bigint2ff::<F>(v)?),
}
}
};
Ok(ret)
}
#[wasm_bindgen]
impl Input {
pub fn from_array(input: js_sys::Array, field: SupportedPrimeField) -> Input {
let data: Vec<(String, Vec<Field>)> = input
.into_iter()
.map(|s| {
let last = js_sys::Array::from(&s);
let p = last
.get(0)
.as_string()
.expect("first argument should be string like");
let v: Vec<Field> = js_sys::Array::from(&last.get(1))
.into_iter()
.map(|p| {
bigint_to_field(p.into(), field.clone())
.expect("failed to cover bigint to field")
})
.collect();
(p, v)
})
.collect();
Input(data)
}
}