fhexmpp — XMPP-shaped FHE maildrop & encrypted subject triage (CKKS on the Niobium Fog)
Not logged in

An example answer to "can we build a real messaging system where the server runs in FHE and the clients hold their private keys?" — rebased on XMPP (RFC 6120/6122 data model) rather than an abstract mailbox. The client side uses real XMPP concepts (JIDs, a roster, <message> stanzas with <subject>/<body>); the server side is a single recorded ct×ct triage circuit (fhetch_sim locally, hollow ring 2^16 for the Fog) that matches a stanza's subject against the recipient's encrypted rule box and returns only an encrypted match vector. The FHE circuit is byte-identical to the verified fhe-messenger triage circuit; the kernel surface was extended by one call (encrypt-to-maildrop: sender encrypts under the RECIPIENT's published keys, per the XMPP "encrypt to the contact's key" model).

Honest boundary line: roster/presence/SASL stay plain, envelope metadata (from/to/when) is visible to the server, and the message body is out-of-scope for FHE (it rides in the client-side stanza log only). What an FHE Fog server can and cannot host today is in design/DESIGN.md.

Roles (demo: two users)

Layout

Diagrams (design/*.dot — hand-written Graphviz sources, SVG the deliverable)

File Shows
topology.svg trust-boundary map: the two clients (all secrets, roster, stanzas), alice's maildrop (public keys + ciphertexts only, sk-guarded), and the Fog worker; which flows cross the boundary as ciphertext vs which stay classical
pipeline.svg one <message> end to end: keygen → rules → send (subject hashed + encrypted under the recipient's pk) → triage → Fog job → watch; the two trust-boundary crossings carry ciphertexts only
circuit.svg the 4,255-instruction ct×ct triage circuit: slot geometry of this demo (invoice/maple/standup + PAD), the four multiplies, and the measured Fog-output scores against the 0.5 threshold / 0.288 ambiguity edge

Build (✅ verified)

Prerequisite: a Release-built niobium-client (cd ~/code/niobium-client && make release).

make build      # cargo build --release
make unit       # 7 Rust unit tests (hash grid, soft-eq extremes, PAD,
                # gray-zone guard, JID parsing, stanza round-trip)
make twin       # plaintext f64 twin: hash grid + soft-eq^8 + expectations

Local sim round-trip (✅ verified)

XMPP-shaped flow at ring 4096: alice keygen → bob keygen → bob rosters alice's maildrop → alice parks her rule box → bob sends subject "maple" (stanza to bob_home/stanza.log, ct_msgrep under alice's pk) → server triage (record + fhetch_sim replay) → plain-FHE differential → alice decrypts the match vector (subject read back from bob's stanza log).

make local

Expected tail:

sent: bob@fhe.example -> alice@fhe.example subject "maple" -> ct_msgrep.bin in alice_drop/
  server departure inventory: cc/pk/mk + ct_rules + ct_one + ct_msgrep (no sk, no plaintext, no stanzas)
  MATCH
[PASS] plain-OpenFHE circuit matches the f64 twin
=== watch: decrypted MATCH vector (stanza subject was: "maple") ===
[PASS] lit slots [1] == expected [1]

Guards (all verified):

make nomatch    # subject "quartz": no slot lights
make canary     # plant sk.bin in the maildrop: server REFUSES with exit 1

Fog round-trip (2^16, hollow record — ✅ verified)

make fog-record       # N=2^16 keygen (both users) + rules + send + hollow record
make fog-submit       # ships the trace; needs fogrs + ~/.fog/credentials

Verified run (the XMPP-shaped flow, job 1145db61, batch, dal1worker1): 132 MB project upload (138.5 MB streamed, 4.6 s), ~11 s worker wall for the 4,255-instruction triage circuit, 4.0 MB encrypted match vector back. Decrypted on bob's client against the stanza from bob's own log — slot 1 (maple) lit at score 1.0, watch PASSed. (fog-submit asserts --expect-hot 1.)

What this does / does NOT do

DOES: XMPP data model (JIDs, roster, stanzas with subject watchword), encrypted ct×ct subject triage, sender-→-recipient encryption against the recipient's published keys, secret-key discipline (client-only, guarded on both sides), local sim + 2^16 hollow Fog-shaped gates.

Does NOT (yet — escalation steps in DESIGN.md): roster fan-out routing on encrypted ids, presence/push, a stateful mailbox, encrypted bodies, MUC, XMPP SASL/TLS transport (would stay classical anyway), or any DeltaChat adaptation.

License

BSD-3-Clause (see LICENSE).