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

25 KiB
Raw Blame History

MPC Party Service 架构文档

概述

MPC Party Service 是 RWA Durian 系统中的多方计算Multi-Party Computation服务端组件。该服务负责参与分布式密钥生成、签名和密钥轮换协议安全地管理服务端的密钥分片。

架构设计原则

1. 六边形架构 (Hexagonal Architecture)

本服务采用六边形架构(又称端口与适配器架构),实现业务逻辑与外部依赖的解耦:

┌─────────────────────────────────────────────────────────────┐
│                      API Layer (Driving Adapters)            │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐          │
│  │ REST API    │  │ gRPC API    │  │ WebSocket   │          │
│  │ Controllers │  │ (Future)    │  │ Handlers    │          │
│  └──────┬──────┘  └──────┬──────┘  └──────┬──────┘          │
└─────────┼────────────────┼────────────────┼─────────────────┘
          │                │                │
          ▼                ▼                ▼
┌─────────────────────────────────────────────────────────────┐
│                    Application Layer                         │
│  ┌─────────────────┐  ┌─────────────────┐                   │
│  │ Command Handlers│  │ Query Handlers  │                   │
│  │ - Keygen        │  │ - GetShareInfo  │                   │
│  │ - Signing       │  │ - ListShares    │                   │
│  │ - Rotate        │  │                 │                   │
│  └────────┬────────┘  └────────┬────────┘                   │
│           │                    │                             │
│  ┌────────▼────────────────────▼────────┐                   │
│  │     Application Services              │                   │
│  │     - MPCPartyApplicationService      │                   │
│  └────────────────┬─────────────────────┘                   │
└───────────────────┼─────────────────────────────────────────┘
                    │
                    ▼
┌─────────────────────────────────────────────────────────────┐
│                      Domain Layer                            │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐          │
│  │  Entities   │  │   Value     │  │  Domain     │          │
│  │ - PartyShare│  │   Objects   │  │  Services   │          │
│  │ - Session   │  │ - ShareId   │  │ - TSS       │          │
│  │   State     │  │ - PartyId   │  │ - Encryption│          │
│  │             │  │ - Threshold │  │             │          │
│  └─────────────┘  └─────────────┘  └─────────────┘          │
│                                                              │
│  ┌─────────────────────────────────────────────────┐        │
│  │              Domain Events                       │        │
│  │  - ShareCreatedEvent                            │        │
│  │  - ShareRotatedEvent                            │        │
│  │  - ShareRevokedEvent                            │        │
│  └─────────────────────────────────────────────────┘        │
└─────────────────────────────────────────────────────────────┘
                    │
                    ▼
┌─────────────────────────────────────────────────────────────┐
│                Infrastructure Layer (Driven Adapters)        │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐          │
│  │  Prisma     │  │   Redis     │  │   Kafka     │          │
│  │  Repository │  │   Cache     │  │   Events    │          │
│  └─────────────┘  └─────────────┘  └─────────────┘          │
│                                                              │
│  ┌─────────────┐  ┌─────────────┐                           │
│  │ Coordinator │  │  Message    │                           │
│  │   Client    │  │  Router     │                           │
│  └─────────────┘  └─────────────┘                           │
└─────────────────────────────────────────────────────────────┘

2. CQRS 模式 (Command Query Responsibility Segregation)

命令和查询分离,提高系统的可扩展性和可维护性:

  • Commands: 改变系统状态的操作

    • ParticipateInKeygenCommand
    • ParticipateInSigningCommand
    • RotateShareCommand
  • Queries: 只读操作

    • GetShareInfoQuery
    • ListSharesQuery

3. 领域驱动设计 (DDD)

  • 聚合根 (Aggregate Root): PartyShare
  • 值对象 (Value Objects): ShareId, PartyId, SessionId, Threshold, ShareData, PublicKey, Signature, MessageHash
  • 领域事件 (Domain Events): 用于解耦和异步处理
  • 仓储接口 (Repository Interfaces): 定义在领域层,实现在基础设施层

目录结构

src/
├── api/                          # API 层 (Driving Adapters)
│   ├── controllers/              # REST 控制器
│   │   └── mpc-party.controller.ts
│   ├── dto/                      # 数据传输对象
│   │   ├── request/              # 请求 DTO
│   │   └── response/             # 响应 DTO
│   └── api.module.ts
│
├── application/                  # 应用层
│   ├── commands/                 # 命令处理器
│   │   ├── participate-keygen/
│   │   ├── participate-signing/
│   │   └── rotate-share/
│   ├── queries/                  # 查询处理器
│   │   ├── get-share-info/
│   │   └── list-shares/
│   ├── services/                 # 应用服务
│   │   └── mpc-party-application.service.ts
│   └── application.module.ts
│
├── domain/                       # 领域层
│   ├── entities/                 # 实体
│   │   ├── party-share.entity.ts
│   │   └── session-state.entity.ts
│   ├── value-objects/            # 值对象
│   │   └── index.ts
│   ├── enums/                    # 枚举
│   │   └── index.ts
│   ├── events/                   # 领域事件
│   │   └── index.ts
│   ├── repositories/             # 仓储接口
│   │   ├── party-share.repository.interface.ts
│   │   └── session-state.repository.interface.ts
│   ├── services/                 # 领域服务
│   │   ├── share-encryption.domain-service.ts
│   │   └── tss-protocol.domain-service.ts
│   └── domain.module.ts
│
├── infrastructure/               # 基础设施层 (Driven Adapters)
│   ├── persistence/              # 持久化
│   │   ├── prisma/               # Prisma ORM
│   │   ├── repositories/         # 仓储实现
│   │   └── mappers/              # 数据映射器
│   ├── redis/                    # Redis 缓存与锁
│   │   ├── cache/
│   │   └── lock/
│   ├── messaging/                # 消息传递
│   │   └── kafka/
│   ├── external/                 # 外部服务客户端
│   │   └── mpc-system/
│   └── infrastructure.module.ts
│
├── shared/                       # 共享模块
│   ├── decorators/               # 装饰器
│   ├── filters/                  # 异常过滤器
│   ├── guards/                   # 守卫
│   └── interceptors/             # 拦截器
│
├── config/                       # 配置
│   └── index.ts
│
├── app.module.ts                 # 根模块
└── main.ts                       # 入口文件

核心组件详解

1. Domain Layer (领域层)

PartyShare 实体

// src/domain/entities/party-share.entity.ts
export class PartyShare {
  private readonly _id: ShareId;
  private readonly _partyId: PartyId;
  private readonly _sessionId: SessionId;
  private readonly _shareType: PartyShareType;
  private readonly _shareData: ShareData;
  private readonly _publicKey: PublicKey;
  private readonly _threshold: Threshold;
  private _status: PartyShareStatus;
  private _lastUsedAt?: Date;
  private readonly _domainEvents: DomainEvent[] = [];

  // 工厂方法 - 创建新分片
  static create(props: CreatePartyShareProps): PartyShare;

  // 工厂方法 - 从持久化数据重建
  static reconstruct(props: ReconstructPartyShareProps): PartyShare;

  // 业务方法
  markAsUsed(): void;
  rotate(newShareData: ShareData, newSessionId: SessionId): PartyShare;
  revoke(reason: string): void;
}

Value Objects (值对象)

值对象是不可变的,通过值来识别:

// ShareId - 分片唯一标识
export class ShareId {
  static create(value: string): ShareId;
  static generate(): ShareId;
  get value(): string;
  equals(other: ShareId): boolean;
}

// Threshold - 门限配置
export class Threshold {
  static create(n: number, t: number): Threshold;
  get n(): number;  // 总分片数
  get t(): number;  // 签名门限
  canSign(availableParties: number): boolean;
}

// ShareData - 加密的分片数据
export class ShareData {
  static create(encryptedData: Buffer, iv: Buffer, authTag: Buffer): ShareData;
  toJSON(): ShareDataJson;
  static fromJSON(json: ShareDataJson): ShareData;
}

Domain Services (领域服务)

// 分片加密服务
export class ShareEncryptionDomainService {
  encrypt(plaintext: Buffer, masterKey: Buffer): EncryptedData;
  decrypt(encryptedData: EncryptedData, masterKey: Buffer): Buffer;
  generateMasterKey(): Buffer;
  deriveKeyFromPassword(password: string, salt: Buffer): Promise<Buffer>;
}

// TSS 协议服务接口
export interface TssProtocolDomainService {
  runKeygen(params: KeygenParams): Promise<KeygenResult>;
  runSigning(params: SigningParams): Promise<SigningResult>;
  runRefresh(params: RefreshParams): Promise<RefreshResult>;
}

2. Application Layer (应用层)

Command Handlers

// ParticipateInKeygenHandler
@CommandHandler(ParticipateInKeygenCommand)
export class ParticipateInKeygenHandler {
  async execute(command: ParticipateInKeygenCommand): Promise<KeygenResultDto> {
    // 1. 加入会话
    const sessionInfo = await this.coordinatorClient.joinSession(/*...*/);

    // 2. 运行 TSS Keygen 协议
    const keygenResult = await this.tssProtocolService.runKeygen(/*...*/);

    // 3. 加密并保存分片
    const encryptedShare = this.encryptionService.encrypt(/*...*/);
    const partyShare = PartyShare.create(/*...*/);
    await this.partyShareRepository.save(partyShare);

    // 4. 发布领域事件
    await this.eventPublisher.publishAll(partyShare.domainEvents);

    return result;
  }
}

Application Service

应用服务协调命令和查询处理器:

@Injectable()
export class MPCPartyApplicationService {
  async participateInKeygen(params: ParticipateKeygenParams): Promise<KeygenResultDto>;
  async participateInSigning(params: ParticipateSigningParams): Promise<SigningResultDto>;
  async rotateShare(params: RotateShareParams): Promise<RotateResultDto>;
  async getShareInfo(shareId: string): Promise<ShareInfoDto>;
  async listShares(params: ListSharesParams): Promise<ListSharesResultDto>;
}

3. Infrastructure Layer (基础设施层)

Repository Implementation

@Injectable()
export class PartyShareRepositoryImpl implements PartyShareRepository {
  constructor(
    private readonly prisma: PrismaService,
    private readonly mapper: PartyShareMapper,
  ) {}

  async save(share: PartyShare): Promise<void> {
    const entity = this.mapper.toPersistence(share);
    await this.prisma.partyShare.create({ data: entity });
  }

  async findById(id: ShareId): Promise<PartyShare | null> {
    const entity = await this.prisma.partyShare.findUnique({
      where: { id: id.value },
    });
    return entity ? this.mapper.toDomain(entity) : null;
  }
}

External Service Clients

// MPC Coordinator Client - 与协调器通信
@Injectable()
export class MPCCoordinatorClient {
  async joinSession(params: JoinSessionParams): Promise<SessionInfo>;
  async reportCompletion(sessionId: string, status: string): Promise<void>;
}

// Message Router Client - P2P 消息传递
@Injectable()
export class MPCMessageRouterClient {
  async subscribeMessages(sessionId: string): Promise<AsyncIterator<Message>>;
  async sendMessage(message: Message): Promise<void>;
}

4. API Layer (API 层)

Controller

@Controller('mpc-party')
@UseGuards(JwtAuthGuard)
export class MPCPartyController {
  // 异步端点 - 立即返回 202
  @Post('keygen/participate')
  @HttpCode(HttpStatus.ACCEPTED)
  async participateInKeygen(@Body() dto: ParticipateKeygenDto): Promise<KeygenAcceptedDto>;

  // 同步端点 - 等待完成
  @Post('keygen/participate-sync')
  async participateInKeygenSync(@Body() dto: ParticipateKeygenDto): Promise<KeygenResultDto>;

  // 查询端点
  @Get('shares')
  async listShares(@Query() query: ListSharesDto): Promise<ListSharesResponseDto>;

  @Get('shares/:shareId')
  async getShareInfo(@Param('shareId') shareId: string): Promise<ShareInfoResponseDto>;

  // 公开端点
  @Public()
  @Get('health')
  health(): HealthStatus;
}

数据流

Keygen 流程

┌──────────┐     ┌──────────┐     ┌──────────┐     ┌──────────┐
│  Client  │     │Controller│     │ Handler  │     │TSS Service│
└────┬─────┘     └────┬─────┘     └────┬─────┘     └────┬─────┘
     │                │                │                │
     │ POST /keygen   │                │                │
     │ /participate   │                │                │
     │───────────────>│                │                │
     │                │ execute()      │                │
     │                │───────────────>│                │
     │                │                │ joinSession()  │
     │                │                │───────────────>│ Coordinator
     │                │                │<───────────────│
     │                │                │                │
     │                │                │ runKeygen()    │
     │                │                │───────────────>│
     │                │                │    ...MPC...   │
     │                │                │<───────────────│
     │                │                │                │
     │                │                │ save(share)    │
     │                │                │───────────────>│ Repository
     │                │                │<───────────────│
     │                │                │                │
     │                │                │ publish(event) │
     │                │                │───────────────>│ Kafka
     │  202 Accepted  │<───────────────│                │
     │<───────────────│                │                │
     │                │                │                │

Signing 流程

┌──────────┐     ┌──────────┐     ┌──────────┐     ┌──────────┐
│  Client  │     │Controller│     │ Handler  │     │TSS Service│
└────┬─────┘     └────┬─────┘     └────┬─────┘     └────┬─────┘
     │                │                │                │
     │ POST /signing  │                │                │
     │ /participate   │                │                │
     │───────────────>│                │                │
     │                │ execute()      │                │
     │                │───────────────>│                │
     │                │                │ findShare()    │
     │                │                │───────────────>│ Repository
     │                │                │<───────────────│
     │                │                │                │
     │                │                │ decrypt()      │
     │                │                │───────────────>│ Encryption
     │                │                │<───────────────│
     │                │                │                │
     │                │                │ runSigning()   │
     │                │                │───────────────>│
     │                │                │    ...MPC...   │
     │                │                │<───────────────│
     │                │                │                │
     │  202 Accepted  │<───────────────│ signature      │
     │<───────────────│                │                │

安全设计

1. 分片加密

所有密钥分片在存储前使用 AES-256-GCM 加密:

// 加密流程
const { encryptedData, iv, authTag } = encryptionService.encrypt(
  shareData,
  masterKey
);

// 存储加密后的数据
const shareData = ShareData.create(encryptedData, iv, authTag);

2. 访问控制

  • JWT Token 验证
  • Party ID 绑定
  • 操作审计日志

3. 安全通信

  • TLS 加密传输
  • 消息签名验证
  • 会话令牌认证

扩展性设计

1. 水平扩展

  • 无状态服务设计
  • Redis 分布式锁
  • Kafka 事件驱动

2. 多协议支持

通过领域服务接口抽象,支持不同的 TSS 实现:

// 接口定义
export interface TssProtocolDomainService {
  runKeygen(params: KeygenParams): Promise<KeygenResult>;
  runSigning(params: SigningParams): Promise<SigningResult>;
  runRefresh(params: RefreshParams): Promise<RefreshResult>;
}

// 可替换实现
// - GG20 实现
// - FROST 实现
// - 其他 TSS 协议

3. 插件化设计

基础设施层的实现可以轻松替换:

  • 数据库Prisma 支持多种数据库
  • 缓存:可替换为其他缓存方案
  • 消息队列:可替换为 RabbitMQ 等

配置管理

// src/config/index.ts
export const configurations = [
  () => ({
    port: parseInt(process.env.APP_PORT, 10) || 3006,
    env: process.env.NODE_ENV || 'development',
    apiPrefix: process.env.API_PREFIX || 'api/v1',

    database: {
      url: process.env.DATABASE_URL,
    },

    redis: {
      host: process.env.REDIS_HOST,
      port: parseInt(process.env.REDIS_PORT, 10) || 6379,
    },

    mpc: {
      coordinatorUrl: process.env.MPC_COORDINATOR_URL,
      messageRouterWsUrl: process.env.MPC_MESSAGE_ROUTER_WS_URL,
      partyId: process.env.MPC_PARTY_ID,
    },

    security: {
      jwtSecret: process.env.JWT_SECRET,
      shareMasterKey: process.env.SHARE_MASTER_KEY,
    },
  }),
];

监控与可观测性

1. 日志

使用 NestJS Logger支持结构化日志

private readonly logger = new Logger(MPCPartyController.name);

this.logger.log(`Keygen request: session=${sessionId}, party=${partyId}`);
this.logger.error(`Keygen failed: ${error.message}`, error.stack);

2. 健康检查

@Get('health')
health() {
  return {
    status: 'ok',
    timestamp: new Date().toISOString(),
    service: 'mpc-party-service',
  };
}

3. 指标(待实现)

  • 请求延迟
  • 错误率
  • MPC 协议执行时间
  • 分片操作统计

依赖关系图

┌─────────────────────────────────────────────────────────────┐
│                         AppModule                            │
├─────────────────────────────────────────────────────────────┤
│  imports:                                                    │
│    ├── ConfigModule (global)                                │
│    ├── JwtModule (global)                                   │
│    ├── DomainModule                                         │
│    ├── InfrastructureModule                                 │
│    ├── ApplicationModule                                    │
│    └── ApiModule                                            │
│                                                              │
│  providers:                                                  │
│    ├── GlobalExceptionFilter                                │
│    ├── TransformInterceptor                                 │
│    └── JwtAuthGuard                                         │
└─────────────────────────────────────────────────────────────┘
         │
         ▼
┌─────────────────┐  ┌─────────────────┐  ┌─────────────────┐
│  DomainModule   │  │Infrastructure   │  │ApplicationModule│
│                 │  │    Module       │  │                 │
│ - Encryption    │◄─┤ - Prisma        │◄─┤ - Handlers      │
│   Service       │  │ - Redis         │  │ - AppService    │
│ - TSS Service   │  │ - Kafka         │  │                 │
│   (interface)   │  │ - Clients       │  │                 │
└─────────────────┘  └─────────────────┘  └─────────────────┘
                              │
                              ▼
                     ┌─────────────────┐
                     │    ApiModule    │
                     │                 │
                     │ - Controllers   │
                     │ - DTOs          │
                     └─────────────────┘

总结

MPC Party Service 采用清晰的分层架构,遵循 DDD 和 CQRS 原则,实现了:

  1. 高内聚低耦合:各层职责明确,依赖于抽象
  2. 可测试性:依赖注入使得单元测试和集成测试易于实现
  3. 可扩展性:插件化设计支持不同的 TSS 协议和基础设施
  4. 安全性:多层安全措施保护敏感的密钥分片
  5. 可观测性:完善的日志和健康检查支持运维监控