NEW dart API interface for crypto providers and their capabilities

This commit is contained in:
JohnE 2026-03-11 17:55:24 -07:00
parent b79878a0b5
commit 37b5ca6e8d
7 changed files with 588 additions and 187 deletions

View File

@ -40,7 +40,7 @@ Phase Title Status Depends on
====== ========================================== ========== ============
1 Project Restructure & FRB Setup Done —
2 Rust Bridge Crate (DTOs + API) Done Phase 1
3 Dart API Surface Not Started Phase 2
3 Dart API Surface Done Phase 2
4 Platform Build Verification Not Started Phase 3
5 Unit Tests Not Started Phase 3
6 Integration Tests & Polish Not Started Phase 4, 5
@ -267,12 +267,20 @@ Exit Criteria
Phase 3 — Dart API Surface
----------------------------
:Status: Not Started
:Status: Done
:Depends on: Phase 2
**Goal:** Build the clean Dart API layer that application code will
consume, wired to the FRB-generated bindings.
Files created:
* ``lib/ccc_crypto.dart````CccCrypto`` static façade (13 methods)
* ``lib/ccc_exceptions.dart`` — sealed ``CccException`` hierarchy (7 subtypes)
* ``lib/ccc_provider_catalog.dart````CccProviderCatalog`` + ``CccAlgorithmInfo``
* ``lib/ccc_self_test.dart````CccSelfTestResult`` + ``CccAlgorithmTestResult``
* ``lib/ccc_cryptography.dart`` — barrel export file (updated)
Tasks
~~~~~
@ -284,50 +292,58 @@ Tasks
- Task
- Status
* - 3.1
- Create ``lib/ccc_crypto.dart`` — primary entry point class
``CccCrypto`` with all public methods:
``cccInit``, ``listProviders``, ``getCapabilities``,
``encryptAead``, ``decryptAead``, ``deriveKey``,
``computeMac``, ``verifyMac``, ``hash``,
- Create ``lib/ccc_crypto.dart````abstract final class CccCrypto``
with 13 static methods: ``init``, ``listProviders``,
``getCapabilities``, ``encryptAead``, ``decryptAead``,
``deriveKey``, ``computeMac``, ``verifyMac``, ``hash``,
``kemGenerateKeypair``, ``kemEncapsulate``, ``kemDecapsulate``,
``runSelfTest``
- ☐
``runSelfTest``; each catches ``CccCryptoError`` and rethrows
as typed ``CccException``
- ✅
* - 3.2
- Create ``lib/ccc_provider_catalog.dart````CccProviderCatalog``
(provider name, algorithms, efficiency/reliability scores)
- ☐
(provider name, per-category algorithm lists with availability,
efficiency/reliability scores); ``CccAlgorithmInfo`` wrapper
- ✅
* - 3.3
- Create ``lib/ccc_self_test.dart````CccSelfTestResult``
(per-algorithm pass/fail, overall status, diagnostics)
- ☐
(per-algorithm pass/fail, overall status, diagnostics);
``CccAlgorithmTestResult`` wrapper
- ✅
* - 3.4
- Create ``lib/ccc_exceptions.dart``structured exception
classes (``CccUnsupportedAlgorithm``, ``CccInvalidKey``,
- Create ``lib/ccc_exceptions.dart````sealed class CccException``
with 7 subtypes (``CccUnsupportedAlgorithm``, ``CccInvalidKey``,
``CccInvalidNonce``, ``CccAuthenticationFailed``,
``CccInternalError``)
- ☐
``CccInvalidInput``, ``CccFeatureNotCompiled``,
``CccInternalError``); factory ``CccException.from()`` using
Dart 3 switch expression/pattern matching
- ✅
* - 3.5
- Create ``lib/ccc_algorithm_ids.dart`` — algorithm ID constants
matching Rust enum discriminants 1-to-1 (values from
``cipher_constants.dart``); no remapping
- ☐
- Algorithm IDs: FRB-generated enums (``CccAeadAlgorithm``,
``CccKdfAlgorithm``, ``CccMacAlgorithm``, ``CccHashAlgorithm``,
``CccKemAlgorithm``) re-exported directly from barrel file;
separate constants file not needed
- ✅
* - 3.6
- Wire all Dart API methods to FRB-generated bindings
-
-
* - 3.7
- Create barrel export file ``lib/ccc_cryptography.dart``
re-exporting the public API
- ☐
- Update barrel export file ``lib/ccc_cryptography.dart``
re-exporting the public API (CccCrypto, enums, DTOs,
exceptions, provider catalog, self-test)
- ✅
* - 3.8
- Remove old placeholder Dart code (``sum``, ``sumAsync``)
- ☐
- Remove old placeholder Dart code; update example app
to use ``CccCrypto.init()`` + ``runSelfTest()`` demo
- ✅
Exit Criteria
~~~~~~~~~~~~~
* ``dart analyze`` reports no errors or warnings.
* Public API matches the contract in the architecture design doc.
* No crypto logic exists in Dart — orchestration only.
* ✅ ``dart analyze`` reports no errors or warnings.
* ✅ Public API matches the contract in the architecture design doc.
* ✅ No crypto logic exists in Dart — orchestration only.
* ✅ ``flutter build macos`` succeeds (44.5 MB).
----

View File

@ -1,9 +1,9 @@
import 'package:flutter/material.dart';
import 'package:ccc_cryptography/src/rust/api/simple.dart';
import 'package:ccc_cryptography/src/rust/frb_generated.dart';
import 'package:ccc_cryptography/ccc_cryptography.dart';
Future<void> main() async {
await RustLib.init();
WidgetsFlutterBinding.ensureInitialized();
await CccCrypto.init();
runApp(const MyApp());
}
@ -15,26 +15,36 @@ class MyApp extends StatefulWidget {
}
class _MyAppState extends State<MyApp> {
late String greetResult;
String _status = 'Running self-test…';
@override
void initState() {
super.initState();
greetResult = greet(name: 'Flutter');
_runSelfTest();
}
Future<void> _runSelfTest() async {
try {
final result = await CccCrypto.runSelfTest();
final providers = CccCrypto.listProviders();
setState(() {
_status = 'Providers: ${providers.join(", ")}\n'
'Self-test: ${result.allPassed ? "ALL PASSED" : "FAILED"}\n'
'${result.results.map((r) => ' ${r.algoName}: ${r.passed ? "" : "${r.errorMessage}"}').join("\n")}';
});
} on CccException catch (e) {
setState(() => _status = 'Error: $e');
}
}
@override
Widget build(BuildContext context) {
const textStyle = TextStyle(fontSize: 25);
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('ccc_cryptography')),
body: Center(
child: Text(
greetResult,
style: textStyle,
textAlign: TextAlign.center,
),
body: Padding(
padding: const EdgeInsets.all(16),
child: Text(_status, style: const TextStyle(fontSize: 16)),
),
),
);

235
lib/ccc_crypto.dart Normal file
View File

@ -0,0 +1,235 @@
/// Primary entry point for CCC cryptographic operations.
///
/// All methods delegate to the Rust bridge via `flutter_rust_bridge`.
/// No cryptographic logic exists in Dart.
///
/// Usage:
/// ```dart
/// await CccCrypto.init();
/// final ct = await CccCrypto.encryptAead(
/// algorithm: CccAeadAlgorithm.aesGcm256,
/// key: key,
/// nonce: nonce,
/// plaintext: data,
/// aad: Uint8List(0),
/// );
/// ```
library;
import 'dart:typed_data';
import 'package:ccc_cryptography/ccc_exceptions.dart';
import 'package:ccc_cryptography/ccc_provider_catalog.dart';
import 'package:ccc_cryptography/ccc_self_test.dart';
import 'package:ccc_cryptography/src/rust/api/crypto.dart' as bridge;
import 'package:ccc_cryptography/src/rust/api/dto.dart';
import 'package:ccc_cryptography/src/rust/frb_generated.dart';
/// Static façade for all CCC cryptographic operations.
///
/// Call [init] once at application startup before using any other method.
abstract final class CccCrypto {
/// Initialise the FRB runtime and register the wolfSSL provider.
///
/// Must be called once before any other [CccCrypto] method.
/// Safe to call multiple times (idempotent).
static Future<void> init() async {
await RustLib.init();
await bridge.cccInit();
}
// Provider info
/// Return the names of all registered crypto providers.
static List<String> listProviders() => bridge.cccListProviders();
/// Return the capability catalog for the default provider.
static Future<CccProviderCatalog> getCapabilities() async {
try {
final caps = await bridge.cccCapabilities();
return CccProviderCatalog.fromCapabilities(caps);
} on CccCryptoError catch (e) {
throw CccException.from(e);
}
}
// AEAD
/// Encrypt [plaintext] with an AEAD algorithm.
///
/// Returns ciphertext with appended authentication tag.
static Future<Uint8List> encryptAead({
required CccAeadAlgorithm algorithm,
required Uint8List key,
required Uint8List nonce,
required Uint8List plaintext,
Uint8List? aad,
}) async {
try {
return await bridge.cccAeadEncrypt(
algorithm: algorithm,
key: key,
nonce: nonce,
plaintext: plaintext,
aad: aad ?? Uint8List(0),
);
} on CccCryptoError catch (e) {
throw CccException.from(e);
}
}
/// Decrypt [ciphertext] (with appended tag) using an AEAD algorithm.
///
/// Throws [CccAuthenticationFailed] if the tag does not verify.
static Future<Uint8List> decryptAead({
required CccAeadAlgorithm algorithm,
required Uint8List key,
required Uint8List nonce,
required Uint8List ciphertext,
Uint8List? aad,
}) async {
try {
return await bridge.cccAeadDecrypt(
algorithm: algorithm,
key: key,
nonce: nonce,
ciphertext: ciphertext,
aad: aad ?? Uint8List(0),
);
} on CccCryptoError catch (e) {
throw CccException.from(e);
}
}
// KDF
/// Derive key material of [length] bytes.
static Future<Uint8List> deriveKey({
required CccKdfAlgorithm algorithm,
required Uint8List ikm,
Uint8List? salt,
Uint8List? info,
required int length,
}) async {
try {
return await bridge.cccKdfDerive(
algorithm: algorithm,
ikm: ikm,
salt: salt ?? Uint8List(0),
info: info ?? Uint8List(0),
length: length,
);
} on CccCryptoError catch (e) {
throw CccException.from(e);
}
}
// MAC
/// Compute a MAC tag over [data].
static Future<Uint8List> computeMac({
required CccMacAlgorithm algorithm,
required Uint8List key,
required Uint8List data,
}) async {
try {
return await bridge.cccMacCompute(
algorithm: algorithm,
key: key,
data: data,
);
} on CccCryptoError catch (e) {
throw CccException.from(e);
}
}
/// Verify a MAC tag. Returns `true` if valid, `false` otherwise.
static Future<bool> verifyMac({
required CccMacAlgorithm algorithm,
required Uint8List key,
required Uint8List data,
required Uint8List mac,
}) async {
try {
return await bridge.cccMacVerify(
algorithm: algorithm,
key: key,
data: data,
mac: mac,
);
} on CccCryptoError catch (e) {
throw CccException.from(e);
}
}
// Hash
/// Compute a cryptographic hash of [data].
static Future<Uint8List> hash({
required CccHashAlgorithm algorithm,
required Uint8List data,
}) async {
try {
return await bridge.cccHash(algorithm: algorithm, data: data);
} on CccCryptoError catch (e) {
throw CccException.from(e);
}
}
// KEM
/// Generate a KEM key pair.
static Future<CccKemKeyPair> kemGenerateKeypair({
required CccKemAlgorithm algorithm,
}) async {
try {
return await bridge.cccKemGenerateKeypair(algorithm: algorithm);
} on CccCryptoError catch (e) {
throw CccException.from(e);
}
}
/// KEM encapsulation produce ciphertext + shared secret from a public key.
static Future<CccKemEncapResult> kemEncapsulate({
required CccKemAlgorithm algorithm,
required Uint8List publicKey,
}) async {
try {
return await bridge.cccKemEncapsulate(
algorithm: algorithm,
publicKey: publicKey,
);
} on CccCryptoError catch (e) {
throw CccException.from(e);
}
}
/// KEM decapsulation recover shared secret from ciphertext + private key.
static Future<Uint8List> kemDecapsulate({
required CccKemAlgorithm algorithm,
required Uint8List privateKey,
required Uint8List ciphertext,
}) async {
try {
return await bridge.cccKemDecapsulate(
algorithm: algorithm,
privateKey: privateKey,
ciphertext: ciphertext,
);
} on CccCryptoError catch (e) {
throw CccException.from(e);
}
}
// Self-test
/// Run the provider self-test suite and return a structured report.
static Future<CccSelfTestResult> runSelfTest() async {
try {
final report = await bridge.cccSelfTest();
return CccSelfTestResult.fromReport(report);
} on CccCryptoError catch (e) {
throw CccException.from(e);
}
}
}

View File

@ -1,147 +1,39 @@
// The original content is temporarily commented out to allow generating a self-contained demo - feel free to uncomment later.
// // The original content is temporarily commented out to allow generating a self-contained demo - feel free to uncomment later.
//
// //
// // import 'dart:async';
// // import 'dart:ffi';
// // import 'dart:io';
// // import 'dart:isolate';
// //
// // import 'ccc_cryptography_bindings_generated.dart';
// //
// // /// A very short-lived native function.
// // ///
// // /// For very short-lived functions, it is fine to call them on the main isolate.
// // /// They will block the Dart execution while running the native function, so
// // /// only do this for native functions which are guaranteed to be short-lived.
// // int sum(int a, int b) => _bindings.sum(a, b);
// //
// // /// A longer lived native function, which occupies the thread calling it.
// // ///
// // /// Do not call these kind of native functions in the main isolate. They will
// // /// block Dart execution. This will cause dropped frames in Flutter applications.
// // /// Instead, call these native functions on a separate isolate.
// // ///
// // /// Modify this to suit your own use case. Example use cases:
// // ///
// // /// 1. Reuse a single isolate for various different kinds of requests.
// // /// 2. Use multiple helper isolates for parallel execution.
// // Future<int> sumAsync(int a, int b) async {
// // final SendPort helperIsolateSendPort = await _helperIsolateSendPort;
// // final int requestId = _nextSumRequestId++;
// // final _SumRequest request = _SumRequest(requestId, a, b);
// // final Completer<int> completer = Completer<int>();
// // _sumRequests[requestId] = completer;
// // helperIsolateSendPort.send(request);
// // return completer.future;
// // }
// //
// // const String _libName = 'ccc_cryptography';
// //
// // /// The dynamic library in which the symbols for [CccCryptographyBindings] can be found.
// // final DynamicLibrary _dylib = () {
// // if (Platform.isMacOS || Platform.isIOS) {
// // return DynamicLibrary.open('$_libName.framework/$_libName');
// // }
// // if (Platform.isAndroid || Platform.isLinux) {
// // return DynamicLibrary.open('lib$_libName.so');
// // }
// // if (Platform.isWindows) {
// // return DynamicLibrary.open('$_libName.dll');
// // }
// // throw UnsupportedError('Unknown platform: ${Platform.operatingSystem}');
// // }();
// //
// // /// The bindings to the native functions in [_dylib].
// // final CccCryptographyBindings _bindings = CccCryptographyBindings(_dylib);
// //
// //
// // /// A request to compute `sum`.
// // ///
// // /// Typically sent from one isolate to another.
// // class _SumRequest {
// // final int id;
// // final int a;
// // final int b;
// //
// // const _SumRequest(this.id, this.a, this.b);
// // }
// //
// // /// A response with the result of `sum`.
// // ///
// // /// Typically sent from one isolate to another.
// // class _SumResponse {
// // final int id;
// // final int result;
// //
// // const _SumResponse(this.id, this.result);
// // }
// //
// // /// Counter to identify [_SumRequest]s and [_SumResponse]s.
// // int _nextSumRequestId = 0;
// //
// // /// Mapping from [_SumRequest] `id`s to the completers corresponding to the correct future of the pending request.
// // final Map<int, Completer<int>> _sumRequests = <int, Completer<int>>{};
// //
// // /// The SendPort belonging to the helper isolate.
// // Future<SendPort> _helperIsolateSendPort = () async {
// // // The helper isolate is going to send us back a SendPort, which we want to
// // // wait for.
// // final Completer<SendPort> completer = Completer<SendPort>();
// //
// // // Receive port on the main isolate to receive messages from the helper.
// // // We receive two types of messages:
// // // 1. A port to send messages on.
// // // 2. Responses to requests we sent.
// // final ReceivePort receivePort = ReceivePort()
// // ..listen((dynamic data) {
// // if (data is SendPort) {
// // // The helper isolate sent us the port on which we can sent it requests.
// // completer.complete(data);
// // return;
// // }
// // if (data is _SumResponse) {
// // // The helper isolate sent us a response to a request we sent.
// // final Completer<int> completer = _sumRequests[data.id]!;
// // _sumRequests.remove(data.id);
// // completer.complete(data.result);
// // return;
// // }
// // throw UnsupportedError('Unsupported message type: ${data.runtimeType}');
// // });
// //
// // // Start the helper isolate.
// // await Isolate.spawn((SendPort sendPort) async {
// // final ReceivePort helperReceivePort = ReceivePort()
// // ..listen((dynamic data) {
// // // On the helper isolate listen to requests and respond to them.
// // if (data is _SumRequest) {
// // final int result = _bindings.sum_long_running(data.a, data.b);
// // final _SumResponse response = _SumResponse(data.id, result);
// // sendPort.send(response);
// // return;
// // }
// // throw UnsupportedError('Unsupported message type: ${data.runtimeType}');
// // });
// //
// // // Send the port to the main isolate on which we can receive requests.
// // sendPort.send(helperReceivePort.sendPort);
// // }, receivePort.sendPort);
// //
// // // Wait until the helper isolate has sent us back the SendPort on which we
// // // can start sending requests.
// // return completer.future;
// // }();
// //
//
// library ccc_cryptography;
//
// export 'src/rust/api/simple.dart';
// export 'src/rust/frb_generated.dart' show RustLib;
//
/// CCC Cryptography Flutter plugin providing cross-platform
/// cryptographic operations via `ccc_rust` and `flutter_rust_bridge`.
///
/// Usage:
/// ```dart
/// import 'package:ccc_cryptography/ccc_cryptography.dart';
///
/// await CccCrypto.init();
/// final ct = await CccCrypto.encryptAead(
/// algorithm: CccAeadAlgorithm.aesGcm256,
/// key: key, nonce: nonce, plaintext: data,
/// );
/// ```
library;
export 'src/rust/api/simple.dart';
export 'src/rust/frb_generated.dart' show RustLib;
// Primary API
export 'ccc_crypto.dart';
// Algorithm enum re-exports (FRB-generated)
export 'src/rust/api/dto.dart'
show
CccAeadAlgorithm,
CccKdfAlgorithm,
CccMacAlgorithm,
CccHashAlgorithm,
CccKemAlgorithm,
CccKemKeyPair,
CccKemEncapResult;
// Exceptions
export 'ccc_exceptions.dart';
// Provider catalog
export 'ccc_provider_catalog.dart';
// Self-test result
export 'ccc_self_test.dart';

70
lib/ccc_exceptions.dart Normal file
View File

@ -0,0 +1,70 @@
/// Structured exception classes for CCC cryptographic operations.
///
/// These wrap the FRB-generated [CccCryptoError] into typed Dart exceptions
/// so consuming code can catch specific failure modes.
library;
import 'package:ccc_cryptography/src/rust/api/dto.dart';
/// Base class for all CCC cryptographic exceptions.
sealed class CccException implements Exception {
/// Human-readable error description.
final String message;
const CccException(this.message);
@override
String toString() => '$runtimeType: $message';
/// Convert a FRB-generated [CccCryptoError] into the appropriate
/// typed [CccException] subclass.
factory CccException.from(CccCryptoError error) {
return switch (error) {
CccCryptoError_UnsupportedAlgorithm(:final field0) =>
CccUnsupportedAlgorithm(field0),
CccCryptoError_InvalidKey(:final field0) => CccInvalidKey(field0),
CccCryptoError_InvalidNonce(:final field0) => CccInvalidNonce(field0),
CccCryptoError_AuthenticationFailed() =>
const CccAuthenticationFailed(),
CccCryptoError_InvalidInput(:final field0) => CccInvalidInput(field0),
CccCryptoError_FeatureNotCompiled(:final field0) =>
CccFeatureNotCompiled(field0),
CccCryptoError_InternalError(:final field0) => CccInternalError(field0),
};
}
}
/// The requested algorithm is not supported by any registered provider.
class CccUnsupportedAlgorithm extends CccException {
const CccUnsupportedAlgorithm(super.message);
}
/// The supplied key is invalid (wrong length, weak key, etc.).
class CccInvalidKey extends CccException {
const CccInvalidKey(super.message);
}
/// The supplied nonce/IV is invalid (wrong length, reuse detected, etc.).
class CccInvalidNonce extends CccException {
const CccInvalidNonce(super.message);
}
/// AEAD authentication tag verification failed ciphertext was tampered.
class CccAuthenticationFailed extends CccException {
const CccAuthenticationFailed() : super('authentication failed');
}
/// The supplied input data is invalid.
class CccInvalidInput extends CccException {
const CccInvalidInput(super.message);
}
/// The requested feature/algorithm is not compiled into the provider.
class CccFeatureNotCompiled extends CccException {
const CccFeatureNotCompiled(super.message);
}
/// An unexpected internal error occurred in the cryptographic provider.
class CccInternalError extends CccException {
const CccInternalError(super.message);
}

View File

@ -0,0 +1,110 @@
/// Provider catalog describes what a registered provider supports.
///
/// Wraps the FRB-generated [CccCapabilities] into a Dart-idiomatic type
/// for querying algorithm availability and quality scores.
library;
import 'package:ccc_cryptography/src/rust/api/dto.dart';
/// Describes the full set of capabilities for a registered provider.
class CccProviderCatalog {
/// Provider name (e.g. "wolfssl").
final String providerName;
/// AEAD algorithms supported by this provider.
final List<CccAlgorithmInfo> aead;
/// KDF algorithms supported by this provider.
final List<CccAlgorithmInfo> kdf;
/// MAC algorithms supported by this provider.
final List<CccAlgorithmInfo> mac;
/// Hash algorithms supported by this provider.
final List<CccAlgorithmInfo> hash;
/// KEM algorithms supported by this provider.
final List<CccAlgorithmInfo> kem;
const CccProviderCatalog._({
required this.providerName,
required this.aead,
required this.kdf,
required this.mac,
required this.hash,
required this.kem,
});
/// Convert from the FRB-generated capabilities DTO.
factory CccProviderCatalog.fromCapabilities(CccCapabilities caps) {
return CccProviderCatalog._(
providerName: caps.providerName,
aead: caps.aead.map(CccAlgorithmInfo._fromEntry).toList(growable: false),
kdf: caps.kdf.map(CccAlgorithmInfo._fromEntry).toList(growable: false),
mac: caps.mac.map(CccAlgorithmInfo._fromEntry).toList(growable: false),
hash: caps.hash.map(CccAlgorithmInfo._fromEntry).toList(growable: false),
kem: caps.kem.map(CccAlgorithmInfo._fromEntry).toList(growable: false),
);
}
/// All available AEAD algorithms.
List<CccAlgorithmInfo> get availableAead =>
aead.where((a) => a.available).toList(growable: false);
/// All available KDF algorithms.
List<CccAlgorithmInfo> get availableKdf =>
kdf.where((a) => a.available).toList(growable: false);
/// All available MAC algorithms.
List<CccAlgorithmInfo> get availableMac =>
mac.where((a) => a.available).toList(growable: false);
/// All available Hash algorithms.
List<CccAlgorithmInfo> get availableHash =>
hash.where((a) => a.available).toList(growable: false);
/// All available KEM algorithms.
List<CccAlgorithmInfo> get availableKem =>
kem.where((a) => a.available).toList(growable: false);
}
/// Describes a single algorithm's availability and quality metrics.
class CccAlgorithmInfo {
/// Numeric algorithm identifier (matches Rust `#[repr(u32)]`).
final int id;
/// Human-readable algorithm name (e.g. "AES-256-GCM").
final String name;
/// Whether this algorithm is available in the provider.
final bool available;
/// Whether the algorithm produces deterministic output for the same input.
final bool deterministicIo;
/// Provider-reported efficiency score (0100).
final int efficiencyScore;
/// Provider-reported reliability score (0100).
final int reliabilityScore;
const CccAlgorithmInfo({
required this.id,
required this.name,
required this.available,
required this.deterministicIo,
required this.efficiencyScore,
required this.reliabilityScore,
});
factory CccAlgorithmInfo._fromEntry(CccAlgorithmEntry e) {
return CccAlgorithmInfo(
id: e.algoId,
name: e.algoName,
available: e.capability.available,
deterministicIo: e.capability.deterministicIo,
efficiencyScore: e.capability.efficiencyScore,
reliabilityScore: e.capability.reliabilityScore,
);
}
}

68
lib/ccc_self_test.dart Normal file
View File

@ -0,0 +1,68 @@
/// Self-test result wraps the FRB-generated report into Dart-idiomatic types.
library;
import 'package:ccc_cryptography/src/rust/api/dto.dart';
/// Result of a single algorithm's self-test.
class CccAlgorithmTestResult {
/// Numeric algorithm identifier.
final int algoId;
/// Human-readable algorithm name.
final String algoName;
/// Whether the algorithm passed its self-test.
final bool passed;
/// Diagnostic message if the test failed; `null` on success.
final String? errorMessage;
const CccAlgorithmTestResult({
required this.algoId,
required this.algoName,
required this.passed,
this.errorMessage,
});
factory CccAlgorithmTestResult._fromDto(CccAlgoTestResult dto) {
return CccAlgorithmTestResult(
algoId: dto.algoId,
algoName: dto.algoName,
passed: dto.passed,
errorMessage: dto.errorMessage,
);
}
}
/// Aggregate result of the provider self-test.
class CccSelfTestResult {
/// Name of the provider that was tested.
final String providerName;
/// Per-algorithm test results.
final List<CccAlgorithmTestResult> results;
/// Whether all algorithms passed.
final bool allPassed;
const CccSelfTestResult._({
required this.providerName,
required this.results,
required this.allPassed,
});
/// Convert from the FRB-generated self-test report DTO.
factory CccSelfTestResult.fromReport(CccSelfTestReport report) {
return CccSelfTestResult._(
providerName: report.providerName,
results: report.results
.map(CccAlgorithmTestResult._fromDto)
.toList(growable: false),
allPassed: report.allPassed,
);
}
/// Algorithms that failed their self-test.
List<CccAlgorithmTestResult> get failures =>
results.where((r) => !r.passed).toList(growable: false);
}