abcb758b672563d8962d92a9b7d5ee6781cd0d05
A malicious server could re-serve an old but valid envelope of an item under a new, higher revision: the AAD does not bind the revision and the Merkle root was only checked when head_revision == cursor. The client took it as the latest version, rolled the item back and signed over it in its next manifest. * kv-model Item: `seq: u64` (serde default 0) and `restores: Option<u64>`. * kv-sync replay module: pure decision rules (check_successor, next_version, stamp, same_content). Every pulled live record must authenticate and have seq > the base's seq, unless it carries restores = t with base_revision < t < revision (edit beat a delete this device never saw) or is identical to the base. Otherwise: Integrity alarm. Tombstones and items without a base pass. * engine: check on every pulled record; edit-beats-delete re-seals with restores = tombstone revision; merges write seq = max + 1 and adopt the remote version when only seq/restores differ. Public engine::next_local_version gives the seq/restores for a local save (used by kv-ffi save_item and the tests). * verify_manifest checks the Merkle root whenever no held item is newer than head_revision (previously only at head == cursor). * Tests: replay alarm (clean and pending receivers, plus kv-ffi), harmless replay of the current version, tampered envelope, concurrent equal-seq edits across three devices, edit-beats-delete with a device that skipped the tombstone and a later replay of the restore, legacy items without seq, hidden item with cursor past the manifest head, and the shared item_replay.json decision table. * gen-vectors: envelope vector item payload now includes seq. FFI surface unchanged. Co-Authored-By: Claude Opus 5.5 <[email protected]>
kestrove-core
Rust workspace that holds all Kestrove crypto and vault logic. Apple,
Android and desktop apps call it through UniFFI. The server uses only kv-proto.
| Crate | Status | Purpose |
|---|---|---|
kv-proto |
✅ M0 | Wire types (Envelope, KDF params, API bodies). No secrets. |
kv-crypto |
✅ M0 | 2SKD (Argon2id + Secret Key), XChaCha20-Poly1305 envelopes, HPKE vault-key sealing, keyset, Ed25519, Secret Key format |
kv-model |
✅ M0 | Items, URL matching (PSL), TOTP (RFC 6238), password generator |
kv-ffi |
✅ M1 | The exported API (VaultCore with SQLite storage, local unlock key, sync; totp_code, match_url, generate_password) |
kv-store |
✅ M1 | SQLite replica (ciphertext only), base copies for merges, 10-version history |
kv-sync |
✅ M1 | TLS 1.3 + SPKI pins, OPAQUE login, RFC 9421 signing, pull/push/merge, signed manifest |
Spec: ../kestrove-spec/docs/02-cryptography.md and 03-sync-protocol.md.
Setup
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh # once
cargo test --workspace
Bindings
./scripts/build-apple.sh # → ../kestrove-apple/Packages/KestroveCore (XCFramework + Swift)
./scripts/build-android.sh # → ../kestrove-android/core-ffi (jniLibs + Kotlin); needs cargo-ndk
The desktop (Tauri) app depends on kv-ffi directly as a Rust crate.
Test vectors and the live-server test
cargo run -p kv-crypto --example gen-vectors # writes crates/kv-crypto/tests/vectors and ../kestrove-spec/vectors
cargo test -p kv-ffi --test live_server -- --ignored # against a fresh local kestrove-server; see the test's docs
Rules
- No
unsafeoutside generated FFI glue. - Secrets live in
Zeroizing<_>. Never log,Debug-print orformat!a secret. - Any change to formats needs a spec change first and new vectors in
kestrove-spec/vectors. cargo deny checkmust pass. There are no GPL dependencies (App Store).
Languages
Rust
98.1%
JavaScript
1.3%
Shell
0.6%