Skip to content

Latest commit

 

History

History

ffi

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 

README.md

WormDB embedding FFI (Path A)

Embed the WormDB engine directly in a native app as a single-node, in-process key/value store — KV + WAL + snapshot persistence, std.crypto (no libsodium), no socket server, no clustering. This is "Path A" from meshguard#102: once libsodium became optional, the engine cross-compiles to mobile/ARM as a plain libc library.

Layout

file role
src/ffi.zig the C-ABI surface (export fn wormdb_*) over Store
ffi/wormdb.h C header for any caller (Swift bridging header / JNI)
ffi/swift/ idiomatic Swift wrapper + runnable PoC (iOS-native language)
ffi/android/ JNI bridge (wormdb_jni.c) + Kotlin WormDB.kt

zig build produces zig-out/lib/libwormdb_ffi.{dylib,so} (and a static .a on iOS, since apps cannot dlopen user dylibs).

API

wormdb_Db *wormdb_open(const char *dir, int persistence);  // WORMDB_PERSIST_{FULL,SNAPSHOT,NONE}
void       wormdb_close(wormdb_Db *db);
int        wormdb_set(wormdb_Db*, const u8 *key, size_t, const u8 *val, size_t);
int        wormdb_set_worm(...);            // write-once entry
int        wormdb_get(wormdb_Db*, const u8 *key, size_t, u8 **out, size_t *out_len);  // free with wormdb_free
int        wormdb_get_meta(wormdb_Db*, const u8 *key, size_t, wormdb_EntryMeta *out);
int        wormdb_scan_prefix(wormdb_Db*, const u8 *prefix, size_t, size_t limit, void *ctx, wormdb_scan_callback);
int        wormdb_append_log(wormdb_Db*, const u8 *log_id, size_t, const u8 *payload, size_t,
                             const u8 *attachment_hashes, size_t attachment_hash_count,
                             uint64_t ingest_time_ms, wormdb_AppendReceipt *out);
int        wormdb_append_log_verify(wormdb_Db*, const u8 *log_id, size_t, wormdb_AppendLogReport *out);
int        wormdb_proof_build_mmr_bundle(wormdb_Db*, const u8 *log_id, size_t,
                                         uint64_t from_seq, uint64_t to_seq,
                                         const u8 public_key[32], const u8 secret_key[64],
                                         uint64_t created_at_ms, uint64_t ingested_at_ms,
                                         const u8 *checkpoint_ext, size_t checkpoint_ext_len,
                                         const u8 *bundle_ext, size_t bundle_ext_len,
                                         u8 **out_bundle, size_t *out_len,
                                         wormdb_ProofBundleInfo *out_info);
int        wormdb_proof_verify_bundle(const u8 *bundle, size_t, wormdb_ProofBundleInfo *out_info);
int        wormdb_mmr_proof_verify(const u8 *proof, size_t, uint64_t seq,
                                   const u8 leaf_hash[32], const u8 expected_root[32]);
int        wormdb_delete(wormdb_Db*, const u8 *key, size_t);
void       wormdb_free(u8 *ptr, size_t len);

Values from wormdb_get are library-owned — release with wormdb_free. The store is internally sharded with per-shard locks, so a handle is safe to share across threads.

wormdb_get_meta returns a caller-owned metadata receipt for a single key: WormDB's local timestamp_ms, is_worm, value_len, and SHA-256(value).

wormdb_scan_prefix scans keys by prefix in lexicographic key order. The callback receives borrowed key/value pointers plus the same metadata receipt shape; copy anything that must survive after the callback returns. limit == 0 means no limit, while a positive limit returns the lexicographic tail to match the engine's existing scanPrefix semantics.

The proof calls expose the WORM append-log and MMR proof spine to native apps: append opaque payload bytes to a named immutable log, verify the local chain, build one encoded proof bundle for a sequence range, and verify that bundle on another device without opening a database. Encoded bundles and wormdb_get buffers are released with wormdb_free.

macOS / Swift — runnable PoC

bash ffi/swift/run.sh

Builds the dylib, compiles ffi/swift/WormDB.swift + main.swift against the bridging header, and runs a demo that sets/gets string + binary values, exercises WORM rejection, deletes, and reopens to prove persistence (WAL replay). This is the same WormDB class an iOS app would ship.

iOS

The Zig source is portable to aarch64-ios; only libc/SDK wiring is needed (Zig stops at "unable to find libSystem" without the SDK sysroot). Produce a static lib per slice and bundle as an .xcframework:

# device (arm64) + simulator (arm64); add x86_64 sim if you need Intel Macs
zig build -Dtarget=aarch64-ios          -Dno-sodium=true \
  --sysroot "$(xcrun --sdk iphoneos --show-sdk-path)"
zig build -Dtarget=aarch64-ios-simulator -Dno-sodium=true \
  --sysroot "$(xcrun --sdk iphonesimulator --show-sdk-path)"
# -> libwormdb_ffi.a per slice; xcodebuild -create-xcframework ...

In Xcode: add the .xcframework, set ffi/wormdb.h as the bridging header, drop in WormDB.swift. Open with context paths under the app sandbox, e.g. FileManager.default.urls(for: .applicationSupportDirectory, ...).

Android

Cross-compile the engine .so per ABI, then build the JNI bridge .so with the NDK, and place both in jniLibs/<abi>/:

# 1. engine: needs an NDK libc file (see deps/meshguard/android-aarch64-libc.conf
#    as a template; point it at your $ANDROID_NDK_HOME sysroot)
zig build -Dtarget=aarch64-linux-android -Dno-sodium=true --libc android-aarch64-libc.conf
#    -> libwormdb_ffi.so

# 2. JNI bridge (CMake/ndk-build), linking libwormdb_ffi + ffi/wormdb.h:
#    $NDK/.../clang --target=aarch64-linux-android21 -shared \
#       ffi/android/wormdb_jni.c -I ffi -Iffi -L<engine.so dir> -lwormdb_ffi \
#       -o libwormdb_jni.so

Add WormDB.kt (package dev.wormdb) to your sources; it System.loadLibrarys both .sos. Open under context.filesDir.

Status (verified in this PoC)

  • ✅ Swift PoC builds + runs on macOS: set/get (string + 256-byte binary), WORM rejection, delete, and persistence across reopen via WAL replay.
  • ✅ wormdb_jni.c compiles against the JDK's jni.h (JNI ABI correct).
  • ✅ zig build test runs FFI tests for append-log writes, encoded MMR bundle construction/verification, and direct MMR proof-byte verification.
  • ✅ FFI library cross-compiles to aarch64-linux-musl (ARM, static-friendly, no libsodium) — same class of build as Android/iOS, which additionally need their NDK/SDK libc.

Not included: clustering / multi-device replication ("Path B") — that layer is Linux-only today.