Most genomic studies begin by asking participants to upload one of the most identifying and irrevocable pieces of data they own, their DNA. I continue to investigate whether multi-party computation can offer a different model, one in which a study can produce useful results without anyone collecting the participants’ genomes in the first place.
That question has now led me to build a proof of concept with Stoffel MPC. One hundred simulated participants successfully computed aggregate allele counts without any party seeing the complete dataset. This post explains what I built, how it performed and what I learned.
Stoffel MPC has launched
Stoffel recently launched version 0.1.0 of its multi-party computation (MPC) platform with the ambitious goal of making privacy-preserving applications accessible to ordinary developers and not just to teams of cryptography boffins.
MPC lets several computers perform calculations on private data without any one of the computers receiving the complete inputs. Although MPC systems have traditionally been difficult to build with Stoffel presents the technology as an approachable developer platform. Applications are written in its Python-like StoffelLang, compiled to bytecode and executed by the Stoffel VM across a set of MPC parties.
We no longer have to rely on a more robust privacy policy or a more secure central database. We can simply avoid collecting the raw data in one place.
Naturally, I wanted to try it with Monadic DNA
Given my ongoing work on Monadic DNA, genomics was an obvious test case. In an earlier experiment, my colleagues and I used Nillion and real genotype data from thirty participants to explore private DNA analysis.
Genetic data is an unusually good test of a privacy system. It is highly identifying, can reveal information about relatives and cannot be changed after a breach. At the same time, many useful genomic studies do not need to inspect individual records. A researcher may only need cohort-level variant counts or a score calculated across the group.
The concrete use case I wanted to explore was a revamped Monadic DNA mobile app. A Monadic DNA user keeps their genotype data on their phone and may choose to participate in a study that needs aggregate statistics across many users (perhaps in return for a payment). The question was whether the app could contribute that data securely without first uploading the user’s complete genotype to Monadic DNA, the researcher or another trusted central service.
Instead of the conventional design where everyone’s genotype data is uploaded to a central service that must protect it, I wanted to see whether Stoffel could let each Monadic DNA app contribute directly to a joint calculation. In that design, no coordinator, application server or individual MPC party receives the complete dataset.
The source code for the experiment is available at github.com/vishakh/stoffel-test.
What the proof of concept is meant to do
The proof of concept simulates one hundred Monadic DNA mobile-app users joining a genomic aggregate study. Each user contributes six synthetic SNP values, which they could have obtained through Monadic DNA, 23andMe or another service. The study calculates the total count for each target allele and a simple weighted score across the cohort.
The important part is the trust boundary. Each simulated user has a separate client identity and a process containing only that user’s six values. The client creates shares locally and sends a different share directly to each MPC party. Only the aggregate counts and score are revealed.
This is deliberately different from putting all one hundred records into one server-side client. That would demonstrate private arithmetic inside the MPC network, but the client would remain a trusted data collector capable of seeing or leaking every genotype.
In the intended Monadic DNA flow, a user would review and consent to a study in the mobile app. The app would select only the DNA values required for that approved computation, create the shares on the phone and send them directly to the MPC parties. Complete DNA data should never pass through Monadic DNA’s servers or another central ingestion service; only the approved aggregate result should leave the MPC computation.
Comparing MPC and fully homomorphic encryption
Multi-party computation (MPC) and fully homomorphic encryption (FHE) both make it possible to calculate over data without exposing the underlying inputs, but they use different models. With FHE, each user typically encrypts their genotype under a public key and a server computes directly on the ciphertexts. With MPC, each user divides their input into shares and sends a different share to each of several computing parties.
The approaches place trust and operational complexity in different places. An FHE system needs a policy for who can decrypt the result. This may involve one key holder or a threshold key shared across several parties. MPC does not rely on one decryption key holder but it requires several sufficiently independent parties to communicate and remain available during the computation.
The performance characteristics also differ by workload and implementation. FHE supports non-interactive encrypted inputs and computation by a single service, although ciphertext operations can be computationally expensive. MPC introduces communication between parties, while simple aggregate arithmetic such as the sums in this experiment is a natural MPC workload. Neither approach is universally better for genomics. The appropriate choice depends on the computation, trust assumptions, deployment constraints and desired interaction model. This PoC explores the MPC option through Stoffel rather than attempting to establish a general advantage over FHE.
To learn more about using FHE for building consumer applications, see https://vishakh.blog/2025/08/06/lessons-from-using-fhe-to-build-a-secure-consumer-app/.
In August 2026, I will also be giving a talk about FHE at the HOPE 26 conference: https://schedule.hope.net/hope26/talks#Using-Fully-Homomorphic-Encryption-to-Build-Real-World-Software
Technical details
The local setup has three types of components:
- One hundred native client processes represent independent users or mobile devices. Each receives a unique, short-lived identity and only its own six synthetic SNP values.
- Four Stoffel MPC parties receive shares from every client and jointly execute the private computation.
- A coordinator authorizes the participants and handles discovery. It does not receive genotype values or perform the genomic calculation.
The coordinator and four MPC parties run in Docker. The clients run as independent native processes outside the Docker network and connect through exposed local addresses. This demonstrates that user-side clients do not inherently need to run alongside the MPC infrastructure.
The private computation is written in StoffelLang. Values marked secret remain shared while the program operates on them. The core aggregation function reads one private value from each user’s input slot and adds the values together:
The program repeats this for all six SNPs. It reveals only the cohort totals and then calculates the weighted cohort score. It never deliberately reveals an individual contribution.
The four parties use Stoffel’s HoneyBadger backend over the BLS12-381 scalar field. In developer terms, HoneyBadger is Stoffel’s general-purpose engine for private arithmetic. The configuration uses four parties and a threshold of one, satisfying HoneyBadger’s n >= 3t + 1 requirement and tolerating one faulty party under the protocol’s assumptions so one bad apple cannot ruin the basket of MPC nodes.
The runner provisions identities, compiles the program, starts the infrastructure and launches clients 50 milliseconds apart. It independently calculates the expected result for the deterministic synthetic fixture, checks the aggregate emitted by the MPC parties and records timing and memory usage. Everything is torn down after the run.
Findings
The one-hundred-user run completed successfully and produced the expected values:
| SNP target allele | Aggregate count |
| --- | --- |
| rs429358 C | 100 |
| rs7412 T | 101 |
| rs6265 A | 99 |
| rs1801133 T | 100 |
| rs4988235 T | 101 |
| rs12913832 G | 99 |
The weighted cohort score was 498, matching the result calculated independently from the fixture.
On my development PC, the benchmark measured:
- 28.26 seconds to start and prepare the infrastructure;
- 6.17 seconds to launch the clients and complete the MPC workload;
- 45.29 seconds for the complete run, including setup, verification and cleanup;
- approximately 1.29 GiB peak memory across the one hundred client processes; and
- approximately 62 MiB peak memory across the coordinator and four MPC containers.
Most of the elapsed time was infrastructure startup rather than the private calculation. This is a local proof of concept rather than a production benchmark but an end-to-end run in under a minute was encouraging.
Scaling from ten to one hundred clients also produced a useful infrastructure lesson. Every client connects to the coordinator and all four parties, creating roughly five hundred client-to-server connections. Launching all clients simultaneously caused intermittent TLS failures while clients waited for MPC input masks. The cryptographic computation was not the bottleneck; the issue was the initial burst of network connections.
Staggering client launches by just 50 milliseconds spread the handshake burst over about five seconds and produced a successful run. It was an encouragingly small adjustment, and a useful reminder that an MPC application is more than its cryptographic protocol. Identity provisioning, TLS handshakes, connection limits, retries, backoff and observability all matter as participation grows.
Developer experience
So does Stoffel make MPC-ing easy? The core developer experience was one of the most encouraging parts of the experiment. StoffelLang is small and readable, its secret types make the privacy boundary visible in the program, and writing the six private sums felt much closer to ordinary application development than to implementing a cryptographic protocol. The repository examples provided a useful path to getting a local coordinator and MPC parties running.
For a version 0.1.0 release, the documentation and examples gave me enough to move from a small example to a working 100-client experiment. The straightforward single-client path is explained clearly. This PoC went beyond that path, using many separately identified clients outside Docker and tuning input-mask capacity and output authorization, so some answers came from the examples and source code rather than a single guide. The code was readable enough to make that investigation productive.
The fact that the private computation was the easiest part is a good sign for Stoffel’s developer-platform goal. As the platform matures, end-to-end deployment guides, a configuration reference, troubleshooting documentation and supported client SDKs could make the same experience even smoother for developers who do not want to inspect implementation details.
The test also clarified the next steps from a successful PoC toward production:
- All four MPC parties ran on one PC. The protocol separated their data, but one machine is not four independent organizations. A production deployment needs parties operated by entities that are unlikely to collude. With this configuration, privacy assumes no more than one party is faulty or colluding. Happily, the Stoffel team provided me with a API key to their MPC cluster so I can test a near-production deployment soon.
- The inputs were deterministic and synthetic. The test harness knew them so it could verify the answer. In a real study, independently operated devices must generate shares locally.
- MPC protects the computation, not the safety of the result. Small cohorts, repeated queries or overlapping groups can reveal individual contributions by subtraction. Production still needs minimum cohort sizes, query controls, consent, auditing and a separate identity authorized to receive results.
- This repository does not yet provide a production-ready mobile SDK. The native Rust clients stand in for phones; packaging and auditing that logic for iOS and Android remains necessary. MPC using hundreds of mobile devices is still pretty niche so the lack of a mobile SDK is far from unreasonable.
- The successful launch staggering is appropriate for this PoC. Testing one thousand simultaneous clients would be the next scale milestone and would require higher RPC limits, robust retries, more memory and realistic infrastructure.
Conclusion
Stoffel made the private computation itself pleasantly straightforward. StoffelLang was expressive enough for the aggregate, the four-party network produced the correct result and one hundred independently identified clients completed the study on a single development machine.
The remaining questions sit around the computation, i.e. who operates the parties, how identities are issued, what happens when mobile clients disconnect and which aggregates are safe to reveal. Stoffel allowed the experiment to move the trust boundary away from a central genotype database and into explicit product and infrastructure decisions that can be designed and audited.
There is naturally more work between a version 0.1.0 PoC and a production deployment. The immediate next step is to run the program on a real cluster operated by the Stoffel team, moving beyond the single-machine local setup (coming soon!). Beyond that, useful steps include independently operated parties, audited mobile client code, resilient connection handling and larger load tests. Still, Stoffel successfully demonstrated the most important part: a credible path to genomic studies that do not begin by collecting everyone’s raw DNA in one database.
For an initial release and a local proof of concept, that is an impressive result. It leaves me cautiously optimistic about Stoffel and genuinely interested in building further with it as the platform develops.