> ## Documentation Index
> Fetch the complete documentation index at: https://docs.everabyte.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Dart / Flutter quickstart

> Use the evb_e2ee_dart FFI binding to encrypt files client-side in Dart and Flutter apps before they reach Everabyte.

The Dart binding wraps the native Rust core via `dart:ffi`. It targets Dart ≥ 3.5. The current loader supports Windows, Linux and macOS desktop library names; this guide does **not** provide an Android or iOS Flutter build procedure.

## 1. Get the binding

The package lives in the public [everabyte/crypto-sdk](https://github.com/everabyte/crypto-sdk) repository — `pub` supports git dependencies with a subdirectory:

```yaml theme={null}
dependencies:
  evb_e2ee_dart:
    git:
      url: https://github.com/everabyte/crypto-sdk.git
      path: bindings/dart
```

The Dart code is a `dart:ffi` wrapper over the native core (`bindings/dart/rust`). You need that native library on each platform you ship:

```bash theme={null}
# Build it yourself (Rust toolchain required)
git clone https://github.com/everabyte/crypto-sdk.git
cd crypto-sdk/bindings/dart/rust && cargo build --release
# → libevb_e2ee_ffi.so (Linux) / .dll (Windows) / .dylib (macOS)

# Point the binding at it
export EVB_E2EE_LIB=/path/to/libevb_e2ee_ffi.so
```

The package loader checks `EVB_E2EE_LIB` and then searches the package's Rust target directory for those desktop library names. Do not assume it automatically loads a Flutter plugin asset. Android needs a separately cross-compiled `.so` for each supported ABI and an Android-aware loader/integration; iOS needs a compatible static/framework integration. Those mobile build and packaging steps are not documented or supported by this quickstart.

```dart theme={null}
import 'package:evb_e2ee_dart/evb_e2ee_dart.dart';
```

## 2. Generate the account key (UMK) — on device

```dart theme={null}
final umk = EvbE2ee.generateUmk(); // 96 bytes: 32 X25519 || 64 ML-KEM seed
final publics = EvbE2ee.umkPublicKeys(
  umk.sublist(0, 32),
  umk.sublist(32),
); // { publicKeyX25519: base64(32), publicKeyMlkem: base64(1184) }
```

Persist only wrapped copies: seal the UMK under a recovery phrase and/or a device secret, and keep those secrets in `flutter_secure_storage` (or your platform keychain). Register the chain with the same `POST /e2ee/keys/register` call as the [TypeScript quickstart](https://docs.everabyte.com/sdk/quickstart-typescript.md#2-generate-the-account-key-umk-once-on-your-machine):

```dart theme={null}
final mnemonic = /* your fresh BIP-39 phrase — show it once, store it outside Everabyte */;
final blob = EvbE2ee.wrapUmkWithMnemonic(umk.sublist(0, 32), umk.sublist(32), mnemonic);

final deviceSecret = EvbE2ee.generateRandom32();       // stays in the secure store
final deviceBlob = EvbE2ee.wrapUmkWithDeviceKey(
  umk.sublist(0, 32), umk.sublist(32), deviceSecret,
);
```

> [!WARNING]
>
> The device wrap key is derived from `deviceSecret`, which must never leave the device — Everabyte receives only the wrapped blob and a public device label. Deriving it from a transmitted value (an ID, a name) would let the server silently recover the key; the SDK's API makes that mistake unrepresentable by taking the secret directly.

## 3. Encrypt before upload

```dart theme={null}
final plaintext = await File('contract.pdf').readAsBytes();

final dek = EvbE2ee.generateRandom32();                 // per-file DEK — never persisted
final fileNonce = EvbE2ee.generateRandom12();
final payload = EvbE2ee.evb1SealAll(dek, fileNonce, plaintext);

final wireName = EvbE2ee.deriveWireAlias(umk.sublist(0, 32), umk.sublist(32), 'contract.pdf');
final encryptedName = EvbE2ee.encryptFileName(dek, 'contract.pdf', EvbE2ee.generateRandom12());
final envelopeJson = EvbE2ee.wrapDekToUmk(dek, publicsX25519Bytes, publicsMlkemBytes);
```

## 4. Upload and attach — same REST contract

1. `POST /files/upload/{bucketId}` — multipart, file part named `wireName` (the opaque alias).
2. `POST /e2ee/files/by-path/envelope` — `{ bucketId, fileName: wireName, encryptedName, ...envelope }`.

If envelope attachment times out, reconcile the result before cleanup: the server may have committed the envelope. When a file ID is known, check `GET /e2ee/files/{fileId}/envelope`. After a confirmed failure, find the uploaded row by bucket and opaque wire name, confirm it has no envelope, and hard-delete it through the file API as required by the E2EE upload contract. Handle retention blocks explicitly.

## 5. Download and decrypt

```dart theme={null}
// GET /e2ee/files/{fileId}/envelope → envelope JSON
// GET /files/{fileId}/stream?download=true → stored ciphertext
final dek = EvbE2ee.unwrapDekFromUmk(envelopeJson, umk.sublist(0, 32), umk.sublist(32));
final original = EvbE2ee.evb1OpenAll(dek, storedCiphertext);
final realName = EvbE2ee.decryptFileName(dek, encryptedName);
```

Every binding opens the same frozen vectors, so a file encrypted here decrypts identically in the Rust crate, the WASM binding and the Everabyte web app.

## Next steps

* [SDK API reference](https://docs.everabyte.com/sdk/api-reference.md) — the full Dart surface alongside Rust and TypeScript.
* [Wire protocol reference](https://docs.everabyte.com/sdk/protocol-reference.md) — formats, versioning and interop rules.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.