NoSQLBuddy
Proof, not trust

How the ZK Audit System works

Every write to your database is captured, committed into a Merkle tree, sealed into an epoch, and anchored on a public blockchain, as a fingerprint only. From there you can disclose individual claims — this operation, this collection, this time range — with a zero-knowledge proof, and anyone can verify it for free without touching your data. Here is the full pipeline, end to end.

ZK Audit pipeline overview: MongoDB write, capture into a keyed Poseidon commitment, per-domain and global Merkle trees, age-encrypted epoch seal anchored to IPFS and Stellar, Audited-Action Disclosure proof, and free on-chain verification

Step 1

Capture every write, from every source.

On replica sets and sharded clusters, a change stream listener watches for every insert, update, delete, drop, rename, and index operation, regardless of whether it came from the shell, the app, or an external client. On standalone MongoDB, where change streams aren't available, an operation interceptor hooks into the driver as a fallback.

Each captured operation is encoded with an unambiguous, length-prefixed binary format, immune to delimiter-injection, and derived into a leaf as a keyed Poseidon vector commitment: leaf = Poseidon(key, opHash, dbHash, collHash, ts, docHash, salt). The key is generated at setup and shared only with authorized auditors, so an attacker who only sees the public leafsignal in a proof can't guess payloads and confirm what happened by brute force. The leaf is then inserted into a 20-level Merkle tree that can hold up to a million entries per epoch. Nothing but the commitment ever leaves the write path.

Capture and accumulate: MongoDB writes flow through a change stream listener or operation interceptor into an append-only audit log, get canonically encoded, and are derived into a keyed Poseidon vector commitment leaf inserted into a Merkle tree backed by JSONL and Sled storage

Step 2

Seal a batch. Publish the fingerprint.

Once 100 events accumulate (or a time threshold passes), the epoch manager freezes the current Merkle root. Optionally, the audit system also reads MongoDB's own oplog directly, the real source of truth, and builds a second SHA-256 Merkle tree over every majority-committed entry in that range. That proves nothing was skipped.

Before leaving the machine, the sealed batch is encrypted with age (XChaCha20-Poly1305, X25519 multi-recipient envelopes) so only the operator and authorized auditors can read it. The ciphertext, never the plaintext, is what gets pinned to IPFS (or via Pinata in dev mode) for decentralized storage.

Alongside the global root, the epoch also computes a super-root over every per-domain root in the batch (see audit domains below). The 32-byte Merkle root, the oplog completeness root, and the domain super-root are all committed to a Soroban smart contract on the Stellar blockchain. That's the entire on-chain footprint: three hashes, an epoch number, and a content identifier — never the raw data.

Seal and publish: epoch lifecycle from accumulating events to threshold to closed root, feeding oplog completeness, age batch encryption, and a domain super-root into IPFS or Pinata and a Stellar Soroban contract

Step 3

Segment the log. Disclose one tenant, not everyone.

Beyond the single global Merkle tree, events are segmented into domains — each the pair (deployment, database), for example rs:rs0 · sales. Every domain gets its own secondary Merkle root, computed deterministically from that domain's leaves in the tamper-verified global log, so you can prove one tenant's record exists without revealing anything about any other domain.

A second aggregation tree is built over every domain root in the batch, one leaf per domain. Its super-rootcommits to the entire set of domains and is written straight into the epoch's on-chain commit metadata — no contract redeploy required. A short authentication path proves a given domain was part of the committed state, the same way a leaf proves its place in any Merkle tree.

A domain can be placed under legal hold, blocking pruning until it's lifted, or logically pruned for retention: its live event metadata drops out of view, but a compact retained commitment — root, count, last index, timestamp — keeps it verifiable and still folded into the super-root. The append-only global tree and on-chain anchor are never touched, so anchored history always stays complete. Integrity and inclusion are guaranteed per domain today; completeness (no writes omitted) remains a global guarantee via the oplog protocol below.

Audit domains and selective disclosure: a global Merkle tree segmented into per-domain roots, aggregated into a super-root anchored on-chain via commit metadata, with legal hold and pruned-domain retention shown feeding the same super-root

Step 4

Disclose a claim. Reveal nothing else.

For any event, NoSQLBuddy can generate an Audited-Action Disclosure proof — a Groth16 zero-knowledge proof (via a Circom circuit compiled with ark-circom and ark-groth16) that opens the leaf's keyed Poseidon commitment in-circuit and proves predicates over its still-private fields: a claimed operation, collection, and time range. Everything else about the event — the document, the database, the exact timestamp, any sibling record — stays private.

Anyone, including someone with no access to your database, can call verify_disclosure on the Soroban contract and get back a yes or no, backed by a BN254 pairing check over Stellar's native host functions. Verification is permissionless and runs as a free, read-only simulation — no funded account, no fee, nothing submitted to the ledger. Calling verify_and_record_disclosure instead appends an on-chain, verifier-attributed record — who checked which claim, and when — turning a one-off verification into citable evidence.

Reader mode compares the local audit log against the roots actually committed on-chain to catch tampering after the fact. And because a single publisher could in theory omit writes, independent attesters on separate replica members recompute the oplog hash themselves and submit signed attestations. The contract only accepts a batch as complete once a K-of-N threshold of attesters agree — a disclosure proof is existential (it shows a matching event exists), while K-of-N attestation is what makes the log exhaustive.

Disclose and verify: an Audited-Action Disclosure proof over predicate claims feeds free, permissionless on-chain verification via verify_disclosure and verify_and_record_disclosure, alongside the parallel, independent K-of-N attester and reader-mode completeness checks

What you get

Four guarantees, backed by math, not policy.

Integrity

No event can be modified, reordered, or inserted without detection. Every write is committed into a Merkle tree the moment it happens, and the root is anchored on-chain.

Selective disclosure

An Audited-Action Disclosure proof shows an event matching a claimed operation, collection, and time range exists in the log, without revealing the document, the database, the exact timestamp, or any other record.

Completeness

Oplog hashing plus K-of-N independent attestation proves that no writes were quietly omitted from the log. This guarantee is global, and orthogonal to what any single disclosure proof can show.

Privacy

Every epoch batch is encrypted with age (XChaCha20-Poly1305, X25519 multi-recipient) before it touches IPFS — only authorized auditors can decrypt. Merkle leaves are a keyed Poseidon vector commitment, so public proof signals resist offline dictionary attacks.

Dev mode runs the full stack locally via Docker on Stellar testnet. Production mode signs natively with your own keypair, stored in your OS keychain, on testnet or mainnet.

An audit log even you can't fake.

Try dev mode locally with the bundled Docker stack, or read the source, the whole pipeline is open.