Skip to content
Merged
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
default:
image: docker.io/ubuntu:20.04
image: registry.gitlab.com/fireblocks/external-docker-images/ubuntu:22.04
tags:
- dev-common-runner
- kub-builders
before_script:
- apt update
- DEBIAN_FRONTEND=noninteractive apt install -y build-essential cmake pkg-config uuid-dev libssl-dev libsecp256k1-dev
Expand Down
6 changes: 6 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
cmake_minimum_required(VERSION 3.13)
project(mpc-lib LANGUAGES C CXX)

option(MPC_LIB_BUILD_BENCHMARKS "Build benchmarking targets (requires Google Benchmark)" OFF)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_EXTENSIONS OFF)

Expand All @@ -16,3 +18,7 @@ if(${CMAKE_SOURCE_DIR} STREQUAL ${PROJECT_SOURCE_DIR} AND NOT MPC_LIB_SKIP_TESTS
enable_testing()
add_subdirectory(test)
endif()

if(MPC_LIB_BUILD_BENCHMARKS)
add_subdirectory(benchmarks)
endif()
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,31 @@ To execute the test suite, run the command from the same build folder:
make test
```

### Benchmarks and Profiling

Build the BAM signing benchmark by enabling the benchmark option during configuration:
```sh
cmake -S . -B build -DMPC_LIB_BUILD_BENCHMARKS=ON
cmake --build build --target bam_sign_benchmark
```

Run the benchmark executable to measure `bam_key_sign` throughput (use `--benchmark_filter` to focus on a specific algorithm):
```sh
./build/benchmarks/bam_sign_benchmark --benchmark_filter=stark
```

To profile the benchmark and visualize the results:
1. Record samples with Linux `perf` (install `hotspot` or another viewer once):
```sh
perf record -F 999 -g ./build/benchmarks/bam_sign_benchmark --benchmark_filter=secp256k1_default
```
2. Open the generated `perf.data` in a graphical viewer, e.g.:
```sh
hotspot perf.data # Qt GUI with flame graphs
# or convert to Speedscope
perf script | speedscope
```

## Usage

A few examples for running a full signing process can be found in the [tests section](https://github.com/fireblocks/mpc-lib/tree/main/test/cosigner)
Expand Down
3 changes: 3 additions & 0 deletions benchmarks/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
add_executable(bam_sign_benchmark bam_sign_benchmark.cpp)
target_link_libraries(bam_sign_benchmark cosigner uuid)
target_include_directories(bam_sign_benchmark PRIVATE ${CMAKE_SOURCE_DIR}/include)
314 changes: 314 additions & 0 deletions benchmarks/bam_sign_benchmark.cpp

Large diffs are not rendered by default.

15 changes: 15 additions & 0 deletions docker/Dockerfile.bookworm
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
FROM debian:bookworm-slim

ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update && apt install -y \
build-essential \
uuid-dev \
libssl-dev \
libsecp256k1-dev \
cmake \
&& rm -rf /var/lib/apt/lists/* \
&& rm -rf /var/cache/apt/archives/*

COPY . /usr/src/mpc-lib/
WORKDIR /usr/src/mpc-lib
2 changes: 1 addition & 1 deletion docker/Dockerfile.24.04 → docker/Dockerfile.focal
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM ubuntu:24.04
FROM ubuntu:focal

ENV DEBIAN_FRONTEND=noninteractive

Expand Down
15 changes: 15 additions & 0 deletions docker/Dockerfile.jammy
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
FROM ubuntu:jammy

ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update && apt install -y \
build-essential \
uuid-dev \
libssl-dev \
libsecp256k1-dev \
cmake \
&& rm -rf /var/lib/apt/lists/* \
&& rm -rf /var/cache/apt/archives/*

COPY . /usr/src/mpc-lib/
WORKDIR /usr/src/mpc-lib/
5 changes: 2 additions & 3 deletions docker/run_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ fi

input_base_name=$(basename ${Dockerfile})
prefix=$(echo ${input_base_name}| awk '{split($0,a,"."); print a[1]}')
tag=$(echo ${input_base_name} | sed "s/^${prefix}\.//" )
tag=$(echo ${input_base_name}| awk '{split($0,a,"."); print a[2]}')

if [ x${prefix} != "xDockerfile" ]; then
echo "Must Select a valid Dockerfile"
Expand All @@ -33,11 +33,10 @@ CURRENT_DIR=`pwd`

cd ${SCRIPT_DIR}/..

docker build --network=host -f ${CURRENT_DIR}/${Dockerfile} . -t $IMAGE_NAME
docker build -f ${CURRENT_DIR}/${Dockerfile} . -t $IMAGE_NAME

docker run \
--rm \
--net=host \
${IMAGE_NAME} bash -c "mkdir build_${IMAGE_NAME};cd build_${IMAGE_NAME};cmake ..;make -j && make -j test"

cd -
Expand Down
15 changes: 6 additions & 9 deletions include/cosigner/asymmetric_eddsa_cosigner.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include "cosigner/platform_service.h"
#include "cosigner_export.h"

#include "crypto/ed25519_algebra/ed25519_algebra.h"
Expand All @@ -22,22 +23,18 @@ namespace cosigner
{

class cmp_key_persistency;
class platform_service;
class cosigner_verifier_chain;
struct eddsa_signature_data;
struct signing_data;

static constexpr size_t SHA256_HASH_SIZE = 32;
typedef std::array<uint8_t, SHA256_HASH_SIZE> eddsa_commitment;
static_assert(sizeof(eddsa_commitment) == SHA256_HASH_SIZE);

struct Rs_and_commitments
{
std::vector<elliptic_curve_point> Rs;
eddsa_commitment R_commitment;
};

class COSIGNER_EXPORT asymmetric_eddsa_cosigner
{
public:
asymmetric_eddsa_cosigner(platform_service& cosigner_service, const cmp_key_persistency& key_persistency);
asymmetric_eddsa_cosigner(platform_service& service, const cmp_key_persistency& key_persistency);
virtual ~asymmetric_eddsa_cosigner() {}

protected:
Expand All @@ -49,7 +46,7 @@ class COSIGNER_EXPORT asymmetric_eddsa_cosigner

platform_service& _service;
const cmp_key_persistency& _key_persistency;
static const std::unique_ptr<elliptic_curve256_algebra_ctx_t, void (*)(elliptic_curve256_algebra_ctx_t*)> _ctx;
std::unique_ptr<elliptic_curve256_algebra_ctx_t, void (*)(elliptic_curve256_algebra_ctx_t*)> _ctx;
};

}
Expand Down
15 changes: 7 additions & 8 deletions include/cosigner/asymmetric_eddsa_cosigner_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,24 +24,23 @@ class COSIGNER_EXPORT asymmetric_eddsa_cosigner_client : public asymmetric_eddsa
class preprocessing_persistency
{
public:
virtual ~preprocessing_persistency();

virtual ~preprocessing_persistency() {}
// This function should allocate preprocessed data array sized size
virtual void create_preprocessed_data(const std::string& key_id, uint64_t size) = 0;
// This function set the value k at index, in case index is larger then larger then array size the function should throw exception
// This function set the value k at index, in case index is larger than the array size the function should throw exception
virtual void store_preprocessed_data(const std::string& key_id, uint64_t index, const ed25519_scalar_t& k) = 0;
// This function load the at index and deletes it, in case index is larger then larger then array size or the value isn't set the function should throw exception
// This function load the at index and deletes it, in case index is larger than the array size or the value isn't set the function should throw exception
virtual void load_preprocessed_data(const std::string& key_id, uint64_t index, ed25519_scalar_t& k) = 0;
virtual void delete_preprocessed_data(const std::string& key_id) = 0;
};

asymmetric_eddsa_cosigner_client(platform_service& cosigner_service, const cmp_key_persistency& key_persistency, preprocessing_persistency& preprocessing_persistency);
~asymmetric_eddsa_cosigner_client();
asymmetric_eddsa_cosigner_client(platform_service& cosigner_service, cmp_key_persistency& key_persistency, preprocessing_persistency& preprocessing_persistency);
~asymmetric_eddsa_cosigner_client() {}

virtual void start_signature_preprocessing(const std::string& tenant_id, const std::string& key_id, const std::string& request_id, uint32_t start_index, uint32_t count, uint32_t total_count, const std::set<uint64_t>& players_ids,
virtual void start_signature_preprocessing(const std::string& tenant_id, const std::string& key_id, const std::string& request_id, uint64_t start_index, uint32_t count, uint32_t total_count, const std::set<uint64_t>& players_ids,
std::vector<std::array<uint8_t, sizeof(commitments_sha256_t)>>& R_commitments);
virtual uint64_t eddsa_sign_offline(const std::string& key_id, const std::string& txid, const signing_data& data, const std::string& metadata_json, const std::set<std::string>& players, const std::set<uint64_t>& players_ids, uint64_t preprocessed_data_index,
const std::map<uint64_t, Rs_and_commitments>& Rs, std::vector<eddsa_signature>& partial_sigs);
const std::map<uint64_t, std::vector<elliptic_curve_point>>& Rs, std::vector<eddsa_signature>& partial_sigs);

private:
preprocessing_persistency& _preprocessing_persistency;
Expand Down
40 changes: 11 additions & 29 deletions include/cosigner/asymmetric_eddsa_cosigner_server.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "cosigner_export.h"

#include "asymmetric_eddsa_cosigner.h"
#include "eddsa_online_signing_service.h"
#include "crypto/commitments/commitments.h"
#include "crypto/ed25519_algebra/ed25519_algebra.h"
#include "cosigner/timing_map.h"
Expand All @@ -11,7 +12,6 @@

#include <array>
#include <map>
#include <mutex>
#include <set>
#include <string>
#include <vector>
Expand All @@ -23,23 +23,8 @@ namespace common
namespace cosigner
{

struct asymmetric_eddsa_signature_data
struct asymmetric_eddsa_signing_metadata : public eddsa_signing_metadata
{
elliptic_curve_scalar k;
elliptic_curve_point R;
std::vector<uint32_t> path;
byte_vector_t message;
uint32_t flags;
~asymmetric_eddsa_signature_data() {OPENSSL_cleanse(k.data, sizeof(asymmetric_eddsa_signature_data));}
};

struct asymmetric_eddsa_signing_metadata
{
std::string key_id;
HDChaincode chaincode;
std::vector<asymmetric_eddsa_signature_data> sig_data;
std::set<uint64_t> signers_ids;
uint32_t version;
uint32_t start_index;
};

Expand All @@ -51,13 +36,12 @@ class COSIGNER_EXPORT asymmetric_eddsa_cosigner_server : public asymmetric_eddsa
class signing_persistency
{
public:
virtual ~signing_persistency();
virtual ~signing_persistency() {}

// This function should allocate preprocessed data array sized size
virtual void create_preprocessed_data(const std::string& key_id, uint64_t size) = 0;
// This function set the value R_commitment at index, in case index is larger then larger then array size the function should throw exception
// This function set the value R_commitment at index, in case index is larger than the array size the function should throw exception
virtual void store_preprocessed_data(const std::string& key_id, uint64_t index, const eddsa_commitment& R_commitment) = 0;
// This function load the at index and deletes it, in case index is larger then larger then array size or the value isn't set the function should throw exception
// This function load the at index and deletes it, in case index is larger than the array size or the value isn't set the function should throw exception
virtual void load_preprocessed_data(const std::string& key_id, uint64_t index, eddsa_commitment& R_commitment) = 0;
virtual void delete_preprocessed_data(const std::string& key_id) = 0;

Expand All @@ -66,27 +50,25 @@ class COSIGNER_EXPORT asymmetric_eddsa_cosigner_server : public asymmetric_eddsa
virtual void delete_commitments(const std::string& txid) = 0;
virtual void store_signing_data(const std::string& txid, const asymmetric_eddsa_signing_metadata& data, bool update) = 0;
virtual void load_signing_data(const std::string& txid, asymmetric_eddsa_signing_metadata& data) = 0;
virtual void delete_temporary_signing_data(const std::string& txid) = 0;
virtual void delete_signing_data(const std::string& txid) = 0;
};

asymmetric_eddsa_cosigner_server(platform_service& cosigner_service, const cmp_key_persistency& key_persistency, signing_persistency& signing_persistency);
asymmetric_eddsa_cosigner_server(platform_service& service, cmp_key_persistency& key_persistency, signing_persistency& signing_persistency);
virtual ~asymmetric_eddsa_cosigner_server() {}

void store_presigning_data(const std::string& key_id, const std::string& request_id, uint32_t start_index, uint32_t count, uint32_t total_count, const std::set<uint64_t>& players_ids,
void store_presigning_data(const std::string& key_id, const std::string& request_id, uint64_t start_index, uint32_t count, uint32_t total_count, const std::set<uint64_t>& players_ids,
uint64_t sender, const std::vector<eddsa_commitment>& R_commitments);

void eddsa_sign_offline(const std::string& key_id, const std::string& txid, const signing_data& data, const std::string& metadata_json, const std::set<std::string>& players, const std::set<uint64_t>& players_ids, uint64_t preprocessed_data_index,
std::vector<eddsa_commitment>& R_commitments, Rs_and_commitments& Rs);
std::vector<eddsa_commitment>& R_commitments, std::vector<elliptic_curve_point>& Rs);
uint64_t decommit_r(const std::string& txid, const std::map<uint64_t, std::vector<eddsa_commitment>>& commitments, std::vector<elliptic_curve_point>& Rs);
uint64_t broadcast_r(const std::string& txid, const std::map<uint64_t, std::vector<elliptic_curve_point>>& players_R, Rs_and_commitments& Rs, uint64_t& send_to);
uint64_t broadcast_r(const std::string& txid, const std::map<uint64_t, std::vector<elliptic_curve_point>>& players_R, std::vector<elliptic_curve_point>& Rs, uint64_t& send_to);
uint64_t broadcast_si(const std::string& txid, uint64_t sender, uint32_t version, const std::vector<eddsa_signature>& partial_sigs, std::vector<eddsa_signature>& sigs, std::set<uint64_t>& send_to, bool& final_signature);
uint64_t get_eddsa_signature(const std::string& txid, const std::map<uint64_t, std::vector<eddsa_signature>>& partial_sigs, std::vector<eddsa_signature>& sigs);

void cancel_signing(const std::string& txid);

private:
bool verify_client_s(const ed25519_point_t& R, const ed25519_scalar_t& s, const ed25519_le_scalar_t& hram, const elliptic_curve_point& public_share, const ed25519_scalar_t& delta);
void commit_to_Rs(const std::string& txid, uint64_t id, const std::vector<elliptic_curve_point>& Rs, eddsa_commitment& commitment);
void finalize_signing(const std::string& txid, size_t count);
signing_persistency& _signing_persistency;

TimingMap _timing_map;
Expand Down
Loading
Loading