Skip to main content
This tutorial builds a small eligibility-score computation. The goal is to model one client value as a share, compute over that share, and reconstruct the derived score explicitly.
This is a small local example. Use the same modeling steps with your own deployment and security validation when moving beyond the tutorial.
Campaign-style Stoffel architecture diagram showing how a StoffelLang program becomes app-prepared inputs, a build contract, and networked MPC runtime execution.

What you will use

  • The stoffel CLI.
  • The Rust SDK from crates.io when you run or adapt the Rust wrapper path.
  • A Share-based StoffelLang program.
Finish Installation before starting.

Create a project

Check the generated program first:

Replace src/main.stfl

Use this simple Share-based program:
The program keeps the input as a Share while it computes, then opens only the final eligibility score as the allowed tutorial output.

Validate and build

Inspect the bytecode if needed:
If your project name produces a different bytecode file name, list target/debug and use that path.

Run locally with a client input

Run the project through local MPC. This starts several MPC nodes/processes locally on your machine and feeds client slot 0 with the private input value:
The returned value is (42 + 25) * 2, not the raw client input.

Iterate in watch mode

For scripts, add --once.

Run the same idea from Rust

The Rust SDK is the primary application API for embedding Stoffel programs in Rust apps. Use the bytecode you already built from src/main.stfl instead of embedding a second sample program in Rust. In this example, .execute_local().await? performs local MPC testing by spawning several MPC nodes/processes on your machine:

Shape the local harness like a participant client

This section is a trusted local development harness. The file handoff and .with_client_input(...) call below expose the fixture plaintext to the local harness process. They prove program behavior; they are not a production privacy architecture and must not be moved into an application backend. For client-owned private input in a deployed app, separate these roles:
The application control plane must not receive the private request field. The participant-owned client obtains public session and client-slot configuration, then connects to the MPC deployment directly. If the participant runtime cannot perform direct client submission, stop at that capability gap or use an explicitly participant-controlled sidecar; do not silently add a plaintext backend gateway. For this tutorial, keep everything on your development machine but split the participant client from the trusted local MPC harness:
Create src/lib.rs:
Create src/app.rs for the ordinary application types:
Create src/bin/local_mpc.rs. This is the trusted local development harness: it loads the bytecode built from src/main.stfl, waits for fixture requests, sees the local fixture plaintext, and runs each score through local MPC. It must not be used as an application backend. Stop it with Ctrl-C when you are done.
Create src/client.rs. This file represents participant-owned client code: it accepts its owner’s request, sends the private score to the trusted local MPC harness, then combines the returned score with ordinary client-side fields. Do not expose EligibilityRequest.private_score as an application-service request schema.
Create src/bin/eligibility_client.rs as a command-line entry point for the client-handling code:
Run the local MPC owner in one terminal:
Then run the client handler from another terminal:
The important local separation is that participant client handling lives in its own module and the Stoffel program owns the private computation. In this tutorial, main.rs starts local MPC nodes and sees fixture plaintext on the same development machine. In a deployed setup, the participant-owned client would load pinned bindings and public deployment config, then submit directly to the separately deployed network. A separate application control plane may manage public metadata, session lifecycle, non-sensitive receipts, and authorized opened aggregates, but it must remain outside the plaintext path.
Want to deploy MPC apps instead of running local development networks? Sign up for Stoffel updates to hear when we launch the platform for deploying MPC apps.

Design notes

  • Identify which input is secret-shared, which policy logic is public, and which computed result should be reconstructed.
  • Keep sensitive values as Share values while computing.
  • Use open() only for outputs you intentionally reveal.
  • For client-directed share outputs beyond this tutorial, prefer MpcOutput.send_to_client or Share.send_to_client.
  • Use stoffel check --print-ir, stoffel run --program-info, and bytecode disassembly when debugging.

Next steps