liboqs 1.0.3 copy "liboqs: ^1.0.3" to clipboard
liboqs: ^1.0.3 copied to clipboard

Dart FFI bindings for liboqs — high-performance post-quantum cryptography (PQC) with ML-KEM, ML-DSA, Falcon, SPHINCS+ for key encapsulation and signatures.

example/lib/main.dart

import 'dart:convert';
import 'dart:typed_data';

import 'package:flutter/material.dart';
import 'package:liboqs/liboqs.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  LibOQS.init();
  runApp(const LiboqsExampleApp());
}

class LiboqsExampleApp extends StatelessWidget {
  const LiboqsExampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'liboqs Example',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.indigo),
        useMaterial3: true,
      ),
      home: const HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  String _output = '';
  bool _isRunning = false;

  void _appendOutput(String text) {
    setState(() {
      _output += '$text\n';
    });
  }

  void _clearOutput() {
    setState(() {
      _output = '';
    });
  }

  Future<void> _runDemo(String name, Future<void> Function() demo) async {
    if (_isRunning) return;

    setState(() {
      _isRunning = true;
      _output = '=== $name ===\n\n';
    });

    try {
      await demo();
    } catch (e) {
      _appendOutput('\nError: $e');
    } finally {
      setState(() {
        _isRunning = false;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('liboqs Example'),
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        actions: [
          IconButton(
            icon: const Icon(Icons.delete_outline),
            onPressed: _clearOutput,
            tooltip: 'Clear output',
          ),
        ],
      ),
      body: Column(
        children: [
          // Library info card
          Card(
            margin: const EdgeInsets.all(16),
            child: Padding(
              padding: const EdgeInsets.all(16),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Text(
                    'liboqs v${LibOQS.getVersion()}',
                    style: Theme.of(context).textTheme.titleLarge,
                  ),
                  const SizedBox(height: 8),
                  Text(
                    '${LibOQS.getSupportedKEMAlgorithms().length} KEM algorithms, '
                    '${LibOQS.getSupportedSignatureAlgorithms().length} Signature algorithms',
                    style: Theme.of(context).textTheme.bodyMedium,
                  ),
                ],
              ),
            ),
          ),

          // Demo buttons
          Padding(
            padding: const EdgeInsets.symmetric(horizontal: 16),
            child: Wrap(
              spacing: 8,
              runSpacing: 8,
              children: [
                _DemoButton(
                  label: 'KEM Demo',
                  icon: Icons.vpn_key,
                  isRunning: _isRunning,
                  onPressed: () =>
                      _runDemo('Key Encapsulation (ML-KEM-768)', _runKemDemo),
                ),
                _DemoButton(
                  label: 'Signature Demo',
                  icon: Icons.verified,
                  isRunning: _isRunning,
                  onPressed: () => _runDemo(
                    'Digital Signatures (ML-DSA-65)',
                    _runSignatureDemo,
                  ),
                ),
                _DemoButton(
                  label: 'Random Demo',
                  icon: Icons.casino,
                  isRunning: _isRunning,
                  onPressed: () =>
                      _runDemo('Random Generation', _runRandomDemo),
                ),
                _DemoButton(
                  label: 'All Algorithms',
                  icon: Icons.list,
                  isRunning: _isRunning,
                  onPressed: () =>
                      _runDemo('Supported Algorithms', _runAlgorithmsDemo),
                ),
              ],
            ),
          ),

          const SizedBox(height: 16),

          // Output area
          Expanded(
            child: Container(
              margin: const EdgeInsets.all(16),
              padding: const EdgeInsets.all(12),
              decoration: BoxDecoration(
                color: Colors.grey[900],
                borderRadius: BorderRadius.circular(8),
              ),
              child: SingleChildScrollView(
                child: SizedBox(
                  width: double.infinity,
                  child: SelectableText(
                    _output.isEmpty ? 'Tap a button to run a demo...' : _output,
                    style: TextStyle(
                      fontFamily: 'monospace',
                      fontSize: 12,
                      color: _output.isEmpty ? Colors.grey : Colors.green[300],
                    ),
                  ),
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }

  Future<void> _runKemDemo() async {
    final kem = KEM.create('ML-KEM-768');

    try {
      _appendOutput('Algorithm: ML-KEM-768');
      _appendOutput('Public key: ${kem.publicKeyLength} bytes');
      _appendOutput('Secret key: ${kem.secretKeyLength} bytes');
      _appendOutput('Ciphertext: ${kem.ciphertextLength} bytes');
      _appendOutput('Shared secret: ${kem.sharedSecretLength} bytes');
      _appendOutput('');

      // Generate key pair
      final keyPair = kem.generateKeyPair();
      _appendOutput('[+] Generated key pair');

      // Encapsulate
      final encResult = kem.encapsulate(keyPair.publicKey);
      _appendOutput('[+] Encapsulated shared secret');

      // Decapsulate
      final sharedSecret = kem.decapsulate(
        encResult.ciphertext,
        keyPair.secretKey,
      );
      _appendOutput('[+] Decapsulated shared secret');

      // Verify
      final match = _compareBytes(encResult.sharedSecret, sharedSecret);
      _appendOutput('[+] Secrets match: $match');
      _appendOutput('');
      _appendOutput('Shared secret (first 32 bytes):');
      _appendOutput(_bytesToHex(sharedSecret.take(32).toList()));

      // Deterministic generation
      if (kem.supportsDeterministicGeneration) {
        _appendOutput('');
        _appendOutput('--- Deterministic Key Generation ---');
        final seed = OQSRandom.generateSeed(kem.seedLength!);
        final kp1 = kem.generateKeyPairDerand(seed);
        final kp2 = kem.generateKeyPairDerand(seed);
        final identical = _compareBytes(kp1.publicKey, kp2.publicKey);
        _appendOutput('[+] Same seed produces identical keys: $identical');
      }
    } finally {
      kem.dispose();
    }
  }

  Future<void> _runSignatureDemo() async {
    final sig = Signature.create('ML-DSA-65');

    try {
      _appendOutput('Algorithm: ML-DSA-65');
      _appendOutput('Public key: ${sig.publicKeyLength} bytes');
      _appendOutput('Secret key: ${sig.secretKeyLength} bytes');
      _appendOutput('Max signature: ${sig.maxSignatureLength} bytes');
      _appendOutput('');

      // Generate key pair
      final keyPair = sig.generateKeyPair();
      _appendOutput('[+] Generated key pair');

      // Sign message
      final message = Uint8List.fromList(
        utf8.encode('Hello, Post-Quantum World!'),
      );
      final signature = sig.sign(message, keyPair.secretKey);
      _appendOutput('[+] Signed message (${signature.length} bytes)');

      // Verify
      final isValid = sig.verify(message, signature, keyPair.publicKey);
      _appendOutput('[+] Signature valid: $isValid');

      // Test with wrong message
      final wrongMessage = Uint8List.fromList(utf8.encode('Wrong message'));
      final isInvalid = sig.verify(wrongMessage, signature, keyPair.publicKey);
      _appendOutput('[+] Wrong message rejected: ${!isInvalid}');
    } finally {
      sig.dispose();
    }
  }

  Future<void> _runRandomDemo() async {
    _appendOutput('Generating random data...');
    _appendOutput('');

    // Random bytes
    final bytes = OQSRandom.generateBytes(32);
    _appendOutput('32 random bytes:');
    _appendOutput(_bytesToHex(bytes.toList()));
    _appendOutput('');

    // Random integers
    final ints = List.generate(10, (_) => OQSRandom.generateInt(1, 100));
    _appendOutput('10 random integers (1-99): $ints');

    // Random booleans
    final bools = List.generate(10, (_) => OQSRandom.generateBool());
    _appendOutput('10 random booleans: $bools');

    // Random doubles
    final doubles = List.generate(5, (_) => OQSRandom.generateDouble());
    _appendOutput(
      '5 random doubles: ${doubles.map((d) => d.toStringAsFixed(4)).toList()}',
    );

    // Shuffle demo
    final list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    _appendOutput('');
    _appendOutput('Original list: $list');
    OQSRandom.shuffleList(list);
    _appendOutput('Shuffled list: $list');

    // Available algorithms
    _appendOutput('');
    _appendOutput(
      'Available RNG algorithms: ${OQSRandom.getAvailableAlgorithms()}',
    );
  }

  Future<void> _runAlgorithmsDemo() async {
    final kems = LibOQS.getSupportedKEMAlgorithms();
    final sigs = LibOQS.getSupportedSignatureAlgorithms();

    _appendOutput('Key Encapsulation Mechanisms (${kems.length}):');
    for (final alg in kems) {
      _appendOutput('  - $alg');
    }

    _appendOutput('');
    _appendOutput('Digital Signatures (${sigs.length}):');
    for (final alg in sigs) {
      _appendOutput('  - $alg');
    }
  }

  bool _compareBytes(Uint8List a, Uint8List b) {
    if (a.length != b.length) return false;
    for (int i = 0; i < a.length; i++) {
      if (a[i] != b[i]) return false;
    }
    return true;
  }

  String _bytesToHex(List<int> bytes) {
    return bytes.map((b) => b.toRadixString(16).padLeft(2, '0')).join('');
  }
}

class _DemoButton extends StatelessWidget {
  final String label;
  final IconData icon;
  final bool isRunning;
  final VoidCallback onPressed;

  const _DemoButton({
    required this.label,
    required this.icon,
    required this.isRunning,
    required this.onPressed,
  });

  @override
  Widget build(BuildContext context) {
    return FilledButton.icon(
      onPressed: isRunning ? null : onPressed,
      icon: Icon(icon, size: 18),
      label: Text(label),
    );
  }
}
2
likes
0
points
339
downloads

Publisher

unverified uploader

Weekly Downloads

Dart FFI bindings for liboqs — high-performance post-quantum cryptography (PQC) with ML-KEM, ML-DSA, Falcon, SPHINCS+ for key encapsulation and signatures.

Repository (GitHub)
View/report issues

Topics

#cryptography #post-quantum #kem #pqc #liboqs

License

unknown (license)

Dependencies

code_assets, ffi, hooks

More

Packages that depend on liboqs