ShrouDB
Search data you've encrypted

Veil

Exact, prefix, contains, and fuzzy search over encrypted fields.

Once an email column is encrypted, you can no longer look anyone up by email. Veil keeps a blind index of keyed tokens instead of plaintext, so you can still search by exact value, prefix, substring, or approximate match. In end-to-end mode the client computes the tokens and the server never sees the value.

Use it from your app

typescript
import { ShrouDB } from "@shroudb/sdk";

const db = new ShrouDB({
  moat: process.env.SHROUDB_URL,   // e.g. http://localhost:8200
  token: process.env.SHROUDB_TOKEN,
});
const b64 = (s: string) => Buffer.from(s).toString("base64");

await db.veil.indexCreate("customer_emails");

// When you save a customer
await db.veil.put("customer_emails", customerId, b64(email));

// Support looks someone up by part of their email
const { results } = await db.veil.search("customer_emails", "alice@", {
  mode: "prefix",
});

What it does

  • Exact, prefix, contains, and fuzzy matching.
  • Stores keyed tokens, never the plaintext value.
  • End-to-end mode: the client computes tokens, the server never sees the value.
  • Index rotation and rebuild.
  • Works alongside Cipher: encrypt the value, index it with Veil.

Turn it on

Veil runs inside Moat, the ShrouDB server. Add this to moat.tomland restart. It shares Moat's encrypted storage, access tokens, and audit log with the other engines.

moat.toml
[engines.veil]
enabled = true   # uses Cipher, which must also be enabled

Commands

Over RESP3, prefix each command with VEIL. Over HTTP, send POST /v1/veil {"args": [...]}. The SDKs have a method for each.

CommandArgsDescription
INDEX CREATE<name>Create a search index
PUT<index> <id> <base64>Index a value
SEARCH<index> <query> [MODE exact|prefix|contains|fuzzy]Search
DELETE<index> <id>Remove an entry
INDEX ROTATE<name>Rotate the index key
INDEX REINDEX<name>Rebuild an index
Try Veil locally
The quickstart takes about five minutes.