Features
- Encrypted at rest — AES-256-CTR or ChaCha20, HMAC-SHA256 per page, verified before decryption
- Full SQL engine — CREATE/DROP TABLE, SELECT with JOINs, subqueries, aggregates, indexes
- ACID transactions — Copy-on-Write B+ tree with shadow paging, no WAL. Snapshot isolation with concurrent readers
- P2P sync — Merkle tree diffing over Noise-encrypted transport with PSK authentication
- Interactive CLI — SQL shell with tab completion, syntax highlighting, 27 dot-commands
- Key hierarchy — Passphrase → Argon2id → Master Key → AES-KW → REK → HKDF → DEK + MAC
- FIPS mode — PBKDF2-HMAC-SHA256 + AES-256-CTR for compliance environments
- Audit logging — HMAC-SHA256 chained tamper-evident log
- Hot backup — Consistent snapshots via MVCC without blocking writes
- Large values — Overflow pages handle values up to any size transparently
- Cross-platform — Windows, Linux, macOS, and more. C FFI (35 functions) and WebAssembly bindings included
- 2,100+ tests — Unit, integration, and torture tests across all crates
Quick Start
As a Library
use ;
use Connection;
// Create a new encrypted database
let db = new
.passphrase
.argon2_profile
.create?;
// SQL
let mut conn = open?;
conn.execute?;
conn.execute?;
let result = conn.query?;
// Key-value (default table)
let mut wtx = db.begin_write?;
wtx.insert?;
wtx.commit?;
let mut rtx = db.begin_read;
assert_eq!;
// Named tables
let mut wtx = db.begin_write?;
wtx.create_table?;
wtx.table_insert?;
wtx.commit?;
// In-memory database (no file I/O, useful for testing and WASM)
let mem_db = new
.passphrase
.create_in_memory?;
CLI
# Create and open a database
# Run SQL interactively
);
) ));
;
# Database operations
# P2P encrypted sync
SQL Support
Statements: CREATE/DROP TABLE, CREATE/DROP INDEX, INSERT, SELECT, UPDATE, DELETE, BEGIN/COMMIT/ROLLBACK, EXPLAIN
Types: INTEGER, REAL, TEXT, BLOB, BOOLEAN
Expressions: JOINs (INNER, LEFT, RIGHT, CROSS), subqueries (scalar, IN, EXISTS), CASE, BETWEEN, LIKE, DISTINCT, GROUP BY/HAVING, ORDER BY, LIMIT/OFFSET
Functions: COUNT, SUM, AVG, MIN, MAX, LENGTH, UPPER, LOWER, SUBSTR, ABS, ROUND, COALESCE, NULLIF, CAST
Parameters: Positional binding with $1, $2, ... and LRU statement cache
Security
No plaintext on disk. Every page is encrypted before writing and authenticated before reading. There is no "unencrypted mode" — the database file is always opaque.
Separate key file. Encryption keys live in {dbname}.citadel-keys, not inside the database. The passphrase never touches disk — it derives a master key in memory via Argon2id (or PBKDF2 in FIPS mode).
Key backup. Export an encrypted key backup with a separate recovery passphrase. If the original passphrase is lost, restore access without re-encrypting the database.
Passphrase change. Re-wraps the root encryption key with the new passphrase. No page re-encryption needed — instant regardless of database size.
Encrypted sync. P2P sync uses the Noise protocol (NNpsk0_25519_ChaChaPoly_BLAKE2s). Both peers must share a 256-bit pre-shared key. Each session generates ephemeral Curve25519 keys for forward secrecy. No data is sent in plaintext.
Architecture
┌─────────────┬───────────────┬───────────────┐
│ citadel-cli │ citadel-ffi │ citadel-wasm │ CLI, C FFI, WebAssembly
├─────────────┴───────────────┴───────────────┤
│ citadel-sql │ SQL parser, planner, executor
├─────────────────────────────────────────────┤
│ citadel │ Database API, builder, sync
├──────────────┬──────────────┬───────────────┤
│ citadel-txn │ citadel-sync │ citadel-crypto│ Transactions, replication, keys
├──────────────┼──────────────┴───────────────┤
│citadel-buffer│ citadel-page │ Buffer pool (SIEVE), page codec
├──────────────┴──────────────────────────────┤
│ citadel-io │ File I/O, fsync, io_uring
├─────────────────────────────────────────────┤
│ citadel-core │ Types, errors, constants
└─────────────────────────────────────────────┘
Page Layout (8208 bytes on disk)
┌──────────┬────────────────────┬──────────┐
│ IV 16B │ Ciphertext 8160B │ MAC 32B │
└──────────┴────────────────────┴──────────┘
Every page gets a fresh random IV. HMAC is verified before decryption to prevent ciphertext manipulation.
Commit Protocol
Shadow paging with a god byte — a single byte controls which of two commit slots is active. Commits are atomic without a write-ahead log:
- Write dirty pages to new locations (CoW)
- Compute Merkle hashes bottom-up
- Update inactive commit slot
- Flip god byte (single-byte atomic write)
Language Bindings
C / C++
The citadel-ffi crate builds as a static or dynamic library with an auto-generated citadel.h header (cbindgen). All functions are panic-safe.
CitadelDb *db = NULL;
;
// Key-value
CitadelWriteTxn *wtx = NULL;
;
;
;
// SQL
CitadelSqlConn *conn = NULL;
;
CitadelSqlResult *result = NULL;
;
;
WebAssembly
The citadel-wasm crate provides a JavaScript API for browser and Node.js environments.
import from "citadel-wasm";
const db = ;
db.;
db.;
const result = db.;
// { columns: ["id", "name"], rows: [[1, "Alice"]] }
db.;
Build with wasm-pack build crates/citadel-wasm --target web.
Building
Requires Rust 1.75 or later.
Feature Flags
| Flag | Description |
|---|---|
audit-log |
Tamper-evident HMAC-chained audit log (default: on) |
fips |
FIPS 140-3 mode: PBKDF2 + AES-256-CTR only |
io-uring |
Linux async I/O via io_uring |
License
MIT OR Apache-2.0