infusion_ffi 1.6.0 copy "infusion_ffi: ^1.6.0" to clipboard
infusion_ffi: ^1.6.0 copied to clipboard

Flutter plugin for the Infusion crypto vault — AEAD encryption, Ed25519 signing, BLAKE3 CIDs, BIP-39 wallets, and capability tokens. Prebuilt binaries for all platforms.

infusion_ffi #

pub.dev Build License: MIT

Languages: 🇧🇷 Português · 🇪🇸 Español

A Flutter plugin for the Infusion cryptographic vault protocol. Provides AEAD encryption, Ed25519 signing, BLAKE3 content identifiers, BIP-39 mnemonic wallets, and capability-based access delegation — all backed by a closed-source Rust core with prebuilt binaries for every platform.


Platform Support #

Platform Architectures Binary delivery
Android arm64-v8a · armeabi-v7a · x86_64 Bundled in package (no download)
iOS arm64 · simulator (arm64 / x86_64) Bundled in package (no download)
Web All modern browsers Bundled Wasm asset
macOS arm64 · x86_64 (universal) Downloaded on first use, then cached
Linux x86_64 · arm64 Downloaded on first use, then cached
Windows x86_64 · arm64 Downloaded on first use, then cached

Desktop binaries are fetched from GitHub Releases, verified with hardcoded SHA-256 checksums, and cached per version under systemTemp/infusion_ffi/<version>/. Subsequent runs load from cache; no internet required.


Installation #

# pubspec.yaml
dependencies:
  infusion_ffi: ^1.5.0-dev.1
flutter pub get

No additional setup is required for Android, iOS, or Web. For desktop, the binary is downloaded automatically on the first call to any InfusionFFI method.


Quick Start #

import 'dart:convert';
import 'dart:typed_data';
import 'package:infusion_ffi/infusion_ffi.dart';

Future<void> main() async {
  // 1. Generate a new BIP-39 wallet (12 or 24 words)
  final phrase = await InfusionFFI.mnemonicGenerate(wordCount: 12);

  // 2. Derive vault keys from the mnemonic
  final keysJson = await InfusionFFI.mnemonicRestore(phrase);
  final keys = jsonDecode(keysJson) as Map<String, dynamic>;

  // 3. Open the vault
  final vault = await InfusionFFI.create(
    encKeyHex:   keys['enc_key_hex']   as String,
    signSeedHex: keys['sign_seed_hex'] as String,
  );

  // 4. Encrypt
  final plaintext = Uint8List.fromList(utf8.encode('Hello, Infusion!'));
  final frame = await vault.seal(data: plaintext, policyId: 0);

  // 5. Decrypt
  final recovered = await vault.open(frame);
  print(utf8.decode(recovered)); // Hello, Infusion!

  // 6. Always dispose to release native memory
  await vault.dispose();
}

API Reference #

Vault Lifecycle #

Create a vault from hex-encoded keys. Always call dispose() when done.

final vault = await InfusionFFI.create(
  encKeyHex:   '...', // 32-byte encryption key, hex-encoded
  signSeedHex: '...', // 32-byte Ed25519 seed, hex-encoded
);

// ... use vault ...

await vault.dispose(); // releases native memory; no-op if already disposed

Encrypt & Decrypt #

seal encrypts data into a self-describing frame that includes the ciphertext, AEAD authentication tag, and metadata. open decrypts and authenticates atomically — it throws if the frame was tampered with.

// Encrypt
final frame = await vault.seal(
  data:     Uint8List.fromList(utf8.encode('secret data')),
  policyId: 0,           // 0 = owner-only (default)
  aad:      optionalAad, // optional additional authenticated data
);

// Decrypt — throws on authentication failure
final plaintext = await vault.open(frame);

// Verify without decrypting
final ok = await vault.verify(frame); // bool

// Detailed result (useful for diagnostics)
final result = await vault.verifyDetailed(frame);
// result.ok   → bool
// result.code → int  (reason code when !ok)
// result.cid  → Uint8List (32-byte BLAKE3 content ID of the frame)

Capability Tokens #

Delegate scoped access to other identities without sharing keys. Tokens are signed by the issuer, carry an expiration timestamp, and bind to a specific Ed25519 public key — making them verifiable by any party that holds the public key.

// Hash the resource being protected
final resourceCid = await InfusionFFI.cid(resourceBytes);

// Issue a READ token valid for 24 hours
final token = await vault.issueCap(
  scopeCid:      resourceCid,
  rights:        0x01,   // bitmask: 0x01 = READ, 0x02 = WRITE
  expTs:         DateTime.now()
      .add(const Duration(hours: 24))
      .millisecondsSinceEpoch ~/ 1000,
  delegatedPub32: recipientPub32, // 32-byte Ed25519 public key
);

// Recipient verifies signature, expiration, and identity
final valid = await vault.verifyCap(
  capToken:       token,
  requesterPub32: recipientPub32,
);

// Open a sealed frame using a delegated token
final plaintext = await vault.open(frame, capToken: token);

Key Derivation #

Derive deterministic 32-byte sub-keys from the vault seed using a context string. Use this to encrypt local storage, derive per-service keys, or generate stable identifiers — without persisting extra secrets.

// Context string uniquely identifies the derived key's purpose
final context = Uint8List.fromList(utf8.encode('storage:user_box'));
final boxKey  = await vault.deriveKey(context); // Uint8List (32 bytes)

// Searchable blind index — deterministic hash of a plaintext term
// Useful for querying encrypted fields without leaking the value
final idx = await vault.blindIndex('user@example.com'); // Uint8List (32 bytes)

BIP-39 Mnemonic Wallet #

Generate a human-readable mnemonic and deterministically derive vault keys from it. Store only the mnemonic (ideally in secure storage); re-derive keys on demand.

// Generate a new mnemonic
final phrase12 = await InfusionFFI.mnemonicGenerate(wordCount: 12);
final phrase24 = await InfusionFFI.mnemonicGenerate(wordCount: 24);

// Restore keys from an existing mnemonic
// Returns a JSON string: {"enc_key_hex": "...", "sign_seed_hex": "..."}
final json = await InfusionFFI.mnemonicRestore(phrase12);
final keys = jsonDecode(json) as Map<String, dynamic>;

final vault = await InfusionFFI.create(
  encKeyHex:   keys['enc_key_hex']   as String,
  signSeedHex: keys['sign_seed_hex'] as String,
);

Ed25519 Signatures #

Sign arbitrary messages and verify signatures against known public keys.

final seed32  = await InfusionFFI.mnemonicRestore(phrase)
    .then((j) => hexDecode((jsonDecode(j) as Map)['sign_seed_hex'] as String));
final message = Uint8List.fromList(utf8.encode('content to sign'));

// Sign
final sig64 = await InfusionFFI.signWithSeed(seed32, message); // 64 bytes

// Derive Ed25519 public key from seed
final pub32 = await InfusionFFI.derivePubkey(seed32); // 32 bytes

// Verify
final valid = await InfusionFFI.verifySignature(
  pub32: pub32,
  msg:   message,
  sig64: sig64,
);

Content Identifiers & Hashing #

// BLAKE3 content ID — 32-byte stable identifier for any byte sequence
final cid = await InfusionFFI.cid(data); // Uint8List (32 bytes)

// SHA-256
final hashBytes = await InfusionFFI.sha256(data);       // Uint8List (32 bytes)
final hashHex   = await InfusionFFI.sha256Hex('input'); // lowercase hex String

// sha256Hex is useful for OIDC/Apple Sign-In nonce derivation:
//   final hashedNonce = await InfusionFFI.sha256Hex(rawNonce);

Desktop: Binary Download #

On macOS, Linux, and Windows, InfusionLoader.load() (called internally on every InfusionFFI operation) downloads the platform binary from GitHub Releases, verifies the SHA-256 checksum against a hardcoded value for this version, and caches it.

First run requires network access. Once cached, the plugin works offline.

Platform Binary filename
macOS (universal) libinfusion_ffi.dylib
Linux x86_64 libinfusion_ffi-linux-x64.so
Linux arm64 libinfusion_ffi-linux-arm64.so
Windows x86_64 infusion_ffi-windows-x64.dll
Windows arm64 infusion_ffi-windows-arm64.dll

Testing #

# All platforms
flutter test

# Web (validates Wasm loading in a real browser)
flutter test --platform chrome

Widget tests using flutter_test block HttpClient by default. For desktop loader tests, use integration_test or allow network access. For web, prefer running a real Flutter app to validate Wasm loading rather than relying on headless test environments.


Security #

Primitive Algorithm Notes
Authenticated encryption ChaCha20-Poly1305 Default; AEAD — open() rejects tampered frames
Signatures Ed25519 High-performance, constant-time, safe curve
Content hashing BLAKE3 Fast, parallel, cryptographically secure
Checksums SHA-256 Used for desktop binary verification and OIDC nonces
Key derivation HKDF Deterministic sub-key derivation from vault seed
Mnemonic BIP-39 12 or 24 words — deterministic key restoration

Secret keys are redacted in debug logs (first 6 + last 4 hex characters only).


License #

The Dart/Flutter wrapper is licensed under the MIT License — see LICENSE.

The Infusion core (compiled Rust binaries) is proprietary software — see BINARY_LICENSE. Redistribution of the prebuilt binaries is permitted only as described in that file.

0
likes
130
points
559
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Flutter plugin for the Infusion crypto vault — AEAD encryption, Ed25519 signing, BLAKE3 CIDs, BIP-39 wallets, and capability tokens. Prebuilt binaries for all platforms.

Topics

#cryptography #encryption #security #ffi

License

MIT (license)

Dependencies

crypto, ffi, flutter, flutter_web_plugins, path, web

More

Packages that depend on infusion_ffi

Packages that implement infusion_ffi