MPCium is a highly resilient, secure MPC engine

Mpcium is a high-performance framework written in Go that implements secure distributed threshold signature schemes using Multi-Party Computation (MPC). Unlike traditional cryptographic systems that store private keys in a single location, Mpcium distributes private key fragments across multiple independent nodes, requiring cooperation from a threshold number of these nodes to perform cryptographic operations like transaction signing.

This architecture provides:

  • Enhanced Security: No single point of compromise
  • Distributed Trust: No need to trust any single entity
  • Fault Tolerance: System remains operational even if some nodes fail
  • Privacy Preservation: No single node possesses the complete key

At its cryptographic core, Mpcium integrates tss-lib, a production-grade threshold signature scheme library developed by Binance. It supports:

  • ECDSA (secp256k1): Bitcoin, Ethereum, BNB, Polygon, and EVM-compatible L2 chains

  • EdDSA (Ed25519): for Solana, Polkadot, Cardano, and other modern blockchains

Archtecture documentation

MPCIUM img

👉 Detailed Architecture Document

Threshold & Nodes

Mpcium uses a t-of-n threshold scheme to securely generate and sign with private keys.

  • n = total number of MPC nodes (key shares)
  • t = minimum number of nodes required to sign

Only t out of n nodes need to participate — the full private key is never reconstructed.

To maintain security against compromised nodes, Mpcium enforces:

t ≥ ⌊n / 2⌋ + 1

Example: 2-of-3 Threshold

  • node0 + node1 → signs successfully
  • node1 + node2 → signs successfully
  • node0 alone → not enough shares

This ensures:

  • No single point of compromise
  • Fault tolerance if some nodes go offline
  • Configurable security by adjusting t and n

Architecture

Overview

Each Mpcium node:

  • Holds a key share in local AES-256 encrypted storage (via Badger KV)
  • Participates in threshold signing using tss-lib
  • Communicates over a resilient messaging layer using NATS
  • Registers itself with Consul for service discovery and health checks
  • Verifies incoming messages using Ed25519-based mutual authentication

Message Flow & Signature Verification

  1. A signing request is broadcast to the MPC cluster through NATS as an authenticated event. Each node verifies the sender's Ed25519 signature before processing the request.
  2. NATS broadcasts the request to the MPC nodes.
  3. Each participating node verifies:
    • The signature of the sender (Ed25519)
    • The authenticity of the message (non-replayable, unique session)
  4. If the node is healthy and within the quorum (t), it:
    • Computes a partial signature using its share
    • Publishes the result back via NATS
  5. Once t partial signatures are received, they are aggregated into a full signature.

Properties

  • No single point of compromise: Keys are never fully assembled
  • Byzantine-resilient: Only t of n nodes are required to proceed
  • Scalable and pluggable: Easily expand the cluster or integrate additional tools
  • Secure peer authentication: All inter-node messages are signed and verified using Ed25519

Installation and Run

Preview usage

Start nodes

$ mpcium start -n node0
$ mpcium start -n node1
$ mpcium start -n node2

Client Implementations

Client


import (
    "github.com/fystack/mpcium/client"
    "github.com/nats-io/nats.go"
)


func main () {
	natsConn, err := nats.Connect(natsURL)
	if err != nil {
		logger.Fatal("Failed to connect to NATS", err)
	}
	defer natsConn.Close()
	mpcClient := client.NewMPCClient(client.Options{
		NatsConn: natsConn,
		KeyPath:  "./event_initiator.key",
	})
	err = mpcClient.OnWalletCreationResult(func(event mpc.KeygenSuccessEvent) {
		logger.Info("Received wallet creation result", "event", event)
	})
	if err != nil {
		logger.Fatal("Failed to subscribe to wallet-creation results", err)
	}

	walletID := uuid.New().String()
	if err := mpcClient.CreateWallet(walletID); err != nil {
		logger.Fatal("CreateWallet failed", err)
	}
	logger.Info("CreateWallet sent, awaiting result...", "walletID", walletID)
}