We welcome contributions to this project! Please follow these guidelines when contributing:
- Fork the repository and create a new branch for your changes
- Make your changes and ensure all tests pass
- Submit a pull request with a clear description of your changes
- All pull requests will be reviewed before merging
-
All commits must be signed with your SSH/GPG key
-
Configure Git to sign commits automatically:
git config --global user.signingkey <SSH signing key path/your-gpg-key-id> git config --global commit.gpgsign true
-
Verify your commits are signed with
git log --show-signature
- Follow the existing code style and conventions
- Include appropriate tests for new functionality
- Update documentation as needed
We use pre-commit hooks to ensure our changes adhere to the project's standards. Please set up pre-commit hooks by running:
./scripts/setup-pre-commit.sh
pre-commit run --all-filesNew releases are created automagically by Release Drafter GH action.
Type of release bump is made of commits (tags feat/bugfix/etc...).
Release is created as draft, so you have to edit it manually and change it to final.
After release creation the build image is starting with tag with release number.
- GPU-based node implementation (the
iris-mpc-gpubinary) iniris-mpc-bins/bin/iris-mpc/server.rs - CPU (HNSW) implementation (the
iris-mpc-hawkbinary) iniris-mpc-bins/bin/iris-mpc/server/iris_mpc_hawk.rs - Example client in
iris-mpc-bins/bin/iris-mpc/client/client.rs
The architecture of both the GPU and CPU client implementations is based on the "semi-honest, honest majority" assumptions for the three participating parties. This means that the protocol is meant to be secure under the assumptions that:
- All parties run their client code and configurations faithfully ("semi-honest")
- At most one party out of the three may act adversarially to attempt to degrade the security properties of the system, i.e. in a three-party system, there is no collusion between multiple parties ("honest majority")
This security model forms the baseline of the implementation, and any attacks or exploits which can succeed under these fairly strong assumptions should be considered meaningful vulnurabilities. Attacks or exploits which require weakening of these assumptions to be viable are not considered critical. However, the codebase does incorporate some mechanisms targeting "defense in depth", providing redundant protections or limited protections under weaker adversarial assumptions, so reports of such attacks are welcome and may be acted on if the costs of mitigation to performance and codebase complexity are acceptable.
keys.json lists the participating organizations and their public key locations. Entries are grouped under iris.parties, which must contain exactly one entry for each of fau, berkeley-university, and kaist-university. Array order is unrestricted; empty, missing, duplicate, and unknown parties are rejected.
| Field | Type | Description |
|---|---|---|
slu |
String | Exactly one of fau, berkeley-university, or kaist-university. |
pub |
String or array of strings | URL of the party’s public key, or multiple URLs providing mirrors of the same key. |
chk |
String | Expected checksum as sha256:<64 hex digits> or sha512:<128 hex digits>. Hex digits are case-insensitive. |
Every URL in pub must serve the same public key bytes, and URL arrays must be nonempty. Consumers should verify the downloaded key against chk before using it. Checksums cover the entire downloaded file without normalization. After checksum verification, CI requires canonical standard base64 encoding of exactly 32 bytes, matching Oxide's decoder. Whitespace (including a trailing newline), missing or excess padding, URL-safe base64 characters, and nonzero unused padding bits are rejected. URLs must use HTTP or HTTPS, have a host, and contain neither credentials nor fragments (#...).
For example, a FAU party entry has this shape:
{
"slu": "fau",
"pub": [
"https://pki-smpc.worldcoin.org/public-key-0"
],
"chk": "sha256:613696db7be07adb5ccb06d50b12a3cb96914346d6f3a050669844c89542b372"
}The Check public key checksums GitHub workflow reports a Validate public key registry check for every pull request and push to main. It runs the validator tests and key validation when changes touch keys.json, certs/**, scripts/check-key-checksums.py, scripts/tests/test_check_key_checksums.py, or .github/workflows/check-key-checksums.yaml. Unrelated changes pass without downloading keys. If the previous commit is unavailable, validation runs conservatively. This internal change detection allows the check to be required without leaving unrelated PRs waiting on a workflow skipped by path filters.
Validation checks every URL, including every mirror, and fails on malformed entries or keys, unsupported algorithms, missing files, download errors, or checksum mismatches. Downloads have a 30-second timeout and all keys have a 1 MiB size limit. A mirror outage fails CI even if another mirror works. Oxide intentionally fails closed on invalid published manifests, so this gate must catch incompatible registry changes before merge. Repository administrators must separately make Validate public key registry a required status check to enforce that gate; adding the workflow alone does not enforce it.
For keys stored in this repository, use a URL such as https://raw.githubusercontent.com/worldcoin/iris-mpc/refs/heads/main/certs/party.pub. CI verifies these URLs against the corresponding file in its checkout, so a PR can add or update both the key and its checksum before the key is available on main. The shorter /worldcoin/iris-mpc/main/certs/party.pub form also works. Missing checkout files fail validation without falling back to the published version. URLs for other repositories or refs, and external mirrors, are downloaded normally. This checks the proposed repository contents; it does not check availability of the raw GitHub URL. Changes to certificate files alone also trigger validation, so update their checksums in keys.json in the same change.
Only SHA-256 and SHA-512 are supported.
Repository-hosted key paths must not contain symlinks, including in parent directories, because GitHub raw URLs do not serve the dereferenced checkout contents.
Raw GitHub hostname matching is case-insensitive and accepts an explicit default port (:443 for HTTPS or :80 for HTTP). When checkout validation is enabled, raw GitHub URLs with credentials or non-default ports are rejected.
Run the same validation locally with python3 scripts/check-key-checksums.py keys.json. To generate a checksum, run sha256sum key.pub or sha512sum key.pub (on macOS, shasum -a 256 key.pub or shasum -a 512 key.pub). Prefix the resulting hex digest with sha256: or sha512:.
To also validate repository-hosted keys against your local checkout, run python3 scripts/check-key-checksums.py keys.json --repository worldcoin/iris-mpc --repo-root ..
NCCL_P2P_DIRECT_DISABLE=1 NCCL_NET=Socket cargo test --release e2e
# run with compute sanitizer (a bit of preprocessing to get the test binary name)
cargo test --release e2e --no-run 2>&1 | grep "Executable tests/e2e.rs" | sed "s/.*(\(.*\))/\1/" | NCCL_P2P_DIRECT_DISABLE=1 NCCL_NET=Socket xargs compute-sanitizer --tool=memcheck
AWS_REGION=eu-north-1 AWS_ACCESS_KEY_ID=xxx AWS_SECRET_ACCESS_KEY=xxx cargo run --release -p iris-mpc-bins --features gpu-reference --bin iris-mpc-gpu
AWS_REGION=eu-north-1 AWS_ACCESS_KEY_ID=xxx AWS_SECRET_ACCESS_KEY=xxx cargo run --release -p iris-mpc-bins --features gpu-reference --bin iris-mpc-gpu -- --party-id {0,1,2} --queue https://sqs.eu-north-1.amazonaws.com/xxx/mpc1.fifo
AWS_ACCESS_KEY_ID=xxx AWS_SECRET_ACCESS_KEY=xxx cargo run --release -p iris-mpc-bins --bin client -- --topic-arn arn:aws:sns:eu-north-1:xxx:mpc.fifo
Please note that this mechanism does not apply to the client part.
Application can be completely configured via environment variables. To see the list of variables please check out contents of the .env* files.
Important!
Please note that there is a dist file per an instance of MPC node. Before running, please make sure to rename the correct dist file to .env.
For now the environment variables are read in via a dotenvy crate for the ease of development.
Not to force developers into a change of approach to work that has been established, overloading the environment variables with CLI arguments is also possible.
List of possible overrides is represented by the following struct:
pub struct Opt {
#[structopt(long)]
requests_queue_url: Option<String>,
#[structopt(long)]
results_topic_arn: Option<String>,
#[structopt(long)]
party_id: Option<usize>,
#[structopt(long)]
bootstrap_url: Option<String>,
#[structopt(long)]
path: Option<String>,
}Please note that due to ambiguity, all the arguments need to be provided using their full names.
Requires a NVIDIA graphics card with recent drivers and CUDA libraries.
The following dependency versions have been confirmed to work:
- nvidia-x11-550.78-6.9.6
- cuda_nvrtc-12.2.140
- libcublas-12.2.5.6
Some Linux distributions have a (lib)cuda package 12.2 which depends on earlier versions of these packages. It might not work.
If you're running with libraries in non-standard paths you'll likely want to setup direnv to automatically load the env vars for configuration.
Then copy .envrc.example to .envrc and setup $PRE_CARGO_LD_LIBRARY_PATH env var to point to your installation of the cuda toolkit libs.
The example file contains a sample WSL env var.
SMPC__REQUESTS_QUEUE_REGION overrides the matching service's input SQS region.
SMPC__RESULTS_TOPIC_REGION overrides the result SNS region for both the matching
service and iris-mpc-anon-stats-server. Both are optional and fall back to the
shared AWS region (SMPC__AWS__REGION). Other clients, including S3 result
payload offloading, keep their existing region configuration.
direnvinstalled on your machine- Run
direnv allowin the root of the project. This will enable you to load all required env variables from the .test.env and .envrc files
Step 1: run ancillary services
docker-compose -f docker-compose.dev.yaml up
Step 2: run service with the init script for Party 0
./scripts/run-server.sh 0 --init-servers # change to 1 or 2 for other parties
The script must run with --init-servers flag at least once. It will create some AWS resources, but after that it can run without it.
./scripts/run-server.sh 1
./scripts/run-server.sh 2 # in a separate shell
The files docker-compose.genesis-db.yaml and docker-compose.hawk-db.yaml use a persistent volume. The user still has to populate the database before use. This is accomplished with the init-test-dbs executable.
For genesis, Dockerfile.postgres is provided, which includes a start-up script to clear the CPU databases on each run. No such functionality is provided for hawk - the database and graph are not reset between runs.
Just run
docker build -f Dockerfile.dev.hawk -t hawk-server-local-build:latest .
docker-compose -f docker-compose.test.yaml upIt will bring up the 3 parties plus all the needed AWS/DB resources
In either option you can send batches of requests to the SNS topics that will then be forwarded to the SQS
queues from which the servers can read. This can be done with the client binary. We provide a bash script to
simplify its invocation:
./scripts/run-client.shThis will send a batch of requests to the SNS topic. You can also run the client by itself with the --help flag to see all the available options.
Check out also the client.rs file for more details.
cargo run -p iris-mpc-bins --bin client -- \
--request-topic-arn arn:aws:sns:us-east-1:000000000000:iris-mpc-input.fifo \
--requests-bucket-name wf-smpcv2-dev-sns-requests \
--public-key-base-url "http://localhost:4566/wf-dev-public-keys" \
--region us-east-1 \
--response-queue-url http://sqs.us-east-1.localhost.localstack.cloud:4566/000000000000/iris-mpc-results-us-east-1.fifo \
--data-from-file signup_sequence_shares_optin_both_sides.json \
--populate-file-data-limit 0- 0 is to use all data in file otherwise one can specify a limit
This will send a batch of requests to the SNS topic. You can also run the client by itself with the --help flag to see all the available options.
Check out also the client.rs file for more details.
cargo test --release -- --test-threads=1
cargo test --release --features db_dependent -- --test-threads=1 # require a runnning postgres instance
If you are using cargo test with non-standard library paths, you might need a workaround.
- Create the generated data (this will be generated to the
iris-mpc-bins/datafolder)
- note you can change the value of the benchmark data to generate less data (100 is required for local stack) in
iris-mpc-bins/resources/iris-mpc-cpu/construct_graph_ptxt_benchmark.toml
cd iris-mpc-bins && cargo run --bin construct-graph-ptxt -- --job-spec resources/iris-mpc-cpu/construct_graph_ptxt_benchmark.toml- Build the hawk genesis binary
docker build -f Dockerfile.genesis.dev.hawk -t hawk-server-genesis:latest .- Run the upgrade server
- note this also instantiates a shares database for Genesis to use (the default is 100). You can edit the value for this in
docker-compose.test.genesis.yaml - by default genesis runs with a max index of 100. This can be edited in
scripts/run-sever-docker.sh
docker-compose -f docker-compose.test.genesis.yaml upNote: This also instantiates iris shares db with shares
cargo run -p iris-mpc-bins --release --bin client -- \
--request-topic-arn arn:aws:sns:eu-north-1:767397716933:gpu-iris-mpc-input.fifo \
--request-topic-region eu-north-1 \
--response-queue-url https://sqs.eu-north-1.amazonaws.com/654654380399/temporal-results.fifo \
--response-queue-region eu-north-1 \
--requests-bucket-name wf-mpc-prod-smpcv2-sns-requests \
--public-key-base-url https://d2k2ck8dyw4s60.cloudfront.net \
--requests-bucket-region eu-north-1Unless otherwise specified, all code in this repository is dual-licensed under either:
- MIT License (LICENSE-MIT)
- Apache License, Version 2.0, with LLVM Exceptions (LICENSE-APACHE)
at your option. This means you may select the license you prefer to use.
Any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
