Welcome to the Coinbase Open Source MPC Library. This repository provides the essential cryptographic protocols that can be utilized to secure asset keys in a decentralized manner using MPC (secure multiparty computation / threshold signing) for blockchain networks.
This cryptographic library is based on the MPC library used at Coinbase to protect cryptoassets, with modifications to make it suitable for public use. The library is designed as a general-purpose cryptographic library for securing cryptoasset keys, allowing developers to build their own applications. Coinbase has invested significantly in building a secure MPC library, and it is our hope that this library will help those interested in deploying MPC to do so easily and securely.
cb-mpc is a native cryptographic library for MPC protocols. It gives application developers the building blocks needed to generate and refresh keyshares, derive supported keys, produce MPC signatures, and support key-backup workflows via publicly verifiable encryption (PVE).
cb-mpc does:
cb-mpc does not:
If you build on the lower-level full API (including internal and low-level functionality), more validation and protocol-composition responsibility shifts to the integrating application. See High-level Public API vs the Full API and Supported Runtime and Deployment Environments for more detail.
The code in this open source library is derived from the code used at Coinbase, with significant changes in order to make it a general-purpose library. In particular, Coinbase applies these protocols with very specific flows as needed in our relevant applications, whereas this code is designed to enable general-purpose use and therefore supports arbitrary flows. In some cases, this generality impacts efficiency, in order to ensure safe default usage.
In addition to releasing the source code for our library, we have published the underlying theoretical work along with detailed specifications. This is a crucial step because merely implementing a theoretical paper can overlook significant errors. At Coinbase, we adhere to the following development process:
The theory documents and specifications are a considerable contribution within themselves, as a resource for cryptographers and practitioners.
Although this library is designed for general use, we have included examples showcasing common applications:
The library comes with various tests and checks to increase the confidence in the code including:
make dudectmake testmake benchmake lintThe cb-mpc library contains two levels of APIs, a public one that contains the API for calling high-level MPC protocols like DKG, threshold signing and publicly-verifiable encryption for backup. These APIs are simple to use, and are recommended for those wishing to use the cb-mpc protocols as is. The second level contains the full cb-mpc API and includes all mid and low-level functions as well. These APIs are intended for users wishing to modify protocols or implement other protocols using the cb-mpc infrastructure. We stress that all functions in the public API are safe, including validation of all externally received inputs. In contrast, not all lower-level APIs include all such validations. For example, an elliptic curve point received from another party in a protocol needs to be validated once and not every time it is used. In addition, some zero-knowledge proofs may depend on other zero-knowledge proofs already being validated. This is taken care of in the public API, but the user is responsible for ensuring all of this when using the lower-level full API. Note that the Coinbase HackerOne bug bounty requires finding a bug in the public API for it to be consider Medium or above. See BUG_BOUNTY.md for details.
docs: the pdf files that define the detailed cryptographic specification and theoretical documentation (you need to enable git-lfs to get them)include: public headers (installed in both public and full install modes)
include/cbmpc/api/ (coinbase::api)include/cbmpc/c_api/ (cbmpc_*)include-internal: internal headers (installed only in full mode), included as <cbmpc/internal/...>src: C++ implementation sourcesdemo-cpp: a collection of examples of common use cases in c++scripts: a collection of scripts used by the Makefiletools/benchmark: a collection of benchmarks for the librarytests/{dudect,integration,unit}: a collection of tests for the libraryThis repository provides a native C++ cryptographic library. It is intended to be embedded into backend services, native applications, and other environments where the calling application can control process isolation, network transport, and secret storage.
The environments that we support are:
x86_64 and Apple Silicon) and 64-bit LinuxBoth native macOS development and the provided Linux Docker environment are intended to be ways to build and test the library. GitHub workflows currently run on Linux using the Docker image.
This library is not a hosted service and does not provide a production networking stack, deployment framework, key-management system, or transport security layer. In production deployments, the integrating application is responsible for:
The library is intended for native environments where the integrating application can enforce those controls. In an MPC deployment, that may mean all parties run in backend services or that some parties run in native client applications on supported platforms. Other targets, including 32-bit systems, browsers, WebAssembly, Windows, and mobile platforms, are not supported.
cb-mpc implements MPC key-generation (dkg and local generation), refresh, derivation, and signing protocols. It does not provide a custody service, policy engine, or application workflow around those protocols.
In the public API, calls like dkg* and refresh* return opaque key_blob / keyset_blob values with each party's share to each party. Those blobs are later passed back into sign*, refresh*, derive*, and related APIs. This means the integrating application owns the lifecycle of those blobs and must treat them as secret key material.
The integrating application is responsible for:
A few practical tips:
key_blob / keyset_blob and no protected backup exists, recovery may depend on the protocol and access structure; do not assume cb-mpc can recreate that party-local secret material for you.detach_private_scalar, get_public_share_compressed, and attach_private_scalar helpers for application-managed backup and restore flows, including verifiable backup schemes such as publicly verifiable encryption (PVE). Follow each protocol's API guidance for the detached output: in particular, an ECDSA-2P P1 scalar-detached blob retains sensitive Paillier material and must be protected like the full key blob.
PVE scalar verification alone does not establish complete P1 recoverability; see
ECDSA-2P P1 backup limitations.refresh* APIs when you want fresh shares for the same (combined) key; if your operational policy requires replacing the key entirely, run a new dkg* flow and migrate in the application layer.The library is responsible for:
For transport, opaque blob handling, session identifiers, and other operational security requirements, see SECURE_USAGE.md.
After cloning the repo, you need to update the submodules with the following command.
git submodule update --init --recursive
Furthermore, to obtain the documentations (in pdf form), you need to enable git-lfs
There are three build modes available:
The library depends on a custom build of OpenSSL 3.6.4 with specific modifications (see External Dependencies). You must build this custom version before compiling the library.
Quick Start:
# Automatic detection of your platform
make openssl
# Or use platform-specific targets:
make openssl-linux # for Linux
make openssl-macos # for x86_64
make openssl-macos-m1 # for ARM64 (Apple Silicon)
Manual Build:
scripts/openssl/build-static-openssl-linux.sh # for Linux
# or
scripts/openssl/build-static-openssl-macos.sh # for x86_64
# or
scripts/openssl/build-static-openssl-macos-m1.sh # for ARM64
Note: These scripts install OpenSSL to /usr/local/opt/[email protected] and may require sudo permission.
Custom Install Location:
If you prefer a different installation path, you can set the CBMPC_OPENSSL_ROOT variable:
# Option 1: Environment variable (before building OpenSSL)
CBMPC_OPENSSL_ROOT=/your/custom/path make openssl
# Option 2: Environment variable (before running cmake)
export CBMPC_OPENSSL_ROOT=/your/custom/path
# Option 3: CMake variable
cmake -DCBMPC_OPENSSL_ROOT=/your/custom/path ...
This project requires a C++17 compliant compiler. We strongly recommend using Clang version 20 or newer. This recommendation is based on our testing, including verification of constant-time properties, which is primarily performed using Clang v20. While we strive for consistent behavior, achieving constant-time properties can be influenced by various factors beyond the compiler, such as hardware and operating system. Consequently, the behavior of the project, including its constant-time characteristics, when compiled with other compilers is not guaranteed to be identical.
apt, yum).brew install llvmexport CC=... CXX=... before running CMake in a clean build directory.Build the library by running
make build
To test the library, run
make test
Running demos and benchmarks:
build/install/ (no sudo).
include/): make install (installs to build/install/public)include-internal/): make install-full (installs to build/install/full)make demo (or make demos)make bench (auto-runs the full install)Notes:
make demo takes care of building + installing the right variants (public vs full) before running each demo.By default the cb-mpc library only installs the public API. To install the full APIs run the following command:
scripts/install.sh --mode full
You can install to a custom prefix:
scripts/install.sh --mode public --prefix /path/to/prefix
# or:
CBMPC_PREFIX=/path/to/prefix scripts/install.sh --mode full
For the Makefile helpers, you can override the default repo-local layout:
# Install under a custom root (creates <root>/{public,full})
make install-all CBMPC_INSTALL_ROOT=/path/to/prefix
# Or override each prefix independently
make install CBMPC_PREFIX_PUBLIC=/path/to/public/prefix
make install-full CBMPC_PREFIX_FULL=/path/to/full/prefix
Our benchmark results can be found at https://coinbase.github.io/cb-mpc
Finally, to clean up, run
make clean
make clean-demos
To use clang-format to lint, we use the clang-format version 14.
Install it with
brew install llvm@14
brew link --force --overwrite llvm@14
then make lint will format all .cpp and .h files in src and tests
We have a Dockerfile that already contains steps for building the proper OpenSSL files. Therefore, the first step is to create the image
make image
You can run the rest of the make commands by invoking them inside docker.
For example, for a one-off testing, you can run
docker run -it --rm -v $(pwd):/code -t cb-mpc bash -c 'make test'
Please note that all cryptographic code has a specification (except for code like wrappers around OpenSSL and the like), but there are some protocol specifications that are not implemented but still appear in the specifications since they may be useful for some application developers.
| Name | Spec | Theory | Code |
| Basic Primitives | spec | theory | code folder |
| Zero-Knowledge Proofs | spec | theory | code folder |
| EC-DKG | spec | theory | coinbase::mpc::eckey |
| ECDSA-2PC | spec | theory | coinbase::mpc::ecdsa2pc |
| ECDSA-MPC | spec | theory | coinbase::mpc::ecdsampc |
| MPC Friendly Derivation | spec | theory | key_share_ecdsa_hdmpc_2p_t |
| Oblivious Transfer (OT) and OT Extension | spec | theory | ot |
| Publicly Verifiable Encryption (PVE) | spec | theory | pve |
| Schnorr | spec | theory | coinbase::mpc::schnorr2p and coinbase::mpc::schnorrmp |
| Threshold Encryption (TDH2) | spec | theory | coinbase::crypto::tdh2 |
Thread-Safety Warning
This library is not inherently thread-safe. Unless explicitly documented otherwise, all data structures and functions assume single-threaded access. If you need to use the library from multiple threads, you must protect every shared object with your own synchronization primitives (e.g.,
std::mutex, channel-based message passing, etc.) to avoid data races.
We have outlined our cryptographic design principles and some conventions regarding our documentation in our design principles document. Furthermore, our secure usage document describes important security guidelines that should be followed when using the library. Finally, we have strived to create a library that is constant-time to prevent side-channel attacks. This effort is highly dependent on the architecture of the CPU and the compiler used to build the library and therefore is not guaranteed on all platforms. We have outlined our efforts in the constant-time document.
We have included copies of certain OpenSSL internal header files that are not exposed through OpenSSL's public API but are necessary for our implementation. These files can be found in our codebase and are used to access specific OpenSSL functionality that we require. This approach ensures we can maintain compatibility while accessing needed internal features.
Note that we change the curve25519.c of the OpenSSL code to remove the static modifier to make the functions externally visible. Given access to these functions, our Curve25519 code implements a constant-time version of the curve. Therefore, we strip the leading 'static' keyword from every line in curve25519.c as follows.
sed -i -e 's/^static//' crypto/ec/curve25519.c
Our implementation modifies OpenSSL's OAEP padding algorithm to support deterministic padding when provided with a seed. The key changes are in the ossl_rsa_padding_add_PKCS1_OAEP_mgf1_ex function, specifically in steps 3e-3h of the PKCS#1 v2.0 (RFC 2437) OAEP encoding process:
RAND_bytes_ex(), our implementation accepts an external seed parameterThe security properties of OAEP remain intact as long as the provided seed maintains appropriate randomness and uniqueness requirements. For standard encryption operations, we recommend using the non-deterministic version that generates random seeds internally.
We used a modified version of the secp256k1 curve implementation from coinbase/secp256k1 which is forked from bitcoin-core/secp256k1. The change made is to allow calling the curve operations from within our C++ codebase.
Note that as indicated in their repository, the curve addition operations of secp256k1 are not constant time. To work around this, we have devised a custom point addition operation that is constant time. Please refer to our documentation for more details.
There are extensive Go wrappers for this C++ library that enable the use of library natively from Go. You can find them in coinbase/cb-mpc-go. The repository also includes demos on how to use the library in Go.
336 followers · starred Mar 2025
1,187 followers · starred Jun 2025
692 followers · starred Mar 2025
453 followers · starred May 2025
Welcome to the Coinbase Open Source MPC Library. This repository provides the essential cryptographic protocols that can be utilized to secure asset keys in a decentralized manner using MPC (secure multiparty computation / threshold signing) for blockchain networks.
This cryptographic library is based on the MPC library used at Coinbase to protect cryptoassets, with modifications to make it suitable for public use. The library is designed as a general-purpose cryptographic library for securing cryptoasset keys, allowing developers to build their own applications. Coinbase has invested significantly in building a secure MPC library, and it is our hope that this library will help those interested in deploying MPC to do so easily and securely.
cb-mpc is a native cryptographic library for MPC protocols. It gives application developers the building blocks needed to generate and refresh keyshares, derive supported keys, produce MPC signatures, and support key-backup workflows via publicly verifiable encryption (PVE).
cb-mpc does:
cb-mpc does not:
If you build on the lower-level full API (including internal and low-level functionality), more validation and protocol-composition responsibility shifts to the integrating application. See High-level Public API vs the Full API and Supported Runtime and Deployment Environments for more detail.
The code in this open source library is derived from the code used at Coinbase, with significant changes in order to make it a general-purpose library. In particular, Coinbase applies these protocols with very specific flows as needed in our relevant applications, whereas this code is designed to enable general-purpose use and therefore supports arbitrary flows. In some cases, this generality impacts efficiency, in order to ensure safe default usage.
In addition to releasing the source code for our library, we have published the underlying theoretical work along with detailed specifications. This is a crucial step because merely implementing a theoretical paper can overlook significant errors. At Coinbase, we adhere to the following development process:
The theory documents and specifications are a considerable contribution within themselves, as a resource for cryptographers and practitioners.
Although this library is designed for general use, we have included examples showcasing common applications:
The library comes with various tests and checks to increase the confidence in the code including:
make dudectmake testmake benchmake lintThe cb-mpc library contains two levels of APIs, a public one that contains the API for calling high-level MPC protocols like DKG, threshold signing and publicly-verifiable encryption for backup. These APIs are simple to use, and are recommended for those wishing to use the cb-mpc protocols as is. The second level contains the full cb-mpc API and includes all mid and low-level functions as well. These APIs are intended for users wishing to modify protocols or implement other protocols using the cb-mpc infrastructure. We stress that all functions in the public API are safe, including validation of all externally received inputs. In contrast, not all lower-level APIs include all such validations. For example, an elliptic curve point received from another party in a protocol needs to be validated once and not every time it is used. In addition, some zero-knowledge proofs may depend on other zero-knowledge proofs already being validated. This is taken care of in the public API, but the user is responsible for ensuring all of this when using the lower-level full API. Note that the Coinbase HackerOne bug bounty requires finding a bug in the public API for it to be consider Medium or above. See BUG_BOUNTY.md for details.
docs: the pdf files that define the detailed cryptographic specification and theoretical documentation (you need to enable git-lfs to get them)include: public headers (installed in both public and full install modes)
include/cbmpc/api/ (coinbase::api)include/cbmpc/c_api/ (cbmpc_*)include-internal: internal headers (installed only in full mode), included as <cbmpc/internal/...>src: C++ implementation sourcesdemo-cpp: a collection of examples of common use cases in c++scripts: a collection of scripts used by the Makefiletools/benchmark: a collection of benchmarks for the librarytests/{dudect,integration,unit}: a collection of tests for the libraryThis repository provides a native C++ cryptographic library. It is intended to be embedded into backend services, native applications, and other environments where the calling application can control process isolation, network transport, and secret storage.
The environments that we support are:
x86_64 and Apple Silicon) and 64-bit LinuxBoth native macOS development and the provided Linux Docker environment are intended to be ways to build and test the library. GitHub workflows currently run on Linux using the Docker image.
This library is not a hosted service and does not provide a production networking stack, deployment framework, key-management system, or transport security layer. In production deployments, the integrating application is responsible for:
The library is intended for native environments where the integrating application can enforce those controls. In an MPC deployment, that may mean all parties run in backend services or that some parties run in native client applications on supported platforms. Other targets, including 32-bit systems, browsers, WebAssembly, Windows, and mobile platforms, are not supported.
cb-mpc implements MPC key-generation (dkg and local generation), refresh, derivation, and signing protocols. It does not provide a custody service, policy engine, or application workflow around those protocols.
In the public API, calls like dkg* and refresh* return opaque key_blob / keyset_blob values with each party's share to each party. Those blobs are later passed back into sign*, refresh*, derive*, and related APIs. This means the integrating application owns the lifecycle of those blobs and must treat them as secret key material.
The integrating application is responsible for:
A few practical tips:
key_blob / keyset_blob and no protected backup exists, recovery may depend on the protocol and access structure; do not assume cb-mpc can recreate that party-local secret material for you.detach_private_scalar, get_public_share_compressed, and attach_private_scalar helpers for application-managed backup and restore flows, including verifiable backup schemes such as publicly verifiable encryption (PVE). Follow each protocol's API guidance for the detached output: in particular, an ECDSA-2P P1 scalar-detached blob retains sensitive Paillier material and must be protected like the full key blob.
PVE scalar verification alone does not establish complete P1 recoverability; see
ECDSA-2P P1 backup limitations.refresh* APIs when you want fresh shares for the same (combined) key; if your operational policy requires replacing the key entirely, run a new dkg* flow and migrate in the application layer.The library is responsible for:
For transport, opaque blob handling, session identifiers, and other operational security requirements, see SECURE_USAGE.md.
After cloning the repo, you need to update the submodules with the following command.
git submodule update --init --recursive
Furthermore, to obtain the documentations (in pdf form), you need to enable git-lfs
There are three build modes available:
The library depends on a custom build of OpenSSL 3.6.4 with specific modifications (see External Dependencies). You must build this custom version before compiling the library.
Quick Start:
# Automatic detection of your platform
make openssl
# Or use platform-specific targets:
make openssl-linux # for Linux
make openssl-macos # for x86_64
make openssl-macos-m1 # for ARM64 (Apple Silicon)
Manual Build:
scripts/openssl/build-static-openssl-linux.sh # for Linux
# or
scripts/openssl/build-static-openssl-macos.sh # for x86_64
# or
scripts/openssl/build-static-openssl-macos-m1.sh # for ARM64
Note: These scripts install OpenSSL to /usr/local/opt/[email protected] and may require sudo permission.
Custom Install Location:
If you prefer a different installation path, you can set the CBMPC_OPENSSL_ROOT variable:
# Option 1: Environment variable (before building OpenSSL)
CBMPC_OPENSSL_ROOT=/your/custom/path make openssl
# Option 2: Environment variable (before running cmake)
export CBMPC_OPENSSL_ROOT=/your/custom/path
# Option 3: CMake variable
cmake -DCBMPC_OPENSSL_ROOT=/your/custom/path ...
This project requires a C++17 compliant compiler. We strongly recommend using Clang version 20 or newer. This recommendation is based on our testing, including verification of constant-time properties, which is primarily performed using Clang v20. While we strive for consistent behavior, achieving constant-time properties can be influenced by various factors beyond the compiler, such as hardware and operating system. Consequently, the behavior of the project, including its constant-time characteristics, when compiled with other compilers is not guaranteed to be identical.
apt, yum).brew install llvmexport CC=... CXX=... before running CMake in a clean build directory.Build the library by running
make build
To test the library, run
make test
Running demos and benchmarks:
build/install/ (no sudo).
include/): make install (installs to build/install/public)include-internal/): make install-full (installs to build/install/full)make demo (or make demos)make bench (auto-runs the full install)Notes:
make demo takes care of building + installing the right variants (public vs full) before running each demo.By default the cb-mpc library only installs the public API. To install the full APIs run the following command:
scripts/install.sh --mode full
You can install to a custom prefix:
scripts/install.sh --mode public --prefix /path/to/prefix
# or:
CBMPC_PREFIX=/path/to/prefix scripts/install.sh --mode full
For the Makefile helpers, you can override the default repo-local layout:
# Install under a custom root (creates <root>/{public,full})
make install-all CBMPC_INSTALL_ROOT=/path/to/prefix
# Or override each prefix independently
make install CBMPC_PREFIX_PUBLIC=/path/to/public/prefix
make install-full CBMPC_PREFIX_FULL=/path/to/full/prefix
Our benchmark results can be found at https://coinbase.github.io/cb-mpc
Finally, to clean up, run
make clean
make clean-demos
To use clang-format to lint, we use the clang-format version 14.
Install it with
brew install llvm@14
brew link --force --overwrite llvm@14
then make lint will format all .cpp and .h files in src and tests
We have a Dockerfile that already contains steps for building the proper OpenSSL files. Therefore, the first step is to create the image
make image
You can run the rest of the make commands by invoking them inside docker.
For example, for a one-off testing, you can run
docker run -it --rm -v $(pwd):/code -t cb-mpc bash -c 'make test'
Please note that all cryptographic code has a specification (except for code like wrappers around OpenSSL and the like), but there are some protocol specifications that are not implemented but still appear in the specifications since they may be useful for some application developers.
| Name | Spec | Theory | Code |
| Basic Primitives | spec | theory | code folder |
| Zero-Knowledge Proofs | spec | theory | code folder |
| EC-DKG | spec | theory | coinbase::mpc::eckey |
| ECDSA-2PC | spec | theory | coinbase::mpc::ecdsa2pc |
| ECDSA-MPC | spec | theory | coinbase::mpc::ecdsampc |
| MPC Friendly Derivation | spec | theory | key_share_ecdsa_hdmpc_2p_t |
| Oblivious Transfer (OT) and OT Extension | spec | theory | ot |
| Publicly Verifiable Encryption (PVE) | spec | theory | pve |
| Schnorr | spec | theory | coinbase::mpc::schnorr2p and coinbase::mpc::schnorrmp |
| Threshold Encryption (TDH2) | spec | theory | coinbase::crypto::tdh2 |
Thread-Safety Warning
This library is not inherently thread-safe. Unless explicitly documented otherwise, all data structures and functions assume single-threaded access. If you need to use the library from multiple threads, you must protect every shared object with your own synchronization primitives (e.g.,
std::mutex, channel-based message passing, etc.) to avoid data races.
We have outlined our cryptographic design principles and some conventions regarding our documentation in our design principles document. Furthermore, our secure usage document describes important security guidelines that should be followed when using the library. Finally, we have strived to create a library that is constant-time to prevent side-channel attacks. This effort is highly dependent on the architecture of the CPU and the compiler used to build the library and therefore is not guaranteed on all platforms. We have outlined our efforts in the constant-time document.
We have included copies of certain OpenSSL internal header files that are not exposed through OpenSSL's public API but are necessary for our implementation. These files can be found in our codebase and are used to access specific OpenSSL functionality that we require. This approach ensures we can maintain compatibility while accessing needed internal features.
Note that we change the curve25519.c of the OpenSSL code to remove the static modifier to make the functions externally visible. Given access to these functions, our Curve25519 code implements a constant-time version of the curve. Therefore, we strip the leading 'static' keyword from every line in curve25519.c as follows.
sed -i -e 's/^static//' crypto/ec/curve25519.c
Our implementation modifies OpenSSL's OAEP padding algorithm to support deterministic padding when provided with a seed. The key changes are in the ossl_rsa_padding_add_PKCS1_OAEP_mgf1_ex function, specifically in steps 3e-3h of the PKCS#1 v2.0 (RFC 2437) OAEP encoding process:
RAND_bytes_ex(), our implementation accepts an external seed parameterThe security properties of OAEP remain intact as long as the provided seed maintains appropriate randomness and uniqueness requirements. For standard encryption operations, we recommend using the non-deterministic version that generates random seeds internally.
We used a modified version of the secp256k1 curve implementation from coinbase/secp256k1 which is forked from bitcoin-core/secp256k1. The change made is to allow calling the curve operations from within our C++ codebase.
Note that as indicated in their repository, the curve addition operations of secp256k1 are not constant time. To work around this, we have devised a custom point addition operation that is constant time. Please refer to our documentation for more details.
There are extensive Go wrappers for this C++ library that enable the use of library natively from Go. You can find them in coinbase/cb-mpc-go. The repository also includes demos on how to use the library in Go.
336 followers · starred Mar 2025
1,187 followers · starred Jun 2025
692 followers · starred Mar 2025
453 followers · starred May 2025