388 lines
14 KiB
ReStructuredText
388 lines
14 KiB
ReStructuredText
===============================================
|
||
CCC Rust Crypto Provider — Architecture Plan
|
||
===============================================
|
||
|
||
:Status: Approved
|
||
:Date: 2026-02-24
|
||
:Author: Engineering
|
||
|
||
|
||
Overview
|
||
--------
|
||
|
||
This document describes the architecture for the **CCC Rust Crypto Provider**,
|
||
the first of three milestones in delivering hardware-grade cryptography to the
|
||
LetUsMsg application.
|
||
|
||
The guiding constraint is *clean separation*: each milestone is a distinct,
|
||
independently testable artifact with no forbidden upward dependencies.
|
||
|
||
----
|
||
|
||
Three-Milestone Strategy
|
||
------------------------
|
||
|
||
============= =================================== ========================== ===========================
|
||
Milestone Repository What ships Depends on
|
||
============= =================================== ========================== ===========================
|
||
**1 (this)** ``ccc_rust`` Pure Rust crypto library wolfSSL (vendored)
|
||
**2** ``ccc_dart_plugin`` Flutter plugin + Dart API ``ccc_rust`` (git/semver)
|
||
**3** ``letusmsg`` (existing app) App integration ``ccc_dart_plugin`` package
|
||
============= =================================== ========================== ===========================
|
||
|
||
Milestone 1 is complete and independently verified *before* any bridge or Dart
|
||
code is written. Milestone 2 owns the ``flutter_rust_bridge`` dependency and
|
||
all generated Dart bindings. Milestone 3 makes no Rust changes; it consumes
|
||
only the published Dart package.
|
||
|
||
----
|
||
|
||
Milestone 1 — ``ccc_rust`` Scope (this repository)
|
||
|
||
**Goal**: a fully tested, provider-agnostic Rust crypto library.
|
||
|
||
**Hard boundaries** — this repo must never contain:
|
||
|
||
* ``flutter_rust_bridge`` or any Flutter/Dart dependency
|
||
* Generated Dart files (``frb_generated.rs``, ``*.dart``)
|
||
* ``flutter_rust_bridge.yaml``
|
||
* Any platform plugin scaffold (``ios/``, ``android/``, ``macos/``)
|
||
|
||
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 in
|
||
``cipher_constants.dart`` — zero Dart changes needed when wiring up.
|
||
3. Key material is zeroed on drop (``zeroize`` crate) everywhere.
|
||
4. A conformance test suite validates NIST/RFC vectors for every algorithm
|
||
before any provider is marked ``available``.
|
||
5. The library has no runtime dependency on Flutter; it is consumable by any
|
||
FFI host (Flutter plugin, Python tests, CLI tools).
|
||
|
||
Repository Layout (Milestone 1 — this repo)
|
||
|
||
::
|
||
|
||
ccc_rust/
|
||
├── Cargo.toml ← workspace manifest (3 members, no bridge)
|
||
├── 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 implementation
|
||
│ ├── Cargo.toml
|
||
│ └── src/
|
||
│ ├── lib.rs
|
||
│ ├── aead.rs ← AES-256-GCM, ChaCha20-Poly1305, XChaCha20-Poly1305
|
||
│ ├── kdf.rs ← HKDF-SHA256/384/512, Argon2id, BLAKE2b-KDF
|
||
│ ├── mac.rs ← HMAC-SHA256/384/512, BLAKE2b-MAC
|
||
│ ├── hash.rs ← SHA-256/384/512, SHA3-256/512, BLAKE2b-512
|
||
│ ├── kem.rs ← X25519, X448 (ML-KEM deferred Phase 5)
|
||
│ ├── capabilities.rs ← probe-at-startup + benchmark()
|
||
│ └── provider.rs ← WolfSslProvider: CryptoProvider impl
|
||
└── tests/
|
||
└── conformance/
|
||
├── Cargo.toml
|
||
└── src/
|
||
└── main.rs ← NIST/RFC vectors for all algorithms
|
||
|
||
Step 1 — Cargo Workspace Scaffold
|
||
|
||
``Cargo.toml``::
|
||
|
||
[workspace]
|
||
resolver = "2"
|
||
members = [
|
||
"crates/ccc-crypto-core",
|
||
"crates/ccc-crypto-wolfssl",
|
||
"tests/conformance",
|
||
]
|
||
|
||
``rust-toolchain.toml``::
|
||
|
||
[toolchain]
|
||
channel = "stable"
|
||
|
||
``.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``
|
||
|
||
wolfSSL is vendored as a git submodule pinned to ``v5.7.2-stable``.
|
||
The crate uses ``cmake`` + ``bindgen`` in ``build.rs`` to build and bind it.
|
||
A ``stub_ffi`` feature bypasses the C build for fast unit-test cycles.
|
||
|
||
wolfSSL Phase 4 Algorithm Coverage
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
=================== ===========================================
|
||
Category Algorithms
|
||
=================== ===========================================
|
||
AEAD AES-256-GCM, ChaCha20-Poly1305,
|
||
XChaCha20-Poly1305
|
||
KDF HKDF-SHA256/384/512, Argon2id, BLAKE2b-KDF
|
||
MAC HMAC-SHA256/384/512, BLAKE2b-MAC
|
||
Hash SHA-256/384/512, SHA3-256/512, BLAKE2b-512
|
||
KEM X25519, X448
|
||
KEM (Phase 5) ML-KEM-768, ML-KEM-1024, Classic McEliece
|
||
=================== ===========================================
|
||
|
||
Capability Probe Strategy
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
``WolfSslProvider::capabilities()`` runs a minimal probe call (encrypt 1 byte;
|
||
decrypt; compare) per algorithm at startup. Sets ``available = probe_succeeded``.
|
||
If the wolfSSL build omits PQ support, ML-KEM entries report
|
||
``available: false`` gracefully.
|
||
|
||
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 library init and cached.
|
||
|
||
|
||
Step 4 — Conformance Test Suite
|
||
|
||
Location: ``tests/conformance/src/main.rs``
|
||
|
||
Run with ``cargo run -p ccc-conformance-tests`` and ``cargo test --workspace``.
|
||
|
||
========================= ================================
|
||
Test Source
|
||
========================= ================================
|
||
AES-256-GCM NIST SP 800-38D vectors
|
||
ChaCha20-Poly1305 RFC 8439 vectors
|
||
XChaCha20-Poly1305 Extended nonce vectors
|
||
HKDF-SHA256/512 RFC 5869 vectors
|
||
HMAC-SHA256/512 RFC 4231 vectors
|
||
SHA-256/512, SHA3, BLAKE2b FIPS / reference vectors
|
||
X25519 DH RFC 7748 vectors
|
||
X448 DH RFC 7748 vectors
|
||
========================= ================================
|
||
|
||
**Gate**: ``ALL VECTORS PASSED`` must print before Milestone 1 is tagged.
|
||
|
||
|
||
Step 5 — Architecture Documentation
|
||
|
||
``docs/ccc_rust_milestone1.rst`` covers:
|
||
|
||
* Crate dependency graph (ASCII)
|
||
* "How to add a new provider" — 7-step trait checklist
|
||
* ``algo: u32`` → cipher constant mapping table
|
||
* Milestone 2 hand-off contract (API surface Milestone 2 must implement against)
|
||
|
||
|
||
Milestone 1 Verification Gate
|
||
|
||
All of the following must pass before the ``v0.1.0`` tag is cut and Milestone 2
|
||
work begins:
|
||
|
||
* ``cargo test --workspace`` — all unit tests pass
|
||
* ``cargo run -p ccc-conformance-tests`` — ``ALL VECTORS PASSED``
|
||
* ``cargo build --target aarch64-apple-ios`` — compiles
|
||
* ``cargo build --target aarch64-linux-android`` — compiles
|
||
* No ``flutter_rust_bridge``, Dart, or Flutter dependency anywhere in the workspace
|
||
* ``cargo audit`` — no known CVEs in dependency tree
|
||
|
||
|
||
Milestone 2 — ``ccc_dart_plugin`` (separate repository)
|
||
|
||
*(Planned — not started. Work begins after Milestone 1 gate passes.)*
|
||
|
||
A separate Dart/Flutter plugin package repository. It contains:
|
||
|
||
* A small Rust bridge crate that references ``ccc_rust`` via git tag:
|
||
|
||
.. code-block:: toml
|
||
|
||
[dependencies]
|
||
ccc-crypto-core = { git = "https://github.com/letusmsg/ccc_rust", tag = "v0.1.0" }
|
||
ccc-crypto-wolfssl = { git = "https://github.com/letusmsg/ccc_rust", tag = "v0.1.0" }
|
||
flutter_rust_bridge = "2"
|
||
|
||
* ``flutter_rust_bridge_codegen generate`` output (``frb_generated.rs``, Dart bindings)
|
||
* Flutter plugin scaffold: ``ios/``, ``android/``, ``macos/``
|
||
* Dart API surface: ``CccCrypto``, ``CccSelfTest``, ``CccProviderCatalog``
|
||
* Flutter integration tests (roundtrip encrypt/decrypt, self-test harness)
|
||
|
||
|
||
Milestone 3 — LetUsMsg App Integration (existing repository)
|
||
|
||
*(Planned — not started. Work begins after Milestone 2 gate passes.)*
|
||
|
||
The existing ``letusmsg`` Flutter app adds ``ccc_dart_plugin`` as a pubspec
|
||
dependency. Changes are confined to:
|
||
|
||
* ``crypto_wolfssl.dart`` — replace ``UnimplementedError`` stubs with plugin calls
|
||
* ``ccc_provider_spec.dart`` — populate ``CccProviderCatalog`` at runtime
|
||
* ``main.dart`` — call ``CccCrypto.cccInit()`` at startup
|
||
* App debug screen — expose ``CccSelfTest.runAll()`` results
|
||
|
||
No Rust changes and no bridge changes are made in Milestone 3.
|
||
|
||
|
||
Phase 8 — Stretch Goal Providers (Future)
|
||
|
||
*(Out of scope for Phase 4. Tracked here for future scheduling.)*
|
||
|
||
================== =====================================================
|
||
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
|
||
================== =====================================================
|
||
|