rwadurian/backend/services/mpc-service/docs/API.md

622 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# MPC Party Service API 文档
## 概述
MPC Party Service 提供 RESTful API用于参与 MPC 密钥生成、签名和密钥轮换操作。
**基础 URL**: `/api/v1/mpc-party`
**认证方式**: Bearer Token (JWT)
## 认证
除了健康检查端点外,所有 API 都需要 JWT 认证:
```http
Authorization: Bearer <token>
```
JWT Payload 结构:
```json
{
"sub": "user-id",
"type": "access",
"partyId": "user123-server",
"iat": 1699887766,
"exp": 1699895766
}
```
## API 端点
### 健康检查
#### GET /health
检查服务健康状态。此端点不需要认证。
**请求**:
```http
GET /api/v1/mpc-party/health
```
**响应** `200 OK`:
```json
{
"success": true,
"data": {
"status": "ok",
"service": "mpc-party-service",
"timestamp": "2024-01-15T10:30:00.000Z"
}
}
```
---
### 密钥生成 (Keygen)
#### POST /keygen/participate
参与 MPC 密钥生成会话(异步)。立即返回 202后台异步执行 MPC 协议。
**请求**:
```http
POST /api/v1/mpc-party/keygen/participate
Content-Type: application/json
Authorization: Bearer <token>
```
**请求体**:
```json
{
"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`:
```json
{
"success": true,
"data": {
"message": "Keygen participation started",
"sessionId": "550e8400-e29b-41d4-a716-446655440000",
"partyId": "user123-server"
}
}
```
**错误响应**:
`400 Bad Request` - 参数验证失败:
```json
{
"success": false,
"message": "Validation failed",
"errors": [
{
"field": "sessionId",
"message": "sessionId must be a UUID"
}
]
}
```
`401 Unauthorized` - 认证失败:
```json
{
"success": false,
"message": "缺少认证令牌"
}
```
---
#### POST /keygen/participate-sync
参与 MPC 密钥生成会话(同步)。等待 MPC 协议完成后返回结果。
**请求**: 与异步端点相同
**响应** `200 OK`:
```json
{
"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 签名会话(异步)。
**请求**:
```http
POST /api/v1/mpc-party/signing/participate
Content-Type: application/json
Authorization: Bearer <token>
```
**请求体**:
```json
{
"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`:
```json
{
"success": true,
"data": {
"message": "Signing participation started",
"sessionId": "660e8400-e29b-41d4-a716-446655440001",
"partyId": "user123-server"
}
}
```
**错误响应**:
`400 Bad Request` - 消息哈希格式无效:
```json
{
"success": false,
"message": "Validation failed",
"errors": [
{
"field": "messageHash",
"message": "messageHash must be a 64-character hex string"
}
]
}
```
---
#### POST /signing/participate-sync
参与 MPC 签名会话(同步)。
**响应** `200 OK`:
```json
{
"success": true,
"data": {
"signature": "1122334455...",
"r": "aabbccdd...",
"s": "11223344...",
"v": 27,
"messageHash": "abcdef1234...",
"publicKey": "03a1b2c3d4e5f6..."
}
}
```
---
### 密钥轮换 (Key Rotation)
#### POST /share/rotate
参与密钥轮换会话(异步)。更新密钥分片而不改变公钥。
**请求**:
```http
POST /api/v1/mpc-party/share/rotate
Content-Type: application/json
Authorization: Bearer <token>
```
**请求体**:
```json
{
"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`:
```json
{
"success": true,
"data": {
"message": "Share rotation started",
"sessionId": "770e8400-e29b-41d4-a716-446655440002",
"partyId": "user123-server"
}
}
```
---
### 分片管理 (Share Management)
#### GET /shares
列出分片,支持过滤和分页。
**请求**:
```http
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`:
```json
{
"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
获取单个分片的详细信息。
**请求**:
```http
GET /api/v1/mpc-party/shares/share_1699887766123_abc123xyz
Authorization: Bearer <token>
```
**响应** `200 OK`:
```json
{
"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`:
```json
{
"success": false,
"message": "Share not found"
}
```
---
## 错误处理
### 错误响应格式
所有错误响应遵循统一格式:
```json
{
"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 枚举
```typescript
enum ShareType {
WALLET = 'wallet', // 用户钱包密钥分片
CUSTODY = 'custody' // 托管密钥分片
}
```
### ShareStatus 枚举
```typescript
enum ShareStatus {
ACTIVE = 'active', // 活跃状态
ROTATED = 'rotated', // 已轮换(旧分片)
REVOKED = 'revoked' // 已撤销
}
```
### Threshold 格式
门限以 `t-of-n` 格式表示:
- `n`: 总分片数
- `t`: 签名所需最小分片数
示例:`2-of-3` 表示 3 个分片中需要 2 个才能签名。
---
## Webhook 事件(通过 Kafka
当关键操作完成时,服务会发布事件到 Kafka
### ShareCreatedEvent
```json
{
"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
```json
{
"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
```json
{
"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
```json
{
"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
```typescript
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 示例
```bash
# 健康检查
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 文档和测试功能。