Skip to main content
This is the flagship app-shaped tutorial. Use it after the Rust SDK quickstart when you want to see the same service boundary in a richer application. The tutorial builds a dating-style matcher. Public app logic owns profiles, accounts, cohort selection, and notifications. Stoffel owns the sensitive computation over private feature and preference vectors. The app opens only the match result it is allowed to route. Runnable source:

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

Read the files in this order:
  1. normal/: see what the trusted backend can compute because it sees every vector and ranking.
  2. private/: see the authorized output model the app should expose.
  3. src/client.rs: see how each dater owns a client slot and private payload.
  4. src/app.rs: see the Rust SDK boundary that validates the cohort, attaches client inputs, runs local MPC, and decodes the output.
  5. src/main.stfl: see the private computation and explicit reveal point.
  6. tests/: see what the tutorial treats as app behavior versus private intermediate state.

Run it

From the tutorial repository root:
Then run the Stoffel project directly:
Expected output:
In the sample, 19 encodes:
Use the concept tutorials when you hit a specific privacy question:

Adapt the pattern

When you adapt the tutorial, keep these invariants:
  1. Public profile and discovery data can stay in normal Rust code.
  2. Each user owns their private feature or preference payload.
  3. The app service validates public shape before running MPC.
  4. The StoffelLang program computes only the sensitive matching boundary.
  5. Scores, rankings, and rejection paths stay private unless the product explicitly names them as outputs.
  6. The final match is routed to named recipients, not treated as a global transcript.
You can change the feature model, cohort construction, output routing, and app UI without changing the core design habit: private intermediate facts are not ordinary backend data.

Next steps