//! Public bridge functions — annotated with `#[frb(sync)]` or `#[frb]` so //! that `flutter_rust_bridge` code-generation emits matching Dart APIs. //! //! All fallible functions return `anyhow::Result` (FRB v2 maps that to a //! Dart `Future` that throws on error). //! //! # Naming convention //! Functions are named `ccc__` so the generated Dart class //! is pleasingly namespaced as `CccBridge.xxxYyy(…)`. use flutter_rust_bridge::frb; use zeroize::Zeroizing; use ccc_crypto_core::{ algorithms::{AeadAlgorithm, HashAlgorithm, KdfAlgorithm, KemAlgorithm, MacAlgorithm}, registry::ProviderRegistry, }; // Provider traits are imported for use in future dispatch methods. #[allow(unused_imports)] use ccc_crypto_core::provider::{AeadProvider, HashProvider, KdfProvider, KemProvider, MacProvider}; use super::dto::{ AeadEncryptRequest, AeadEncryptResult, AlgorithmCapabilityDto, HashRequest, KdfDeriveRequest, KemEncapResultDto, KemKeyPairDto, MacComputeRequest, ProviderCapabilitiesDto, SelfTestReportDto, }; // ────────────────────────────────────────────────────────────────────────────── // Initialisation // ────────────────────────────────────────────────────────────────────────────── /// Initialise the CCC Rust layer. /// /// **Must** be called once before any other bridge function, typically during /// the app's boot sequence in `main.dart` (or `AppState.init()`). /// /// Registers the wolfSSL provider into the global [`ProviderRegistry`]. /// Subsequent calls are no-ops. #[frb(sync)] pub fn ccc_init() { static ONCE: std::sync::OnceLock<()> = std::sync::OnceLock::new(); ONCE.get_or_init(|| { let _ = env_logger::try_init(); // tolerate error when already initialised ccc_crypto_wolfssl::init(); log::info!("[ccc-bridge] wolfSSL provider registered"); }); } // ────────────────────────────────────────────────────────────────────────────── // Provider registry queries // ────────────────────────────────────────────────────────────────────────────── /// List all registered provider names. #[frb(sync)] pub fn ccc_list_providers() -> Vec { ProviderRegistry::global().list() } /// Retrieve full capabilities for a named provider. /// /// Returns `None` if the provider is not registered. #[frb(sync)] pub fn ccc_capabilities(provider_name: String) -> Option { let reg = ProviderRegistry::global(); let guard = reg.get(&provider_name)?; Some(guard.capabilities().into()) } /// List all algorithms of a specific family that are **available** in a provider. /// /// `family` is one of `"aead"`, `"kdf"`, `"mac"`, `"hash"`, `"kem"`. #[frb(sync)] pub fn ccc_available_algorithms( provider_name: String, family: String, ) -> Vec { let reg = ProviderRegistry::global(); let Some(guard) = reg.get(&provider_name) else { return vec![] }; // Convert the full capability map to DTO (which flattens HashMaps → Vecs). let caps_dto: ProviderCapabilitiesDto = guard.capabilities().into(); let mut list = match family.as_str() { "aead" => caps_dto.aead, "kdf" => caps_dto.kdf, "mac" => caps_dto.mac, "hash" => caps_dto.hash, "kem" => caps_dto.kem, _ => vec![], }; list.retain(|c| c.available); list } // ────────────────────────────────────────────────────────────────────────────── // AEAD // ────────────────────────────────────────────────────────────────────────────── /// Encrypt with an AEAD cipher. /// /// Returns `ciphertext || 16-byte authentication tag` on success. /// /// # Errors /// Propagates [`ccc_crypto_core::error::CryptoError`] as an `anyhow::Result`. pub fn ccc_aead_encrypt(req: AeadEncryptRequest) -> anyhow::Result { let algo = AeadAlgorithm::from_u32(req.algo_id) .ok_or_else(|| anyhow::anyhow!("unknown AEAD algo_id: {}", req.algo_id))?; let reg = ProviderRegistry::global(); let guard = reg .get("wolfssl") .ok_or_else(|| anyhow::anyhow!("wolfssl provider not registered"))?; let ct_tag = guard.encrypt_aead(algo, &req.key, &req.nonce, &req.plaintext, &req.aad)?; Ok(AeadEncryptResult { ciphertext_and_tag: ct_tag }) } /// Decrypt with an AEAD cipher. /// /// Expects `ciphertext || 16-byte authentication tag` as `ciphertext_and_tag`. /// Returns plaintext on success; returns an error if authentication fails. pub fn ccc_aead_decrypt( algo_id: u32, key: Vec, nonce: Vec, ciphertext_and_tag: Vec, aad: Vec, ) -> anyhow::Result> { let algo = AeadAlgorithm::from_u32(algo_id) .ok_or_else(|| anyhow::anyhow!("unknown AEAD algo_id: {}", algo_id))?; let reg = ProviderRegistry::global(); let guard = reg .get("wolfssl") .ok_or_else(|| anyhow::anyhow!("wolfssl provider not registered"))?; Ok(guard.decrypt_aead(algo, &key, &nonce, &ciphertext_and_tag, &aad)?) } // ────────────────────────────────────────────────────────────────────────────── // KDF // ────────────────────────────────────────────────────────────────────────────── /// Derive a key using a KDF. /// /// Returns the derived key bytes (length = `req.out_length`). pub fn ccc_kdf_derive(req: KdfDeriveRequest) -> anyhow::Result> { let algo = KdfAlgorithm::from_u32(req.algo_id) .ok_or_else(|| anyhow::anyhow!("unknown KDF algo_id: {}", req.algo_id))?; let reg = ProviderRegistry::global(); let guard = reg .get("wolfssl") .ok_or_else(|| anyhow::anyhow!("wolfssl provider not registered"))?; let out: Zeroizing> = guard.derive_key(algo, &req.ikm, &req.salt, &req.info, req.out_length as usize)?; // Dart does not share memory with Rust; returning a plain Vec is safe. Ok(out.to_vec()) } // ────────────────────────────────────────────────────────────────────────────── // MAC // ────────────────────────────────────────────────────────────────────────────── /// Compute a MAC tag. pub fn ccc_mac_compute(req: MacComputeRequest) -> anyhow::Result> { let algo = MacAlgorithm::from_u32(req.algo_id) .ok_or_else(|| anyhow::anyhow!("unknown MAC algo_id: {}", req.algo_id))?; let reg = ProviderRegistry::global(); let guard = reg .get("wolfssl") .ok_or_else(|| anyhow::anyhow!("wolfssl provider not registered"))?; Ok(guard.compute_mac(algo, &req.key, &req.data)?) } /// Verify a MAC tag in constant time (returns `true` if authentic). pub fn ccc_mac_verify( algo_id: u32, key: Vec, data: Vec, mac_bytes: Vec, ) -> anyhow::Result { let algo = MacAlgorithm::from_u32(algo_id) .ok_or_else(|| anyhow::anyhow!("unknown MAC algo_id: {}", algo_id))?; let reg = ProviderRegistry::global(); let guard = reg .get("wolfssl") .ok_or_else(|| anyhow::anyhow!("wolfssl provider not registered"))?; Ok(guard.verify_mac(algo, &key, &data, &mac_bytes)?) } // ────────────────────────────────────────────────────────────────────────────── // Hash // ────────────────────────────────────────────────────────────────────────────── /// Compute a cryptographic hash. pub fn ccc_hash(req: HashRequest) -> anyhow::Result> { let algo = HashAlgorithm::from_u32(req.algo_id) .ok_or_else(|| anyhow::anyhow!("unknown Hash algo_id: {}", req.algo_id))?; let reg = ProviderRegistry::global(); let guard = reg .get("wolfssl") .ok_or_else(|| anyhow::anyhow!("wolfssl provider not registered"))?; Ok(guard.hash(algo, &req.data)?) } // ────────────────────────────────────────────────────────────────────────────── // KEM // ────────────────────────────────────────────────────────────────────────────── /// Generate a KEM key pair. pub fn ccc_kem_generate_keypair(algo_id: u32) -> anyhow::Result { let algo = KemAlgorithm::from_u32(algo_id) .ok_or_else(|| anyhow::anyhow!("unknown KEM algo_id: {}", algo_id))?; let reg = ProviderRegistry::global(); let guard = reg .get("wolfssl") .ok_or_else(|| anyhow::anyhow!("wolfssl provider not registered"))?; // WolfSslProvider also implements KemProvider. // Down-cast via concrete type via the global init path. use ccc_crypto_wolfssl::provider::WolfSslProvider; let _ = guard; // release the Arc lock before constructing a temporary let temp = WolfSslProvider::new(); Ok(temp.generate_keypair(algo)?.into()) } /// Encapsulate a shared secret to a public key. pub fn ccc_kem_encapsulate(algo_id: u32, public_key: Vec) -> anyhow::Result { let algo = KemAlgorithm::from_u32(algo_id) .ok_or_else(|| anyhow::anyhow!("unknown KEM algo_id: {}", algo_id))?; use ccc_crypto_wolfssl::provider::WolfSslProvider; let temp = WolfSslProvider::new(); Ok(temp.encapsulate(algo, &public_key)?.into()) } /// Decapsulate a shared secret using a private key. /// /// Returns the shared secret bytes. pub fn ccc_kem_decapsulate( algo_id: u32, private_key: Vec, ciphertext: Vec, ) -> anyhow::Result> { let algo = KemAlgorithm::from_u32(algo_id) .ok_or_else(|| anyhow::anyhow!("unknown KEM algo_id: {}", algo_id))?; use ccc_crypto_wolfssl::provider::WolfSslProvider; let temp = WolfSslProvider::new(); let secret: Zeroizing> = temp.decapsulate(algo, &private_key, &ciphertext)?; Ok(secret.to_vec()) } // ────────────────────────────────────────────────────────────────────────────── // Self-test // ────────────────────────────────────────────────────────────────────────────── /// Run the embedded NIST / RFC test vectors for the wolfSSL provider. /// /// Returns a full [`SelfTestReportDto`]; `all_passed == true` means every /// algorithm passed its vectors. Check individual `results` for details. pub fn ccc_self_test() -> anyhow::Result { let reg = ProviderRegistry::global(); let guard = reg .get("wolfssl") .ok_or_else(|| anyhow::anyhow!("wolfssl provider not registered"))?; Ok(guard.self_test().into()) }