多签钱包、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,转载请注明原文链接:https://www.cnblogs.com/ffffox/p/19001212

浙公网安备 33010602011771号