449 lines
17 KiB
ReStructuredText
449 lines
17 KiB
ReStructuredText
===============================================
|
||
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<Mutex<...>>)
|
||
│ │ └── 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<AeadAlgorithm, AlgorithmCapability>
|
||
kdf: HashMap<KdfAlgorithm, AlgorithmCapability>
|
||
mac: HashMap<MacAlgorithm, AlgorithmCapability>
|
||
hash: HashMap<HashAlgorithm, AlgorithmCapability>
|
||
kem: HashMap<KemAlgorithm, AlgorithmCapability>
|
||
|
||
``KemKeyPair``::
|
||
|
||
public_key: Zeroizing<Vec<u8>>
|
||
private_key: Zeroizing<Vec<u8>>
|
||
|
||
``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<Vec<u8>, CryptoError>;
|
||
fn decrypt_aead(
|
||
&self, algo: AeadAlgorithm,
|
||
key: &[u8], nonce: &[u8],
|
||
ciphertext: &[u8], aad: &[u8],
|
||
) -> Result<Vec<u8>, CryptoError>;
|
||
}
|
||
|
||
pub trait KdfProvider {
|
||
fn derive_key(
|
||
&self, algo: KdfAlgorithm,
|
||
ikm: &[u8], salt: &[u8], info: &[u8], length: usize,
|
||
) -> Result<Zeroizing<Vec<u8>>, CryptoError>;
|
||
}
|
||
|
||
pub trait MacProvider {
|
||
fn compute_mac(
|
||
&self, algo: MacAlgorithm, key: &[u8], data: &[u8],
|
||
) -> Result<Vec<u8>, CryptoError>;
|
||
fn verify_mac(
|
||
&self, algo: MacAlgorithm, key: &[u8],
|
||
data: &[u8], mac: &[u8],
|
||
) -> Result<bool, CryptoError>;
|
||
}
|
||
|
||
pub trait HashProvider {
|
||
fn hash(
|
||
&self, algo: HashAlgorithm, data: &[u8],
|
||
) -> Result<Vec<u8>, CryptoError>;
|
||
}
|
||
|
||
pub trait KemProvider {
|
||
fn generate_keypair(
|
||
&self, algo: KemAlgorithm,
|
||
) -> Result<KemKeyPair, CryptoError>;
|
||
fn encapsulate(
|
||
&self, algo: KemAlgorithm, public_key: &[u8],
|
||
) -> Result<(Vec<u8>, Zeroizing<Vec<u8>>), CryptoError>;
|
||
fn decapsulate(
|
||
&self, algo: KemAlgorithm,
|
||
private_key: &[u8], ciphertext: &[u8],
|
||
) -> Result<Zeroizing<Vec<u8>>, 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<Mutex<HashMap<&'static str, Box<dyn CryptoProvider + Send + Sync>>>>
|
||
fn register(name, provider)
|
||
fn get(name) -> Option<Arc<dyn CryptoProvider>>
|
||
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<String>
|
||
ccc_provider_capabilities(provider) → CapabilitiesDto
|
||
ccc_aead_encrypt(provider, algo: u32, key, nonce, plaintext, aad)
|
||
→ Result<Vec<u8>>
|
||
ccc_aead_decrypt(provider, algo: u32, key, nonce, ciphertext, aad)
|
||
→ Result<Vec<u8>>
|
||
ccc_derive_key(provider, algo: u32, ikm, salt, info, length: u32)
|
||
→ Result<Vec<u8>>
|
||
ccc_compute_mac(provider, algo: u32, key, data)
|
||
→ Result<Vec<u8>>
|
||
ccc_verify_mac(provider, algo: u32, key, data, mac)
|
||
→ Result<bool>
|
||
ccc_hash(provider, algo: u32, data) → Result<Vec<u8>>
|
||
ccc_kem_generate_keypair(provider, algo: u32)
|
||
→ Result<KemKeyPairDto>
|
||
ccc_kem_encapsulate(provider, algo: u32, public_key)
|
||
→ Result<KemEncapDto>
|
||
ccc_kem_decapsulate(provider, algo: u32, private_key, ciphertext)
|
||
→ Result<Vec<u8>>
|
||
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<u8>, private_key: Vec<u8> }``
|
||
|
||
``KemEncapDto { ciphertext: Vec<u8>, shared_secret: Vec<u8> }``
|
||
|
||
``SelfTestDto { provider: String, results: Vec<AlgoTestResult> }``
|
||
|
||
``AlgoTestResult { algo_id: u32, algo_name: String, passed: bool,
|
||
error_message: Option<String> }``
|
||
|
||
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<List<int>> encrypt(Map<String, dynamic> 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)
|