CryptDough, aka CDough, is a Multi-Party Computation (MPC) framework built for secure mixed workload applications including Machine Learning inference, Relational queries, and timeseries analytics. Users can implement their target computation using declarative protocol-agnostic API. The framework is built for ease of use for non-MPC experts while enabling extensibility for cryptographers interested in implementing more MPC protocols or operators.
You can find the complete documentation here.
This work is to appear in SOSP2026 under title CryptDough: A unified analytics engine for secure multiparty computation.
To access the CryptDough Artifact Evaluation Guide for SOSP 2026, please go to sosp-replication
NOTICE: This is an academic proof-of-concept prototype, delivered as is without guarantees and is not meant for production use. Please, reach out to authors for more details.
- Dependencies
- Building CryptDough
- Running CryptDough
- Writing New CryptDough Programs
- Creating a Cluster
This repository is organized as follows:
bench/: MPC applications used for benchmarking primitives, operators, and different literature computations (Queries and models).doc/: Framework documentationexamples/: Example applicationsinclude/: Framework implementation including (i) core functionality of CryptDough (core/), including the implementation of the MPC primitives for the different protocols (core/protocols/), containers with data abstractions for the supported workloads (core/containers/), MPC operators (core/operators/), and party communication interfaces and implementation (core/communication/), as well as the framework backend (backend/).scripts/: Various scripts for testing and benchmarking CryptDoughtests/: the test suite
The project is written in C++ 20 and requires installation of (i) apt-available packages found in _setup_required.sh and (ii) open source projects on github such as {libOTe, Blaze, SecureJoin}.
You can install all dependencies on Ubuntu by running the following command:
mkdir build; cd build && ../scripts/setup/setup.sh
For non-Ubuntu systems (Mac, other *nix), you will need to install these packages yourself:
git cmake pkg-config build-essential manpages-dev gfortran wget libsqlite3-0 libsqlite3-dev libsodium23 libsodium-dev libopenmpi3 libopenmpi-dev openmpi-bin openmpi-common libopenblas-dev libblas-dev python3 python3-pip libtool autoconf automake
Note that: OpenMPI used for one of the communicator interface implementation. The other one called "nocopy" does not use it.
In addition to the following open source libraries:
- libOTe, used for secure Beaver triples (2PC).
- secure-join, used for a two-party oblivious pseudorandom function (OPRF) with secret-shared output.
- Blaze, used for Machine Learning operators, can be turned on (similarly off) using command
cmake -DUSE_BLAZE=ON ..
Note: the above dependencies may impose additional restrictions on the environment. For example, they may not support all Linux distributions that cdough's online phase supports.
Important
You should still run setup.sh even if you install the dependencies manually, because other libraries will be compiled and built manually. You can ignore errors from, e.g. apt not being installed.
CryptDough is a multi-party computation framework and requires installation on different nodes, where each node is a computing party. However, for testing purposes, we enable running computation from either a single-node or a cluster.
Please, review the following subsections for information for each mode. All instructions assume *nix systems.
When running an MPC computation in single-node mode, each computing party will be a different process in this node. This mode requires the typical dependencies setup (see above). Simply clone this repository then run the setup script as follows:
$ git clone https://github.com/CASP-Systems-BU/CryptDough
$ mkdir -p ./CryptDough/build
$ cd ./CryptDough/build
$ ../scripts/setup/setup.shIf you do not have apt (other Linux, macOS, etc.) you will need to install the
dependencies manually (see above).
If you want to use CryptDough where each computing party runs as a process on a separate node, you need to establish connection among the computing nodes then choose an arbitrary node to be node0. This node0 should have ssh-access to the other nodes. We will use this node in this setup to compile the MPC program, distribute it to other computing parties, and coordinate the computation. We provide instructions on how you can do so using different cloud service providers below.
Warning
Having SSH access into all other nodes, of course, compromises the non-collusion assumption of multi-party computation. We require SSH access here for ease of development and testing. However, in a real system, cdough nodes would need to be configured out-of-band. We do not currently support this setup.
Connections between parties do not use TLS for MPC. SSH is only used for setup.
Make sure that the repo is cloned on node0 then:
- First, we run
scripts/_update_hostfile.shto write to/etc/hosts/so that we can refer to the servers asnode0,node1, etc. - Second, we run the deployment script
./scripts/orchestration/deploy.shwith the location of the repository and the names of the servers. The following example assumes a four-party setup, although we can achieve a setup with fewer parties by simply not entering the corresponding IP address(es) and name(s). Replace<ip-X>with the IP address ofnodeX.
$ git clone https://github.com/CASP-Systems-BU/CryptDough
$ cd CryptDough
$ ./scripts/setup/_update_hostfile.sh -x node -i <ip-0>,<ip-1>,<ip-2>,<ip-3>
$ ./scripts/orchestration/deploy.sh ~/CryptDough node0 node1 node2 node3deploy.sh runs setup.sh, so we do not need to run setup.sh explicitly. If you are on a machine without apt, you will need to install dependencies manually on all machines, as specified above.
This section describes the process to compile and run programs. To run programs, you must be in the build directory. You can follow the standard cmake patterns for compiling cdough programs, and we provide commands for running programs in a local or distributed fashion. Compilation is the same in either case.
Assuming all dependencies are installed correctly, the following example compiles a single program, TPCH Q1, in the replicated three-party protocol (the default).
$ mkdir build
$ cd build
$ cmake .. -DPROTOCOL=3
$ make q1Various options can be specified to cmake.
-DPROTOCOL=Nto change the protocol. We currently support-DPROTOCOL=1a single-party plaintext test protocol-DPROTOCOL=2ABY two party dishonest majority protocol with Beaver Triples-DPROTOCOL=3Araki et al. three party replicated honest majority protocol (the default)-DPROTOCOL=4Fantastic Four honest-majority malicious 4PC protocol-DPROTOCOL=5SPDZ2k dishonest-majority malicious protocol with arbitrary number of parties. We currently support the online phase only.
-DNO_X86_SSE=1to disable x86 hardware optimizations (you will get warnings otherwise if built on ARM platforms, like newer Macs)-DPROFILE=1enable profiling (compile with-pg)-DEXTRA=XXXpass the additional argumentXXXtomake-DCOMM=XXXenable the given communicator. Options are"MPI" "NOCOPY". If you do not specify anything, CMake will useNOCOPY.-DTRIPLES=XXXspecify the kind of Beaver triples to use for 2PC (ZERO(all zeros, for profiling the online phase),DUMMY(insecurely generated, fast), orREAL(secure)).
We provide some cmake shortcuts to make compiling multiple executables easier.
# compile everything
$ make -j
# compile tests
$ make -j tests-only
# compile all tpch queries
$ make -j tpch-queries
# compile queries for the secretflow comparison
$ make -j secretflow-queries
# compile all other queries
$ make -j other-queriesSee debug/cdough_debug.h and CMakeLists.txt for more information on compile options. Not all compile options are made available via CMake and instead must be manually configured within cdough_debug.h.
We provide an execution harness script, run_experiment.py, which automates the compilation and execution process. This is the recommended method of running cdough programs.
To see a comprehensive set of options for the run_experiment script, simply run it with -h to display a help message:
$ ../scripts/run_experiment.py -hKey options include:
-pProtocol (1-5); default: 3-npcNumber of parties; default: protocol number or 2 for SPDZ2k-sSetting (same/lan/wan); default: same-cCommunicator (mpi/nocopy); default: mpi for same, nocopy otherwise-nNumber of communicator threads (NoCopyComm only); default: -1-rNumber of rows (comma-separated INT or a^b expressions); default: 2^20-dUse powers of 10 for -r flag (allows ranges like 6-8 to expand to [10^6, 10^7, 10^8])-fScale factor for TPC-H queries (overrides -r if set)-tNumber of threads as powers of 2 (MIN or MIN-MAX)-TNumber of threads (arbitrary); default: 0-bBatch size; default: -12-eNumber of repetitions; default: 1-oOptimization level (0-3); default: 2-yType of Beaver triples for 2PC (zero/dummy/real); default: zero-mAdditional cmake arguments (can be repeated)-aAdditional experiment arguments (can be repeated)-xPrefix for remote nodes; default: node
For testing and development, you may want to run cdough programs locally. In this setting, separate processes act as each node of the multi-party computation.
A minimal test:
$ cd build
$ ../scripts/run_experiment.py test_primitives
# ... everything should pass ...This command will run the program test_primitives.cpp with all default options:
- Replicated 3PC
sameenvironment- MPI communicator
- 1 thread
- etc.
Tip
We recommend always using mpi for local (-s same) tests. The no-copy communicator performs poorly over the loopback interface.
We can try a different program:
$ ../scripts/run_experiment.py micro_primitives
# ...
Vector 1048576 x 32b
[=SW] Start
[ SW] Reserve MUL 1.625e-06 sec
[ SW] Reserve AND 4.25e-06 sec
[ SW] AND 0.01723 sec
[ SW] MULT 0.01167 sec
[ SW] EQ 0.04605 sec
[ SW] GR 0.07226 sec
[ SW] RCA 0.1298 sec
[ SW] RCA< 0.05846 sec
[ SW] Dot Product 0.008903 secMore rows (
$ ../scripts/run_experiment.py -r 2^24 micro_primitives
# ...
Vector 16777216 x 32b
[=SW] Start
[ SW] Reserve MUL 9.59e-07 sec
[ SW] Reserve AND 3.541e-06 sec
[ SW] AND 0.1686 sec
[ SW] MULT 0.1992 sec
[ SW] EQ 1.14 sec
[ SW] GR 1.499 sec
[ SW] RCA 1.913 sec
[ SW] RCA< 0.8353 sec
[ SW] Dot Product 0.1913 secA different protocol (Malicious-secure Fantastic 4PC):
$ ../scripts/run_experiment.py -r 2^24 -p 4 micro_primitives
# ...
Vector 16777216 x 32b
[=SW] Start
[ SW] Reserve MUL 1.167e-06 sec
[ SW] Reserve AND 3.958e-06 sec
[ SW] AND 1.126 sec
[ SW] MULT 1.109 sec
[ SW] EQ 6.42 sec
[ SW] GR 8.01 sec
[ SW] RCA 4.401 sec
[ SW] RCA< 2.709 sec
[ SW] Dot Product 1.449 secOr more threads:
$ ../scripts/run_experiment.py -r 2^24 -p 4 -T 4 micro_primitives
# ...
Vector 16777216 x 32b
[=SW] Start
[ SW] Reserve MUL 1.421e-05 sec
[ SW] Reserve AND 3.875e-06 sec
[ SW] AND 0.7819 sec
[ SW] MULT 0.5872 sec
[ SW] EQ 3.194 sec
[ SW] GR 4.201 sec
[ SW] RCA 2.858 sec
[ SW] RCA< 2.194 sec
[ SW] Dot Product 0.8624 secYou should not expect much of a speedup with more threads when running locally: this is the number of worker threads per party. There is also a main thread per party. In the above example, therefore, we have 4 parties, each with
CryptDough programs can be run over LAN just by changing the setting (-s) argument to run_experiment.py:
$ ../scripts/run_experiment.py -s lan -c nocopy -n 4 -T 8 micro_sorting
This runs the micro_sorting experiment, with the 3PC protocol (the default), on nodes node0, node1, and node2. We use the nocopy communicator with 4 communication threads and 8 worker threads. run_experiment.py takes care of configuring the other nodes, and copies the compiled binary from node0 to all other nodes in the cluster.
Warning
cdough programs will crash in mysterious ways if different versions of a binary are present on different hosts.
Tip
We recommend using -c nocopy for LAN tests. We have found -n 4 (4 communication threads) sufficient for the LAN environment.
If your machines are named something else, you can specify a new prefix with -x [node]. However, our scripts assume a consistent numbering:
$ ../scripts/run_experiment.py -s lan -p 4 -x lab-server- test_primitivesThis will run test_primitives, with the 4PC protocol, on nodes lab-server-0,lab-server-1, lab-server-2, and lab-server-3.
To check the scaling behavior of cdough, we can use the variable-thread (-t) argument. This example will run micro_sorting in LAN, with the 3PC protocol, using 1, 2, 4, 8, 16, 32 worker threads.
$ ../scripts/run_experiment.py -s lan -c nocopy -n 4 -t 0-5 micro_sortingCryptDough demonstrates practical performance over the internet (WAN). However, it is tricky to deploy a geodistributed WAN cluster. We provide a way to apply artifical delay and bandwidth throttling, uses the Linux tc qdisc. If your cluster machines are physically in LAN setup, you can use this very easy to use WAN simulator as follows:
# Assuming pwd = ./build
# Turn on simWAN for node0 (implied), node1, node2, and node3
$ ../scripts/comm/cluster-wan-sim.sh on node{1,2,3}
# Run your experiment
# [Soon, run_experiment will handle running cluster-wan-sim for you]
$ ../scripts/run_experiment.py -s wan ...
# Disable simWAN
$ ../scripts/comm/cluster-wan-sim.sh off node{1,2,3}This simple script makes some assumptions about the network topology (e.g., that all nodes are routable over the same interface), so modifications may be required for more complex deployments.
cluster-wan-sim also runs ping just as a sanity check:
# from node0
$ ping -q -c 3 node1
# ...
rtt min/avg/max/mdev = 0.177/0.235/0.270/0.041 ms
$ ./scripts/cluster-wan-sim.sh on node{1,2,3}
# ...
Enabling WAN on bond0@ 6Gbit, 10ms
# ...
# Latency has increased:
rtt min/avg/max/mdev = 20.321/20.394/20.446/0.053 ms
# ...
$ ./scripts/cluster-wan-sim.sh off node{1,2,3}
# ...
# Back to normal:
rtt min/avg/max/mdev = 0.150/0.200/0.258/0.044 msYou can use iperf to check the bandwidth limiter.
Tests can be compiled and run like any other program. Tests can be run in LAN, but this just slows things down without exercising much functionality, so we recommend running tests locally. We provide a script to automate running the entire test suite.
The syntax is:
../scripts/testing/run_multithread_test.sh [protocol=3] [threads=1]
For example:
# Run the test suite under 3PC with 1 thread...
$ ../scripts/testing/run_multithread_test.sh
# 4PC and 2 threads...
$ ../scripts/testing/run_multithread_test.sh 4 2
# 2PC and 1 thread
$ ../scripts/testing/run_multithread_test.sh 2Queries (/bench/queries) can be run in the same way as other programs, but we also provide a test harness to run an entire suite of queries.
$ ../scripts/query-experiments.sh
Usage: ../scripts/query-experiments.sh <tpch|other|secretflow> <sf> <protocol> <threads> <enviro=lan> <query_range=1..22>The first argument specifies the suite of queries:
tpch: run all tpch queries. Optionally, specify a range of queries as the final argument in Bash syntax:- Comma separated values:
1,2,9,14will run TPC-H queries 1, 2, 9, and 14. - Ranges:
8..20will run TPC-H queries 8 through 20, inclusive. - The two syntaxes cannot currently be mixed.
- Comma separated values:
other: run the other 9 queries from the cdough papersecretflow: run the SecretFlow queries
The next argument, sf refers to Scale Factor. For TPC-H, this is a well-defined term in the specification. For other queries, we define SF1 to be approximately the same size, on average; that is, about 5M rows.
enviro is as in run_experiment.py: it may be lan, wan, or same (local).
See the examples for some simple programs that showcase the main features of the framework. Example 0 contains a minimal C++ file you can use to get started with your own programs.
CMakeLists.txt only looks in certain directories for C++ sources. New programs should be placed into the examples/, bench/, or tests/ directories. Alternatively, modify CMakeLists.txt to look for your sources.
We provide instructions for launching a cluster both on AWS and on CloudLab. For AWS, we provide a cluster launching script, and for CloudLab, we provide simple step-by-step instructions. Of course, other types of clusters will work, but we do not provide an automated process for creating them.
To deploy an AWS cluster, you will need an AWS access key and secret key. This is often already stored inside ~/.aws/credentials, in which case no action is needed. If it is not (or if you do not wish to create such a file), enter your access key and secret key into scripts/orchestration/aws/secrets.sh and run the following command before proceeding.
$ source scripts/orchestration/aws/secrets.shTo create the cluster, run the following command.
$ ./scripts/orchestration/aws/deploy-aws-cluster.sh <cluster-name> <number-of-nodes>You will now have access to a cluster with your specified number of nodes. To setup the repository, follow the instructions in the section about building cdough.
From the main page in CloudLab, execute the following operations.
click the 'Experiments' dropdown in the upper left and select 'Start Experiment'
click 'Next'
enter your desired number of nodes (2, 3, or 4)
select either Ubuntu 22 or Ubuntu 24 as your operating system
select any Intel-based server type
click 'Next'
give the cluster an arbitrary name
use the default node names (node0, node1, ...)
click 'Next'
click 'Finish'
When the cluster has been successfully created, you can SSH into node0 and follow the instructions in the section about building cdough. Note that on CloudLab, you do not need to run the _update_hostfile.sh script, as CloudLab has already configured the servers to recognize each other as node0, node1, and so on.