Fireblocks MPC
Summary
ExpandThe Fireblocks MPC library is a C++ implementation of threshold cryptographic protocols that enable distributed key generation, signing, and secret sharing without any single party holding a complete private key. The codebase implements core multi-party computation primitives including Shamir secret sharing, Feldman and Pedersen verifiable secret sharing schemes, Paillier homomorphic encryption, Damgård-Fujisaki commitment proofs, and threshold ECDSA signing built atop OpenSSL's BIGNUM and elliptic curve facilities. The architecture is structured around discrete protocol modules — each encapsulating a round of an interactive MPC ceremony — with a serialization layer for marshaling protocol messages between participants and a proof system for zero-knowledge verification of participant honesty.
The codebase employs several meaningful security controls consistent with cryptographic library best practices. Sensitive big-number values are allocated through OpenSSL's secure BIGNUM interfaces, and the library makes deliberate use of BN_CTX scoping to manage temporary values during multi-step arithmetic operations. Commitment schemes and zero-knowledge proofs are used throughout to enforce protocol correctness, and the Paillier implementation includes proper parameter validation for key generation and ciphertext operations. The use of constant-time comparison functions in select verification paths demonstrates awareness of side-channel risks, and the library performs range checks on deserialized protocol messages to reject malformed inputs before they reach core arithmetic routines.
The overall security posture of the Fireblocks MPC library is sound at the protocol level, with the five findings identified in this assessment concentrated in implementation-layer concerns rather than fundamental design flaws. The protocol logic correctly implements the academic constructions it targets, and the modular separation of ceremony rounds limits the blast radius of any single implementation defect. The most high concern is a stack overflow vector arising from unbounded stack allocation controlled by external input, which could be exploited by a malicious ceremony participant to achieve denial of service or potentially code execution in the context of the MPC process.
Findings
5 issues identified
Stack overflow via unbounded alloca with user-controlled length
range_proofs.c:872
View Details
Description
The function range_proof_pailler_quadratic_generate_basis computes salted_msg_len from sizeof(PAILLER_LARGE_FACTORS_QUADRATIC_ZKP_SEED) + aad_len + d_size and passes the result to alloca(). The aad_len parameter is a uint32_t from caller input with no upper bound check. A large aad_len causes stack overflow; a wrapping aad_len causes a small allocation followed by an out-of-bounds memcpy.
Impact
An MPC participant providing a crafted aad buffer with a very large aad_len could corrupt the stack, crash the process, or potentially achieve code execution. In an MPC signing service context this could lead to denial of service or key material exposure.
Recommendation
Add an upper bound check on the total allocation size before calling alloca, or switch to heap allocation with malloc. Use uint64_t for intermediate size computation to detect overflow.
Fix
Adds overflow-safe size computation using uint64_t and bounds the total alloca size to 8192 bytes. Inputs exceeding this are rejected with ZKP_INVALID_PARAMETER.
src/common/crypto/zero_knowledge_proof/range_proofs.c
Polynomial coefficient not cleansed on error paths in create_shares
verifiable_secret_sharing.c:75
View Details
Description
In create_shares, the stack variable ‘coefficient’ is populated with raw polynomial coefficients via BN_bn2binpad inside a loop. The OPENSSL_cleanse call is placed after the loop, but if generator_mul or BN_bn2binpad fails on any iteration after the first, execution jumps to cleanup without cleansing. Polynomial coefficients are secret material that directly protects the shared secret.
Impact
A leaked polynomial coefficient reduces the effective threshold of the secret sharing scheme. If an attacker obtains k shares plus one coefficient from memory, they can reconstruct the secret with fewer shares than intended. Exploitation requires a separate memory read primitive.
Recommendation
Move the OPENSSL_cleanse call for coefficient into the cleanup block so it executes on both success and error paths.
Fix
Moves the OPENSSL_cleanse of the coefficient buffer from after the loop (success-only path) to the cleanup label (always-executed path), ensuring polynomial coefficients are zeroed from the stack regardless of whether the function succeeds or fails.
src/common/crypto/shamir_secret_sharing/verifiable_secret_sharing.c
BN_CTX stack corruption on early return in damgard_fujisaki_verify_commitment_internal
damgard_fujisaki.c:195
View Details
Description
After BN_CTX_start(ctx) is called, if BN_CTX_get(ctx) returns NULL the function takes an early return without calling BN_CTX_end(ctx). This corrupts the BN_CTX internal stack, affecting all subsequent BIGNUM operations using that context.
Impact
BN_CTX stack corruption can cause crashes, memory corruption, or incorrect cryptographic computations in subsequent MPC protocol operations sharing the same context.
Recommendation
Route the error through the existing cleanup label which calls BN_CTX_end(ctx).
Fix
Routes the OOM error through the cleanup label so BN_CTX_end is always called after BN_CTX_start, maintaining the BN_CTX stack invariant.
src/common/crypto/commitments/damgard_fujisaki.c
Variable-time scalar multiplication leaks secret MPC key shares
src/common/crypto/ed25519_algebra/ed25519_algebra.c
View Details
Description
The internal ed25519_scalar_mult function uses ge_double_scalarmult_vartime to compute arbitrary-point scalar multiplication. This function has data-dependent branching based on the scalar’s non-adjacent form representation: it skips leading zero bits (leaking bit-length) and conditionally executes point additions based on the scalar’s NAF digits. In MPC protocols where the scalar represents a secret key share, this timing variation enables side-channel recovery of the secret.
Impact
An attacker with timing measurement capability (co-located process, shared infrastructure) can observe execution time differences that correlate with the secret scalar’s Hamming weight and bit pattern. Repeated observations across MPC protocol executions can progressively recover secret key shares, ultimately compromising the threshold private key.
Recommendation
Replace the variable-time ge_double_scalarmult_vartime call with a constant-time double-and-add ladder using the existing fe_cmov branchless conditional move primitive.
Fix
Replaces the variable-time scalar multiplication with a constant-time double-and-add ladder. Every iteration unconditionally doubles and computes the addition, then uses fe_cmov (branchless conditional move) to select the correct result. The Ed25519 twisted Edwards addition formula is complete for a=-1 with non-square d, so unconditional addition is always well-defined.
src/common/crypto/ed25519_algebra/ed25519_algebra.c
Secret scalars not cleared from stack in proof generation
diffie_hellman_log.c:74
View Details
Description
diffie_hellman_log_zkp_generate declares secret scalars d (random nonce), y (random nonce), e (challenge), and tmp on the stack but never zeroes them before returning. Recovery of d allows computing secret b from z = eb + d; recovery of y allows computing secret from w = esecret + y. The codebase is inconsistent: schnorr_zkp_generate_impl properly calls OPENSSL_cleanse(k, sizeof(k)) for its nonce.
Impact
An attacker with memory access (core dump, cold boot, separate vulnerability) could recover random nonces and derive secret key shares from the proof equations.
Recommendation
Zero all sensitive stack variables using OPENSSL_cleanse before returning, consistent with the pattern in schnorr.c.
Fix
Adds OPENSSL_cleanse calls to securely erase all sensitive stack-allocated scalars before returning, consistent with the pattern used in schnorr_zkp_generate_impl.
src/common/crypto/zero_knowledge_proof/diffie_hellman_log.c
Conclusion
ExpandThe Fireblocks MPC codebase reflects a mature understanding of threshold cryptographic protocol design, with clean separation between protocol rounds, careful use of OpenSSL’s BIGNUM arithmetic for large-integer operations, and structured commitment and proof verification at each protocol phase. However, the implementation exhibits a recurring pattern of incomplete resource cleanup on error paths — three of the five findings involve sensitive cryptographic material (polynomial coefficients, secret scalars, or BN_CTX stack frames) that persist in memory or in a corrupted state when functions exit through exceptional control flow. This pattern suggests that while the primary success paths have received careful attention, systematic hardening of error and early-return paths has not yet been applied uniformly across the library.
The low-severity finding involving unbounded alloca with participant-controlled length parameters represents a concrete exploitable vector: a malicious participant in an MPC ceremony could supply a crafted message triggering stack exhaustion or controlled stack overflow in a peer’s process. The low-severity findings around variable-time elliptic curve scalar multiplication and insufficient secret clearing pose a more nuanced but real risk in deployment environments where an attacker may share physical or virtual hardware with MPC nodes, enabling cache-timing or memory-remanence attacks against key share material. Taken together, these findings indicate that the library’s threat model should be extended to explicitly account for adversarial participants attempting implementation-level attacks beyond protocol deviations.
Prior to production deployment, the alloca usage must be replaced with heap allocation guarded by a strict maximum length check, as this is the only finding that enables remote exploitation without physical or side-channel access. The error-path cleanup issues and secret-clearing gaps should be addressed in a focused pass applying RAII-style scoped cleaners or explicit memset_s/OPENSSL_cleanse calls to all functions handling secret polynomial coefficients, scalar values, and proof intermediaries. Adopting constant-time elliptic curve operations — either through OpenSSL’s EC_POINT_mul with appropriate flags or a dedicated constant-time curve library — would close the timing side-channel and bring the implementation in line with the security guarantees the MPC protocol is designed to provide.
On-Chain Verification
Compare these values with the on-chain attestation
Verify: download the markdown and compare the hash
sha256sum fireblocks-mpc.md
Legal Disclaimer: This report covers the code submitted for analysis. It does not account for infrastructure, deployment configuration, third-party dependencies, or changes made after the audit date. Automated analysis may produce false positives or miss context-dependent vulnerabilities. audited.xyz provides this report “as is” without warranty of any kind.