confium_wasm/
composite.rs1use confium_composite::{CompositeSignature as RustComposite, VerificationResult};
5use wasm_bindgen::prelude::*;
6
7#[wasm_bindgen]
11pub struct CompositeSignature {
12 inner: RustComposite,
13}
14
15#[wasm_bindgen]
16impl CompositeSignature {
17 #[wasm_bindgen(constructor)]
28 pub fn from_json(json: &str) -> Result<CompositeSignature, JsValue> {
29 let inner: RustComposite = serde_json::from_str(json)
30 .map_err(|e| js_err(&format!("invalid composite signature JSON: {e}")))?;
31 Ok(Self { inner })
32 }
33
34 #[wasm_bindgen(getter)]
36 pub fn component_count(&self) -> usize {
37 self.inner.component_count()
38 }
39
40 #[wasm_bindgen(getter)]
42 pub fn algorithms(&self) -> Vec<String> {
43 self.inner
44 .algorithms()
45 .into_iter()
46 .map(String::from)
47 .collect()
48 }
49
50 #[wasm_bindgen]
58 pub fn verify(&self, message: &[u8]) -> Result<CompositeVerificationResult, JsValue> {
59 let result = self
60 .inner
61 .verify(message, |algorithm, public_key, m, signature| {
62 if algorithm == confium_composite::ED25519 {
63 confium_composite::ed25519_verifier(algorithm, public_key, m, signature)
64 } else if algorithm == "ECDSA-P256" || algorithm == "ECDSA" {
65 p256_verifier(public_key, m, signature)
66 } else {
67 Err(format!("unsupported algorithm: {algorithm}"))
68 }
69 })
70 .map_err(|e| js_err(&e.to_string()))?;
71 Ok(CompositeVerificationResult { inner: result })
72 }
73}
74
75fn p256_verifier(public_key: &[u8], message: &[u8], signature: &[u8]) -> Result<(), String> {
79 use p256::ecdsa::{Signature, VerifyingKey, signature::Verifier};
80 let vk = VerifyingKey::from_sec1_bytes(public_key)
81 .map_err(|e| format!("invalid P-256 public key: {e}"))?;
82 let sig = Signature::from_der(signature).map_err(|e| format!("invalid DER signature: {e}"))?;
83 vk.verify(message, &sig).map_err(|e| format!("verify: {e}"))
84}
85
86#[wasm_bindgen]
88pub struct CompositeVerificationResult {
89 inner: VerificationResult,
90}
91
92#[wasm_bindgen]
93impl CompositeVerificationResult {
94 #[wasm_bindgen(getter)]
96 pub fn all_verified(&self) -> bool {
97 self.inner.all_verified
98 }
99
100 #[wasm_bindgen(getter)]
104 pub fn per_component_json(&self) -> String {
105 let entries: Vec<String> = self
108 .inner
109 .per_component
110 .iter()
111 .map(|c| {
112 let alg = serde_json::to_string(&c.algorithm).unwrap_or_else(|_| "\"\"".into());
113 let err = match &c.error {
114 Some(e) => format!(
115 ",\"error\":{}",
116 serde_json::to_string(e).unwrap_or_else(|_| "null".into())
117 ),
118 None => String::new(),
119 };
120 format!(
121 "{{\"index\":{},\"algorithm\":{},\"verified\":{}{}}}",
122 c.index, alg, c.verified, err
123 )
124 })
125 .collect();
126 format!("[{}]", entries.join(","))
127 }
128}
129
130fn js_err(msg: &str) -> JsValue {
131 JsValue::from_str(msg)
132}