1140 lines
35 KiB
Markdown
Executable File
1140 lines
35 KiB
Markdown
Executable File
# MPC-System 集成指南
|
||
|
||
> **面向后端服务开发者**: 如何与 MPC 分布式签名系统集成,发起密钥生成和签名会话
|
||
|
||
---
|
||
|
||
## 📚 目录
|
||
|
||
1. [系统架构理解](#1-系统架构理解)
|
||
2. [服务职责说明](#2-服务职责说明)
|
||
3. [标准 MPC 会话类型](#3-标准-mpc-会话类型)
|
||
4. [集成方式](#4-集成方式)
|
||
5. [完整示例代码](#5-完整示例代码)
|
||
6. [故障排查](#6-故障排查)
|
||
|
||
---
|
||
|
||
## 1. 系统架构理解
|
||
|
||
### 1.1 为什么需要这些服务?
|
||
|
||
MPC-System 实现了一个**真正的分布式多方计算系统**,遵循以下核心原则:
|
||
|
||
```
|
||
核心设计理念:
|
||
├── 私钥永不完整存在于任何单点
|
||
├── 所有参与方地位对等 (无主从关系)
|
||
├── Coordinator 只协调流程,不参与计算
|
||
└── 密钥分片物理隔离存储
|
||
```
|
||
|
||
### 1.2 架构层次图
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ 业务层 (您的服务) │
|
||
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
|
||
│ │ API Gateway │ │ MPC Service │ │ Wallet App │ │
|
||
│ │ │ │ │ │ (前端) │ │
|
||
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
|
||
│ │ │ │ │
|
||
│ └────────────────┼────────────────┘ │
|
||
│ ▼ │
|
||
└──────────────────────────┼──────────────────────────────────────┘
|
||
│
|
||
┌─────────────────┼─────────────────┐
|
||
│ MPC-System 边界 (独立部署) │
|
||
│ ▼ │
|
||
┌────────┴─────────────────────────────────────────────────────┐
|
||
│ Account Service (入口层) │
|
||
│ 端口: 4000 │
|
||
│ 职责: ❶ 统一入口 ❷ 账户管理 ❸ 认证授权 ❹ 业务编排 │
|
||
│ API: POST /api/v1/mpc/keygen │
|
||
│ POST /api/v1/mpc/sign │
|
||
└──────────────────────┬───────────────────────────────────────┘
|
||
│
|
||
┌─────────────┼─────────────────┐
|
||
│ ▼ │
|
||
┌────────┴──────────────────────────────┴──────────────────────┐
|
||
│ 协调层 (不参与 MPC 计算) │
|
||
│ │
|
||
│ ┌───────────────────────┐ ┌───────────────────────┐ │
|
||
│ │ Session Coordinator │ │ Message Router │ │
|
||
│ │ 端口: 8081/50051 │◄──►│ 端口: 8082/50051 │ │
|
||
│ ├───────────────────────┤ ├───────────────────────┤ │
|
||
│ │ ✓ 会话生命周期管理 │ │ ✓ P2P 消息路由 │ │
|
||
│ │ ✓ 参与方注册与认证 │ │ ✓ gRPC Stream 推送 │ │
|
||
│ │ ✓ 状态机控制 │ │ ✓ 消息持久化 │ │
|
||
│ │ ✓ 超时保护 │ │ ✓ 离线消息缓存 │ │
|
||
│ │ │ │ │ │
|
||
│ │ ✗ 不参与 MPC 计算 │ │ ✗ 不解密 MPC 消息 │ │
|
||
│ │ ✗ 不存储密钥分片 │ │ ✗ 不参与 MPC 计算 │ │
|
||
│ └───────────────────────┘ └───────────────────────┘ │
|
||
└───────────────────────────────────────────────────────────────┘
|
||
│
|
||
┌─────────────┼─────────────────┐
|
||
│ ▼ │
|
||
┌────────┴──────────────────────────────┴──────────────────────┐
|
||
│ MPC 计算层 (真正执行 TSS 协议的参与方) │
|
||
│ │
|
||
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
||
│ │ Server Party │ │ Server Party │ │ Server Party │ │
|
||
│ │ 1 │ │ 2 │ │ 3 │ │
|
||
│ │ (50051) │ │ (50051) │ │ (50051) │ │
|
||
│ ├──────────────┤ ├──────────────┤ ├──────────────┤ │
|
||
│ │ ✓ 运行 tss-lib│ │ ✓ 运行 tss-lib│ │ ✓ 运行 tss-lib│ │
|
||
│ │ ✓ 存储加密分片│ │ ✓ 存储加密分片│ │ ✓ 存储加密分片│ │
|
||
│ │ ✓ 参与 TSS │ │ ✓ 参与 TSS │ │ ✓ 参与 TSS │ │
|
||
│ └──────────────┘ └──────────────┘ └──────────────┘ │
|
||
│ │
|
||
│ ┌──────────────────────────────────────────────────┐ │
|
||
│ │ Server Party API (无状态) │ │
|
||
│ │ 端口: 8083 │ │
|
||
│ │ ✓ 为用户设备动态生成密钥分片 │ │
|
||
│ │ ✓ 不存储用户分片(返回给调用方) │ │
|
||
│ └──────────────────────────────────────────────────┘ │
|
||
└───────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## 2. 服务职责说明
|
||
|
||
### 2.1 Account Service - 为什么需要它?
|
||
|
||
**核心职责**: MPC 系统的**统一业务入口**
|
||
|
||
#### 存在的原因:
|
||
|
||
1. **业务语义转换**
|
||
- 外部: "创建钱包账户" → 内部: "发起 2-of-3 keygen 会话 + 3 个参与方"
|
||
- 外部: "交易签名" → 内部: "发起 sign 会话 + 加载账户分片"
|
||
|
||
2. **账户生命周期管理**
|
||
- 账户创建/激活/暂停/恢复
|
||
- 密钥分片元数据存储 (不是分片本身)
|
||
- 账户恢复流程编排
|
||
|
||
3. **认证授权**
|
||
- 用户登录验证
|
||
- API 密钥认证
|
||
- JWT 令牌管理
|
||
|
||
4. **业务编排**
|
||
- 协调 Session Coordinator 创建会话
|
||
- 协调 Server Parties 参与 TSS
|
||
- 聚合结果并持久化
|
||
|
||
#### 典型数据存储 (PostgreSQL):
|
||
```sql
|
||
-- 账户表 (不存储私钥!)
|
||
CREATE TABLE accounts (
|
||
id UUID PRIMARY KEY,
|
||
username VARCHAR(255) UNIQUE NOT NULL,
|
||
email VARCHAR(255) UNIQUE NOT NULL,
|
||
public_key BYTEA NOT NULL, -- 群公钥
|
||
threshold_n INT NOT NULL, -- 总参与方数
|
||
threshold_t INT NOT NULL, -- 签名阈值
|
||
status VARCHAR(50) NOT NULL,
|
||
created_at TIMESTAMP NOT NULL
|
||
);
|
||
|
||
-- 分片元数据表 (存储分片在哪,但不存储分片内容)
|
||
CREATE TABLE account_shares (
|
||
id UUID PRIMARY KEY,
|
||
account_id UUID REFERENCES accounts(id),
|
||
share_type VARCHAR(50) NOT NULL, -- user_device / server / recovery
|
||
party_id VARCHAR(255) NOT NULL,
|
||
party_index INT NOT NULL,
|
||
device_type VARCHAR(50), -- android / ios / server
|
||
storage_location VARCHAR(255), -- 分片存储位置标识
|
||
is_active BOOLEAN DEFAULT true,
|
||
created_at TIMESTAMP NOT NULL
|
||
);
|
||
```
|
||
|
||
**关键点**: Account Service 只知道"分片存在于哪里",而不存储实际的加密分片内容。
|
||
|
||
---
|
||
|
||
### 2.2 Session Coordinator - 会话协调器
|
||
|
||
**核心职责**: MPC 会话的**生命周期管理器** (但不参与计算)
|
||
|
||
#### 主要功能:
|
||
|
||
```go
|
||
// 会话状态机
|
||
created → waiting → in_progress → completed/failed/expired
|
||
```
|
||
|
||
1. **会话创建**
|
||
- 生成 session_id
|
||
- 为每个参与方生成 join_token (JWT)
|
||
- 记录会话元数据
|
||
|
||
2. **参与方管理**
|
||
- 验证参与方身份 (join_token)
|
||
- 追踪参与方状态: invited → joined → ready → computing → completed
|
||
- 控制参与方数量限制
|
||
|
||
3. **会话编排**
|
||
- 等待所有参与方就绪
|
||
- 触发 TSS 协议启动
|
||
- 收集完成状态
|
||
|
||
4. **超时保护**
|
||
- 会话过期自动清理
|
||
- 防止僵尸会话占用资源
|
||
|
||
#### 典型数据存储:
|
||
```sql
|
||
-- 会话表
|
||
CREATE TABLE mpc_sessions (
|
||
id UUID PRIMARY KEY,
|
||
session_type VARCHAR(50) NOT NULL, -- keygen / sign
|
||
threshold_n INT NOT NULL,
|
||
threshold_t INT NOT NULL,
|
||
status VARCHAR(50) NOT NULL,
|
||
message_hash BYTEA, -- 签名会话的待签消息
|
||
public_key BYTEA, -- keygen 完成后的群公钥
|
||
signature BYTEA, -- sign 完成后的签名
|
||
created_at TIMESTAMP NOT NULL,
|
||
expires_at TIMESTAMP NOT NULL
|
||
);
|
||
|
||
-- 参与方表
|
||
CREATE TABLE session_participants (
|
||
id UUID PRIMARY KEY,
|
||
session_id UUID REFERENCES mpc_sessions(id),
|
||
party_id VARCHAR(255) NOT NULL,
|
||
party_index INT NOT NULL,
|
||
status VARCHAR(50) NOT NULL,
|
||
device_type VARCHAR(50),
|
||
joined_at TIMESTAMP
|
||
);
|
||
```
|
||
|
||
**关键点**: Coordinator 只管理会话元数据,从不参与 MPC 计算,也看不到密钥分片。
|
||
|
||
---
|
||
|
||
### 2.3 Message Router - 消息路由器
|
||
|
||
**核心职责**: MPC 参与方之间的**通信基础设施**
|
||
|
||
#### 为什么需要独立的消息路由?
|
||
|
||
TSS 协议需要参与方之间频繁交换消息 (通常 3-9 轮):
|
||
|
||
```
|
||
Round 1: Party 0 → Party 1, Party 2 (承诺值)
|
||
Round 2: Party 1 → Party 0, Party 2 (秘密分享)
|
||
Round 3: 所有参与方互相广播 (验证值)
|
||
...
|
||
```
|
||
|
||
如果没有统一路由器,每个参与方需要:
|
||
- 知道所有其他参与方的网络地址
|
||
- 维护 N² 个连接
|
||
- 处理离线消息重传
|
||
|
||
**Message Router 解决的问题:**
|
||
|
||
1. **P2P 消息中继**
|
||
- 统一的消息入口
|
||
- 自动路由到目标参与方
|
||
- 支持广播和点对点
|
||
|
||
2. **实时推送 (gRPC Stream)**
|
||
```protobuf
|
||
rpc SubscribeMessages(SubscribeRequest) returns (stream MPCMessage);
|
||
```
|
||
- 长连接推送消息
|
||
- 低延迟 (毫秒级)
|
||
|
||
3. **消息持久化**
|
||
- 离线参与方的消息缓存
|
||
- 消息去重和排序
|
||
- 支持轮询回退 (如果 Stream 不可用)
|
||
|
||
4. **安全性**
|
||
- 消息是端到端加密的 (tss-lib 加密)
|
||
- Router 只转发,不解密内容
|
||
- 按 session_id 隔离
|
||
|
||
#### 典型数据流:
|
||
```
|
||
Party 0 (tss-lib) → Message Router → Party 1 (tss-lib)
|
||
↓ ↑
|
||
加密消息 payload 原样转发
|
||
(Router 看不懂) (不解密)
|
||
```
|
||
|
||
---
|
||
|
||
### 2.4 Server Parties - MPC 计算节点
|
||
|
||
**核心职责**: **真正执行 TSS 协议的参与方**
|
||
|
||
#### 特点:
|
||
|
||
1. **运行完整的 tss-lib**
|
||
- 与客户端地位完全对等
|
||
- 执行相同的 Keygen/Signing 算法
|
||
|
||
2. **存储加密的密钥分片**
|
||
```
|
||
Server Party 1 → 分片 1 (AES-256-GCM 加密) → PostgreSQL
|
||
Server Party 2 → 分片 2 (AES-256-GCM 加密) → PostgreSQL
|
||
Server Party 3 → 分片 3 (AES-256-GCM 加密) → PostgreSQL
|
||
```
|
||
|
||
3. **物理隔离**
|
||
- 3 个 Party 独立部署 (可以在不同服务器)
|
||
- 互相看不到对方的分片
|
||
- 任意 2 个被攻破也无法重建私钥
|
||
|
||
4. **自动参与会话**
|
||
- 监听 Session Coordinator 的事件
|
||
- 自动加入指定的 keygen/sign 会话
|
||
- 完成后上报结果
|
||
|
||
---
|
||
|
||
### 2.5 Server Party API - 用户分片生成服务
|
||
|
||
**核心职责**: 为**用户设备**提供临时分片生成 (无状态)
|
||
|
||
#### 为什么需要它?
|
||
|
||
**场景**: 用户在手机 App 上创建钱包
|
||
|
||
```
|
||
问题: 手机端无法直接参与服务端的 MPC 会话 (网络/性能限制)
|
||
解决: Server Party API 代表用户参与一次 keygen,生成分片后返回
|
||
```
|
||
|
||
#### 工作流程:
|
||
|
||
```
|
||
1. 手机 App 调用: POST /api/v1/keygen/generate-user-share
|
||
↓
|
||
2. Server Party API:
|
||
- 代表用户加入 MPC 会话
|
||
- 与 Server Party 1, 2 执行 TSS Keygen
|
||
- 获得用户的密钥分片
|
||
↓
|
||
3. 返回加密分片给手机
|
||
↓
|
||
4. 手机存储到 Android KeyStore / iOS Secure Enclave
|
||
↓
|
||
5. Server Party API 丢弃分片 (不存储)
|
||
```
|
||
|
||
**关键特性**:
|
||
- **无状态**: 不存储任何分片
|
||
- **即时返回**: 同步 API (等待 keygen 完成)
|
||
- **端到端加密**: 可选用户公钥加密分片
|
||
|
||
---
|
||
|
||
### 2.6 服务间关系总结
|
||
|
||
```
|
||
┌──────────────────────────────────────────────────────┐
|
||
│ 关系矩阵 │
|
||
├──────────────────────────────────────────────────────┤
|
||
│ │
|
||
│ Account Service │
|
||
│ ├─ 调用 → Session Coordinator (创建会话) │
|
||
│ ├─ 调用 → Server Party API (生成用户分片) │
|
||
│ └─ 查询 → Session Coordinator (会话状态) │
|
||
│ │
|
||
│ Session Coordinator │
|
||
│ ├─ 读写 → PostgreSQL (会话元数据) │
|
||
│ ├─ 发布 → RabbitMQ (会话事件) │
|
||
│ └─ 被调用 ← Server Parties (加入会话) │
|
||
│ │
|
||
│ Message Router │
|
||
│ ├─ 转发 → MPC 消息 (端到端加密) │
|
||
│ ├─ 持久化 → PostgreSQL (离线消息) │
|
||
│ └─ Stream → gRPC Stream (实时推送) │
|
||
│ │
|
||
│ Server Parties │
|
||
│ ├─ 监听 → RabbitMQ (会话创建事件) │
|
||
│ ├─ 调用 → Session Coordinator (加入会话) │
|
||
│ ├─ 通信 → Message Router (交换 MPC 消息) │
|
||
│ └─ 存储 → PostgreSQL (加密分片) │
|
||
│ │
|
||
│ Server Party API │
|
||
│ ├─ 调用 → Session Coordinator (加入会话) │
|
||
│ ├─ 通信 → Message Router (交换 MPC 消息) │
|
||
│ └─ 返回 → 用户分片 (不存储) │
|
||
│ │
|
||
└──────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## 3. 标准 MPC 会话类型
|
||
|
||
### 3.1 Keygen 会话 (密钥生成)
|
||
|
||
**目的**: 分布式生成 ECDSA 密钥对,无任何单点知道完整私钥
|
||
|
||
#### 参与方配置:
|
||
|
||
```json
|
||
{
|
||
"threshold_n": 3, // 总共 3 个参与方
|
||
"threshold_t": 2, // 至少 2 个参与方才能签名
|
||
"participants": [
|
||
{
|
||
"party_id": "user_device_001",
|
||
"device_type": "android"
|
||
},
|
||
{
|
||
"party_id": "server_party_1",
|
||
"device_type": "server"
|
||
},
|
||
{
|
||
"party_id": "server_party_2",
|
||
"device_type": "server"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
#### 输出:
|
||
|
||
```json
|
||
{
|
||
"public_key": "04a1b2c3d4...", // 群公钥 (以太坊地址)
|
||
"shares": [
|
||
{
|
||
"party_id": "user_device_001",
|
||
"share_data": "encrypted_share_1" // 用户分片 (加密)
|
||
},
|
||
{
|
||
"party_id": "server_party_1",
|
||
"share_data": "encrypted_share_2" // 服务端存储
|
||
},
|
||
{
|
||
"party_id": "server_party_2",
|
||
"share_data": "encrypted_share_3" // 服务端存储
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
#### 常见阈值方案:
|
||
|
||
| 方案 | 场景 | 参与方 | 优势 |
|
||
|-----|------|--------|------|
|
||
| 2-of-3 | 个人钱包 | 用户设备 + 2 个服务器 | 用户 + 1 个服务器即可签名 |
|
||
| 3-of-5 | 企业多签 | 5 个高管 | 需要 3 人同意 (民主决策) |
|
||
| 2-of-2 | 两方托管 | 用户 + 服务商 | 必须双方同意 |
|
||
| 4-of-7 | 高安全审批 | 7 个董事会成员 | 需要过半数同意 |
|
||
|
||
---
|
||
|
||
### 3.2 Sign 会话 (门限签名)
|
||
|
||
**目的**: 使用密钥分片对消息进行 ECDSA 签名
|
||
|
||
#### 参与方配置:
|
||
|
||
```json
|
||
{
|
||
"account_id": "uuid-of-account",
|
||
"message_hash": "a1b2c3d4...", // 待签消息 (SHA-256)
|
||
"participants": [
|
||
{
|
||
"party_id": "user_device_001",
|
||
"share_data": "encrypted_share" // 用户提供本地分片
|
||
},
|
||
{
|
||
"party_id": "server_party_1" // 服务端自动加载分片
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
**注意**: Sign 会话只需要 `threshold_t` 个参与方 (例如 2-of-3 中的 2 个)
|
||
|
||
#### 输出:
|
||
|
||
```json
|
||
{
|
||
"signature": "3045022100...", // DER 编码签名
|
||
"r": "a1b2c3d4...", // 签名 R 值
|
||
"s": "e5f6g7h8...", // 签名 S 值
|
||
"v": 0 // 恢复 ID (以太坊需要)
|
||
}
|
||
```
|
||
|
||
#### 验证签名:
|
||
|
||
```javascript
|
||
// 以太坊 / 比特币标准验证
|
||
const publicKey = "04a1b2c3d4...";
|
||
const messageHash = "hash_of_transaction";
|
||
const signature = { r, s, v };
|
||
|
||
const isValid = ecrecover(messageHash, signature) === publicKey;
|
||
```
|
||
|
||
---
|
||
|
||
### 3.3 恢复会话 (密钥恢复)
|
||
|
||
**场景**: 用户丢失手机,需要恢复钱包
|
||
|
||
#### 两种恢复方案:
|
||
|
||
**方案 A: 使用恢复分片 (推荐)**
|
||
```
|
||
初始 Keygen: user_device + server_1 + recovery_backup (3 方)
|
||
用户丢失设备后:
|
||
→ 使用 recovery_backup + server_1 执行 Sign (2-of-3 仍可用)
|
||
→ 生成新的 user_device_new 分片 (重新 keygen)
|
||
```
|
||
|
||
**方案 B: 社交恢复**
|
||
```
|
||
初始 Keygen: user + server + guardian_1 + guardian_2 + guardian_3 (5 方, 3-of-5)
|
||
用户丢失设备后:
|
||
→ 联系 3 个 guardians
|
||
→ 执行新的 keygen 生成新分片
|
||
```
|
||
|
||
---
|
||
|
||
## 4. 集成方式
|
||
|
||
### 4.1 推荐架构
|
||
|
||
```
|
||
┌────────────────────────────────────────────────┐
|
||
│ 您的后端服务架构 │
|
||
│ │
|
||
│ ┌──────────────┐ ┌──────────────┐ │
|
||
│ │ API Gateway │ │ Wallet Service│ │
|
||
│ │ (Kong/Nginx) │─────►│ │ │
|
||
│ └──────────────┘ │ • 用户管理 │ │
|
||
│ │ • 交易构建 │ │
|
||
│ │ • 余额查询 │ │
|
||
│ └───────┬──────┘ │
|
||
│ │ │
|
||
└────────────────────────────────┼───────────────┘
|
||
│
|
||
调用 MPC-System API
|
||
│
|
||
┌────────────────────────────────▼───────────────┐
|
||
│ MPC-System (独立部署) │
|
||
│ ┌──────────────────────────────────────┐ │
|
||
│ │ Account Service: http://mpc:4000 │ │
|
||
│ └──────────────────────────────────────┘ │
|
||
└────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 4.2 环境配置
|
||
|
||
**方式 1: Docker Compose (开发/测试)**
|
||
|
||
```yaml
|
||
# docker-compose.yml
|
||
version: '3.8'
|
||
|
||
services:
|
||
# 您的服务
|
||
wallet-service:
|
||
build: ./wallet-service
|
||
environment:
|
||
- MPC_BASE_URL=http://mpc-account-service:4000
|
||
- MPC_API_KEY=your_secure_api_key
|
||
depends_on:
|
||
- mpc-account-service
|
||
|
||
# MPC 系统 (一键部署)
|
||
mpc-account-service:
|
||
image: rwadurian/mpc-account-service:latest
|
||
ports:
|
||
- "4000:8080"
|
||
environment:
|
||
- MPC_API_KEY=your_secure_api_key
|
||
- DATABASE_URL=postgresql://...
|
||
depends_on:
|
||
- mpc-session-coordinator
|
||
- mpc-postgres
|
||
|
||
mpc-session-coordinator:
|
||
image: rwadurian/mpc-session-coordinator:latest
|
||
# ... 其他配置
|
||
|
||
# ... 其他 MPC 服务
|
||
```
|
||
|
||
**方式 2: Kubernetes (生产)**
|
||
|
||
```yaml
|
||
# values.yaml
|
||
mpc:
|
||
accountService:
|
||
enabled: true
|
||
replicaCount: 3
|
||
image: rwadurian/mpc-account-service:v1.0.0
|
||
|
||
sessionCoordinator:
|
||
enabled: true
|
||
replicaCount: 2
|
||
|
||
serverParties:
|
||
count: 3
|
||
resources:
|
||
requests:
|
||
memory: "2Gi"
|
||
cpu: "1000m"
|
||
```
|
||
|
||
---
|
||
|
||
## 5. 完整示例代码
|
||
|
||
### 5.1 场景: 用户创建钱包
|
||
|
||
#### 步骤 1: 创建 Keygen 会话
|
||
|
||
```bash
|
||
# HTTP API
|
||
POST http://mpc-account-service:4000/api/v1/mpc/keygen
|
||
Content-Type: application/json
|
||
X-API-Key: your_api_key
|
||
|
||
{
|
||
"threshold_n": 3,
|
||
"threshold_t": 2,
|
||
"participants": [
|
||
{
|
||
"party_id": "user_device_12345",
|
||
"device_type": "android",
|
||
"device_id": "android_device_uuid"
|
||
},
|
||
{
|
||
"party_id": "server_party_1",
|
||
"device_type": "server",
|
||
"platform": "linux"
|
||
},
|
||
{
|
||
"party_id": "server_party_2",
|
||
"device_type": "server",
|
||
"platform": "linux"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
**响应**:
|
||
```json
|
||
{
|
||
"session_id": "550e8400-e29b-41d4-a716-446655440000",
|
||
"session_type": "keygen",
|
||
"threshold_n": 3,
|
||
"threshold_t": 2,
|
||
"join_tokens": {
|
||
"user_device_12345": "eyJhbGciOiJIUzI1NiIs...",
|
||
"server_party_1": "eyJhbGciOiJIUzI1NiIs...",
|
||
"server_party_2": "eyJhbGciOiJIUzI1NiIs..."
|
||
},
|
||
"status": "created"
|
||
}
|
||
```
|
||
|
||
#### 步骤 2: 为用户生成分片
|
||
|
||
```bash
|
||
# 调用 Server Party API 代表用户参与 keygen
|
||
POST http://mpc-server-party-api:8083/api/v1/keygen/generate-user-share
|
||
Content-Type: application/json
|
||
X-API-Key: your_api_key
|
||
|
||
{
|
||
"session_id": "550e8400-e29b-41d4-a716-446655440000",
|
||
"party_id": "user_device_12345",
|
||
"join_token": "eyJhbGciOiJIUzI1NiIs...",
|
||
"user_public_key": "optional_hex_for_e2e_encryption"
|
||
}
|
||
```
|
||
|
||
**响应 (大约 30-90 秒后)**:
|
||
```json
|
||
{
|
||
"success": true,
|
||
"session_id": "550e8400-e29b-41d4-a716-446655440000",
|
||
"party_id": "user_device_12345",
|
||
"party_index": 0,
|
||
"share_data": "a1b2c3d4e5f6...", // 加密的用户分片 (hex)
|
||
"public_key": "04a1b2c3d4e5f6..." // 群公钥
|
||
}
|
||
```
|
||
|
||
#### 步骤 3: 将分片和公钥返回给用户
|
||
|
||
```javascript
|
||
// 前端 (React Native / Flutter)
|
||
const response = await createWallet(userId);
|
||
|
||
// 存储分片到设备安全存储
|
||
await SecureStore.setItemAsync(
|
||
`wallet_share_${userId}`,
|
||
response.share_data
|
||
);
|
||
|
||
// 存储公钥 (用于显示地址)
|
||
const ethereumAddress = publicKeyToAddress(response.public_key);
|
||
await AsyncStorage.setItem(`wallet_address_${userId}`, ethereumAddress);
|
||
```
|
||
|
||
---
|
||
|
||
### 5.2 场景: 用户签名交易
|
||
|
||
#### 步骤 1: 构建交易并计算哈希
|
||
|
||
```javascript
|
||
// 后端: 构建以太坊交易
|
||
const txParams = {
|
||
to: "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
|
||
value: ethers.utils.parseEther("1.0"),
|
||
gasLimit: 21000,
|
||
gasPrice: ethers.utils.parseUnits("50", "gwei"),
|
||
nonce: await provider.getTransactionCount(walletAddress),
|
||
chainId: 1
|
||
};
|
||
|
||
const txHash = ethers.utils.keccak256(
|
||
ethers.utils.serializeTransaction(txParams)
|
||
);
|
||
// txHash: 0xa1b2c3d4e5f6...
|
||
```
|
||
|
||
#### 步骤 2: 创建 Sign 会话
|
||
|
||
```bash
|
||
POST http://mpc-account-service:4000/api/v1/mpc/sign
|
||
Content-Type: application/json
|
||
X-API-Key: your_api_key
|
||
|
||
{
|
||
"account_id": "user_account_uuid",
|
||
"message_hash": "a1b2c3d4e5f6...", // 去掉 0x 前缀
|
||
"participants": [
|
||
{
|
||
"party_id": "user_device_12345",
|
||
"device_type": "android"
|
||
},
|
||
{
|
||
"party_id": "server_party_1",
|
||
"device_type": "server"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
**响应**:
|
||
```json
|
||
{
|
||
"session_id": "660e8400-e29b-41d4-a716-446655440001",
|
||
"session_type": "sign",
|
||
"account_id": "user_account_uuid",
|
||
"message_hash": "a1b2c3d4e5f6...",
|
||
"threshold_t": 2,
|
||
"join_tokens": {
|
||
"user_device_12345": "eyJhbGciOiJIUzI1NiIs...",
|
||
"server_party_1": "eyJhbGciOiJIUzI1NiIs..."
|
||
},
|
||
"status": "created"
|
||
}
|
||
```
|
||
|
||
#### 步骤 3: 使用用户分片参与签名
|
||
|
||
```bash
|
||
POST http://mpc-server-party-api:8083/api/v1/sign/with-user-share
|
||
Content-Type: application/json
|
||
X-API-Key: your_api_key
|
||
|
||
{
|
||
"session_id": "660e8400-e29b-41d4-a716-446655440001",
|
||
"party_id": "user_device_12345",
|
||
"join_token": "eyJhbGciOiJIUzI1NiIs...",
|
||
"share_data": "a1b2c3d4e5f6...", // 用户的加密分片 (从设备存储读取)
|
||
"message_hash": "a1b2c3d4e5f6..."
|
||
}
|
||
```
|
||
|
||
**响应 (大约 5-15 秒后)**:
|
||
```json
|
||
{
|
||
"success": true,
|
||
"session_id": "660e8400-e29b-41d4-a716-446655440001",
|
||
"party_id": "user_device_12345",
|
||
"signature": "3045022100a1b2c3...",
|
||
"r": "a1b2c3d4e5f6...",
|
||
"s": "e5f6g7h8i9j0...",
|
||
"v": 0
|
||
}
|
||
```
|
||
|
||
#### 步骤 4: 广播交易到区块链
|
||
|
||
```javascript
|
||
// 组装完整签名
|
||
const signedTx = ethers.utils.serializeTransaction(txParams, {
|
||
r: "0x" + response.r,
|
||
s: "0x" + response.s,
|
||
v: response.v
|
||
});
|
||
|
||
// 广播到以太坊网络
|
||
const txResponse = await provider.sendTransaction(signedTx);
|
||
const receipt = await txResponse.wait();
|
||
|
||
console.log("Transaction hash:", receipt.transactionHash);
|
||
```
|
||
|
||
---
|
||
|
||
### 5.3 Go SDK 示例
|
||
|
||
```go
|
||
package main
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"github.com/rwadurian/mpc-client-sdk-go"
|
||
)
|
||
|
||
func main() {
|
||
// 初始化 MPC 客户端
|
||
client := mpc.NewClient(&mpc.Config{
|
||
BaseURL: "http://mpc-account-service:4000",
|
||
APIKey: "your_api_key",
|
||
Timeout: 5 * time.Minute,
|
||
})
|
||
|
||
ctx := context.Background()
|
||
|
||
// 创建钱包
|
||
keygenReq := &mpc.KeygenRequest{
|
||
ThresholdN: 3,
|
||
ThresholdT: 2,
|
||
Participants: []mpc.Participant{
|
||
{PartyID: "user_device", DeviceType: "android"},
|
||
{PartyID: "server_party_1", DeviceType: "server"},
|
||
{PartyID: "server_party_2", DeviceType: "server"},
|
||
},
|
||
}
|
||
|
||
keygenResp, err := client.CreateKeygen(ctx, keygenReq)
|
||
if err != nil {
|
||
panic(err)
|
||
}
|
||
|
||
fmt.Printf("Session ID: %s\n", keygenResp.SessionID)
|
||
fmt.Printf("Join Token: %s\n", keygenResp.JoinTokens["user_device"])
|
||
|
||
// 生成用户分片
|
||
shareReq := &mpc.GenerateUserShareRequest{
|
||
SessionID: keygenResp.SessionID,
|
||
PartyID: "user_device",
|
||
JoinToken: keygenResp.JoinTokens["user_device"],
|
||
}
|
||
|
||
shareResp, err := client.GenerateUserShare(ctx, shareReq)
|
||
if err != nil {
|
||
panic(err)
|
||
}
|
||
|
||
fmt.Printf("Public Key: %s\n", shareResp.PublicKey)
|
||
fmt.Printf("User Share: %s\n", shareResp.ShareData)
|
||
|
||
// 存储分片到数据库
|
||
// ...
|
||
|
||
// 稍后签名交易
|
||
signReq := &mpc.SignRequest{
|
||
AccountID: "user_account_uuid",
|
||
MessageHash: "a1b2c3d4e5f6...",
|
||
Participants: []mpc.SignParticipant{
|
||
{PartyID: "user_device", ShareData: shareResp.ShareData},
|
||
{PartyID: "server_party_1"},
|
||
},
|
||
}
|
||
|
||
signResp, err := client.CreateSign(ctx, signReq)
|
||
if err != nil {
|
||
panic(err)
|
||
}
|
||
|
||
fmt.Printf("Signature R: %s\n", signResp.R)
|
||
fmt.Printf("Signature S: %s\n", signResp.S)
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 5.4 Python SDK 示例
|
||
|
||
```python
|
||
from mpc_client import MPCClient
|
||
|
||
# 初始化客户端
|
||
client = MPCClient(
|
||
base_url="http://mpc-account-service:4000",
|
||
api_key="your_api_key"
|
||
)
|
||
|
||
# 创建钱包
|
||
keygen_response = client.create_keygen(
|
||
threshold_n=3,
|
||
threshold_t=2,
|
||
participants=[
|
||
{"party_id": "user_device", "device_type": "ios"},
|
||
{"party_id": "server_party_1", "device_type": "server"},
|
||
{"party_id": "server_party_2", "device_type": "server"},
|
||
]
|
||
)
|
||
|
||
print(f"Session ID: {keygen_response.session_id}")
|
||
|
||
# 生成用户分片
|
||
share_response = client.generate_user_share(
|
||
session_id=keygen_response.session_id,
|
||
party_id="user_device",
|
||
join_token=keygen_response.join_tokens["user_device"]
|
||
)
|
||
|
||
print(f"Public Key: {share_response.public_key}")
|
||
print(f"User Share: {share_response.share_data}")
|
||
|
||
# 签名交易
|
||
sign_response = client.sign_transaction(
|
||
account_id="user_account_uuid",
|
||
message_hash="a1b2c3d4e5f6...",
|
||
participants=[
|
||
{"party_id": "user_device", "share_data": share_response.share_data},
|
||
{"party_id": "server_party_1"}
|
||
]
|
||
)
|
||
|
||
print(f"Signature: {sign_response.signature}")
|
||
```
|
||
|
||
---
|
||
|
||
## 6. 故障排查
|
||
|
||
### 6.1 常见错误
|
||
|
||
#### 错误 1: "session not found"
|
||
|
||
**原因**: 会话已过期或不存在
|
||
|
||
**解决**:
|
||
```bash
|
||
# 检查会话状态
|
||
GET http://mpc-account-service:4000/api/v1/mpc/sessions/{session_id}
|
||
|
||
# 会话默认 10 分钟过期,确保在有效期内完成操作
|
||
```
|
||
|
||
#### 错误 2: "insufficient participants"
|
||
|
||
**原因**: 参与方数量不足
|
||
|
||
**解决**:
|
||
```json
|
||
// 确保 Sign 会话至少有 threshold_t 个参与方
|
||
{
|
||
"account_id": "...",
|
||
"participants": [
|
||
{"party_id": "user_device"},
|
||
{"party_id": "server_party_1"} // 2-of-3 需要至少 2 个
|
||
]
|
||
}
|
||
```
|
||
|
||
#### 错误 3: "invalid join token"
|
||
|
||
**原因**: Token 过期或被篡改
|
||
|
||
**解决**:
|
||
- 重新创建会话获取新 token
|
||
- 检查服务端时钟同步 (JWT 依赖时间)
|
||
|
||
#### 错误 4: "keygen failed: timeout"
|
||
|
||
**原因**: TSS 协议执行超时
|
||
|
||
**排查步骤**:
|
||
```bash
|
||
# 1. 检查 Server Parties 是否都在运行
|
||
docker compose ps | grep server-party
|
||
|
||
# 2. 查看 Message Router 日志
|
||
docker compose logs message-router | grep ERROR
|
||
|
||
# 3. 检查网络连通性
|
||
docker compose exec server-party-1 nc -zv message-router 50051
|
||
```
|
||
|
||
---
|
||
|
||
### 6.2 性能优化
|
||
|
||
#### Keygen 性能
|
||
|
||
| 阈值方案 | 预期时间 | 优化建议 |
|
||
|---------|---------|---------|
|
||
| 2-of-3 | 30-60s | 正常 |
|
||
| 3-of-5 | 90-120s | 增加 CPU 资源 |
|
||
| 4-of-7 | 180-240s | 考虑异步处理 |
|
||
|
||
#### Sign 性能
|
||
|
||
| 阈值方案 | 预期时间 | 优化建议 |
|
||
|---------|---------|---------|
|
||
| 2-of-3 | 5-10s | 正常 |
|
||
| 3-of-5 | 10-15s | 使用 gRPC Stream |
|
||
| 4-of-7 | 15-20s | 批量签名 |
|
||
|
||
#### 并发优化
|
||
|
||
```yaml
|
||
# docker-compose.yml
|
||
services:
|
||
mpc-session-coordinator:
|
||
deploy:
|
||
replicas: 3 # 水平扩展
|
||
resources:
|
||
limits:
|
||
cpus: '2'
|
||
memory: 2G
|
||
```
|
||
|
||
---
|
||
|
||
### 6.3 监控指标
|
||
|
||
**关键指标**:
|
||
|
||
```yaml
|
||
# Prometheus metrics
|
||
mpc_keygen_duration_seconds{quantile="0.95"} < 120
|
||
mpc_sign_duration_seconds{quantile="0.95"} < 15
|
||
mpc_session_success_rate > 0.99
|
||
mpc_active_sessions < 100
|
||
```
|
||
|
||
**日志示例**:
|
||
```
|
||
[INFO] Session 550e8400 created: type=keygen, participants=3
|
||
[INFO] Party user_device joined session 550e8400
|
||
[INFO] Party server_party_1 joined session 550e8400
|
||
[INFO] Session 550e8400 started: all parties ready
|
||
[INFO] Keygen completed: session=550e8400, duration=45.2s
|
||
```
|
||
|
||
---
|
||
|
||
## 7. 安全建议
|
||
|
||
### 7.1 API 密钥管理
|
||
|
||
```bash
|
||
# 生成强密钥
|
||
openssl rand -base64 48
|
||
|
||
# 环境变量方式 (推荐)
|
||
export MPC_API_KEY="your_generated_key"
|
||
|
||
# 定期轮换 (每 90 天)
|
||
```
|
||
|
||
### 7.2 网络隔离
|
||
|
||
```yaml
|
||
# docker-compose.yml
|
||
networks:
|
||
mpc-internal:
|
||
internal: true # 内部服务网络
|
||
|
||
public:
|
||
driver: bridge # 外部访问网络
|
||
|
||
services:
|
||
mpc-account-service:
|
||
networks:
|
||
- public # 暴露给外部
|
||
- mpc-internal
|
||
|
||
mpc-session-coordinator:
|
||
networks:
|
||
- mpc-internal # 仅内部访问
|
||
```
|
||
|
||
### 7.3 审计日志
|
||
|
||
```sql
|
||
-- 记录所有 MPC 操作
|
||
CREATE TABLE mpc_audit_logs (
|
||
id SERIAL PRIMARY KEY,
|
||
session_id UUID NOT NULL,
|
||
operation VARCHAR(50) NOT NULL,
|
||
user_id VARCHAR(255),
|
||
ip_address INET,
|
||
user_agent TEXT,
|
||
request_body JSONB,
|
||
response_status INT,
|
||
created_at TIMESTAMP DEFAULT NOW()
|
||
);
|
||
|
||
-- 查询异常活动
|
||
SELECT * FROM mpc_audit_logs
|
||
WHERE response_status >= 400
|
||
AND created_at > NOW() - INTERVAL '1 hour';
|
||
```
|
||
|
||
---
|
||
|
||
## 8. 附录
|
||
|
||
### 8.1 完整 API 参考
|
||
|
||
详细 API 文档请参考:
|
||
- [Account Service API](docs/02-api-reference.md#account-service-api)
|
||
- [Session Coordinator gRPC](api/proto/session_coordinator.proto)
|
||
- [Message Router gRPC](api/proto/message_router.proto)
|
||
|
||
### 8.2 SDK 下载
|
||
|
||
- Go SDK: `go get github.com/rwadurian/mpc-client-sdk-go`
|
||
- Python SDK: `pip install mpc-client-sdk`
|
||
- JavaScript SDK: `npm install @rwadurian/mpc-client-sdk`
|
||
|
||
### 8.3 联系支持
|
||
|
||
- GitHub Issues: https://github.com/rwadurian/mpc-system/issues
|
||
- Email: mpc-support@rwadurian.com
|
||
- 文档: https://docs.rwadurian.com/mpc-system
|
||
|
||
---
|
||
|
||
**文档版本**: 1.0.0
|
||
**最后更新**: 2025-12-05
|
||
**适用于**: MPC-System v1.0.0+
|