13 KiB
13 KiB
MPC Party Service API 文档
概述
MPC Party Service 提供 RESTful API,用于参与 MPC 密钥生成、签名和密钥轮换操作。
基础 URL: /api/v1/mpc-party
认证方式: Bearer Token (JWT)
认证
除了健康检查端点外,所有 API 都需要 JWT 认证:
Authorization: Bearer <token>
JWT Payload 结构:
{
"sub": "user-id",
"type": "access",
"partyId": "user123-server",
"iat": 1699887766,
"exp": 1699895766
}
API 端点
健康检查
GET /health
检查服务健康状态。此端点不需要认证。
请求:
GET /api/v1/mpc-party/health
响应 200 OK:
{
"success": true,
"data": {
"status": "ok",
"service": "mpc-party-service",
"timestamp": "2024-01-15T10:30:00.000Z"
}
}
密钥生成 (Keygen)
POST /keygen/participate
参与 MPC 密钥生成会话(异步)。立即返回 202,后台异步执行 MPC 协议。
请求:
POST /api/v1/mpc-party/keygen/participate
Content-Type: application/json
Authorization: Bearer <token>
请求体:
{
"sessionId": "550e8400-e29b-41d4-a716-446655440000",
"partyId": "user123-server",
"joinToken": "join-token-abc123",
"shareType": "wallet",
"userId": "user-id-123"
}
| 字段 | 类型 | 必填 | 描述 |
|---|---|---|---|
| sessionId | string (UUID) | 是 | 会话唯一标识 |
| partyId | string | 是 | 参与方 ID,格式:{identifier}-{type} |
| joinToken | string | 是 | 加入会话的令牌 |
| shareType | enum | 是 | 分片类型:wallet 或 custody |
| userId | string | 否 | 关联的用户 ID |
响应 202 Accepted:
{
"success": true,
"data": {
"message": "Keygen participation started",
"sessionId": "550e8400-e29b-41d4-a716-446655440000",
"partyId": "user123-server"
}
}
错误响应:
400 Bad Request - 参数验证失败:
{
"success": false,
"message": "Validation failed",
"errors": [
{
"field": "sessionId",
"message": "sessionId must be a UUID"
}
]
}
401 Unauthorized - 认证失败:
{
"success": false,
"message": "缺少认证令牌"
}
POST /keygen/participate-sync
参与 MPC 密钥生成会话(同步)。等待 MPC 协议完成后返回结果。
请求: 与异步端点相同
响应 200 OK:
{
"success": true,
"data": {
"shareId": "share_1699887766123_abc123xyz",
"publicKey": "03a1b2c3d4e5f6...",
"threshold": "2-of-3",
"sessionId": "550e8400-e29b-41d4-a716-446655440000",
"partyId": "user123-server"
}
}
签名 (Signing)
POST /signing/participate
参与 MPC 签名会话(异步)。
请求:
POST /api/v1/mpc-party/signing/participate
Content-Type: application/json
Authorization: Bearer <token>
请求体:
{
"sessionId": "660e8400-e29b-41d4-a716-446655440001",
"partyId": "user123-server",
"joinToken": "join-token-def456",
"messageHash": "abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890",
"publicKey": "03a1b2c3d4e5f6..."
}
| 字段 | 类型 | 必填 | 描述 |
|---|---|---|---|
| sessionId | string (UUID) | 是 | 签名会话唯一标识 |
| partyId | string | 是 | 参与方 ID |
| joinToken | string | 是 | 加入会话的令牌 |
| messageHash | string (hex, 64 chars) | 是 | 待签名的消息哈希 |
| publicKey | string (hex) | 是 | 对应的公钥 |
响应 202 Accepted:
{
"success": true,
"data": {
"message": "Signing participation started",
"sessionId": "660e8400-e29b-41d4-a716-446655440001",
"partyId": "user123-server"
}
}
错误响应:
400 Bad Request - 消息哈希格式无效:
{
"success": false,
"message": "Validation failed",
"errors": [
{
"field": "messageHash",
"message": "messageHash must be a 64-character hex string"
}
]
}
POST /signing/participate-sync
参与 MPC 签名会话(同步)。
响应 200 OK:
{
"success": true,
"data": {
"signature": "1122334455...",
"r": "aabbccdd...",
"s": "11223344...",
"v": 27,
"messageHash": "abcdef1234...",
"publicKey": "03a1b2c3d4e5f6..."
}
}
密钥轮换 (Key Rotation)
POST /share/rotate
参与密钥轮换会话(异步)。更新密钥分片而不改变公钥。
请求:
POST /api/v1/mpc-party/share/rotate
Content-Type: application/json
Authorization: Bearer <token>
请求体:
{
"sessionId": "770e8400-e29b-41d4-a716-446655440002",
"partyId": "user123-server",
"joinToken": "join-token-ghi789",
"publicKey": "03a1b2c3d4e5f6..."
}
| 字段 | 类型 | 必填 | 描述 |
|---|---|---|---|
| sessionId | string (UUID) | 是 | 轮换会话唯一标识 |
| partyId | string | 是 | 参与方 ID |
| joinToken | string | 是 | 加入会话的令牌 |
| publicKey | string (hex) | 是 | 要轮换的密钥公钥 |
响应 202 Accepted:
{
"success": true,
"data": {
"message": "Share rotation started",
"sessionId": "770e8400-e29b-41d4-a716-446655440002",
"partyId": "user123-server"
}
}
分片管理 (Share Management)
GET /shares
列出分片,支持过滤和分页。
请求:
GET /api/v1/mpc-party/shares?partyId=user123-server&status=active&page=1&limit=10
Authorization: Bearer <token>
查询参数:
| 参数 | 类型 | 必填 | 默认值 | 描述 |
|---|---|---|---|---|
| partyId | string | 否 | - | 按参与方 ID 过滤 |
| status | enum | 否 | - | 按状态过滤:active, rotated, revoked |
| shareType | enum | 否 | - | 按类型过滤:wallet, custody |
| publicKey | string | 否 | - | 按公钥过滤 |
| page | number | 否 | 1 | 页码(从 1 开始) |
| limit | number | 否 | 20 | 每页数量(1-100) |
响应 200 OK:
{
"success": true,
"data": {
"items": [
{
"id": "share_1699887766123_abc123xyz",
"partyId": "user123-server",
"sessionId": "550e8400-e29b-41d4-a716-446655440000",
"shareType": "wallet",
"publicKey": "03a1b2c3d4e5f6...",
"threshold": "2-of-3",
"status": "active",
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-15T10:30:00.000Z"
}
],
"total": 1,
"page": 1,
"limit": 10,
"totalPages": 1
}
}
GET /shares/:shareId
获取单个分片的详细信息。
请求:
GET /api/v1/mpc-party/shares/share_1699887766123_abc123xyz
Authorization: Bearer <token>
响应 200 OK:
{
"success": true,
"data": {
"id": "share_1699887766123_abc123xyz",
"partyId": "user123-server",
"sessionId": "550e8400-e29b-41d4-a716-446655440000",
"shareType": "wallet",
"publicKey": "03a1b2c3d4e5f6...",
"threshold": "2-of-3",
"status": "active",
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-15T10:30:00.000Z",
"lastUsedAt": "2024-01-15T12:00:00.000Z"
}
}
错误响应:
404 Not Found:
{
"success": false,
"message": "Share not found"
}
错误处理
错误响应格式
所有错误响应遵循统一格式:
{
"success": false,
"message": "错误描述",
"errors": [
{
"field": "字段名",
"message": "具体错误信息"
}
],
"statusCode": 400,
"timestamp": "2024-01-15T10:30:00.000Z",
"path": "/api/v1/mpc-party/keygen/participate"
}
HTTP 状态码
| 状态码 | 描述 |
|---|---|
| 200 | 成功 |
| 202 | 已接受(异步操作) |
| 400 | 请求参数错误 |
| 401 | 未认证 |
| 403 | 无权限 |
| 404 | 资源不存在 |
| 500 | 服务器内部错误 |
业务错误码
| 错误码 | 描述 |
|---|---|
| SHARE_NOT_FOUND | 分片不存在 |
| SHARE_REVOKED | 分片已撤销 |
| INVALID_SESSION | 无效的会话 |
| SESSION_EXPIRED | 会话已过期 |
| THRESHOLD_NOT_MET | 参与方数量未达到门限 |
| ENCRYPTION_ERROR | 加密/解密错误 |
| TSS_PROTOCOL_ERROR | TSS 协议执行错误 |
数据模型
ShareType 枚举
enum ShareType {
WALLET = 'wallet', // 用户钱包密钥分片
CUSTODY = 'custody' // 托管密钥分片
}
ShareStatus 枚举
enum ShareStatus {
ACTIVE = 'active', // 活跃状态
ROTATED = 'rotated', // 已轮换(旧分片)
REVOKED = 'revoked' // 已撤销
}
Threshold 格式
门限以 t-of-n 格式表示:
n: 总分片数t: 签名所需最小分片数
示例:2-of-3 表示 3 个分片中需要 2 个才能签名。
Webhook 事件(通过 Kafka)
当关键操作完成时,服务会发布事件到 Kafka:
ShareCreatedEvent
{
"eventType": "share.created",
"eventId": "evt_1699887766123_xyz",
"occurredAt": "2024-01-15T10:30:00.000Z",
"payload": {
"shareId": "share_1699887766123_abc123xyz",
"partyId": "user123-server",
"sessionId": "550e8400-e29b-41d4-a716-446655440000",
"shareType": "wallet",
"publicKey": "03a1b2c3d4e5f6...",
"threshold": "2-of-3"
}
}
ShareRotatedEvent
{
"eventType": "share.rotated",
"eventId": "evt_1699887766124_abc",
"occurredAt": "2024-01-15T11:00:00.000Z",
"payload": {
"newShareId": "share_1699887766124_def456uvw",
"oldShareId": "share_1699887766123_abc123xyz",
"partyId": "user123-server",
"sessionId": "770e8400-e29b-41d4-a716-446655440002"
}
}
ShareRevokedEvent
{
"eventType": "share.revoked",
"eventId": "evt_1699887766125_def",
"occurredAt": "2024-01-15T12:00:00.000Z",
"payload": {
"shareId": "share_1699887766123_abc123xyz",
"partyId": "user123-server",
"reason": "Security audit requirement"
}
}
SigningCompletedEvent
{
"eventType": "signing.completed",
"eventId": "evt_1699887766126_ghi",
"occurredAt": "2024-01-15T13:00:00.000Z",
"payload": {
"sessionId": "660e8400-e29b-41d4-a716-446655440001",
"signature": "1122334455...",
"publicKey": "03a1b2c3d4e5f6...",
"messageHash": "abcdef1234..."
}
}
速率限制
| 端点类型 | 限制 |
|---|---|
| 健康检查 | 无限制 |
| 查询端点 | 100 次/分钟 |
| Keygen | 10 次/分钟 |
| Signing | 60 次/分钟 |
| Rotation | 5 次/分钟 |
超出限制时返回 429 Too Many Requests。
SDK 使用示例
TypeScript/JavaScript
import axios from 'axios';
const api = axios.create({
baseURL: 'https://api.example.com/api/v1/mpc-party',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
});
// 参与 Keygen
async function participateInKeygen(params: {
sessionId: string;
partyId: string;
joinToken: string;
shareType: 'wallet' | 'custody';
}) {
const response = await api.post('/keygen/participate', params);
return response.data;
}
// 参与签名
async function participateInSigning(params: {
sessionId: string;
partyId: string;
joinToken: string;
messageHash: string;
publicKey: string;
}) {
const response = await api.post('/signing/participate', params);
return response.data;
}
// 列出分片
async function listShares(params?: {
partyId?: string;
status?: string;
page?: number;
limit?: number;
}) {
const response = await api.get('/shares', { params });
return response.data;
}
// 获取分片信息
async function getShareInfo(shareId: string) {
const response = await api.get(`/shares/${shareId}`);
return response.data;
}
cURL 示例
# 健康检查
curl -X GET https://api.example.com/api/v1/mpc-party/health
# 参与 Keygen
curl -X POST https://api.example.com/api/v1/mpc-party/keygen/participate \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"sessionId": "550e8400-e29b-41d4-a716-446655440000",
"partyId": "user123-server",
"joinToken": "join-token-abc123",
"shareType": "wallet",
"userId": "user-id-123"
}'
# 列出分片
curl -X GET "https://api.example.com/api/v1/mpc-party/shares?partyId=user123-server&page=1&limit=10" \
-H "Authorization: Bearer <token>"
Swagger 文档
在非生产环境,Swagger UI 可通过以下地址访问:
http://localhost:3006/api/docs
提供交互式 API 文档和测试功能。