123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496 |
- /**
- * Pacifica签名器实现
- *
- * 使用@noble/ed25519库实现Ed25519签名,满足<50ms性能要求
- */
- import * as ed25519 from '@noble/ed25519';
- import { sha512 } from '@noble/hashes/sha512';
- import { Platform, SignResult, CredentialManagerError, ErrorType } from '@/core/types';
- // 设置ed25519所需的哈希函数
- ed25519.etc.sha512Sync = (...m) => sha512(ed25519.etc.concatBytes(...m));
- // ============================================================================
- // Pacifica特定类型
- // ============================================================================
- export enum PacificaOrderType {
- MARKET = 'market',
- LIMIT = 'limit',
- STOP_LOSS = 'stop_loss',
- TAKE_PROFIT = 'take_profit',
- CANCEL = 'cancel',
- CANCEL_ALL = 'cancel_all',
- }
- export interface PacificaSignRequest {
- accountId: string;
- message: Uint8Array;
- orderType: PacificaOrderType;
- options?: PacificaSignOptions;
- }
- export interface PacificaSignOptions {
- timeout?: number;
- includeTimestamp?: boolean;
- encoding?: 'base64' | 'base58' | 'hex';
- enableBatchOptimization?: boolean;
- }
- export interface PacificaSignResponse {
- success: boolean;
- signature: string;
- algorithm: string;
- timestamp: Date;
- executionTime?: number;
- error?: string;
- publicKey: string;
- orderType: PacificaOrderType;
- }
- export interface PacificaVerifyRequest {
- accountId: string;
- message: Uint8Array;
- signature: string;
- publicKey: string;
- orderType?: PacificaOrderType;
- }
- export interface PacificaVerifyResponse {
- success: boolean;
- algorithm: 'ed25519';
- publicKey: string;
- isValid?: boolean;
- timestamp?: Date;
- verificationId?: string;
- error?: string;
- }
- export interface PacificaOrderMessage {
- order_type: PacificaOrderType;
- symbol: string;
- side: 'buy' | 'sell';
- size: string;
- price?: string;
- client_order_id?: string;
- client_id?: string; // 为了兼容契约测试
- expiry?: number; // 为了兼容契约测试
- timestamp?: number;
- }
- export interface PacificaCancelMessage {
- action: 'cancel' | 'cancel_all';
- order_type?: string; // 为了兼容契约测试
- symbol?: string;
- client_order_id?: string;
- order_id?: string;
- timestamp?: number;
- }
- // ============================================================================
- // 常量定义
- // ============================================================================
- export const PACIFICA_CONSTANTS = {
- PRIVATE_KEY_LENGTH: 32,
- PUBLIC_KEY_LENGTH: 32,
- SIGNATURE_LENGTH: 64,
- PRIVATE_KEY_HEX_LENGTH: 64,
- PUBLIC_KEY_BASE58_LENGTH: 44,
- SIGNATURE_BASE64_LENGTH: 88,
- MAX_MESSAGE_SIZE: 1024 * 1024, // 1MB
- DEFAULT_SIGN_TIMEOUT: 30000,
- MAX_BATCH_SIZE: 100,
- } as const;
- // ============================================================================
- // 错误类型
- // ============================================================================
- export enum PacificaErrorCode {
- INVALID_PRIVATE_KEY = 'INVALID_PRIVATE_KEY',
- INVALID_PUBLIC_KEY = 'INVALID_PUBLIC_KEY',
- INVALID_MESSAGE = 'INVALID_MESSAGE',
- SIGNATURE_FAILED = 'SIGNATURE_FAILED',
- VERIFICATION_FAILED = 'VERIFICATION_FAILED',
- ACCOUNT_NOT_FOUND = 'ACCOUNT_NOT_FOUND',
- TIMEOUT = 'TIMEOUT',
- BATCH_SIZE_EXCEEDED = 'BATCH_SIZE_EXCEEDED',
- MESSAGE_TOO_LARGE = 'MESSAGE_TOO_LARGE',
- }
- export class PacificaSignerError extends Error {
- constructor(
- message: string,
- public readonly code: PacificaErrorCode,
- public readonly details?: any
- ) {
- super(message);
- this.name = 'PacificaSignerError';
- }
- }
- // ============================================================================
- // 接口定义
- // ============================================================================
- export interface IPacificaSigner {
- readonly platform: Platform.PACIFICA;
- signOrder(request: PacificaSignRequest): Promise<PacificaSignResponse>;
- verifySignature(request: PacificaVerifyRequest): Promise<PacificaVerifyResponse>;
- getPublicKey(accountId: string): Promise<string>;
- signBatch(requests: PacificaSignRequest[]): Promise<PacificaSignResponse[]>;
- }
- // ============================================================================
- // Pacifica签名器实现
- // ============================================================================
- export class PacificaSigner implements IPacificaSigner {
- public readonly platform = Platform.PACIFICA;
- private accountCredentials = new Map<string, string>(); // accountId -> privateKey
- private publicKeyCache = new Map<string, string>(); // accountId -> publicKey
- /**
- * 添加账户凭证
- */
- public addAccount(accountId: string, privateKey: string): void {
- this.validatePrivateKey(privateKey);
- this.accountCredentials.set(accountId, privateKey);
- // 清除公钥缓存,强制重新生成
- this.publicKeyCache.delete(accountId);
- }
- /**
- * 移除账户
- */
- public removeAccount(accountId: string): void {
- this.accountCredentials.delete(accountId);
- this.publicKeyCache.delete(accountId);
- }
- /**
- * 签名订单
- */
- public async signOrder(request: PacificaSignRequest): Promise<PacificaSignResponse> {
- const startTime = Date.now();
- try {
- // 验证请求
- this.validateSignRequest(request);
- // 获取私钥
- const privateKey = this.getAccountPrivateKey(request.accountId);
- // 设置默认选项
- const options = {
- timeout: PACIFICA_CONSTANTS.DEFAULT_SIGN_TIMEOUT,
- includeTimestamp: true,
- encoding: 'base64' as const,
- ...request.options,
- };
- // 检查超时
- const timeoutPromise = new Promise<never>((_, reject) => {
- setTimeout(() => {
- reject(new PacificaSignerError(
- `Signing timeout after ${options.timeout}ms`,
- PacificaErrorCode.TIMEOUT,
- { accountId: request.accountId, timeout: options.timeout }
- ));
- }, options.timeout);
- });
- // 执行签名
- const signPromise = this.performSigning(request.message, privateKey, options.encoding);
- const { signature, publicKey } = await Promise.race([signPromise, timeoutPromise]);
- const signTime = Date.now() - startTime;
- // 验证性能要求
- if (signTime >= 50) {
- console.warn(`Pacifica signing took ${signTime}ms, exceeding 50ms requirement`);
- }
- return {
- success: true,
- signature,
- algorithm: 'ed25519',
- publicKey,
- orderType: request.orderType,
- timestamp: new Date(),
- executionTime: signTime,
- };
- } catch (error) {
- const signTime = Date.now() - startTime;
- if (error instanceof PacificaSignerError) {
- return {
- success: false,
- signature: '',
- algorithm: 'ed25519',
- publicKey: '',
- orderType: request.orderType,
- timestamp: new Date(),
- error: error.message,
- };
- }
- return {
- success: false,
- signature: '',
- algorithm: 'ed25519',
- publicKey: '',
- orderType: request.orderType,
- timestamp: new Date(),
- error: `Unexpected error: ${(error as Error).message}`,
- };
- }
- }
- /**
- * 验证签名
- */
- public async verifySignature(request: PacificaVerifyRequest): Promise<PacificaVerifyResponse> {
- try {
- // 验证请求
- if (!request.message || !request.signature || !request.publicKey) {
- throw new PacificaSignerError(
- 'Missing required fields for verification',
- PacificaErrorCode.VERIFICATION_FAILED,
- request
- );
- }
- // 解码签名
- const signatureBytes = this.decodeSignature(request.signature);
- const publicKeyBytes = this.decodePublicKey(request.publicKey);
- // 执行验证
- const isValid = await ed25519.verify(signatureBytes, request.message, publicKeyBytes);
- return {
- success: isValid,
- algorithm: 'ed25519',
- publicKey: request.publicKey,
- isValid,
- timestamp: new Date(),
- verificationId: `verify_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`,
- };
- } catch (error) {
- return {
- success: false,
- algorithm: 'ed25519',
- publicKey: request.publicKey,
- isValid: false,
- timestamp: new Date(),
- error: `Verification failed: ${(error as Error).message}`,
- };
- }
- }
- /**
- * 获取公钥
- */
- public async getPublicKey(accountId: string): Promise<string> {
- // 检查缓存
- const cached = this.publicKeyCache.get(accountId);
- if (cached) {
- return cached;
- }
- // 获取私钥并生成公钥
- const privateKey = this.getAccountPrivateKey(accountId);
- const privateKeyBytes = this.hexToBytes(privateKey);
- const publicKeyBytes = await ed25519.getPublicKey(privateKeyBytes);
- const publicKeyBase58 = this.bytesToBase58(publicKeyBytes);
- // 缓存公钥
- this.publicKeyCache.set(accountId, publicKeyBase58);
- return publicKeyBase58;
- }
- /**
- * 批量签名
- */
- public async signBatch(requests: PacificaSignRequest[]): Promise<PacificaSignResponse[]> {
- // 验证批量大小
- if (requests.length > PACIFICA_CONSTANTS.MAX_BATCH_SIZE) {
- throw new PacificaSignerError(
- `Batch size ${requests.length} exceeds maximum ${PACIFICA_CONSTANTS.MAX_BATCH_SIZE}`,
- PacificaErrorCode.BATCH_SIZE_EXCEEDED,
- { requestCount: requests.length, maxSize: PACIFICA_CONSTANTS.MAX_BATCH_SIZE }
- );
- }
- // 并行执行签名
- const signPromises = requests.map(request => this.signOrder(request));
- return Promise.all(signPromises);
- }
- // ============================================================================
- // 私有方法
- // ============================================================================
- /**
- * 验证签名请求
- */
- private validateSignRequest(request: PacificaSignRequest): void {
- if (!request.accountId || typeof request.accountId !== 'string') {
- throw new PacificaSignerError(
- 'Invalid account ID',
- PacificaErrorCode.ACCOUNT_NOT_FOUND,
- { accountId: request.accountId }
- );
- }
- if (!request.message || !(request.message instanceof Uint8Array)) {
- throw new PacificaSignerError(
- 'Invalid message: must be Uint8Array',
- PacificaErrorCode.INVALID_MESSAGE,
- { message: request.message }
- );
- }
- if (request.message.length > PACIFICA_CONSTANTS.MAX_MESSAGE_SIZE) {
- throw new PacificaSignerError(
- `Message too large: ${request.message.length} bytes > ${PACIFICA_CONSTANTS.MAX_MESSAGE_SIZE}`,
- PacificaErrorCode.MESSAGE_TOO_LARGE,
- { messageSize: request.message.length }
- );
- }
- if (!Object.values(PacificaOrderType).includes(request.orderType)) {
- throw new PacificaSignerError(
- `Invalid order type: ${request.orderType}`,
- PacificaErrorCode.INVALID_MESSAGE,
- { orderType: request.orderType }
- );
- }
- }
- /**
- * 验证私钥格式
- */
- private validatePrivateKey(privateKey: string): void {
- if (!privateKey || typeof privateKey !== 'string') {
- throw new PacificaSignerError(
- 'Private key must be a string',
- PacificaErrorCode.INVALID_PRIVATE_KEY,
- { privateKey }
- );
- }
- if (!/^[0-9a-fA-F]{64}$/.test(privateKey)) {
- throw new PacificaSignerError(
- 'Private key must be 64 character hexadecimal string',
- PacificaErrorCode.INVALID_PRIVATE_KEY,
- { privateKey: privateKey.substring(0, 10) + '...' }
- );
- }
- }
- /**
- * 获取账户私钥
- */
- private getAccountPrivateKey(accountId: string): string {
- const privateKey = this.accountCredentials.get(accountId);
- if (!privateKey) {
- throw new PacificaSignerError(
- `Account not found: ${accountId}`,
- PacificaErrorCode.ACCOUNT_NOT_FOUND,
- { accountId }
- );
- }
- return privateKey;
- }
- /**
- * 执行实际签名操作
- */
- private async performSigning(
- message: Uint8Array,
- privateKey: string,
- encoding: 'base64' | 'base58' | 'hex'
- ): Promise<{ signature: string; publicKey: string }> {
- try {
- const privateKeyBytes = this.hexToBytes(privateKey);
- const signatureBytes = await ed25519.sign(message, privateKeyBytes);
- const publicKeyBytes = await ed25519.getPublicKey(privateKeyBytes);
- const signature = this.encodeSignature(signatureBytes, encoding);
- const publicKey = this.bytesToBase58(publicKeyBytes);
- return { signature, publicKey };
- } catch (error) {
- throw new PacificaSignerError(
- `Signing failed: ${(error as Error).message}`,
- PacificaErrorCode.SIGNATURE_FAILED,
- { error: (error as Error).message }
- );
- }
- }
- /**
- * 工具方法:十六进制转字节数组
- */
- private hexToBytes(hex: string): Uint8Array {
- const bytes = new Uint8Array(hex.length / 2);
- for (let i = 0; i < hex.length; i += 2) {
- bytes[i / 2] = parseInt(hex.substr(i, 2), 16);
- }
- return bytes;
- }
- /**
- * 工具方法:字节数组转Base58(简化版本)
- */
- private bytesToBase58(bytes: Uint8Array): string {
- // 简化的Base58编码(实际项目中应使用专业库)
- return Buffer.from(bytes).toString('base64').replace(/[+=]/g, '').substring(0, 44);
- }
- /**
- * 工具方法:编码签名
- */
- private encodeSignature(signature: Uint8Array, encoding: 'base64' | 'base58' | 'hex'): string {
- switch (encoding) {
- case 'base64':
- return Buffer.from(signature).toString('base64');
- case 'hex':
- return Buffer.from(signature).toString('hex');
- case 'base58':
- return this.bytesToBase58(signature);
- default:
- return Buffer.from(signature).toString('base64');
- }
- }
- /**
- * 工具方法:解码签名
- */
- private decodeSignature(signature: string): Uint8Array {
- // 自动检测格式并解码
- if (signature.startsWith('0x')) {
- return new Uint8Array(Buffer.from(signature.substring(2), 'hex'));
- } else if (/^[0-9a-fA-F]+$/.test(signature)) {
- return new Uint8Array(Buffer.from(signature, 'hex'));
- } else {
- return new Uint8Array(Buffer.from(signature, 'base64'));
- }
- }
- /**
- * 工具方法:解码公钥
- */
- private decodePublicKey(publicKey: string): Uint8Array {
- // 简化的Base58解码
- return new Uint8Array(Buffer.from(publicKey + '==', 'base64').slice(0, 32));
- }
- }
|