What this teaches
A dating app does not only store sensitive data. It computes over it. The platform may show public profiles, photos, prompts, and basic account metadata. Matching often depends on more sensitive context: what someone is looking for, how candidates score, how rankings are derived, and which conflicts or rejections happen along the way. The tutorial teaches the app boundary:Privacy boundary
The final match still leaks something. If Alice learns she matched with Emery, Alice learns a fact about the joint process. The point is to keep that necessary output from expanding into raw vectors, score tables, rankings, and rejection traces.
Code map
normal/: see what the trusted backend can compute because it sees every vector and ranking.private/: see the authorized output model the app should expose.src/client.rs: see how each dater owns a client slot and private payload.src/app.rs: see the Rust SDK boundary that validates the cohort, attaches client inputs, runs local MPC, and decodes the output.src/main.stfl: see the private computation and explicit reveal point.tests/: see what the tutorial treats as app behavior versus private intermediate state.
Run it
From the tutorial repository root:19 encodes:
Mental model links
Use the concept tutorials when you hit a specific privacy question:- If you want a smaller example focused only on “open one result, not the whole decision board,” read Private lottery reveal boundary.
- If you want a focused example of private state transitions and recipient-specific views, read N-party Battleship hidden state.
- If you are adapting this to your own product, use Design the privacy boundary.
Adapt the pattern
When you adapt the tutorial, keep these invariants:- Public profile and discovery data can stay in normal Rust code.
- Each user owns their private feature or preference payload.
- The app service validates public shape before running MPC.
- The StoffelLang program computes only the sensitive matching boundary.
- Scores, rankings, and rejection paths stay private unless the product explicitly names them as outputs.
- The final match is routed to named recipients, not treated as a global transcript.