19 KiB
19 KiB
Service Party App - 分布式共管钱包桌面应用
概述
Service Party App 是一个跨平台 Electron 桌面应用,用于参与分布式多方共管钱包的创建和签名过程。用户可以在各自的电脑上运行此应用,通过扫描邀请二维码或输入邀请码加入共管钱包创建会话,参与 TSS (Threshold Signature Scheme) 密钥生成协议。
应用场景
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Service Party │ │ Service Party │ │ Service Party │
│ App (用户A) │ │ App (用户B) │ │ App (用户C) │
└────────┬────────┘ └────────┬────────┘ └────────┬────────┘
│ │ │
│ 创建会话/生成邀请码 │ 输入邀请码加入 │ 输入邀请码加入
│ │ │
└───────────────────────┼───────────────────────┘
│
┌────────────┴────────────┐
│ Account Service │
│ (HTTP API - 会话管理) │
└────────────┬────────────┘
│
┌────────────┴────────────┐
│ Message Router │
│ (gRPC 消息路由) │
└────────────┬────────────┘
│
┌────────────┴────────────┐
│ TSS Keygen/Sign │
│ (分布式密钥生成/签名) │
└─────────────────────────┘
典型使用流程
Keygen 流程 (密钥生成)
- 发起方 在 Service Party App 输入钱包名称和用户名称,创建共管钱包会话
- 发起方 获得邀请码 (格式: XXXX-XXXX-XXXX),分享给其他参与方
- 参与方 在各自电脑上打开 Service Party App,输入邀请码加入
- 等待所有参与方就绪 (24小时超时)
- 所有参与方到齐后,自动开始 TSS 密钥生成协议
- 完成后,每个参与方在本地 SQLite 保存自己的加密 share
Sign 流程 (签名)
- 发起方 从本地 SQLite 选择要签名的钱包
- 发起方 输入待签名的消息哈希,创建签名会话
- 发起方 获得签名邀请码,分享给其他参与方 (必须是 keygen 时的参与方)
- 参与方 输入邀请码加入签名会话
- 等待足够数量的参与方 (threshold_t + 1 人,24小时超时)
- 参与方到齐后,自动开始 TSS 签名协议
- 完成后,返回签名结果,可用于广播交易
目录结构
backend/mpc-system/services/service-party-app/
├── electron/ # Electron 主进程
│ ├── main.ts # 主进程入口
│ ├── preload.ts # 预加载脚本 (安全 IPC)
│ └── modules/
│ ├── grpc-client.ts # gRPC 客户端 (连接 Message Router)
│ ├── account-client.ts # HTTP 客户端 (连接 Account Service)
│ ├── tss-handler.ts # TSS 协议处理器
│ ├── database.ts # 本地 SQLite 存储 (AES-256-GCM 加密)
│ ├── address-derivation.ts # 地址派生 (多链支持)
│ ├── kava-client.ts # Kava 区块链客户端
│ └── kava-tx-service.ts # Kava 交易构建服务
│
├── src/ # React 前端 (渲染进程)
│ ├── App.tsx # 应用入口
│ ├── pages/
│ │ ├── Home.tsx # 主页 - Share 列表
│ │ ├── Join.tsx # 加入会话页面
│ │ ├── Create.tsx # 创建会话页面
│ │ ├── Session.tsx # 会话进度页面
│ │ ├── Sign.tsx # 签名页面
│ │ └── Settings.tsx # 设置页面
│ ├── components/ # UI 组件
│ ├── stores/
│ │ └── appStore.ts # Zustand 状态管理
│ ├── types/
│ │ └── electron.d.ts # TypeScript 类型定义
│ └── utils/
│ └── address.ts # 地址工具函数
│
├── tss-party/ # Go TSS 子进程
│ ├── main.go # TSS 协议执行程序
│ ├── go.mod # Go 模块定义
│ └── go.sum # 依赖锁定
│
├── proto/ # gRPC Proto 文件
│ └── message_router.proto # Message Router 接口定义
│
├── package.json # Node.js 依赖
├── electron-builder.json # Electron 打包配置
├── tsconfig.json # TypeScript 配置
├── tsconfig.electron.json # Electron TypeScript 配置
├── vite.config.ts # Vite 构建配置
└── build-windows.bat # Windows 一键编译脚本
技术架构
技术栈
| 组件 | 技术 | 说明 |
|---|---|---|
| 桌面框架 | Electron 28+ | 跨平台支持 Windows/Mac/Linux |
| 前端框架 | React 18 + TypeScript | 与 admin-web 保持一致 |
| 构建工具 | Vite | 快速开发和构建 |
| 状态管理 | Zustand | 轻量级状态管理 |
| gRPC 客户端 | @grpc/grpc-js | Node.js gRPC 实现 (连接 Message Router) |
| HTTP 客户端 | Fetch API | 连接 Account Service |
| TSS 协议 | Go 子进程 | 使用 bnb-chain/tss-lib |
| 本地存储 | sql.js (SQLite) | 纯 JavaScript SQLite 实现 |
| 加密算法 | AES-256-GCM | Share 加密存储,PBKDF2 密钥派生 |
| 打包工具 | electron-builder | 多平台打包 |
服务连接
┌─────────────────────────────────────────────────────────────┐
│ Service Party App │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ main.ts ││
│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ││
│ │ │ grpcClient │ │accountClient │ │ database │ ││
│ │ │ (gRPC) │ │ (HTTP) │ │ (SQLite) │ ││
│ │ └──────┬───────┘ └──────┬───────┘ └──────────────┘ ││
│ │ │ │ ││
│ └─────────┼─────────────────┼──────────────────────────────┘│
└────────────┼─────────────────┼───────────────────────────────┘
│ │
│ gRPC (TLS) │ HTTPS
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ Message Router │ │ Account Service │
│ (消息路由) │ │ (会话管理) │
└─────────────────┘ └─────────────────┘
Account Service HTTP API
Service Party App 通过 HTTP 调用 Account Service 管理会话:
| 端点 | 方法 | 说明 |
|---|---|---|
/api/v1/co-managed/sessions |
POST | 创建 Keygen 会话 |
/api/v1/co-managed/sessions/:sessionId/join |
POST | 加入会话 |
/api/v1/co-managed/sessions/:sessionId |
GET | 获取会话状态 |
/api/v1/co-managed/sessions/by-invite-code/:code |
GET | 通过邀请码查询会话 |
/api/v1/co-managed/sign |
POST | 创建 Sign 会话 |
/api/v1/co-managed/sign/by-invite-code/:code |
GET | 通过邀请码查询签名会话 |
/health |
GET | 健康检查 |
TSS 子进程架构
为什么使用 Go 子进程而不是 WASM?
- 稳定性: tss-lib 是复杂的密码学库,Go 原生执行比 WASM 更稳定
- 性能: 原生执行性能优于 WASM
- 兼容性: 避免 WASM 在不同平台的兼容性问题
- 调试: 更容易调试和排查问题
┌──────────────────────────────────────────────────────────────┐
│ Electron App (TypeScript) │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ tss-handler.ts │ │
│ │ - 启动 Go 子进程 (spawn) │ │
│ │ - stdin/stdout JSON 消息通信 │ │
│ │ - 转发 gRPC 消息到子进程 │ │
│ │ - 接收子进程输出并处理 │ │
│ └───────────────────────┬────────────────────────────────┘ │
└──────────────────────────┼───────────────────────────────────┘
│ spawn + JSON IPC
▼
┌──────────────────────────────────────────────────────────────┐
│ tss-party (Go 子进程) │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ - 使用 bnb-chain/tss-lib v2 │ │
│ │ - 执行 GG20 Keygen 协议 (4 轮) │ │
│ │ - 执行 GG20 Signing 协议 │ │
│ │ - 通过 stdin 接收 MPC 消息 │ │
│ │ - 通过 stdout 发送 MPC 消息 │ │
│ │ - 完成后返回公钥 + 加密 share / 签名结果 │ │
│ └────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
IPC 消息格式
Electron 主进程与 Go 子进程之间使用 JSON 消息通信:
// 发送给 Go 子进程的消息
interface IncomingMessage {
type: 'incoming';
fromPartyIndex: number;
isBroadcast: boolean;
payload: string; // base64 encoded
}
// Go 子进程发出的消息
interface OutgoingMessage {
type: 'outgoing' | 'result' | 'error' | 'progress';
isBroadcast?: boolean;
toParties?: string[];
payload?: string; // base64 encoded
publicKey?: string; // base64 encoded (keygen result)
encryptedShare?: string; // base64 encoded (keygen result)
signature?: string; // base64 encoded (sign result)
partyIndex?: number;
round?: number;
totalRounds?: number;
error?: string;
}
核心功能
1. 加入会话
用户通过以下方式加入共管钱包创建/签名会话:
- 输入邀请码: 手动输入 12 位邀请码 (格式: XXXX-XXXX-XXXX)
- 扫描二维码: 使用摄像头扫描邀请二维码 (可选)
- 粘贴邀请链接: 手动粘贴邀请链接 (可选)
2. TSS 密钥生成 (Keygen)
参与 GG20 (Gennaro-Goldfeder 2020) 门限签名密钥生成协议:
- 支持任意 T-of-N 阈值配置
- 4 轮消息交换
- 零知识证明保证安全性
- 每个参与方获得自己的 share,无需信任其他方
- 24 小时超时等待所有参与方
3. TSS 签名 (Sign)
参与 GG20 门限签名协议:
- 使用 Keygen 时保存的 share
- 仅需 threshold_t + 1 个参与方即可签名
- 24 小时超时等待足够参与方
- 返回可用于广播的签名结果
4. 本地 SQLite 存储
Share 使用 AES-256-GCM 加密后存储在本地 SQLite 数据库:
interface ShareRecord {
id: string; // Share 唯一标识 (UUID)
session_id: string; // Keygen 会话 ID
wallet_name: string; // 钱包名称
party_id: string; // 参与方 ID
party_index: number; // 参与方索引
threshold_t: number; // 签名阈值
threshold_n: number; // 总参与方数
public_key_hex: string; // 钱包公钥 (hex)
encrypted_share: string; // AES-256-GCM 加密的 share
created_at: string; // 创建时间
last_used_at: string | null; // 最后使用时间
participants_json: string; // JSON: 参与方列表 [{partyId, name}]
}
重要: participants_json 字段存储了 Keygen 时所有参与方的信息,Sign 时必须从这里选择参与方。
5. 地址派生
支持从公钥派生多链地址:
- Kava (主链)
- Cosmos 系列链
- Ethereum 兼容链
6. Kava 交易
支持构建和广播 Kava 交易:
- 查询余额
- 构建转账交易 (待 TSS 签名)
- 广播已签名交易
- 查询交易状态
7. 备份与恢复
- 导出备份: 将加密的 share 导出为文件
- 导入恢复: 从备份文件恢复 share
- 密码保护: 备份文件使用用户密码加密
编译与运行
前置条件
- Node.js 18+
- Go 1.21+
- npm 或 pnpm
Windows 一键编译
cd backend/mpc-system/services/service-party-app
build-windows.bat
编译 TSS 子进程
# Windows
cd backend/mpc-system/services/service-party-app/tss-party
go build -o ../bin/win32-x64/tss-party.exe .
# macOS (Intel)
GOOS=darwin GOARCH=amd64 go build -o ../bin/darwin-x64/tss-party .
# macOS (Apple Silicon)
GOOS=darwin GOARCH=arm64 go build -o ../bin/darwin-arm64/tss-party .
# Linux
GOOS=linux GOARCH=amd64 go build -o ../bin/linux-x64/tss-party .
开发模式
cd backend/mpc-system/services/service-party-app
# 安装依赖
npm install
# 启动开发服务器
npm run dev
生产构建
# 构建前端 + Electron
npm run build
# 打包 Windows 安装包
npm run build:win
# 输出目录: release/
配置
设置页面配置项
| 配置项 | 说明 | 默认值 |
|---|---|---|
| Message Router 地址 | gRPC 服务地址 | mpc-grpc.szaiai.com:443 |
| Account 服务地址 | HTTP API 地址 | https://api.szaiai.com |
| 自动备份 | 创建 share 后自动备份 | false |
| 备份目录 | 自动备份文件保存位置 | (空) |
安全考虑
Share 安全
- 本地加密: Share 使用 AES-256-GCM 加密存储
- 密钥派生: 加密密钥由用户密码通过 PBKDF2 派生 (100,000 次迭代)
- 内存保护: Share 在内存中的时间尽量短
- 安全删除: 删除 share 时同时删除派生地址和签名历史
网络安全
- TLS 加密: 与 Message Router 的 gRPC 连接使用 TLS (端口 443)
- HTTPS: 与 Account Service 的 HTTP 连接使用 HTTPS
- 消息签名: MPC 消息包含签名验证
- 会话隔离: 每个会话使用独立的密钥对
应用安全
- 代码签名: 发布的应用经过代码签名
- 沙箱隔离: Electron 渲染进程在沙箱中运行
- Context Isolation: preload 脚本使用 contextBridge 安全暴露 API
与现有系统的集成
与 Message Router 的通信 (gRPC)
Service Party App
│
│ gRPC (TLS)
▼
┌─────────────────────┐
│ Message Router │
│ ┌───────────────┐ │
│ │ RegisterParty │ │ ← 注册为参与方
│ │ Heartbeat │ │ ← 心跳保活 (30秒)
│ │ JoinSession │ │ ← 加入会话
│ │ Subscribe │ │ ← 订阅消息
│ │ RouteMessage │ │ ← 发送消息
│ │ ReportDone │ │ ← 报告完成
│ └───────────────┘ │
└─────────────────────┘
与 Account Service 的通信 (HTTP)
Service Party App
│
│ HTTPS
▼
┌─────────────────────┐
│ Account Service │
│ ┌───────────────┐ │
│ │ CreateSession │ │ ← 创建 Keygen/Sign 会话
│ │ JoinSession │ │ ← 加入会话
│ │ GetSession │ │ ← 查询会话状态
│ │ ByInviteCode │ │ ← 通过邀请码查询
│ └───────────────┘ │
└─────────────────────┘
数据流
-
Keygen 创建:
- App → Account Service: 创建会话,获取 session_id + invite_code
- App → Message Router: RegisterParty
- App → Message Router: SubscribeSessionEvents
- 等待其他参与方加入...
-
Keygen 加入:
- App → Account Service: 通过 invite_code 查询 session_id
- App → Message Router: RegisterParty
- App → Account Service: JoinSession
- 等待所有参与方就绪...
-
Keygen 执行:
- Message Router 通知所有参与方开始
- 各 App 启动 TSS 子进程
- 通过 Message Router 交换 MPC 消息
- 完成后各自保存 share 到本地 SQLite
-
Sign 创建:
- App → SQLite: 读取 share 和 participants_json
- App → Account Service: 创建签名会话,指定参与方列表
- 分享 invite_code 给其他参与方
-
Sign 执行:
- 足够参与方加入后自动开始
- 通过 Message Router 交换 MPC 消息
- 完成后返回签名结果