https://github.com/bardiakz/oqs
oqs - A Dart FFI wrapper for liboqs, delivering post-quantum cryptographic algorithms. Supports NIST-standardized KEMs (e.g., ML-KEM) and signatures (e.g., ML-DSA), optimized for Flutter and cross-platform applications (Android, iOS, Linux, macOS, Windows). MIT Licensed.
https://github.com/bardiakz/oqs
cryptography dart ffi flutter kem kyber liboqs ml-dsa ml-kem oqs pqc quantom-cryptography
Last synced: 4 months ago
JSON representation
oqs - A Dart FFI wrapper for liboqs, delivering post-quantum cryptographic algorithms. Supports NIST-standardized KEMs (e.g., ML-KEM) and signatures (e.g., ML-DSA), optimized for Flutter and cross-platform applications (Android, iOS, Linux, macOS, Windows). MIT Licensed.
- Host: GitHub
- URL: https://github.com/bardiakz/oqs
- Owner: bardiakz
- License: mit
- Created: 2025-07-19T15:12:01.000Z (11 months ago)
- Default Branch: main
- Last Pushed: 2026-02-14T19:01:02.000Z (4 months ago)
- Last Synced: 2026-02-14T21:57:29.336Z (4 months ago)
- Topics: cryptography, dart, ffi, flutter, kem, kyber, liboqs, ml-dsa, ml-kem, oqs, pqc, quantom-cryptography
- Language: Dart
- Homepage:
- Size: 255 KB
- Stars: 4
- Watchers: 1
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
- Agents: AGENTS.md
Awesome Lists containing this project
README
# OQS for Dart
[](https://pub.dev/packages/oqs)
[](LICENSE)
Dart FFI bindings for [liboqs](https://github.com/open-quantum-safe/liboqs), providing post-quantum KEM and signature primitives.
## Version Compatibility
| `oqs` package | `liboqs` |
|---|---|
| `3.x` | `0.15.x` |
| `2.x` | `0.14.x` (legacy) |
`3.0.0` is a breaking release aligned to `liboqs 0.15.0`.
## Install
```yaml
dependencies:
oqs: ^3.1.0
```
## Native Library Setup
You need a native `liboqs` library for your platform.
### Option 1: Prebuilt binaries (Recommended)
Download pre-built binaries from:
- https://github.com/bardiakz/liboqs-binaries/releases
**Supported platforms:**
- Linux: x86_64, ARM64 (aarch64)
- macOS: ARM64 (Apple Silicon)
- Windows: x64
- iOS: XCFramework (device + simulator)
- Android: armeabi-v7a, arm64-v8a, x86, x86_64
**Using the all-platforms archive:**
```bash
# Extract the combined archive
tar -xzf liboqs-0.15.0-all-platforms.tar.gz
# Use in your Dart code
LibOQSLoader.loadLibrary(binaryRoot: '/path/to/liboqs-0.15.0');
```
The all-platforms archive contains architecture-separated binaries:
```
liboqs-0.15.0/
lib/x86_64/liboqs.so # Linux x86_64
lib/aarch64/liboqs.so # Linux ARM64
lib/liboqs.dylib # macOS ARM64
bin/oqs.dll # Windows x64
android/arm64-v8a/ # Android binaries
liboqs.xcframework/ # iOS
```
### Option 2: Build from source
```bash
git clone https://github.com/open-quantum-safe/liboqs.git
cd liboqs
mkdir build && cd build
cmake -GNinja -DCMAKE_INSTALL_PREFIX=/usr/local ..
ninja
ninja install
```
### Optional explicit paths
```dart
import 'package:oqs/oqs.dart';
LibOQSLoader.customPaths = LibraryPaths(
windows: r'C:\libs\oqs.dll',
linuxX64: '/usr/local/lib/liboqs.so',
linuxArm64: '/usr/local/lib/liboqs.so', // For ARM64 systems
macOS: '/opt/homebrew/lib/liboqs.dylib',
);
```
## Library Loading Guide
`LibOQSLoader.loadLibrary()` uses fallback strategies in this exact order:
1. `explicitPath` argument
2. `LibOQSLoader.customPaths` (`LibraryPaths`)
3. Deprecated `LibOQSLoader.customPath`
4. Environment variable (`LIBOQS_PATH`, or `envVarName`)
5. `binaryRoot` extracted release layout
6. Package-relative paths
7. System loader/default name (`liboqs.so`, `oqs.dll`, `liboqs.dylib`)
8. Legacy default paths (`bin//...`)
If all fail, `LibraryLoadException` includes all attempted strategies.
### Auto Path Selection (Package-relative)
`PackageRelativeStrategy` checks:
- `./bin/`
- `./lib/`
- `./lib/native/`
- `./native/`
- `./blobs/`
- Android extras:
- `./lib/arm64-v8a/liboqs.so`
- `./lib/armeabi-v7a/liboqs.so`
- `./lib/x86_64/liboqs.so`
- `./lib/x86/liboqs.so`
### Platform Notes
- **Linux**: Automatically detects x86_64 vs ARM64 (aarch64) architecture
- **iOS**: Uses `DynamicLibrary.process()` (XCFramework/static linking), not `DynamicLibrary.open(...)`
- **Android**: ABI-specific selection supported through `LibraryPaths.currentPlatformPath`
- **macOS/Windows**: System resolution works when library is installed in standard paths
### Recommended Config Patterns
Use explicit, deterministic config for production:
```dart
final lib = LibOQSLoader.loadLibrary(
explicitPath: '/opt/liboqs/lib/liboqs.so',
);
```
Or per-platform config:
```dart
LibOQSLoader.customPaths = LibraryPaths(
windows: r'C:\oqs\oqs.dll',
linuxX64: '/usr/local/lib/liboqs.so',
linuxArm64: '/usr/local/lib/liboqs.so',
macOS: '/opt/homebrew/lib/liboqs.dylib',
androidArm64: '/data/local/tmp/liboqs.so',
);
```
Or extracted release root:
```dart
final lib = LibOQSLoader.loadLibrary(binaryRoot: '/opt/liboqs-0.15.0');
```
### Cache Behavior
- Loader caches resolved `DynamicLibrary` by default.
- Update paths at runtime: set `LibOQSLoader.customPaths = ...` (this clears cache).
- Manual reset: `LibOQSLoader.clearCache()`.
### Debug Checklist
1. Verify `LibOQS.getVersion()` returns non-empty string.
2. Print `LibOQS.getSupportedKEMAlgorithms()` to confirm expected build features.
3. If loading fails, inspect thrown `LibraryLoadException` strategy list and fix the earliest intended path.
## Quick Start
```dart
import 'dart:typed_data';
import 'package:oqs/oqs.dart';
void main() {
LibOQS.init();
final kems = LibOQS.getSupportedKEMAlgorithms();
if (kems.isEmpty) {
throw StateError('No enabled KEM algorithms in loaded liboqs');
}
final kem = KEM.create(kems.first)!;
final kp = kem.generateKeyPair();
final enc = kem.encapsulate(kp.publicKey);
final dec = kem.decapsulate(enc.ciphertext, kp.secretKey);
print(dec.length == enc.sharedSecret.length); // true
kem.dispose();
LibOQS.cleanup();
}
```
## API Notes
- Prefer runtime algorithm discovery:
- `LibOQS.getSupportedKEMAlgorithms()`
- `LibOQS.getSupportedSignatureAlgorithms()`
- Do not hard-code key/signature lengths. Use:
- `kem.publicKeyLength`, `kem.secretKeyLength`, `kem.ciphertextLength`
- `sig.publicKeyLength`, `sig.secretKeyLength`, `sig.maxSignatureLength`
- Deterministic keypair generation is algorithm-dependent:
- `kem.supportsDeterministicGeneration`
- `kem.seedLength`
## Signature Example
```dart
import 'dart:convert';
import 'dart:typed_data';
import 'package:oqs/oqs.dart';
void main() {
final sigAlgs = LibOQS.getSupportedSignatureAlgorithms();
if (sigAlgs.isEmpty) {
throw StateError('No enabled signature algorithms');
}
final sig = Signature.create(sigAlgs.first);
final kp = sig.generateKeyPair();
final msg = Uint8List.fromList(utf8.encode('hello pqc'));
final s = sig.sign(msg, kp.secretKey);
final ok = sig.verify(msg, s, kp.publicKey);
print(ok); // true
sig.dispose();
}
```
## Migration to 3.x (`liboqs 0.15.0`)
1. Upgrade dependency in `pubspec.yaml` to `^3.1.0`.
2. Ensure native `liboqs` binary is `0.15.x`.
3. Replace fixed algorithm assumptions (`Kyber*`, `Dilithium*`) with runtime discovery.
4. Remove hard-coded size assertions and read lengths from each algorithm instance.
5. Re-run tests against every target platform binary you ship.
## Common Problems
### Library not found
Set `LibOQSLoader.customPaths` or install `liboqs` to standard system paths.
### Algorithm not available
Enabled algorithms depend on how your `liboqs` binary was built. Check:
```dart
print(LibOQS.getSupportedKEMAlgorithms());
print(LibOQS.getSupportedSignatureAlgorithms());
```
## Security Notes
- Use NIST-standardized algorithms (`ML-KEM-*`, `ML-DSA-*`) for production.
- Dispose algorithm objects (`kem.dispose()`, `sig.dispose()`) when done.
- Keep `liboqs` binaries updated and track security advisories.
- Do not share mutable crypto object state across isolates/threads.
## Examples
See the [`example/`](example/) directory for end-to-end usage samples.