=============================================== CCC Rust Crypto Provider — Architecture Plan =============================================== :Status: Approved :Phase: 4 :Date: 2026-02-23 :Author: Engineering Overview -------- Replace the Dart-only crypto stubs with a Cargo workspace of native Rust crates. A shared trait/capability core defines the contract every provider must satisfy. Per-provider sub-crates implement that contract. ``flutter_rust_bridge`` auto-generates ``dart:ffi`` bindings so Dart code calls Rust directly with no platform-channel overhead. wolfSSL / wolfCrypt is the first (and only Phase 4) provider. All future libraries slot into the same trait with zero changes to the core. Guiding Principles ------------------ 1. Every provider reports its own capabilities at runtime — no compile-time hard-coding of ``available: true/false``. 2. Algorithm IDs in Rust map 1-to-1 to the integer constants already in ``cipher_constants.dart`` — zero Dart routing changes needed. 3. Key material is zeroed on drop (``zeroize`` crate) everywhere. 4. A conformance / self-test suite validates cross-provider byte-identity before any provider is marked ``available``. 5. The Rust workspace has no runtime dependency on Flutter; it is a pure native library that could be consumed by any FFI host. FFI Bridge Decision ------------------- ``flutter_rust_bridge`` (FRB) is used rather than raw ``dart:ffi`` hand-wiring. FRB **is** ``dart:ffi`` — it uses ``dart:ffi`` under the hood and introduces no platform channels. The difference from raw ``dart:ffi`` is: ========================= ========================== ========================== Aspect flutter_rust_bridge Raw dart:ffi ========================= ========================== ========================== Rust-side code Clean idiomatic Rust ``extern "C"`` with C ABI Dart bindings **Auto-generated** Hand-written every field Async / isolate support Automatic Manual wiring Cross-type safety Codegen validates at build Discovered at runtime Beginner-friendliness High Low ========================= ========================== ========================== Repository Layout (target state) --------------------------------- :: ccc_rust/ ├── Cargo.toml ← workspace manifest (3 members) ├── rust-toolchain.toml ← pinned stable toolchain ├── .cargo/ │ └── config.toml ← cross-compile target aliases ├── vendors/ │ ├── README.md ← submodule pin rationale + upgrade notes │ └── wolfssl/ ← git submodule (wolfSSL/wolfssl @ v5.7.2-stable) ├── crates/ │ ├── ccc-crypto-core/ ← shared traits, enums, registry │ │ ├── Cargo.toml │ │ └── src/ │ │ ├── lib.rs │ │ ├── algorithms.rs ← algorithm enums (values == cipher_constants.dart) │ │ ├── capabilities.rs ← AlgorithmCapability, ProviderCapabilities │ │ ├── error.rs ← CryptoError enum │ │ ├── provider.rs ← CryptoProvider umbrella trait │ │ ├── registry.rs ← ProviderRegistry (OnceLock>) │ │ └── types.rs ← KemKeyPair, SelfTestReport, BenchmarkReport │ ├── ccc-crypto-wolfssl/ ← wolfSSL provider impl │ │ ├── Cargo.toml │ │ └── src/ │ │ ├── lib.rs │ │ ├── aead.rs ← AES-256-GCM, ChaCha20-Poly1305 │ │ ├── kdf.rs ← HKDF, Argon2id │ │ ├── mac.rs ← HMAC-SHA256/384/512 │ │ ├── hash.rs ← SHA-2, SHA-3, BLAKE2b │ │ ├── kem.rs ← X25519, X448, ML-KEM (if PQ build) │ │ ├── capabilities.rs ← probe-at-startup + benchmark │ │ └── provider.rs ← WolfSslProvider: CryptoProvider impl │ └── ccc-flutter-bridge/ ← flutter_rust_bridge entry point │ ├── Cargo.toml │ └── src/ │ ├── lib.rs │ ├── bridge.rs ← #[frb] exported functions │ └── dto.rs ← CapabilitiesDto, KemKeyPairDto, SelfTestDto ├── tests/ │ └── conformance/ │ ├── aes_gcm_vectors.rs │ ├── chacha_vectors.rs │ ├── hkdf_vectors.rs │ ├── hmac_vectors.rs │ └── cross_provider.rs ├── flutter_src/ │ └── ccc/ ← existing Dart files (minimal changes) └── docs/ Step 1 — Cargo Workspace Scaffold ---------------------------------- Files ~~~~~ ``Cargo.toml``:: [workspace] resolver = "2" members = [ "crates/ccc-crypto-core", "crates/ccc-crypto-wolfssl", "crates/ccc-flutter-bridge", ] ``rust-toolchain.toml``:: [toolchain] channel = "1.77" ``.cargo/config.toml``:: [alias] build-ios = "build --target aarch64-apple-ios" build-android-arm64 = "build --target aarch64-linux-android" build-android-x64 = "build --target x86_64-linux-android" build-macos = "build --target aarch64-apple-darwin" Step 2 — ``ccc-crypto-core`` Trait Crate ----------------------------------------- Algorithm Enumerations ~~~~~~~~~~~~~~~~~~~~~~ All discriminant values match the integer constants in ``cipher_constants.dart`` exactly, so the Dart cipher-sequencing logic requires zero changes. =================== ========================================================= Enum Variants → value =================== ========================================================= ``AeadAlgorithm`` AesGcm256=12, ChaCha20Poly1305=13, XChaCha20Poly1305=14, Ascon128a=15 ``KdfAlgorithm`` Sha256=1, Sha384=2, Sha512=3, Blake2b512=4 ``MacAlgorithm`` HmacSha256=30, HmacSha512=32, Blake2bMac=33 ``HashAlgorithm`` Sha256=40, Sha384=41, Sha512=42, Blake2b512=43, Sha3_256=44 ``KemAlgorithm`` X25519=50, X448=51, MlKem768=52, MlKem1024=53, ClassicMcEliece=54 =================== ========================================================= Key Structs ~~~~~~~~~~~ ``AlgorithmCapability``:: available: bool deterministic_io: bool efficiency_score: u8 // populated by WolfSslProvider::benchmark() reliability_score: u8 // populated by WolfSslProvider::self_test() ``ProviderCapabilities``:: provider_name: &'static str aead: HashMap kdf: HashMap mac: HashMap hash: HashMap kem: HashMap ``KemKeyPair``:: public_key: Zeroizing> private_key: Zeroizing> ``CryptoError``:: UnsupportedAlgorithm(String) InvalidKey(String) InvalidNonce(String) AuthenticationFailed InternalError(String) Provider Traits ~~~~~~~~~~~~~~~ .. code-block:: rust pub trait AeadProvider { fn encrypt_aead( &self, algo: AeadAlgorithm, key: &[u8], nonce: &[u8], plaintext: &[u8], aad: &[u8], ) -> Result, CryptoError>; fn decrypt_aead( &self, algo: AeadAlgorithm, key: &[u8], nonce: &[u8], ciphertext: &[u8], aad: &[u8], ) -> Result, CryptoError>; } pub trait KdfProvider { fn derive_key( &self, algo: KdfAlgorithm, ikm: &[u8], salt: &[u8], info: &[u8], length: usize, ) -> Result>, CryptoError>; } pub trait MacProvider { fn compute_mac( &self, algo: MacAlgorithm, key: &[u8], data: &[u8], ) -> Result, CryptoError>; fn verify_mac( &self, algo: MacAlgorithm, key: &[u8], data: &[u8], mac: &[u8], ) -> Result; } pub trait HashProvider { fn hash( &self, algo: HashAlgorithm, data: &[u8], ) -> Result, CryptoError>; } pub trait KemProvider { fn generate_keypair( &self, algo: KemAlgorithm, ) -> Result; fn encapsulate( &self, algo: KemAlgorithm, public_key: &[u8], ) -> Result<(Vec, Zeroizing>), CryptoError>; fn decapsulate( &self, algo: KemAlgorithm, private_key: &[u8], ciphertext: &[u8], ) -> Result>, CryptoError>; } pub trait CryptoProvider: AeadProvider + KdfProvider + MacProvider + HashProvider + Send + Sync { fn provider_name(&self) -> &'static str; fn capabilities(&self) -> ProviderCapabilities; fn self_test(&self) -> SelfTestReport; fn benchmark(&self) -> BenchmarkReport; } ``ProviderRegistry``:: OnceLock>>> fn register(name, provider) fn get(name) -> Option> fn list() -> Vec<&'static str> Step 3 — wolfSSL Submodule + ``ccc-crypto-wolfssl`` ----------------------------------------------------- Submodule Registration:: git submodule add https://github.com/wolfSSL/wolfssl vendors/wolfssl git -C vendors/wolfssl checkout v5.7.2-stable ``crates/ccc-crypto-wolfssl/Cargo.toml`` key dependencies:: wolfssl = { version = "0.1", features = ["pq", "blake2", "argon2"] } zeroize = { version = "1", features = ["derive"] } ccc-crypto-core = { path = "../ccc-crypto-core" } wolfSSL Phase 4 Algorithm Coverage ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ =================== =========================================== Category Algorithms =================== =========================================== AEAD AES-256-GCM, ChaCha20-Poly1305 KDF HKDF-SHA256/384/512, PBKDF2, Argon2id MAC HMAC-SHA256/384/512, Poly1305 Hash SHA-256/384/512, SHA3-256/512, BLAKE2b-512 KEM (if PQ build) X25519, X448, ML-KEM-768, ML-KEM-1024 =================== =========================================== Capability Probe Strategy ~~~~~~~~~~~~~~~~~~~~~~~~~~ ``WolfSslProvider::capabilities()`` runs a minimal probe call per algorithm at startup (encrypt 1-byte payload; decrypt; compare). Sets ``available = probe_succeeded``. If the wolfSSL build does not include PQ support, ML-KEM entries gracefully report ``available: false``. Benchmark Strategy ~~~~~~~~~~~~~~~~~~ ``WolfSslProvider::benchmark()`` encrypts a 1 MB buffer × 100 iterations per AEAD algorithm, measures wall-clock throughput, normalises to a 0–100 ``efficiency_score``. Run once at ``ccc_init()`` and cached. Step 4 — ``ccc-flutter-bridge`` Entry-Point Crate --------------------------------------------------- Exported Functions (``#[frb]`` tagged) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. code-block:: text ccc_init() → initialise registry + run benchmarks ccc_list_providers() → Vec ccc_provider_capabilities(provider) → CapabilitiesDto ccc_aead_encrypt(provider, algo: u32, key, nonce, plaintext, aad) → Result> ccc_aead_decrypt(provider, algo: u32, key, nonce, ciphertext, aad) → Result> ccc_derive_key(provider, algo: u32, ikm, salt, info, length: u32) → Result> ccc_compute_mac(provider, algo: u32, key, data) → Result> ccc_verify_mac(provider, algo: u32, key, data, mac) → Result ccc_hash(provider, algo: u32, data) → Result> ccc_kem_generate_keypair(provider, algo: u32) → Result ccc_kem_encapsulate(provider, algo: u32, public_key) → Result ccc_kem_decapsulate(provider, algo: u32, private_key, ciphertext) → Result> ccc_self_test(provider) → SelfTestDto DTO Structs ~~~~~~~~~~~ ``CapabilitiesDto`` — mirrors ``ProviderCapabilities``, uses primitive types so ``flutter_rust_bridge`` can auto-generate the Dart data class. ``KemKeyPairDto { public_key: Vec, private_key: Vec }`` ``KemEncapDto { ciphertext: Vec, shared_secret: Vec }`` ``SelfTestDto { provider: String, results: Vec }`` ``AlgoTestResult { algo_id: u32, algo_name: String, passed: bool, error_message: Option }`` Step 5 — Flutter Build Integration ------------------------------------ * Add ``flutter_rust_bridge: ^2`` to ``pubspec.yaml`` * Run ``flutter_rust_bridge_codegen generate`` → emits ``flutter_src/ccc_crypto_bindings/ccc_crypto.dart`` * ``crate-type = ["cdylib", "staticlib"]`` in ``ccc-flutter-bridge/Cargo.toml`` (``cdylib`` for Android / Linux / macOS, ``staticlib`` for iOS) * Cargokit handles cross-compilation inside standard Flutter plugin dirs (``ios/``, ``android/``, ``macos/``) Step 6 — Dart Layer Wiring --------------------------- ``crypto_wolfssl.dart`` ~~~~~~~~~~~~~~~~~~~~~~~~ Replace ``UnimplementedError`` stubs: .. code-block:: dart @override Future> encrypt(Map input, {CryptoContext? context}) async { final algo = context?.cipherSequence?.first ?? CipherConstants.AES_GCM_256; final key = _resolveKey(context); final nonce = _generateNonce(algo); return CccCrypto.ccmAeadEncrypt( provider: 'wolfssl', algo: algo, key: key, nonce: nonce, plaintext: _encodePayload(input), aad: _buildAad(context)); } ``ccc_provider_spec.dart`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Convert ``CccProviderCatalog.capabilities`` from a compile-time static map to a runtime-populated map. At app start call:: await CccCrypto.cccInit(); final providers = await CccCrypto.cccListProviders(); for (final name in providers) { final dto = await CccCrypto.cccProviderCapabilities(provider: name); CccProviderCatalog.populate(name, dto); } ``CccSelfTest`` ~~~~~~~~~~~~~~~~ New Dart class that wraps ``CccCrypto.cccSelfTest(provider: name)`` and exposes per-algorithm pass/fail results in the app's debug diagnostics screen. Step 7 — Conformance Test Suite --------------------------------- Location: ``tests/conformance/`` * ``aes_gcm_vectors.rs`` — NIST SP 800-38D GCM test vectors * ``chacha_vectors.rs`` — RFC 8439 ChaCha20-Poly1305 test vectors * ``hkdf_vectors.rs`` — RFC 5869 HKDF-SHA256 / SHA512 test vectors * ``hmac_vectors.rs`` — RFC 4231 HMAC-SHA256 / SHA512 test vectors * ``cross_provider.rs`` — encrypt with wolfSSL → decrypt expectation matches the reference output from the Dart ``cryptography`` package for the same key/nonce/plaintext/aad (validates ``deterministic_io: true``) Step 8 — Architecture Documentation -------------------------------------- ``docs/phase4_rust_architecture.rst`` covers: * Crate dependency graph (ASCII) * "How to add a new provider" — the 7-step trait checklist * ``algo: u32`` → cipher constant mapping table * Stretch-goal Phase 8 "Omni-Crypto" provider list Phase 8 — Stretch Goal Provider List -------------------------------------- *(Fully out of scope for Phase 4. Documented here for future planning.)* ================== ===================================================== Library Rust crate / approach ================== ===================================================== libsodium ``sodiumoxide`` or ``safe_libsodium`` OpenSSL ``openssl`` crate BoringSSL ``boring`` crate RustCrypto Pure-Rust trait impls; no native dep liboqs Open Quantum Safe — ML-KEM, BIKE, HQC, Falcon, Dilithium, SPHINCS+ Signal libsignal ``libsignal`` (Apache-2 subset) Botan ``botan`` crate mbedTLS ``mbedtls`` crate Nettle ``nettle-sys`` crate ================== ===================================================== Verification Checklist ----------------------- * ``cargo test --workspace`` passes including all NIST vectors * ``cargo build --target aarch64-apple-ios`` succeeds * ``cargo build --target aarch64-linux-android`` succeeds * Flutter integration test: roundtrip encrypt/decrypt 1 KB via ``CryptoWolfSsl`` Dart class * ``CccSelfTest.runAll()`` returns all-pass in the app debug screen * Cross-provider conformance: Dart ↔ wolfSSL byte-identity confirmed (``deterministic_io: true`` verified for AES-256-GCM and ChaCha20-Poly1305)