






















一、MPC
MPC 全称 Secure Multi-Party Computation(多方安全计算),让多个参与方在「不泄露各自私密数据」的前提下,共同完成计算并得到正确结果,全程数据不共享、不落地、不暴露原始信息。在区块链 / 智能合约开发场景中,MPC 最核心的落地应用是MPC钱包(多方签名),解决了「私钥单点泄露」的致命问题。
官方定义
MPC 是一种密码学协议,允许多个互不信任的参与方,各自持有私密数据,在不向任何第三方(包括其他参与方)泄露自身数据的情况下,协同完成指定计算,最终仅输出计算结果,全程原始数据始终处于加密 / 分片状态。
核心本质:「数据可用不可见,计算协同不共享」
MPC 核心工作原理
MPC 的核心底层是秘密分享(Secret Sharing) + 同态加密 / 混淆电路,以区块链最常用的MPC 签名(如 ECDSA/Ed25519 签名)为例,原理极简拆解:
主流 MPC 签名协议(区块链专用)
区块链 MPC 签名有成熟的标准化协议,目前主流的是:
个人 / 智能合约开发者适用的 MPC 方案
个人 MPC 钱包(直接使用,无需开发)
适合个人管理资产、合约签名,开箱即用:
Coinbase Wallet MPC:Coinbase 推出的 MPC 钱包,支持 EVM/Solana,2-of-3 多签(手机 + 邮箱 + 信任联系人),社交恢复,无硬件,适合新手 / 开发者;
Argent X:以太坊生态主流 MPC 钱包,2-of-2 多签(手机 + guardian),支持合约部署、DApp 交互,Gas 优化;
Safe {Wallet}(原 Gnosis Safe)MPC 版:多签钱包的 MPC 升级,支持 1-of-1 到 N-of-N,适合开发者 / 团队管理合约部署私钥;
Web3Auth MPC:支持社交登录(谷歌 / 邮箱)+ MPC 分片,私钥分片在用户设备 + Web3Auth 节点,易用性极高,适合 DApp 用户。
开发者 MPC SDK(集成到项目 / 脚本)
适合智能合约开发者,将 MPC 签名集成到部署脚本、DApp 中:
Coinbase MPC SDK:开源 SDK,支持 ECDSA/Ed25519,可自定义分片数量,集成到合约部署脚本;
Fireblocks MPC SDK:企业级 MPC SDK,支持多链,适合批量合约部署、资产操作;
FROST SDK:开源 FROST 协议实现,轻量高效,适合个人开发者自定义 MPC 方案;
Web3Auth Core Kit:开源 MPC SDK,支持社交登录 + 分片管理,适合 DApp 前端集成。
开源 MPC 库(自主搭建,极客 / 开发者)
适合想深入研究、自主搭建 MPC 方案的开发者:
mpc-crypto:开源 MPC 密码学库,支持 ECDSA/Ed25519 签名;
frost-ed25519:Ed25519 的 FROST 协议实现,适配区块链签名;
gg20-ecdsa:GG20 协议的 ECDSA 实现,兼容以太坊 / 比特币。
总结:硬件钱包是「离线保险柜」,MPC 钱包是「分布式密码箱」,KMS 是「云保险柜」,三者各有侧重。
二、TSS
是什么?
门限签名(TSS)是一种分布式数字签名方案,核心是将单个私钥拆分成多个密钥分片,由多个参与方分别持有;只有当至少达到指定门限数量(t-of-n) 的参与方协同合作时,才能生成有效签名,单个 / 不足门限数量的参与方无法单独签名,且全程不会出现完整私钥。
TSS 是MPC(多方安全计算)在数字签名领域的核心落地应用(属于 MPC 子集),也是当前区块链、交易所、钱包解决「私钥单点泄露」的主流技术,和传统「链上多签(Multisig)」是完全不同的技术路径。
TSS 遵循t-of-n门限规则:
关键特性(区块链 / 交易所核心价值)
TSS 核心工作原理
以区块链最常用的 ECDSA-secp256k1 TSS(适配以太坊 / 比特币),2-of-3为例
阶段 1:分布式密钥生成(DKG)
阶段 2:分布式签名(链下协同)
阶段 3:链上验证
TSS分类
1)按签名算法分类(区块链主流)
| 算法类型 | 适配场景 | 主流协议 | 代表应用 |
|---|---|---|---|
2)按门限类型分类
固定门限 TSS:t/n 提前设定(如 2-of-3),签名前无法修改,最常用;
动态门限 TSS:可实时调整 t/n(如 2-of-3 → 3-of-5),适合企业级灵活权限控制;
分层门限 TSS:多层门限嵌套(如核心层 3-of-5 + 操作层 2-of-3),交易所大额资产专用。
主流TSS协议
GG18/GG20(最成熟的 ECDSA TSS)
开发者:Goldfeder 等密码学家,2018/2020 年发布;
特点:抗恶意节点、兼容 ECDSA,支持 2-of-n 门限;
应用:Coinbase、Kraken 等交易所,早期 MPC 钱包;
局限:签名需 2-3 轮通信,效率略低。
FROST(新一代轻量 TSS)
全称:Flexible Round-Optimized Schnorr Threshold Signatures;
特点:单轮签名、效率极高、支持 Ed25519/ECDSA,容错性强;
应用:新公链、去中心化交易所、个人 MPC 钱包(如 Argent X);
优势:比 GG20 快 50%+,适合移动端 / 轻量级设备。
MPC-CMP(Fireblocks 自研 TSS)
全称:MPC-Coordinated Multiparty Protocol;
特点:单轮签名、速度提升 800%,支持冷 / 热钱包混合;
应用:Bitfinex、中小交易所、金融机构;
优势:开源免费,适配高频交易场景。
MuSig2(比特币专用 Schnorr TSS)
特点:适配比特币 Taproot,签名结果和单签一致,隐私性极强;
应用:比特币多签钱包、冷存储方案。
TSS 核心应用场景
交易所资产安全(核心场景)
热钱包:采用 2-of-3/3-of-5 TSS,私钥分片在多服务器,防止单点泄露;
冷钱包:离线设备 + 在线服务器 TSS 混合,大额资产离线保护,小额资产 TSS 快速流转;
代表:Binance、Coinbase、Fireblocks 客户均采用 TSS 作为核心安全方案。
个人 / 开发者 MPC 钱包
2-of-3 门限:私钥分片在手机、电脑、云备份,任意 2 个设备即可签名;
无助记词:通过分片恢复,替代传统助记词,避免备份泄露;
代表:Argent X、Coinbase Wallet MPC、Web3Auth。
智能合约开发与部署
合约部署私钥:采用 TSS 分片管理,防止部署私钥泄露导致合约被攻击;
DApp 交互:用户用 TSS 钱包签名,无需暴露私钥,提升 DApp 安全性;
批量签名:TSS 支持批量交易签名,适合合约批量部署 / 调用。
企业级多签管理
团队权限:2-of-3 门限(2 个员工 + 1 个管理员),防止单人操作风险;
审计合规:签名操作全程可追溯,满足金融 / 政务监管要求。
TSS vs 链上多签(Multisig):核心区别(必懂)
这是最易混淆的点,TSS 是链下分布式签名,Multisig 是链上合约多签,二者目标一致(多方授权),但技术路径、成本、兼容性差异极大:
| 对比维度 | TSS(门限签名) | 链上多签(Multisig) | 核心差异 |
|---|---|---|---|
关键结论
个人 / 高频场景:首选 TSS(无 Gas、便捷、兼容所有链);
大额资产 / 强监管场景:可 TSS + Multisig 混合(如交易所热钱包 TSS + 冷钱包 Multisig)。
简单说:链上多签是「合约管权限」,TSS 是「密码学管私钥」,TSS 更安全、更灵活、更适配所有区块链场景。
三、多签(Multisig)
多签(Multisignature)是一种需要多个私钥持有者共同授权才能完成交易 / 操作的安全机制,核心遵循「t-of-n 门限规则」:
多签的核心类型(链上 vs 链下)
区块链多签分两类,核心差异在于「签名验证位置」:
为什么?
链上多签核心工作原理(以太坊 EVM 链举例)
以「2-of-2 多签合约」为例,核心流程:
多签合约示例代码
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/**
* @title Simple2of2Multisig
* @dev 简化版2-of-2链上多签合约,支持ETH转账和合约调用
* 核心功能:提交交易→收集2个签名→执行交易
*/
contract Simple2of2Multisig {
// 授权人地址(2个)
address public immutable owner1;
address public immutable owner2;
// 交易结构体:存储待执行的交易信息
struct Transaction {
address to; // 接收方地址
uint256 value; // 转账ETH金额(wei)
bytes data; // 调用合约的calldata(空则为纯ETH转账)
bool executed; // 是否已执行
uint8 confirmCount; // 已收集的签名数量
}
// 交易ID → 交易信息
mapping(uint256 => Transaction) public transactions;
// 交易ID → 授权人地址 → 是否已签名
mapping(uint256 => mapping(address => bool)) public isConfirmed;
// 交易计数器(生成唯一交易ID)
uint256 public txCount;
// 事件:提交交易
event TransactionSubmitted(uint256 indexed txId, address indexed submitter, address to, uint256 value);
// 事件:确认交易(签名)
event TransactionConfirmed(uint256 indexed txId, address indexed confirmer);
// 事件:执行交易
event TransactionExecuted(uint256 indexed txId, address indexed executor);
// 修饰器:仅授权人可调用
modifier onlyOwner() {
require(msg.sender == owner1 || msg.sender == owner2, "Not an owner");
_;
}
// 修饰器:交易未执行
modifier notExecuted(uint256 txId) {
require(!transactions[txId].executed, "Transaction already executed");
_;
}
// 构造函数:初始化2个授权人
constructor(address _owner1, address _owner2) {
require(_owner1 != address(0) && _owner2 != address(0) && _owner1 != _owner2, "Invalid owners");
owner1 = _owner1;
owner2 = _owner2;
}
/**
* @dev 提交交易(任意授权人可提交)
* @param _to 接收方地址
* @param _value 转账ETH金额(wei)
* @param _data 合约调用数据(空则为纯ETH转账)
* @return txId 生成的交易ID
*/
function submitTransaction(
address _to,
uint256 _value,
bytes calldata _data
) external onlyOwner returns (uint256 txId) {
require(_to != address(0), "Invalid to address");
txId = txCount;
transactions[txId] = Transaction({
to: _to,
value: _value,
data: _data,
executed: false,
confirmCount: 0
});
txCount++;
emit TransactionSubmitted(txId, msg.sender, _to, _value);
}
/**
* @dev 确认交易(签名,任意授权人可确认)
* @param txId 交易ID
*/
function confirmTransaction(uint256 txId) external onlyOwner notExecuted(txId) {
Transaction storage txn = transactions[txId];
require(!isConfirmed[txId][msg.sender], "Already confirmed");
isConfirmed[txId][msg.sender] = true;
txn.confirmCount++;
emit TransactionConfirmed(txId, msg.sender);
}
/**
* @dev 执行交易(需收集2个签名,任意授权人可执行)
* @param txId 交易ID
*/
function executeTransaction(uint256 txId) external onlyOwner notExecuted(txId) {
Transaction storage txn = transactions[txId];
// 验证签名数量≥2(2-of-2门限)
require(txn.confirmCount >= 2, "Not enough confirmations");
// 标记交易已执行
txn.executed = true;
// 执行交易:转账ETH或调用合约
(bool success, ) = txn.to.call{value: txn.value}(txn.data);
require(success, "Transaction execution failed");
emit TransactionExecuted(txId, msg.sender);
}
/**
* @dev 接收ETH(合约可存储ETH)
*/
receive() external payable {}
}
步骤 1:部署合约
输入2个授权人地址(如 Owner1: 0xAAA...,Owner2: 0xBBB...);
部署合约(执行Constructor初始化合约 校验授权人地址合法性,存储 2 个授权人),记录合约地址(如 0xCCC...);
步骤 2:提交交易
用Owner1的地址调用submitTransaction,提交交易,生成交易ID,存储交易信息,触发提交事件;
记录返回的txId(如 0);
步骤 3:确认交易(收集签名)
confirmTransaction 确认交易(签名) 校验授权人身份→校验未重复签名→增加签名数→触发确认事件
用 Owner1 的地址调用confirmTransaction(0)(第一个签名);
用 Owner2 的地址调用confirmTransaction(0)(第二个签名,达到 2-of-2 门限)。
步骤 4:执行交易
用任意授权人(如 Owner1)调用executeTransaction(0)执行交易;
查看区块链浏览器:合约向 0xDDD... 转账 0.005 ETH,交易执行成功。
四、时间锁(Timelock)核心定义
是什么?
时间锁是区块链 / 智能合约中强制延迟执行操作的安全机制,核心逻辑是:当用户提交一笔操作(如转账、合约升级、多签交易)后,必须等待预设的延迟时间(如 24 小时),且当前区块时间超过该延迟时间阈值时,操作才能被执行;未到时间则无法执行。
本质是给关键操作增加「冷却期 / 反悔期」,防止恶意操作、误操作或内部攻击,是智能合约安全的核心组件(尤其适配多签、DAO、合约升级场景)。
关键术语
时间锁的核心作用
基础时间锁合约示例
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/**
* @title GenericTimelock
* @dev 通用型相对时间锁合约
* 核心逻辑:提交操作→等待delay秒→执行操作(支持ETH转账/合约调用)
*/
contract GenericTimelock {
// 管理员:有权提交/执行/撤销操作(生产环境可替换为多签地址)
address public immutable admin;
// 延迟时间(秒):提交后需等待该时间才能执行
uint256 public immutable delay;
// 操作结构体:存储待执行的操作信息
struct Operation {
address to; // 接收方地址
uint256 value; // 转账ETH金额(wei)
bytes data; // 合约调用calldata
uint256 proposalTime;// 提交时间(区块时间)
bool executed; // 是否已执行
bool canceled; // 是否已撤销
}
// 操作ID → 操作信息(操作ID=keccak256(操作关键参数),避免重复)
mapping(bytes32 => Operation) public operations;
// 事件:提交操作
event OperationProposed(bytes32 indexed opId, address indexed proposer, address to, uint256 value);
// 事件:执行操作
event OperationExecuted(bytes32 indexed opId, address indexed executor);
// 事件:撤销操作
event OperationCanceled(bytes32 indexed opId, address indexed canceler);
// 修饰器:仅管理员可调用
modifier onlyAdmin() {
require(msg.sender == admin, "Not admin");
_;
}
// 修饰器:操作未执行且未撤销
modifier validOperation(bytes32 opId) {
Operation storage op = operations[opId];
require(op.proposalTime > 0, "Operation does not exist");
require(!op.executed, "Operation already executed");
require(!op.canceled, "Operation canceled");
_;
}
// 修饰器:操作已到可执行时间
modifier timeLockPassed(bytes32 opId) {
Operation storage op = operations[opId];
require(block.timestamp >= op.proposalTime + delay, "Time lock not passed");
_;
}
/**
* @dev 构造函数
* @param _admin 管理员地址(生产环境建议设为多签合约地址)
* @param _delay 延迟时间(秒),建议≥86400(24小时)
*/
constructor(address _admin, uint256 _delay) {
require(_admin != address(0), "Invalid admin");
require(_delay > 0, "Delay must be > 0");
admin = _admin;
delay = _delay;
}
/**
* @dev 生成操作ID(唯一标识,防止重复提交)
* @param to 接收方
* @param value 转账金额
* @param data 调用数据
* @return opId 操作ID
*/
function getOperationId(
address to,
uint256 value,
bytes calldata data
) public pure returns (bytes32 opId) {
opId = keccak256(abi.encodePacked(to, value, data));
}
/**
* @dev 提交操作(提案)
* @param to 接收方地址
* @param value 转账ETH金额
* @param data 合约调用数据(空则为纯ETH转账)
* @return opId 操作ID
*/
function proposeOperation(
address to,
uint256 value,
bytes calldata data
) external onlyAdmin returns (bytes32 opId) {
require(to != address(0), "Invalid to address");
opId = getOperationId(to, value, data);
require(operations[opId].proposalTime == 0, "Operation already proposed");
operations[opId] = Operation({
to: to,
value: value,
data: data,
proposalTime: block.timestamp,
executed: false,
canceled: false
});
emit OperationProposed(opId, msg.sender, to, value);
return opId;
}
/**
* @dev 执行操作(需等待时间锁到期)
* @param to 接收方地址(需与提交时一致)
* @param value 转账金额(需与提交时一致)
* @param data 调用数据(需与提交时一致)
*/
function executeOperation(
address to,
uint256 value,
bytes calldata data
) external onlyAdmin validOperation(getOperationId(to, value, data)) timeLockPassed(getOperationId(to, value, data)) {
bytes32 opId = getOperationId(to, value, data);
Operation storage op = operations[opId];
// 标记操作已执行
op.executed = true;
// 执行转账/合约调用
(bool success, ) = op.to.call{value: op.value}(op.data);
require(success, "Operation execution failed");
emit OperationExecuted(opId, msg.sender);
}
/**
* @dev 撤销操作(仅未执行/未到期时可撤销)
* @param to 接收方地址
* @param value 转账金额
* @param data 调用数据
*/
function cancelOperation(
address to,
uint256 value,
bytes calldata data
) external onlyAdmin validOperation(getOperationId(to, value, data)) {
bytes32 opId = getOperationId(to, value, data);
operations[opId].canceled = true;
emit OperationCanceled(opId, msg.sender);
}
/**
* @dev 接收ETH(合约可存储ETH)
*/
receive() external payable {}
}
调用流程
多签 + 时间锁整合合约(生产级核心场景)
多签合约仅解决 “多人授权”,但缺少 “反悔期”;时间锁仅解决 “延迟执行”,但缺少 “多人授权”—— 二者结合是生产环境资产安全的黄金组合(如 Gnosis Safe 的时间锁模块)。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/**
* @title MultisigWithTimelock
* @dev 2-of-2多签 + 时间锁整合合约
* 核心流程:提交交易→收集2个签名→等待delay秒→执行交易
*/
contract MultisigWithTimelock {
// 多签授权人
address public immutable owner1;
address public immutable owner2;
// 时间锁延迟(秒)
uint256 public immutable delay;
// 交易结构体:整合多签+时间锁
struct Transaction {
address to;
uint256 value;
bytes data;
uint256 proposalTime; // 提交时间(时间锁起点)
bool executed;
bool canceled;
uint8 confirmCount; // 多签签名数
}
mapping(uint256 => Transaction) public transactions;
mapping(uint256 => mapping(address => bool)) public isConfirmed;
uint256 public txCount;
// 事件
event TransactionProposed(uint256 indexed txId, address indexed proposer);
event TransactionConfirmed(uint256 indexed txId, address indexed confirmer);
event TransactionExecuted(uint256 indexed txId, address indexed executor);
event TransactionCanceled(uint256 indexed txId, address indexed canceler);
// 修饰器:仅授权人
modifier onlyOwner() {
require(msg.sender == owner1 || msg.sender == owner2, "Not owner");
_;
}
// 修饰器:交易有效(未执行/未撤销)
modifier validTx(uint256 txId) {
Transaction storage txn = transactions[txId];
require(txn.proposalTime > 0, "Tx does not exist");
require(!txn.executed, "Tx executed");
require(!txn.canceled, "Tx canceled");
_;
}
// 修饰器:时间锁到期
modifier timelockPassed(uint256 txId) {
Transaction storage txn = transactions[txId];
require(block.timestamp >= txn.proposalTime + delay, "Timelock not passed");
_;
}
// 修饰器:多签签名数≥2
modifier enoughConfirmations(uint256 txId) {
require(transactions[txId].confirmCount >= 2, "Not enough confirmations");
_;
}
constructor(address _owner1, address _owner2, uint256 _delay) {
require(_owner1 != _owner2 && _owner1 != address(0), "Invalid owners");
require(_delay > 0, "Delay > 0");
owner1 = _owner1;
owner2 = _owner2;
delay = _delay;
}
/**
* @dev 提交交易(多签授权人提交,启动时间锁)
*/
function proposeTx(address to, uint256 value, bytes calldata data) external onlyOwner returns (uint256 txId) {
require(to != address(0), "Invalid to");
txId = txCount;
transactions[txId] = Transaction({
to: to,
value: value,
data: data,
proposalTime: block.timestamp,
executed: false,
canceled: false,
confirmCount: 0
});
txCount++;
emit TransactionProposed(txId, msg.sender);
}
/**
* @dev 确认交易(多签签名)
*/
function confirmTx(uint256 txId) external onlyOwner validTx(txId) {
Transaction storage txn = transactions[txId];
require(!isConfirmed[txId][msg.sender], "Already confirmed");
isConfirmed[txId][msg.sender] = true;
txn.confirmCount++;
emit TransactionConfirmed(txId, msg.sender);
}
/**
* @dev 执行交易(需:2个签名+时间锁到期)
*/
function executeTx(uint256 txId) external onlyOwner validTx(txId) enoughConfirmations(txId) timelockPassed(txId) {
Transaction storage txn = transactions[txId];
txn.executed = true;
(bool success, ) = txn.to.call{value: txn.value}(txn.data);
require(success, "Tx failed");
emit TransactionExecuted(txId, msg.sender);
}
/**
* @dev 撤销交易(仅未执行/未到期时)
*/
function cancelTx(uint256 txId) external onlyOwner validTx(txId) {
transactions[txId].canceled = true;
emit TransactionCanceled(txId, msg.sender);
}
receive() external payable {}
}
学习技术不是用来写HelloWorld和Demo的,而是要用来解决线上系统的真实问题的.
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。