# 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 文档和测试功能。
