多簽錢包、MPC錢包及混合方案
多簽錢包、MPC錢包及混合方案詳解
一、多簽錢包和MPC錢包的區別
| 特性 | 多簽錢包 | MPC錢包 |
|---|---|---|
| 私鑰管理 | 每個參與者持有完整私鑰分片,共m個私鑰 | 私鑰通過密碼學算法拆分為n個碎片,無完整私鑰存在 |
| 簽名機制 | 需收集至少k個完整簽名,在鏈上驗證 | 鏈下聚合部分簽名,生成一個有效簽名提交鏈上 |
| 安全性 | 依賴參與者誠實性,單點泄露有風險 | 抗合謀攻擊,單點泄露不影響整體安全 |
| 鏈上記錄 | 所有簽名公開可見,透明度高 | 僅顯示最終簽名,隱私性好 |
| 效率 | 多次鏈上交互,Gas費高 | 一次鏈上提交,效率高 |
| 兼容性 | 依賴鏈上多簽腳本或合約 | 兼容所有支持標準簽名的區塊鏈 |
二、多簽+MPC混合方案
混合方案結合了兩者優勢:使用MPC技術生成和管理私鑰碎片,同時采用多簽機制控制簽名閾值,實現"分布式密鑰生成+多方授權驗證"的雙重安全。
核心設計思路
- 采用MPC技術生成私鑰碎片,避免完整私鑰存在
- 設置多簽閾值控制(如3-of-5),需足夠多參與方共同簽名
- 鏈下聚合簽名,鏈上驗證簽名有效性和閾值達標情況
以下是“多簽+MPC混合方案”的具體實現代碼,包含鏈下MPC簽名模塊和鏈上多簽驗證合約,核心邏輯是:通過MPC生成分布式簽名,再通過多簽合約驗證簽名是否符合閾值要求。
1、鏈下MPC簽名模塊(Python實現門限簽名)
基于Shamir秘密共享和ECDSA門限簽名,實現私鑰分片生成與簽名聚合(模擬MPC核心邏輯)。
import random
import hashlib
from typing import List, Tuple
from ecdsa import SigningKey, VerifyingKey, NIST256p
from ecdsa.util import number_to_string, string_to_number
# 橢圓曲線參數(兼容以太坊secp256k1,此處簡化用NIST256p)
curve = NIST256p
generator = curve.generator
order = curve.order
class MPCThresholdSign:
def __init__(self, threshold: int, num_parties: int):
self.threshold = threshold # 簽名閾值(如3-of-5)
self.num_parties = num_parties # 參與方數量
self.private_shares = [] # 私鑰分片
self.public_keys = [] # 各參與方的公鑰(用于驗證部分簽名)
def generate_keys(self) -> None:
"""生成MPC私鑰分片和對應公鑰"""
# 生成隨機多項式(k-1次)
coefficients = [random.randint(1, order-1) for _ in range(self.threshold)]
# 私鑰分片 = 多項式在x=1..n處的取值
for x in range(1, self.num_parties+1):
share = 0
for i in range(self.threshold):
share += coefficients[i] * (x ** i)
share %= order
self.private_shares.append(share)
# 計算對應公鑰(用于驗證部分簽名)
for share in self.private_shares:
pub_key = (share * generator).to_string()
self.public_keys.append(pub_key)
def partial_sign(self, share_idx: int, message: bytes) -> Tuple[int, int]:
"""生成部分簽名(每個參與方用自己的分片簽名)"""
if share_idx < 0 or share_idx >= self.num_parties:
raise ValueError("無效的參與方索引")
sk = self.private_shares[share_idx]
# 計算消息哈希
hash_msg = hashlib.sha256(message).digest()
hash_int = int.from_bytes(hash_msg, byteorder='big') % order
# ECDSA部分簽名(簡化版)
k = random.randint(1, order-1) # 隨機數
r = (k * generator).x() % order # 簽名r值
s = (pow(k, -1, order) * (hash_int + sk * r)) % order # 部分簽名s值
return (r, s)
def aggregate_signatures(self, partial_sigs: List[Tuple[int, int]]) -> Tuple[int, int]:
"""聚合部分簽名為完整ECDSA簽名(需滿足閾值)"""
if len(partial_sigs) < self.threshold:
raise ValueError(f"需要至少{self.threshold}個部分簽名")
# 拉格朗日插值聚合s值(簡化邏輯)
r = partial_sigs[0][0] # 假設所有r值相同(實際需驗證)
s_total = 0
for i in range(len(partial_sigs)):
x_i = i + 1 # 參與方索引(1-based)
# 拉格朗日系數
lagrange = 1
for j in range(len(partial_sigs)):
if i != j:
x_j = j + 1
lagrange *= (0 - x_j) * pow(x_i - x_j, -1, order)
lagrange %= order
s_total += partial_sigs[i][1] * lagrange
s_total %= order
return (r, s_total)
2、鏈上多簽驗證合約(Solidity實現)
合約負責驗證MPC生成的簽名是否符合多簽閾值,并執行交易。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
/**
* @title MultiSigMPC
* @dev 多簽+MPC混合方案:鏈上驗證MPC生成的簽名是否符合多簽閾值
*/
contract MultiSigMPC is ReentrancyGuard {
using ECDSA for bytes32;
address[] public signers; // MPC參與方地址(公鑰哈希)
uint256 public threshold; // 簽名閾值(如3-of-5)
mapping(bytes32 => uint256) public signatureCount; // 交易哈希→已簽名次數
event TransactionProposed(bytes32 indexed txHash, address proposer, address to, uint256 value, bytes data);
event TransactionSigned(bytes32 indexed txHash, address signer, uint256 count);
event TransactionExecuted(bytes32 indexed txHash, address executor);
/**
* @param _signers MPC參與方地址列表
* @param _threshold 簽名閾值(需≤參與方數量)
*/
constructor(address[] memory _signers, uint256 _threshold) {
require(_signers.length > 0, "至少需要1個參與方");
require(_threshold > 0 && _threshold <= _signers.length, "無效閾值");
signers = _signers;
threshold = _threshold;
}
/**
* @dev 檢查地址是否為MPC參與方
*/
function isSigner(address _addr) public view returns (bool) {
for (uint256 i = 0; i < signers.length; i++) {
if (signers[i] == _addr) return true;
}
return false;
}
/**
* @dev 提交MPC生成的簽名,累計簽名次數
* @param to 接收地址
* @param value 轉賬金額
* @param data 附加數據
* @param r ECDSA簽名r值
* @param s ECDSA簽名s值
*/
function signTransaction(
address to,
uint256 value,
bytes calldata data,
uint256 r,
uint256 s
) external nonReentrant {
require(isSigner(msg.sender), "不是授權參與方");
// 計算交易哈希(用于去重和計數)
bytes32 txHash = keccak256(abi.encodePacked(to, value, data, block.chainid));
// 驗證簽名是否由msg.sender的MPC分片生成(核心:關聯MPC公鑰與地址)
bytes32 messageHash = txHash.toEthSignedMessageHash();
address signer = messageHash.recover(uint256(r), uint256(s));
require(signer == msg.sender, "簽名無效(與參與方地址不匹配)");
// 累計簽名次數
signatureCount[txHash]++;
emit TransactionSigned(txHash, msg.sender, signatureCount[txHash]);
}
/**
* @dev 當簽名次數達標時,執行交易
*/
function executeTransaction(
address to,
uint256 value,
bytes calldata data,
uint256 r,
uint256 s
) external nonReentrant returns (bool) {
bytes32 txHash = keccak256(abi.encodePacked(to, value, data, block.chainid));
require(signatureCount[txHash] >= threshold, "簽名次數未達標");
// 再次驗證聚合簽名有效性(最終確認)
bytes32 messageHash = txHash.toEthSignedMessageHash();
address aggSigner = messageHash.recover(uint256(r), uint256(s));
// 聚合簽名需對應MPC公鑰(此處簡化為檢查是否為參與方之一)
require(isSigner(aggSigner), "聚合簽名無效");
// 執行交易
(bool success, ) = to.call{value: value}(data);
require(success, "交易執行失敗");
emit TransactionExecuted(txHash, msg.sender);
return success;
}
// 接收ETH
receive() external payable {}
}
3、混合方案工作流程(使用示例)
# 1. 初始化MPC門限簽名(3-of-5方案)
mpc = MPCThresholdSign(threshold=3, num_parties=5)
mpc.generate_keys()
print("MPC參與方公鑰:", [pk.hex()[:10]+"..." for pk in mpc.public_keys])
# 2. 生成交易數據
message = b"transfer 1 ETH to 0x742d35Cc6634C0532925a3b844Bc454e4438f44e"
# 3. MPC參與方生成部分簽名(模擬3個參與方簽名)
partial_sigs = []
for i in [0, 2, 4]: # 選擇3個參與方
sig = mpc.partial_sign(share_idx=i, message=message)
partial_sigs.append(sig)
print(f"參與方{i}的部分簽名: (r={sig[0]}, s={sig[1]})")
# 4. 聚合部分簽名為完整簽名
agg_sig = mpc.aggregate_signatures(partial_sigs)
print("聚合后的完整簽名: (r={}, s={})".format(agg_sig[0], agg_sig[1]))
# 5. 鏈上多簽合約驗證與執行(模擬)
"""
Solidity合約部署后,執行流程:
1. 3個MPC參與方分別調用signTransaction,提交簽名
2. 當簽名計數≥3時,調用executeTransaction執行轉賬
3. 合約驗證簽名有效性和參與方權限,最終完成交易
"""
4、核心邏輯說明
-
鏈下MPC模塊:
- 通過Shamir秘密共享生成5個私鑰分片,每個參與方持有1個。
- 交易簽名時,至少3個參與方生成部分簽名,通過拉格朗日插值聚合為完整ECDSA簽名(符合區塊鏈標準)。
-
鏈上多簽合約:
- 維護授權參與方列表和簽名閾值(3-of-5)。
- 參與方提交簽名后,合約累計計數,達到閾值后允許執行交易。
- 關鍵驗證:確保簽名來自授權參與方,防止未授權簽名。
-
混合優勢:
- MPC確保私鑰不落地(無單點泄露風險),多簽合約確保簽名符合閾值(防少數人濫用)。
- 簽名在鏈下聚合(高效),驗證在鏈上完成(透明可審計)。
該方案兼顧了MPC的分布式安全和多簽的鏈上可控性,適合機構級資產托管(如交易所冷錢包、DAO國庫)等高頻次、高安全性需求場景。實際生產環境中需補充密碼學安全細節(如防重放攻擊、隨機數安全生成)和合約審計。
三、混合方案工作流程解析
graph TD
%% 初始化階段
A["開始"] --> B["創建混合方案配置(設置3-of-5門限)"]
B --> C["MPC分布式密鑰生成\n? 生成隨機多項式\n? 拆分私鑰為5個碎片"]
C --> D["分發生成:\n? 5個私鑰碎片(分發給參與方)\n? 群組公鑰(鏈上可見)\n? 分片公鑰(驗證用)"]
%% 簽名生成階段
D --> E["發起交易(含轉賬信息、接收地址)"]
E --> F["參與方生成部分簽名\n? 基于各自私鑰碎片\n? 輸出部分簽名(r_i,s_i)"]
%% 簽名聚合階段
F --> G{"收集到≥3個部分簽名?"}
G -->|否| H["等待更多簽名"]
G -->|是| I["MPC簽名聚合\n? 拉格朗日插值法\n? 聚合為完整簽名(R,S)"]
%% 多簽驗證階段
I --> J["多簽合約驗證\n1. 檢查簽名計數≥3\n2. 驗證聚合簽名與群組公鑰匹配"]
J --> K{"驗證通過?"}
K -->|否| L["交易駁回"]
K -->|是| M["執行交易(資產轉移完成)"]
-
初始化階段
- 創建門限簽名器,設置參數(如3-of-5,表示5個參與方中至少需要3個簽名)
- 生成私鑰分片:使用Shamir秘密共享算法,將私鑰拆分為5個分片,每個參與方持有一個
- 計算公鑰:每個分片對應一個公鑰,同時生成群組公鑰(等同于完整私鑰對應的公鑰)
-
簽名階段
- 交易發起后,參與方使用自己的私鑰分片生成部分簽名
- 部分簽名包含r和s值,僅使用分片信息,不涉及完整私鑰
-
聚合階段
- 收集至少3個部分簽名
- 使用拉格朗日插值算法聚合部分簽名,生成完整有效的簽名
- 聚合過程不需要恢復完整私鑰,直接通過數學運算組合
-
驗證階段
- 多簽驗證器檢查簽名數量是否達到閾值
- 驗證聚合簽名是否有效(使用群組公鑰)
- 驗證通過后執行交易
四、混合方案的優勢與應用場景
優勢
- 安全性增強:MPC防止完整私鑰泄露,多簽機制防止單點濫用
- 靈活性高:可動態調整參與方和閾值,適應不同場景需求
- 兼容性好:生成的簽名與標準簽名格式兼容,可在任何支持ECDSA的區塊鏈上使用
- 可審計性:多簽機制保留簽名記錄,滿足合規審計需求
應用場景
- 機構資產托管:交易所冷錢包、銀行數字資產儲備
- DAO國庫管理:集體決策管理組織資金
- 跨境支付:多方授權的大額跨境轉賬
- 高安全要求場景:醫療數據加密、政務系統密鑰管理
混合方案結合了MPC的分布式密鑰安全和多簽的權限控制優勢,是目前高價值數字資產管理的最佳實踐之一。
本文來自博客園,作者:ffffox,轉載請注明原文鏈接:http://www.rzrgm.cn/ffffox/p/19001212

浙公網安備 33010602011771號