Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
18 changes: 10 additions & 8 deletions .clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,20 @@ Standard: c++17
ColumnLimit: 120

IncludeCategories:
- Regex: "<benchmark/benchmark.h>"
Priority: -2
SortPriority: -2
- Regex: "<cbmpc/core/precompiled.h>"
Priority: -1
SortPriority: -1
# Prefer a simple, stable include ordering:
# 1) System/third-party headers: <...>
# 2) Project headers: <cbmpc/...>
# 3) Local/relative headers: "..."
#
# Public headers are required to be self-contained and must not rely on
# include ordering (enforced by build/tests), so we avoid special-casing
# specific headers here.
- Regex: "^<cbmpc/.*>$"
Priority: 2
SortPriority: 2
- Regex: '^".*"$'
Priority: 6
SortPriority: 6
Priority: 3
SortPriority: 3
- Regex: "^<.*>$"
Priority: 1
SortPriority: 1
187 changes: 152 additions & 35 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,63 +14,180 @@ on:
- "dev/**"
- "docs/**"
- ".gitignore"
workflow_dispatch:
inputs:
heavy:
description: "Run heavier checks (demos)"
type: boolean
default: false
schedule:
# Weekly “deep” checks to keep PR CI fast.
- cron: "0 7 * * 1"

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read

jobs:
tests:
changes:
name: Detect changed paths
runs-on: ubuntu-latest
timeout-minutes: 10
outputs:
install_smoke: ${{ steps.detect.outputs.install_smoke }}
demos: ${{ steps.detect.outputs.demos }}
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0
with:
egress-policy: audit
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
# Ensure we can diff reliably for push events.
fetch-depth: 0
- id: detect
name: Classify changed paths
shell: bash
env:
BEFORE_SHA: ${{ github.event.before }}
run: |-
set -euo pipefail

install_smoke=false
demos=false

changed_files=""
if [ "${GITHUB_EVENT_NAME}" = "pull_request" ]; then
# `actions/checkout` checks out a merge commit by default for PRs.
# Its parents are: base (HEAD^1) and head (HEAD^2).
if git rev-parse -q --verify HEAD^2 >/dev/null 2>&1; then
base_sha="$(git rev-parse HEAD^1)"
head_sha="$(git rev-parse HEAD^2)"
changed_files="$(git diff --name-only "${base_sha}" "${head_sha}" || true)"
else
# Fallback: if the checkout isn't a merge commit, diff against the base branch ref.
git fetch --no-tags --prune --depth=1 origin "${GITHUB_BASE_REF}"
changed_files="$(git diff --name-only "origin/${GITHUB_BASE_REF}" HEAD || true)"
fi
elif [ "${GITHUB_EVENT_NAME}" = "push" ]; then
# For pushes, compare the previous and current commit SHAs.
if [ -n "${BEFORE_SHA:-}" ] && [ "${BEFORE_SHA}" != "0000000000000000000000000000000000000000" ]; then
changed_files="$(git diff --name-only "${BEFORE_SHA}" "${GITHUB_SHA}" || true)"
else
# Initial commit / force-push edge case: fall back to listing files in the commit.
changed_files="$(git show --name-only --pretty='' "${GITHUB_SHA}" || true)"
fi
else
# schedule / workflow_dispatch: no diff-based gating (heavier jobs are enabled explicitly).
changed_files=""
fi

echo "Changed files:"
printf '%s\n' "${changed_files}"

while IFS= read -r f; do
[ -z "${f}" ] && continue

# “Installed library smoke” should run when we change the public API surface or the
# build/install plumbing that consumers rely on.
case "${f}" in
include/cbmpc/api/*|src/cbmpc/api/*|include/cbmpc/capi/*|src/cbmpc/capi/*|scripts/install.sh|CMakeLists.txt|cmake/*|Makefile|Dockerfile|scripts/openssl/*)
install_smoke=true
;;
esac

# “All demos” should run when demo code or demo plumbing changes.
case "${f}" in
demo-cpp/*|demo-api/*|scripts/run-demos.sh)
demos=true
;;
esac
done <<< "${changed_files}"

echo "install_smoke=${install_smoke}" >> "${GITHUB_OUTPUT}"
echo "demos=${demos}" >> "${GITHUB_OUTPUT}"

core:
name: Core (lint + unit + sanitizers)
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0
with:
egress-policy: audit
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Build Docker image
run: |-
set -euo pipefail
make submodules
make image
- name: Lint + unit tests (Debug)
run: |-
set -euo pipefail
docker run --rm -v $(pwd):/code -t cb-mpc bash -c 'make lint && make test BUILD_TYPE=Debug TEST_LABEL=unit'
- name: Sanitizers (ASAN+UBSAN)
run: |-
set -euo pipefail
docker run --rm -v $(pwd):/code -t cb-mpc bash -c 'make sanitize'

# Heavier checks run only on schedule or manual dispatch to keep PR CI fast.
demos:
name: Heavy (all demos)
needs: changes
if: |
github.event_name == 'schedule' ||
(github.event_name == 'workflow_dispatch' && inputs.heavy == 'true') ||
((github.event_name == 'pull_request' || github.event_name == 'push') && needs.changes.outputs.demos == 'true')
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0
with:
egress-policy: audit
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- run: |-
echo "Run tests"
set -euo pipefail
make submodules
make image
docker run --rm -v $(pwd):/code -t cb-mpc bash -c 'make lint && make full-test'
lib-tests:
docker run --rm -v $(pwd):/code -t cb-mpc bash -c '
set -euo pipefail
make install-all BUILD_TYPE=Release
BUILD_TYPE=Release bash scripts/run-demos.sh --run basic_primitive
BUILD_TYPE=Release bash scripts/run-demos.sh --run zk
BUILD_TYPE=Release bash scripts/run-demos.sh --run parallel_transport
BUILD_TYPE=Release bash scripts/run-demos.sh --run-api pve
BUILD_TYPE=Release bash scripts/run-demos.sh --run-api hd_keyset_ecdsa_2p
BUILD_TYPE=Release bash scripts/run-demos.sh --run-api ecdsa_mp_pve_backup
BUILD_TYPE=Release bash scripts/run-demos.sh --run-api schnorr_2p_pve_batch_backup
'

install-demo-smoke:
name: Heavy (install + demo smoke)
needs: changes
if: |
(github.event_name == 'pull_request' || github.event_name == 'push') &&
needs.changes.outputs.install_smoke == 'true' &&
needs.changes.outputs.demos != 'true'
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0
with:
egress-policy: audit

- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- run: |-
echo "Test on installed library"
set -euo pipefail
make submodules
make image
docker run --rm -v "$(pwd)":/code -t cb-mpc bash -lc '
# Smoke-test “installed library” flow without running every demo.
docker run --rm -v $(pwd):/code -t cb-mpc bash -c '
set -euo pipefail
cd /code
# Never re-touch submodules inside the container; avoids git safe.directory pain.
# If you insist on touching git here, you MUST first: git config --global --add safe.directory /code
if ! command -v go >/dev/null 2>&1; then
apt-get update
apt-get install -y --no-install-recommends ca-certificates curl git
GO_VERSION="${GO_VERSION:-1.24.6}"
GO_FILENAME="go${GO_VERSION}.linux-amd64.tar.gz"
GO_SHA256="bbca37cc395c974ffa4893ee35819ad23ebb27426df87af92e93a9ec66ef8712"
curl -fsSLo "/tmp/${GO_FILENAME}" "https://go.dev/dl/${GO_FILENAME}"
printf '"'"'%s %s\n'"'"' "$GO_SHA256" "/tmp/$GO_FILENAME" | sha256sum --check --status -
tar -C /usr/local -xzf "/tmp/${GO_FILENAME}"
rm -f "/tmp/${GO_FILENAME}"
ln -sf /usr/local/go/bin/* /usr/local/bin/
fi
export PATH="/usr/local/go/bin:$PATH"
export GOTOOLCHAIN=auto
go version
export CGO_ENABLED=1
make build
make install
make benchmark-build
# Run demos (Go + C++) with cgo on
BUILD_TYPE=${BUILD_TYPE:-Release} bash scripts/run-demos.sh --run-all
make test-go
make test-go-race
'
make install-all BUILD_TYPE=Release
BUILD_TYPE=Release bash scripts/run-demos.sh --run basic_primitive
BUILD_TYPE=Release bash scripts/run-demos.sh --run-api pve
'
7 changes: 3 additions & 4 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ on:
- '**/*.h'
- '**/*.hpp'
- '**/*.c'
- '**/*.go'
- '**/*.py'

permissions:
Expand All @@ -30,7 +29,7 @@ jobs:
strategy:
fail-fast: false
matrix:
language: [ 'cpp', 'go', 'python' ]
language: [ 'cpp', 'python' ]

steps:
- name: Harden the runner (Audit all outbound calls)
Expand All @@ -52,9 +51,9 @@ jobs:
- name: Install language dependencies
run: |
sudo apt-get update
sudo apt-get install -y cmake golang-go
sudo apt-get install -y cmake

- if: matrix.language == 'go' || matrix.language == 'python'
- if: matrix.language == 'python'
name: Autobuild
uses: github/codeql-action/autobuild@fca7ace96b7d713c7035871441bd52efbe39e27e # v3.28.19
- if: matrix.language == 'cpp'
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ a.out

# CMake generated files
**build/
cmake_test_discovery_*.json

# ctest files
**Testing/
Expand Down
26 changes: 26 additions & 0 deletions BUG_BOUNTY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# CB-MPC (Coinbase Multi-Party Computation) Open Source Release

Coinbase is proud to announce the open-sourcing of our MPC cryptography library! You can access it here: https://github.com/coinbase/cb-mpc. This significant milestone underscores our commitment to transparency, security, and promoting innovation within the cryptographic community.

With this release, we aim to:

* Enhance the security of the field by enabling developers to quickly deploy threshold signing/MPC for protecting cryptoassets in their applications.
* Increase transparency regarding Coinbase’s use of MPC, and encourage collaboration within the developer community.

Note that while the code is based on Coinbase's production environment, it is not exactly the same, and it has been modified to make it useful as a general-purpose library.

The primary focus of our bug bounty program will include identifying and addressing potential vulnerabilities in our open-source MPC implementation. Given the sensitive nature of these cryptographic protocols, it's imperative to safeguard against any exploits that could compromise cryptoassets. Responsible disclosure via the Bug Bounty Program or directly is encouraged (for direct disclosure see https://github.com/coinbase/cb-mpc/blob/master/SECURITY.md).

Through community collaboration and vigilant security reviews, we aspire to provide an easy to use and highly secure MPC library to help developers secure cryptoassets across the entire cryptocurrency and blockchain ecosystem.

To keep this bounty focused on issues that affect real integrations, eligible reports should target vulnerabilities reachable through the library's supported public APIs. High-level protocol entry points are exposed via the public C++ headers under `include/cbmpc/api/` (e.g., signing, DKG, TDH2).

For **Medium** and above, submissions must include a proof-of-concept that triggers the issue through those public APIs. Reports may reference or require fixes in `include-internal/` for root cause and impact analysis, but the PoC must not use `include-internal/` as the entry point. Demo applications and sample code under `demo-*`, and the C API headers under `include/cbmpc/c_api/*`, are not in scope for this bug bounty program.

| Vulnerability Tier | Description | Reward |
|:-------------------|:--------------------------------|:------------------------------------------|
| **Extreme** | Open Source Bugs (cb-mpc): not applicable | Up to $1,000,000 |
| **Critical** | Open Source Bugs (cb-mpc): High-severity vulnerabilities in supported high-level protocols from the public API (e.g., Signing, DKG, TDH2) that are easily exploitable and can lead to key compromise. Examples: significant disclosure of sensitive data (key material), remote code execution. Private by default; triggers new releases for all supported versions. | $50,000 |
| **High** | Open Source Bugs (cb-mpc): High-severity vulnerabilities in supported high-level protocols from the public API that are less easily exploitable. Private by default; triggers new release for all supported versions within a reasonable timeframe. | $15,000 |
| **Medium** | Open Source Bugs (cb-mpc): Vulnerabilities that are hard to exploit, limited in impact, or present in less commonly used scenarios, but are still demonstrable via the supported public APIs. Bugs in lower-level cryptographic primitives (e.g., ZKPs, commitments) are eligible when reachable from those protocols. Private until next release; released with subsequent updates. | $2,000 |
| **Low** | Open Source Bugs (cb-mpc): Non-cryptographic issues including low-level non-cryptographic APIs, crashes, or deprecated cryptographic code. Any vulnerability in code that is released under “beta” is always low. Fixed immediately in latest development versions; may be backported to older versions. | $200 |
42 changes: 40 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -84,21 +84,57 @@ else()
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${BIN_DIR}/${CMAKE_BUILD_TYPE})
endif()

include_directories(${ROOT_DIR}/include)
include_directories(${ROOT_DIR}/include-internal)
include_directories(${SRC_DIR})

add_subdirectory(src/cbmpc/core)
add_subdirectory(src/cbmpc/crypto)
add_subdirectory(src/cbmpc/zk)
add_subdirectory(src/cbmpc/protocol)
add_subdirectory(src/cbmpc/ffi)
add_subdirectory(src/cbmpc/api)
add_subdirectory(src/cbmpc/c_api)

add_library(
cbmpc STATIC $<TARGET_OBJECTS:cbmpc_core> $<TARGET_OBJECTS:cbmpc_crypto>
$<TARGET_OBJECTS:cbmpc_zk> $<TARGET_OBJECTS:cbmpc_protocol>
$<TARGET_OBJECTS:cbmpc_ffi>)
$<TARGET_OBJECTS:cbmpc_api>
$<TARGET_OBJECTS:cbmpc_c_api>)

link_openssl(cbmpc)

# ------------- Public headers smoke check ---------------------------
#
# Compile a TU that includes all public headers with include paths limited to
# `include/` (plus OpenSSL headers). This ensures public headers do not
# accidentally depend on `include-internal/`.
#
if(NOT DEFINED CBMPC_OPENSSL_ROOT)
if(DEFINED ENV{CBMPC_OPENSSL_ROOT})
set(CBMPC_OPENSSL_ROOT $ENV{CBMPC_OPENSSL_ROOT})
else()
set(CBMPC_OPENSSL_ROOT "/usr/local/opt/openssl@3.6.1")
endif()
endif()

set(_cbmpc_public_headers_smoke_src "${ROOT_DIR}/tests/public_headers_smoke.cpp")
set(_cbmpc_public_headers_smoke_obj "${CMAKE_BINARY_DIR}/cbmpc_public_headers_smoke.o")

add_custom_command(
OUTPUT "${_cbmpc_public_headers_smoke_obj}"
COMMAND "${CMAKE_CXX_COMPILER}"
-std=c++17
"-I${ROOT_DIR}/include"
"-I${CBMPC_OPENSSL_ROOT}/include"
-c "${_cbmpc_public_headers_smoke_src}"
-o "${_cbmpc_public_headers_smoke_obj}"
DEPENDS "${_cbmpc_public_headers_smoke_src}"
COMMENT "Compiling public headers smoke TU"
VERBATIM
)

add_custom_target(public-only-check DEPENDS "${_cbmpc_public_headers_smoke_obj}")

# ------------- Tests ---------------------------

if(NOT IS_MACOS)
Expand All @@ -107,5 +143,7 @@ endif()

if(BUILD_TESTS)
enable_testing()
add_test(NAME PublicHeadersSmoke COMMAND "${CMAKE_COMMAND}" --build "${CMAKE_BINARY_DIR}" --target public-only-check)
set_tests_properties(PublicHeadersSmoke PROPERTIES RUN_SERIAL TRUE LABELS "unit")
add_subdirectory(tests)
endif()
7 changes: 4 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
clang-20 \
clang-format-20 \
lld-20 \
llvm-20 \
libfuzzer-20-dev \
libclang-rt-20-dev \
&& rm -rf /var/lib/apt/lists/* \
Expand All @@ -36,9 +37,9 @@ WORKDIR /build
COPY scripts/openssl/build-static-openssl-linux.sh .
RUN sh build-static-openssl-linux.sh \
&& mkdir -p /usr/local/lib64 /usr/local/lib /usr/local/include \
&& ln -sf /usr/local/opt/openssl@3.2.0/lib64/libcrypto.a /usr/local/lib64/libcrypto.a \
&& ln -sf /usr/local/opt/openssl@3.2.0/lib64/libcrypto.a /usr/local/lib/libcrypto.a \
&& ln -sf /usr/local/opt/openssl@3.2.0/include/openssl /usr/local/include/openssl \
&& ln -sf /usr/local/opt/openssl@3.6.1/lib64/libcrypto.a /usr/local/lib64/libcrypto.a \
&& ln -sf /usr/local/opt/openssl@3.6.1/lib64/libcrypto.a /usr/local/lib/libcrypto.a \
&& ln -sf /usr/local/opt/openssl@3.6.1/include/openssl /usr/local/include/openssl \
&& rm -rf /build

WORKDIR /code
Loading
Loading