#[cfg(feature = "wasm")]
use wasm_bindgen::prelude::*;
#[cfg(feature = "wasm")]
use crate::{
blsag::{key_images_match, sign_blsag_hex, verify_blsag_hex},
keys::generate_keypair_hex,
sag::{sign, verify},
sign_compact_blsag,
sign_compact_sag,
verify_compact,
CompactSignature,
};
#[cfg(feature = "wasm")]
pub fn set_panic_hook() {
console_error_panic_hook::set_once();
}
#[cfg(feature = "wasm")]
#[wasm_bindgen]
pub struct WasmRingSignature {
c0: String,
s: Box<[JsValue]>,
}
#[cfg(feature = "wasm")]
#[wasm_bindgen]
impl WasmRingSignature {
#[wasm_bindgen(constructor)]
pub fn new(c0: String, s: Box<[JsValue]>) -> WasmRingSignature {
WasmRingSignature { c0, s }
}
#[wasm_bindgen(getter)]
pub fn c0(&self) -> String {
self.c0.clone()
}
#[wasm_bindgen(getter)]
pub fn s(&self) -> Box<[JsValue]> {
self.s.clone()
}
}
#[cfg(feature = "wasm")]
#[wasm_bindgen]
pub struct WasmBlsagSignature {
c0: String,
s: Box<[JsValue]>,
key_image: String,
}
#[cfg(feature = "wasm")]
#[wasm_bindgen]
impl WasmBlsagSignature {
#[wasm_bindgen(constructor)]
pub fn new(c0: String, s: Box<[JsValue]>, key_image: String) -> WasmBlsagSignature {
WasmBlsagSignature { c0, s, key_image }
}
#[wasm_bindgen(getter)]
pub fn c0(&self) -> String {
self.c0.clone()
}
#[wasm_bindgen(getter)]
pub fn s(&self) -> Box<[JsValue]> {
self.s.clone()
}
#[wasm_bindgen(getter)]
pub fn key_image(&self) -> String {
self.key_image.clone()
}
}
#[cfg(feature = "wasm")]
#[wasm_bindgen]
pub struct WasmKeyPair {
private_key_hex: String,
public_key_hex: String,
}
#[cfg(feature = "wasm")]
#[wasm_bindgen]
impl WasmKeyPair {
#[wasm_bindgen(constructor)]
pub fn new(private_key_hex: String, public_key_hex: String) -> WasmKeyPair {
WasmKeyPair {
private_key_hex,
public_key_hex,
}
}
#[wasm_bindgen(getter)]
pub fn private_key_hex(&self) -> String {
self.private_key_hex.clone()
}
#[wasm_bindgen(getter)]
pub fn public_key_hex(&self) -> String {
self.public_key_hex.clone()
}
}
#[cfg(feature = "wasm")]
#[wasm_bindgen(start)]
pub fn start() {
set_panic_hook();
}
#[cfg(feature = "wasm")]
#[wasm_bindgen]
pub fn wasm_generate_keypair(format: &str) -> Result<WasmKeyPair, JsValue> {
let keypair = generate_keypair_hex(format);
Ok(WasmKeyPair {
private_key_hex: keypair.private_key_hex,
public_key_hex: keypair.public_key_hex,
})
}
#[cfg(feature = "wasm")]
#[wasm_bindgen]
pub fn wasm_sign(
message: &[u8],
private_key_hex: &str,
ring_pubkeys: Box<[JsValue]>,
) -> Result<WasmRingSignature, JsValue> {
let ring_pubkeys_vec: Vec<String> = ring_pubkeys
.iter()
.map(|v| {
v.as_string()
.ok_or_else(|| JsValue::from_str("Invalid public key"))
})
.collect::<Result<Vec<String>, JsValue>>()?;
let signature = sign(message, private_key_hex, &ring_pubkeys_vec)
.map_err(|e| JsValue::from_str(&format!("Error: {}", e)))?;
let s_values: Vec<JsValue> = signature.s.iter().map(|s| JsValue::from_str(s)).collect();
Ok(WasmRingSignature {
c0: signature.c0,
s: s_values.into_boxed_slice(),
})
}
#[cfg(feature = "wasm")]
#[wasm_bindgen]
pub fn wasm_verify(
signature: &WasmRingSignature,
message: &[u8],
ring_pubkeys: Box<[JsValue]>,
) -> Result<bool, JsValue> {
let ring_pubkeys_vec: Vec<String> = ring_pubkeys
.iter()
.map(|v| {
v.as_string()
.ok_or_else(|| JsValue::from_str("Invalid public key"))
})
.collect::<Result<Vec<String>, JsValue>>()?;
let s_values: Vec<String> = signature
.s
.iter()
.map(|v| {
v.as_string()
.ok_or_else(|| JsValue::from_str("Invalid s value"))
})
.collect::<Result<Vec<String>, JsValue>>()?;
let rust_signature = crate::RingSignature {
c0: signature.c0.clone(),
s: s_values,
};
let result = verify(&rust_signature, message, &ring_pubkeys_vec)
.map_err(|e| JsValue::from_str(&format!("Error: {}", e)))?;
Ok(result)
}
#[cfg(feature = "wasm")]
#[wasm_bindgen]
pub fn wasm_sign_blsag(
message: &[u8],
private_key_hex: &str,
ring_pubkeys: Box<[JsValue]>,
) -> Result<WasmBlsagSignature, JsValue> {
let ring_pubkeys_vec: Vec<String> = ring_pubkeys
.iter()
.map(|v| {
v.as_string()
.ok_or_else(|| JsValue::from_str("Invalid public key"))
})
.collect::<Result<Vec<String>, JsValue>>()?;
let (signature, key_image) = sign_blsag_hex(message, private_key_hex, &ring_pubkeys_vec)
.map_err(|e| JsValue::from_str(&format!("Error: {}", e)))?;
let s_values: Vec<JsValue> = signature.s.iter().map(|s| JsValue::from_str(s)).collect();
Ok(WasmBlsagSignature {
c0: signature.c0,
s: s_values.into_boxed_slice(),
key_image,
})
}
#[cfg(feature = "wasm")]
#[wasm_bindgen]
pub fn wasm_verify_blsag(
signature: &WasmBlsagSignature,
message: &[u8],
ring_pubkeys: Box<[JsValue]>,
) -> Result<bool, JsValue> {
let ring_pubkeys_vec: Vec<String> = ring_pubkeys
.iter()
.map(|v| {
v.as_string()
.ok_or_else(|| JsValue::from_str("Invalid public key"))
})
.collect::<Result<Vec<String>, JsValue>>()?;
let s_values: Vec<String> = signature
.s
.iter()
.map(|v| {
v.as_string()
.ok_or_else(|| JsValue::from_str("Invalid s value"))
})
.collect::<Result<Vec<String>, JsValue>>()?;
let rust_signature = crate::types::BlsagSignature {
c0: signature.c0.clone(),
s: s_values,
};
let result = verify_blsag_hex(
&rust_signature,
&signature.key_image,
message,
&ring_pubkeys_vec,
)
.map_err(|e| JsValue::from_str(&format!("Error: {}", e)))?;
Ok(result)
}
#[cfg(feature = "wasm")]
#[wasm_bindgen]
pub fn wasm_key_images_match(image1: &str, image2: &str) -> Result<bool, JsValue> {
let ki1 = crate::types::KeyImage::from_hex(image1)
.map_err(|e| JsValue::from_str(&format!("Error parsing key image 1: {}", e)))?;
let ki2 = crate::types::KeyImage::from_hex(image2)
.map_err(|e| JsValue::from_str(&format!("Error parsing key image 2: {}", e)))?;
Ok(key_images_match(&ki1, &ki2))
}
#[cfg(feature = "wasm")]
#[wasm_bindgen]
pub fn wasm_sign_compact_sag(
message: &[u8],
private_key_hex: &str,
ring_pubkeys: Box<[JsValue]>,
) -> Result<String, JsValue> {
let ring_pubkeys_vec: Vec<String> = ring_pubkeys
.iter()
.map(|v| {
v.as_string()
.ok_or_else(|| JsValue::from_str("Invalid public key"))
})
.collect::<Result<Vec<String>, JsValue>>()?;
sign_compact_sag(message, private_key_hex, &ring_pubkeys_vec)
.map_err(|e| JsValue::from_str(&format!("Error: {}", e)))
}
#[cfg(feature = "wasm")]
#[wasm_bindgen]
pub fn wasm_sign_compact_blsag(
message: &[u8],
private_key_hex: &str,
ring_pubkeys: Box<[JsValue]>,
) -> Result<String, JsValue> {
let ring_pubkeys_vec: Vec<String> = ring_pubkeys
.iter()
.map(|v| {
v.as_string()
.ok_or_else(|| JsValue::from_str("Invalid public key"))
})
.collect::<Result<Vec<String>, JsValue>>()?;
sign_compact_blsag(message, private_key_hex, &ring_pubkeys_vec)
.map_err(|e| JsValue::from_str(&format!("Error: {}", e)))
}
#[cfg(feature = "wasm")]
#[wasm_bindgen]
pub fn wasm_verify_compact(
compact_signature: &str,
message: &[u8],
ring_pubkeys: Box<[JsValue]>,
) -> Result<bool, JsValue> {
let ring_pubkeys_vec: Vec<String> = ring_pubkeys
.iter()
.map(|v| {
v.as_string()
.ok_or_else(|| JsValue::from_str("Invalid public key"))
})
.collect::<Result<Vec<String>, JsValue>>()?;
verify_compact(compact_signature, message, &ring_pubkeys_vec)
.map_err(|e| JsValue::from_str(&format!("Error: {}", e)))
}
#[cfg(feature = "wasm")]
#[wasm_bindgen]
pub fn wasm_get_compact_signature_info(compact_signature: &str) -> Result<JsValue, JsValue> {
let compact_sig = CompactSignature::deserialize(compact_signature)
.map_err(|e| JsValue::from_str(&format!("Error: {}", e)))?;
let variant = compact_sig.variant();
let size = compact_signature.len();
let info = js_sys::Object::new();
js_sys::Reflect::set(
&info,
&JsValue::from_str("variant"),
&JsValue::from_str(variant),
)
.map_err(|_| JsValue::from_str("Failed to set variant"))?;
js_sys::Reflect::set(
&info,
&JsValue::from_str("size"),
&JsValue::from_f64(size as f64),
)
.map_err(|_| JsValue::from_str("Failed to set size"))?;
Ok(info.into())
}