lib-q-core 0.0.4

Core types and traits for lib-Q post-quantum cryptography library
Documentation
//! Common WASM patterns and utilities for lib-Q
//!
//! This module provides shared WASM structures and utilities to eliminate
//! code duplication across the library.

#[cfg(feature = "wasm")]
use js_sys::Uint8Array;
#[cfg(feature = "wasm")]
use wasm_bindgen::prelude::*;

#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")]
#[allow(unused_imports)]
use alloc::string::String;

/// Common trait for WASM key pairs
#[cfg(feature = "wasm")]
pub trait WasmKeyPair {
    fn public_key(&self) -> Uint8Array;
    fn secret_key(&self) -> Uint8Array;
}

/// Generic WASM key pair implementation
#[cfg(feature = "wasm")]
#[wasm_bindgen]
pub struct WasmKeyPairImpl {
    public_key: Uint8Array,
    secret_key: Uint8Array,
}

#[cfg(feature = "wasm")]
#[wasm_bindgen]
impl WasmKeyPairImpl {
    #[wasm_bindgen(constructor)]
    pub fn new(public_key: Uint8Array, secret_key: Uint8Array) -> WasmKeyPairImpl {
        WasmKeyPairImpl {
            public_key,
            secret_key,
        }
    }

    #[wasm_bindgen(getter)]
    pub fn public_key(&self) -> Uint8Array {
        self.public_key.clone()
    }

    #[wasm_bindgen(getter)]
    pub fn secret_key(&self) -> Uint8Array {
        self.secret_key.clone()
    }
}

#[cfg(feature = "wasm")]
impl WasmKeyPair for WasmKeyPairImpl {
    fn public_key(&self) -> Uint8Array {
        self.public_key.clone()
    }

    fn secret_key(&self) -> Uint8Array {
        self.secret_key.clone()
    }
}

/// WASM-compatible hash result
#[cfg(feature = "wasm")]
#[wasm_bindgen]
pub struct HashResultWasm {
    hash: Uint8Array,
    algorithm: String,
}

#[cfg(feature = "wasm")]
#[wasm_bindgen]
impl HashResultWasm {
    #[wasm_bindgen(constructor)]
    pub fn new(hash: Uint8Array, algorithm: String) -> HashResultWasm {
        HashResultWasm { hash, algorithm }
    }

    #[wasm_bindgen(getter)]
    pub fn hash(&self) -> Uint8Array {
        self.hash.clone()
    }

    #[wasm_bindgen(getter)]
    pub fn algorithm(&self) -> String {
        self.algorithm.clone()
    }
}

/// Stable numeric category id for programmatic `switch` in JS (FNV-1a 32-bit of `code`).
#[cfg(feature = "wasm")]
fn wasm_error_code_numeric(code: &str) -> u32 {
    const OFFSET_BASIS: u32 = 0x811C_9DC5;
    const PRIME: u32 = 0x0100_0193;
    let mut hash = OFFSET_BASIS;
    for b in code.as_bytes() {
        hash ^= u32::from(*b);
        hash = hash.wrapping_mul(PRIME);
    }
    hash
}

/// Structured error for JavaScript callers: `{ "code", "codeNumeric", "message" }`.
#[cfg(feature = "wasm")]
pub fn wasm_js_error(code: &str, message: impl core::fmt::Display) -> JsValue {
    use alloc::format;

    let code_numeric = wasm_error_code_numeric(code);
    let v = serde_json::json!({
        "code": code,
        "codeNumeric": code_numeric,
        "message": format!("{message}"),
    });
    serde_wasm_bindgen::to_value(&v).unwrap_or_else(|_| {
        JsValue::from_str("lib-q-core: failed to serialize structured WASM error")
    })
}

/// Utility functions for WASM conversions
#[cfg(feature = "wasm")]
pub mod conversions {
    use alloc::vec::Vec;

    use js_sys::Uint8Array;

    /// Convert Rust Vec<u8> to WASM Uint8Array
    pub fn vec_to_uint8array(data: &[u8]) -> Uint8Array {
        let array = Uint8Array::new_with_length(data.len() as u32);
        array.copy_from(data);
        array
    }

    /// Convert WASM Uint8Array to Rust Vec<u8>
    pub fn uint8array_to_vec(array: &Uint8Array) -> Vec<u8> {
        let length = array.length() as usize;
        let mut vec = alloc::vec![0u8; length];
        array.copy_to(&mut vec);
        vec
    }
}

#[cfg(test)]
mod tests {

    #[test]
    fn test_wasm_common_structure() {
        // Test that the module compiles correctly
        // In a real WASM environment, these would be tested with wasm-bindgen-test
        // This is a placeholder for WASM-specific initialization
    }
}