├── .env.example
├── .eslintrc.json
├── .gitignore
├── .gitlab-ci.yml
├── .gitlab
└── ci
│ ├── api.yml
│ ├── core.yml
│ └── protocol.yml
├── .prettierrc
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── README_CN.md
├── docker-compose.yml
├── docs
├── API.md
├── ARCHITECTURE.md
├── CI_CD.md
├── DEPLOYMENT.md
├── DEVELOPMENT.md
└── assets
│ └── logo.svg
├── jest.config.js
├── package-lock.json
├── package.json
├── packages
├── ai
│ ├── .gitignore
│ ├── README.md
│ ├── data
│ │ ├── training-data.json
│ │ └── training-labels.json
│ ├── docs
│ │ └── api.md
│ ├── examples
│ │ └── advanced-training.ts
│ ├── package.json
│ ├── src
│ │ ├── core
│ │ │ ├── ClientManager.ts
│ │ │ ├── FederatedCoordinator.ts
│ │ │ ├── FederatedLearningProtocol.ts
│ │ │ ├── ModelAggregator.ts
│ │ │ ├── PrivacyManager.ts
│ │ │ ├── algorithms
│ │ │ │ └── FederatedAlgorithms.ts
│ │ │ ├── defense
│ │ │ │ └── ModelDefense.ts
│ │ │ ├── federated.ts
│ │ │ ├── optimization
│ │ │ │ └── DistributedOptimizer.ts
│ │ │ ├── privacy.ts
│ │ │ ├── privacy
│ │ │ │ ├── DifferentialPrivacy.ts
│ │ │ │ ├── HomomorphicEncryption.ts
│ │ │ │ └── ZeroKnowledgeProof.ts
│ │ │ ├── secure
│ │ │ │ └── SecureAggregation.ts
│ │ │ └── types.ts
│ │ ├── index.ts
│ │ ├── models
│ │ │ └── base.ts
│ │ ├── types.ts
│ │ └── types
│ │ │ ├── federated.ts
│ │ │ └── index.ts
│ ├── test
│ │ └── federated.test.ts
│ ├── tsconfig.json
│ └── tsconfig.tsbuildinfo
├── crypto
│ ├── docs
│ │ └── api.md
│ ├── jest.config.js
│ ├── package.json
│ ├── src
│ │ ├── core
│ │ │ ├── __tests__
│ │ │ │ ├── asymmetric.test.ts
│ │ │ │ ├── elgamal.test.ts
│ │ │ │ ├── hash.test.ts
│ │ │ │ ├── homomorphic.test.ts
│ │ │ │ ├── kdf.test.ts
│ │ │ │ ├── symmetric.test.ts
│ │ │ │ └── zkp.test.ts
│ │ │ ├── asymmetric.ts
│ │ │ ├── asymmetric
│ │ │ │ └── __tests__
│ │ │ │ │ ├── elgamal.test.ts
│ │ │ │ │ └── rsa.test.ts
│ │ │ ├── blind
│ │ │ │ └── __tests__
│ │ │ │ │ └── blind-signature.test.ts
│ │ │ ├── cipher
│ │ │ │ └── __tests__
│ │ │ │ │ ├── aes-cfb.test.ts
│ │ │ │ │ ├── aes-ctr.test.ts
│ │ │ │ │ ├── aes-ofb.test.ts
│ │ │ │ │ ├── aes.test.ts
│ │ │ │ │ ├── chacha20.test.ts
│ │ │ │ │ └── xchacha20.test.ts
│ │ │ ├── curve25519
│ │ │ │ └── __tests__
│ │ │ │ │ └── curve25519.test.ts
│ │ │ ├── dh
│ │ │ │ └── __tests__
│ │ │ │ │ └── diffie-hellman.test.ts
│ │ │ ├── ecdsa
│ │ │ │ └── __tests__
│ │ │ │ │ └── ecdsa.test.ts
│ │ │ ├── ed25519
│ │ │ │ └── __tests__
│ │ │ │ │ └── ed25519.test.ts
│ │ │ ├── eddsa
│ │ │ │ └── __tests__
│ │ │ │ │ └── ed25519.test.ts
│ │ │ ├── elgamal.ts
│ │ │ ├── encryption.ts
│ │ │ ├── hash.ts
│ │ │ ├── hash
│ │ │ │ └── __tests__
│ │ │ │ │ ├── argon2.test.ts
│ │ │ │ │ ├── blake2.test.ts
│ │ │ │ │ ├── sha2.test.ts
│ │ │ │ │ └── sha3.test.ts
│ │ │ ├── homomorphic.ts
│ │ │ ├── homomorphic
│ │ │ │ ├── __tests__
│ │ │ │ │ └── fhe.test.ts
│ │ │ │ ├── advanced.ts
│ │ │ │ ├── bootstrap.ts
│ │ │ │ ├── crt.ts
│ │ │ │ ├── fft.ts
│ │ │ │ ├── fhe.ts
│ │ │ │ ├── fpga.ts
│ │ │ │ ├── gpu.ts
│ │ │ │ ├── keyswitch.ts
│ │ │ │ ├── memory.ts
│ │ │ │ ├── ml.ts
│ │ │ │ ├── ntt.ts
│ │ │ │ └── simd.ts
│ │ │ ├── kdf.ts
│ │ │ ├── kdf
│ │ │ │ └── __tests__
│ │ │ │ │ ├── hkdf.test.ts
│ │ │ │ │ └── pbkdf2.test.ts
│ │ │ ├── mac
│ │ │ │ ├── __tests__
│ │ │ │ │ ├── hmac.test.ts
│ │ │ │ │ └── poly1305.test.ts
│ │ │ │ ├── hmac.ts
│ │ │ │ └── poly1305.ts
│ │ │ ├── symmetric.ts
│ │ │ ├── symmetric
│ │ │ │ ├── __tests__
│ │ │ │ │ ├── aes.test.ts
│ │ │ │ │ └── chacha20-poly1305.test.ts
│ │ │ │ ├── aes.ts
│ │ │ │ └── chacha20-poly1305.ts
│ │ │ ├── threshold
│ │ │ │ └── __tests__
│ │ │ │ │ └── threshold-signature.test.ts
│ │ │ ├── tls
│ │ │ │ ├── __tests__
│ │ │ │ │ ├── handshake.test.ts
│ │ │ │ │ ├── key-schedule.test.ts
│ │ │ │ │ └── record-layer.test.ts
│ │ │ │ ├── constants.ts
│ │ │ │ ├── handshake.ts
│ │ │ │ ├── key-schedule.ts
│ │ │ │ └── record-layer.ts
│ │ │ ├── xchacha20
│ │ │ │ ├── __tests__
│ │ │ │ │ └── xchacha20.test.ts
│ │ │ │ └── xchacha20.ts
│ │ │ ├── zkp.ts
│ │ │ └── zkp
│ │ │ │ ├── __tests__
│ │ │ │ ├── chaum-pedersen.test.ts
│ │ │ │ ├── fiat-shamir.test.ts
│ │ │ │ ├── homomorphic.test.ts
│ │ │ │ ├── or-proof.test.ts
│ │ │ │ ├── pedersen.test.ts
│ │ │ │ ├── range.test.ts
│ │ │ │ └── schnorr.test.ts
│ │ │ │ ├── chaum-pedersen.ts
│ │ │ │ ├── fiat-shamir.ts
│ │ │ │ ├── homomorphic.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── or-proof.ts
│ │ │ │ ├── pedersen.ts
│ │ │ │ ├── range.ts
│ │ │ │ └── schnorr.ts
│ │ ├── index.ts
│ │ ├── types.ts
│ │ ├── types
│ │ │ └── index.ts
│ │ └── utils
│ │ │ └── hash.ts
│ ├── test
│ │ └── encryption.test.ts
│ ├── tsconfig.json
│ └── tsconfig.tsbuildinfo
├── protocol
│ ├── README.md
│ ├── docs
│ │ ├── api.md
│ │ ├── deployment.md
│ │ └── examples.md
│ ├── package.json
│ ├── src
│ │ ├── core
│ │ │ ├── __tests__
│ │ │ │ ├── blind-signature.test.ts
│ │ │ │ ├── commitment.test.ts
│ │ │ │ ├── key-exchange.test.ts
│ │ │ │ ├── mpc.benchmark.ts
│ │ │ │ ├── mpc.test.ts
│ │ │ │ ├── recovery.test.ts
│ │ │ │ ├── ring-signature.test.ts
│ │ │ │ ├── threshold-signature.test.ts
│ │ │ │ └── zkp.test.ts
│ │ │ ├── base.ts
│ │ │ ├── blind-signature.ts
│ │ │ ├── commitment.ts
│ │ │ ├── key-exchange.ts
│ │ │ ├── mpc.ts
│ │ │ ├── privacy.ts
│ │ │ ├── recovery.ts
│ │ │ ├── ring-signature.ts
│ │ │ ├── threshold-signature.ts
│ │ │ ├── training.ts
│ │ │ ├── types.ts
│ │ │ └── zkp.ts
│ │ ├── index.ts
│ │ ├── marketplace
│ │ │ ├── AccessManager.ts
│ │ │ ├── AssetRegistry.ts
│ │ │ ├── DataMarketplace.ts
│ │ │ ├── DataMarketplaceService.ts
│ │ │ ├── IncentiveManager.ts
│ │ │ ├── MarketPaymentIntegrator.ts
│ │ │ ├── OrderMatcher.ts
│ │ │ ├── PriceOracle.ts
│ │ │ └── QualityAssessor.ts
│ │ ├── tee
│ │ │ ├── TrustedExecutionManager.ts
│ │ │ └── TrustedExecutionService.ts
│ │ ├── token
│ │ │ ├── TokenContract.ts
│ │ │ └── TokenEconomyManager.ts
│ │ ├── types.ts
│ │ ├── types
│ │ │ └── index.ts
│ │ └── utils
│ │ │ ├── logger.ts
│ │ │ ├── validation.ts
│ │ │ └── validator.ts
│ ├── test
│ │ └── privacy.test.ts
│ ├── tsconfig.json
│ └── tsconfig.tsbuildinfo
└── ui
│ ├── package-lock.json
│ └── package.json
├── public
└── index.html
├── scripts
└── setup-dev.sh
├── src
├── App.tsx
├── api
│ ├── client.ts
│ └── services.ts
├── components
│ ├── DataVisualization.tsx
│ ├── DatasetList.tsx
│ ├── ModelConfig.tsx
│ ├── TrainingTaskList.tsx
│ ├── analysis
│ │ ├── AdvancedAnalysis.tsx
│ │ └── DataAnalysis.tsx
│ ├── auth
│ │ └── AuthProvider.tsx
│ └── training
│ │ └── TrainingProgress.tsx
├── core
│ ├── encryption.ts
│ ├── federated-learning.ts
│ ├── losses.ts
│ ├── model.ts
│ ├── neural-network.ts
│ ├── optimizers.ts
│ ├── preprocessing.ts
│ └── privacy-protocol.ts
├── hooks
│ ├── useDataAnalysis.ts
│ ├── useDatasets.ts
│ ├── useTrainingProgress.ts
│ └── useTrainingTasks.ts
├── index.tsx
├── layouts
│ └── MainLayout.tsx
├── pages
│ ├── DatasetsPage.tsx
│ ├── TrainingPage.tsx
│ └── auth
│ │ ├── LoginPage.tsx
│ │ └── RegisterPage.tsx
├── services
│ └── websocket.ts
└── types
│ └── index.ts
├── tsconfig.json
└── yarn.lock
/.env.example:
--------------------------------------------------------------------------------
1 | # Environment
2 | NODE_ENV=development
3 |
4 | # API Configuration
5 | API_PORT=3000
6 | API_HOST=localhost
7 |
8 | # Database Configuration
9 | DB_HOST=localhost
10 | DB_PORT=5432
11 | DB_NAME=cipher_nexus
12 | DB_USER=postgres
13 | DB_PASSWORD=your_password
14 |
15 | # Redis Configuration
16 | REDIS_HOST=localhost
17 | REDIS_PORT=6379
18 |
19 | # JWT Configuration
20 | JWT_SECRET=your_jwt_secret
21 | JWT_EXPIRES_IN=7d
22 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": true,
3 | "parser": "@typescript-eslint/parser",
4 | "plugins": [
5 | "@typescript-eslint"
6 | ],
7 | "extends": [
8 | "eslint:recommended",
9 | "plugin:@typescript-eslint/recommended"
10 | ],
11 | "rules": {
12 | "@typescript-eslint/explicit-module-boundary-types": "error",
13 | "@typescript-eslint/no-explicit-any": "warn",
14 | "@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }]
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Dependencies
2 | node_modules/
3 | .pnp
4 | .pnp.js
5 |
6 | # Production
7 | dist/
8 | build/
9 |
10 | # Testing
11 | coverage/
12 |
13 | # Environment
14 | .env
15 | .env.local
16 | .env.development.local
17 | .env.test.local
18 | .env.production.local
19 |
20 | # IDE
21 | .idea/
22 | .vscode/
23 | *.swp
24 | *.swo
25 |
26 | # Logs
27 | npm-debug.log*
28 | yarn-debug.log*
29 | yarn-error.log*
30 |
31 | # System
32 | .DS_Store
33 | Thumbs.db
34 | .npmrc
35 |
36 | # SSH keys
37 | .ssh/
38 |
--------------------------------------------------------------------------------
/.gitlab-ci.yml:
--------------------------------------------------------------------------------
1 | stages:
2 | - lint
3 | - test
4 | - build
5 | - deploy
6 |
7 | variables:
8 | DOCKER_DRIVER: overlay2
9 | DOCKER_TLS_CERTDIR: ""
10 |
11 | include:
12 | - local: .gitlab/ci/*.yml
13 |
14 | cache:
15 | paths:
16 | - node_modules/
17 | - packages/*/node_modules/
18 |
19 | lint:
20 | stage: lint
21 | script:
22 | - npm run lint
23 | - npm run type-check
24 |
25 | test:
26 | stage: test
27 | script:
28 | - npm run test:coverage
29 | coverage: '/All files[^|]*\|[^|]*\s+([\d\.]+)/'
30 | artifacts:
31 | reports:
32 | coverage_report:
33 | coverage_format: cobertura
34 | path: coverage/cobertura-coverage.xml
35 |
36 | build:
37 | stage: build
38 | script:
39 | - npm run build
40 | artifacts:
41 | paths:
42 | - dist/
43 |
44 | deploy:
45 | stage: deploy
46 | script:
47 | - npm run deploy
48 | environment:
49 | name: production
50 | only:
51 | - master
--------------------------------------------------------------------------------
/.gitlab/ci/api.yml:
--------------------------------------------------------------------------------
1 | build:ai:
2 | stage: build
3 | script:
4 | - cd packages/ai
5 | - npm run build
6 |
7 | artifacts:
8 | paths:
9 | - packages/ai/dist
10 |
11 | build:protocol:
12 | stage: build
13 | script:
14 | - cd packages/protocol
15 | - npm run build
16 |
17 | artifacts:
18 | paths:
19 | - packages/protocol/dist
20 |
21 | build:crypto:
22 | stage: build
23 | script:
24 | - cd packages/crypto
25 | - npm run build
26 |
27 | artifacts:
28 | paths:
29 | - packages/crypto/dist
30 |
31 | test:ai:
32 | stage: test
33 | script:
34 | - cd packages/ai
35 | - npm run test:coverage
36 | coverage: '/All files[^|]*\|[^|]*\s+([\d\.]+)/'
37 | artifacts:
38 | reports:
39 | coverage_report:
40 | coverage_format: cobertura
41 | path: packages/ai/coverage/cobertura-coverage.xml
42 |
43 | integration:ai:
44 | stage: test
45 | services:
46 | - docker:dind
47 | script:
48 | - docker-compose up -d
49 | - cd packages/ai
50 | - npm run test:integration
51 | artifacts:
52 | reports:
53 | junit: packages/ai/test-results/integration/*.xml
54 |
55 | test:crypto:
56 | stage: test
57 | script:
58 | - cd packages/crypto
59 | - npm run test:coverage
60 | coverage: '/All files[^|]*\|[^|]*\s+([\d\.]+)/'
61 | artifacts:
62 | reports:
63 | coverage_report:
64 | coverage_format: cobertura
65 | path: packages/crypto/coverage/cobertura-coverage.xml
66 |
67 | integration:crytpo:
68 | stage: test
69 | services:
70 | - docker:dind
71 | script:
72 | - docker-compose up -d
73 | - cd packages/crypto
74 | - npm run test:integration
75 | artifacts:
76 | reports:
77 | junit: packages/crypto/test-results/integration/*.xml
78 |
79 | test:protocol:
80 | stage: test
81 | script:
82 | - cd packages/protocol
83 | - npm run test:coverage
84 | coverage: '/All files[^|]*\|[^|]*\s+([\d\.]+)/'
85 | artifacts:
86 | reports:
87 | coverage_report:
88 | coverage_format: cobertura
89 | path: packages/protocol/coverage/cobertura-coverage.xml
90 |
91 | integration:protocol:
92 | stage: test
93 | services:
94 | - docker:dind
95 | script:
96 | - docker-compose up -d
97 | - cd packages/protocol
98 | - npm run test:integration
99 | artifacts:
100 | reports:
101 | junit: packages/protocol/test-results/integration/*.xml
102 |
--------------------------------------------------------------------------------
/.gitlab/ci/core.yml:
--------------------------------------------------------------------------------
1 | build:core:
2 | stage: build
3 | script:
4 | - cd packages/core
5 | - npm run build
6 | artifacts:
7 | paths:
8 | - packages/core/dist/
9 |
10 | test:core:
11 | stage: test
12 | script:
13 | - cd packages/core
14 | - npm run test:coverage
15 | coverage: '/All files[^|]*\|[^|]*\s+([\d\.]+)/'
16 | artifacts:
17 | reports:
18 | coverage_report:
19 | coverage_format: cobertura
20 | path: packages/core/coverage/cobertura-coverage.xml
--------------------------------------------------------------------------------
/.gitlab/ci/protocol.yml:
--------------------------------------------------------------------------------
1 | build:protocol:
2 | stage: build
3 | script:
4 | - cd packages/protocol
5 | - npm run build
6 | artifacts:
7 | paths:
8 | - packages/protocol/dist/
9 |
10 | test:protocol:
11 | stage: test
12 | script:
13 | - cd packages/protocol
14 | - npm run test:coverage
15 | coverage: '/All files[^|]*\|[^|]*\s+([\d\.]+)/'
16 | artifacts:
17 | reports:
18 | coverage_report:
19 | coverage_format: cobertura
20 | path: packages/protocol/coverage/cobertura-coverage.xml
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "semi": true,
3 | "trailingComma": "es5",
4 | "singleQuote": true,
5 | "printWidth": 100,
6 | "tabWidth": 2
7 | }
8 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to Cipher Nexus
2 |
3 | We love your input! We want to make contributing to Cipher Nexus as easy and transparent as possible, whether it's:
4 |
5 | - Reporting a bug
6 | - Discussing the current state of the code
7 | - Submitting a fix
8 | - Proposing new features
9 | - Becoming a maintainer
10 |
11 | ## Development Process
12 |
13 | We use GitHub to host code, to track issues and feature requests, as well as accept pull requests.
14 |
15 | 1. Fork the repo and create your branch from `main`.
16 | 2. If you've added code that should be tested, add tests.
17 | 3. If you've changed APIs, update the documentation.
18 | 4. Ensure the test suite passes.
19 | 5. Make sure your code lints.
20 | 6. Issue that pull request!
21 |
22 | ## Pull Request Process
23 |
24 | 1. Update the README.md with details of changes to the interface, if applicable.
25 | 2. Update the docs/ with any necessary documentation changes.
26 | 3. The PR will be merged once you have the sign-off of two other developers.
27 |
28 | ## Any contributions you make will be under the MIT Software License
29 |
30 | In short, when you submit code changes, your submissions are understood to be under the same [MIT License](http://choosealicense.com/licenses/mit/) that covers the project. Feel free to contact the maintainers if that's a concern.
31 |
32 | ## Report bugs using GitHub's [issue tracker](https://github.com/ciphernx/Cipher-Nexus/issues)
33 |
34 | We use GitHub issues to track public bugs. Report a bug by [opening a new issue](https://github.com/ciphernx/Cipher-Nexus/issues/new).
35 |
36 | ## Write bug reports with detail, background, and sample code
37 |
38 | **Great Bug Reports** tend to have:
39 |
40 | - A quick summary and/or background
41 | - Steps to reproduce
42 | - Be specific!
43 | - Give sample code if you can.
44 | - What you expected would happen
45 | - What actually happens
46 | - Notes (possibly including why you think this might be happening, or stuff you tried that didn't work)
47 |
48 | ## Use a Consistent Coding Style
49 |
50 | * Use TypeScript for type safety
51 | * 2 spaces for indentation rather than tabs
52 | * You can try running `npm run lint` for style unification
53 |
54 | ## License
55 |
56 | By contributing, you agree that your contributions will be licensed under its MIT License.
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Cipher Nexus
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README_CN.md:
--------------------------------------------------------------------------------
1 | # Cipher Nexus
2 |
3 |
4 |

5 |
6 |
7 | 一个保护数据隐私的 AI 框架,支持安全的联邦学习和数据市场,在推进 AI 能力的同时保护数据隐私。
8 |
9 | [English](README.md) | [中文](README_CN.md)
10 |
11 | ## 概述
12 |
13 | Cipher Nexus 是一个综合性的 AI 框架,将联邦学习与隐私计算和安全数据市场功能相结合。它通过先进的密码学技术和可信执行环境,在确保数据隐私和安全的同时实现协作机器学习。
14 |
15 | 该框架解决了 AI 开发中的关键挑战:
16 | - **数据隐私**:在模型训练和推理过程中保护敏感数据
17 | - **协作学习**:使多方能够在不共享原始数据的情况下训练 AI 模型
18 | - **数据变现**:为高质量训练数据创建安全的市场
19 | - **模型安全**:确保模型完整性并防止未授权访问
20 |
21 | ## 核心功能
22 |
23 | - **先进的 AI 能力**
24 | - 基于联邦学习的分布式模型训练
25 | - 安全的模型聚合和更新机制
26 | - 隐私保护的推理和预测
27 | - 支持多种 AI 模型架构
28 |
29 | - **隐私计算基础设施**
30 | - 用于数据集保护的差分隐私
31 | - 用于安全计算的同态加密
32 | - 用于验证的零知识证明
33 | - 安全多方计算协议
34 |
35 | - **可信执行环境**
36 | - 用于敏感计算的安全飞地
37 | - 硬件级隔离和保护
38 | - 远程认证机制
39 | - 安全密钥管理
40 |
41 | - **数据市场**
42 | - 带访问控制的通证化数据资产
43 | - 质量评估和验证
44 | - 安全数据交换协议
45 | - 公平定价机制
46 |
47 | - **代币经济**
48 | - 数据共享激励机制
49 | - 模型训练贡献奖励
50 | - 用于协议决策的治理代币
51 | - 用于安全的质押机制
52 |
53 | ## 系统架构
54 |
55 | ```mermaid
56 | graph TD
57 | A[客户端节点] -->|模型更新| B[基础设施管理器]
58 | B --> C[资源管理器]
59 | B --> D[任务调度器]
60 | B --> E[隐私管理器]
61 |
62 | F[数据提供方] -->|数据资产| G[数据市场]
63 | G --> H[代币合约]
64 | G --> I[访问控制]
65 |
66 | J[模型训练] -->|加密更新| K[联邦协调器]
67 | K --> L[模型聚合器]
68 | K --> M[隐私计算]
69 |
70 | N[TEE管理器] -->|安全执行| O[计算节点]
71 | O --> P[资源监控]
72 | O --> Q[状态管理]
73 | ```
74 |
75 | ## 模块说明
76 |
77 | - `@ciphernx/ai`: 联邦学习和模型管理
78 | - 实现联邦学习协议
79 | - 模型训练和聚合
80 | - 隐私保护机制
81 | - 支持主流 AI 框架
82 | - 安全模型服务和推理
83 |
84 | - `@cipher-nexus/core`: 基础设施和资源管理
85 | - 计算节点管理
86 | - 资源分配
87 | - 任务调度
88 | - 性能监控
89 | - 容错机制
90 |
91 | - `@ciphernx/crypto`: 密码学原语和协议
92 | - 同态加密
93 | - 零知识证明
94 | - 安全多方计算
95 | - 密钥管理
96 | - 隐私预算
97 |
98 | - `@ciphernx/protocol`: 网络协议和数据市场
99 | - 数据资产管理
100 | - 访问控制
101 | - 交易处理
102 | - 质量验证
103 | - 信誉系统
104 |
105 | - `@ciphernx/ui`: 用户界面组件
106 | - 数据集管理
107 | - 模型训练监控
108 | - 系统管理界面
109 | - 分析仪表盘
110 | - 隐私设置控制
111 |
112 | ## 快速开始
113 |
114 | 1. 安装依赖
115 | ```bash
116 | npm install
117 | ```
118 |
119 | 2. 启动开发服务器
120 | ```bash
121 | npm run dev
122 | ```
123 |
124 | 3. 构建项目
125 | ```bash
126 | npm run build
127 | ```
128 |
129 | ## 文档
130 |
131 | - [API 文档](docs/API.md)
132 | - [架构设计](docs/ARCHITECTURE.md)
133 | - [部署指南](docs/DEPLOYMENT.md)
134 | - [开发指南](docs/DEVELOPMENT.md)
135 |
136 | ## 许可证
137 |
138 | MIT 许可证
139 |
140 | ## 常见问题
141 |
142 | ### AI 为什么需要隐私?
143 | - 数据安全:AI 训练需要大量数据,这些数据往往包含敏感信息(个人信息、商业机密等)
144 | - 法律合规:全球各地的数据保护法规(如 GDPR、CCPA)对数据隐私提出了严格要求
145 | - 用户信任:保护用户隐私是建立用户信任的关键,影响 AI 系统的采用率
146 | - 防止滥用:避免 AI 模型被用于未经授权的目的或被恶意攻击者利用
147 | - 跨组织协作:使不同组织能够在保护各自数据隐私的前提下进行 AI 协作
148 |
149 | ### 我们的 AI 隐私框架有什么特点?
150 | - 全面的隐私保护机制:
151 | * 联邦学习支持分布式训练
152 | * 差分隐私保护个体数据
153 | * 同态加密实现加密计算
154 | * 零知识证明确保计算正确性
155 | - 可信执行环境(TEE)保障
156 | - 灵活的数据市场机制
157 | - 代币经济激励系统
158 | - 模块化设计便于扩展
159 | - 完整的隐私度量和审计机制
160 |
161 | ### 为什么要使用我们的框架?
162 | - 一站式解决方案:集成了主流隐私计算技术
163 | - 性能优化:在保护隐私的同时保持高效率
164 | - 易于使用:提供友好的 API 和完善的文档
165 | - 安全可靠:多层次的安全保障机制
166 | - 社区支持:开源项目持续改进
167 | - 合规性:符合主流隐私保护法规
168 |
169 | ### 谁可以在什么需求下使用我们的隐私框架?
170 | - 适用人群:
171 | * 企业 AI 团队
172 | * 研究机构
173 | * 医疗机构
174 | * 金融机构
175 | * 政府部门
176 | * 数据服务提供商
177 |
178 | - 适用场景:
179 | * 跨组织数据协作
180 | * 医疗数据分析
181 | * 金融风控建模
182 | * 隐私保护的推荐系统
183 | * 多方安全计算
184 | * 需要严格数据保护的 AI 应用
185 |
186 | ### 我们是如何赋能加密货币的?
187 | - 代币经济系统设计:
188 | * 实用代币用于支付计算资源和数据访问
189 | * 治理代币用于社区治理和决策
190 | * 激励机制奖励数据提供者和验证者
191 | * 通证化数据资产
192 | - 隐私保护机制与加密货币的结合:
193 | * 零知识证明验证交易合法性
194 | * 同态加密支持加密状态下的计算
195 | * 安全多方计算实现隐私保护交易
196 | * 环签名提供交易匿名性
197 | - 智能合约功能:
198 | * 自动化市场制造者(AMM)
199 | * 去中心化交易
200 | * 质押合约
201 | * 治理合约
202 | - 经济模型创新:
203 | * 双通证模型
204 | * 动态定价机制
205 | * 通缩机制
206 | * 流动性挖矿
207 | - 跨链互操作:
208 | * 跨链资产转移
209 | * 跨链消息传递
210 | * 原子交换
211 | * 资产桥接
212 | - 安全保障:
213 | * 多重签名钱包
214 | * 时间锁定
215 | * 预言机整合
216 | * 紧急暂停
217 | - 生态系统建设:
218 | * 开发者激励
219 | * 社区建设
220 | * 合作伙伴计划
221 | * 去中心化自治组织(DAO)
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3.8'
2 |
3 | services:
4 | # Database
5 | postgres:
6 | image: postgres:14
7 | environment:
8 | POSTGRES_DB: cipher_nexus
9 | POSTGRES_USER: postgres
10 | POSTGRES_PASSWORD: password
11 | ports:
12 | - "5432:5432"
13 | volumes:
14 | - postgres_data:/var/lib/postgresql/data
15 |
16 | # Redis Cache
17 | redis:
18 | image: redis:6
19 | ports:
20 | - "6379:6379"
21 |
22 | # AI Service
23 | ai_service:
24 | build:
25 | context: ./packages/ai
26 | dockerfile: Dockerfile
27 | ports:
28 | - "5000:5000"
29 | depends_on:
30 | - postgres
31 |
32 | volumes:
33 | postgres_data:
34 |
--------------------------------------------------------------------------------
/docs/assets/logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | preset: 'ts-jest',
3 | testEnvironment: 'node',
4 | roots: ['/packages'],
5 | testMatch: ['**/__tests__/**/*.ts?(x)', '**/?(*.)+(spec|test).ts?(x)'],
6 | moduleNameMapper: {
7 | '^@cipher-nexus/(.*)$': '/packages//src' // Fix path mapping here
8 | }
9 | };
10 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@cipher-nexus/ui",
3 | "version": "1.0.0",
4 | "private": true,
5 | "dependencies": {
6 | "@emotion/react": "^11.11.0",
7 | "@emotion/styled": "^11.11.0",
8 | "@mui/icons-material": "^5.11.16",
9 | "@mui/lab": "^5.0.0-alpha.129",
10 | "@mui/material": "^5.13.0",
11 | "@testing-library/jest-dom": "^5.16.5",
12 | "@testing-library/react": "^13.4.0",
13 | "@testing-library/user-event": "^13.5.0",
14 | "@types/jest": "^27.5.2",
15 | "@types/node": "^16.18.27",
16 | "@types/react": "^18.2.6",
17 | "@types/react-dom": "^18.2.4",
18 | "@visx/scale": "^3.0.0",
19 | "@visx/xychart": "^3.1.2",
20 | "axios": "^1.4.0",
21 | "events": "^3.3.0",
22 | "react": "^18.2.0",
23 | "react-dom": "^18.2.0",
24 | "react-router-dom": "^6.11.1",
25 | "react-scripts": "5.0.1",
26 | "recharts": "^2.6.2",
27 | "typescript": "^4.9.5",
28 | "web-vitals": "^2.1.4"
29 | },
30 | "scripts": {
31 | "start": "react-scripts start",
32 | "build": "react-scripts build",
33 | "test": "react-scripts test",
34 | "eject": "react-scripts eject",
35 | "lint": "eslint src --ext .ts,.tsx",
36 | "format": "prettier --write \"src/**/*.{ts,tsx}\""
37 | },
38 | "eslintConfig": {
39 | "extends": [
40 | "react-app",
41 | "react-app/jest"
42 | ]
43 | },
44 | "browserslist": {
45 | "production": [
46 | ">0.2%",
47 | "not dead",
48 | "not op_mini all"
49 | ],
50 | "development": [
51 | "last 1 chrome version",
52 | "last 1 firefox version",
53 | "last 1 safari version"
54 | ]
55 | },
56 | "devDependencies": {
57 | "@typescript-eslint/eslint-plugin": "^5.59.5",
58 | "@typescript-eslint/parser": "^5.59.5",
59 | "eslint": "^8.40.0",
60 | "eslint-config-prettier": "^8.8.0",
61 | "eslint-plugin-prettier": "^4.2.1",
62 | "eslint-plugin-react": "^7.32.2",
63 | "prettier": "^2.8.8"
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/packages/ai/.gitignore:
--------------------------------------------------------------------------------
1 | # Dependencies
2 | node_modules/
3 | .npm
4 |
5 | # Build output
6 | dist/
7 | build/
8 |
9 | # IDE
10 | .idea/
11 | .vscode/
12 | *.swp
13 | *.swo
14 |
15 | # Logs
16 | logs/
17 | *.log
18 | npm-debug.log*
19 |
20 | # Runtime data
21 | pids/
22 | *.pid
23 | *.seed
24 | *.pid.lock
25 |
26 | # Testing
27 | coverage/
28 |
29 | # Environment variables
30 | .env
31 | .env.local
32 | .env.*.local
33 |
34 | # Misc
35 | .DS_Store
36 | *.pem
37 | .cache/
--------------------------------------------------------------------------------
/packages/ai/README.md:
--------------------------------------------------------------------------------
1 | # @ciphernx/ai
2 |
3 | Advanced AI module integrating cryptographic and protocol functionalities.
4 |
5 | ## Features
6 |
7 | - Multiple model type support (TensorFlow, PyTorch, Scikit-learn, etc.)
8 | - Data augmentation capabilities
9 | - Model compression and optimization
10 | - Distributed training support
11 | - Model interpretability tools
12 |
13 | ## Installation
14 |
15 | ```bash
16 | npm install @ciphernx/ai
17 | ```
18 |
19 | Or install from the repository:
20 |
21 | ```bash
22 | npm run setup
23 | ```
24 |
25 | ## Usage
26 |
27 | See the examples directory for detailed usage examples. Here's a quick start:
28 |
29 | ```typescript
30 | import { ModelFactory, ModelType, TaskType } from '@ciphernx/ai';
31 |
32 | async function main() {
33 | const model = await ModelFactory.createModel({
34 | type: ModelType.TENSORFLOW,
35 | path: 'models/classifier',
36 | inputShape: [28, 28, 1],
37 | outputShape: [10],
38 | taskType: TaskType.CLASSIFICATION
39 | });
40 |
41 | // Train the model
42 | // ...
43 | }
44 | ```
45 |
46 | ## Development
47 |
48 | 1. Install dependencies:
49 | ```bash
50 | npm run setup
51 | ```
52 |
53 | 2. Build the package:
54 | ```bash
55 | npm run build
56 | ```
57 |
58 | 3. Run tests:
59 | ```bash
60 | npm test
61 | ```
62 |
63 | 4. Run example:
64 | ```bash
65 | npm run example
66 | ```
67 |
68 | ## License
69 |
70 | MIT
--------------------------------------------------------------------------------
/packages/ai/data/training-data.json:
--------------------------------------------------------------------------------
1 | [
2 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
3 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
4 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
5 | ]
--------------------------------------------------------------------------------
/packages/ai/data/training-labels.json:
--------------------------------------------------------------------------------
1 | [0, 1, 2]
--------------------------------------------------------------------------------
/packages/ai/docs/api.md:
--------------------------------------------------------------------------------
1 | # AI Package API Documentation
2 |
3 | ## Overview
4 |
5 | The AI package provides core functionality for federated learning, model management, and distributed training.
6 |
7 | ## Core Components
8 |
9 | ### FederatedLearningProtocol
10 |
11 | ```typescript
12 | class FederatedLearningProtocol extends EventEmitter {
13 | constructor(modelConfig: ModelConfig, fedConfig: FederatedConfig);
14 |
15 | async initialize(): Promise;
16 | async registerClient(clientState: ClientState): Promise;
17 | async startTrainingRound(): Promise;
18 | async submitUpdate(clientId: string, update: ModelUpdate): Promise;
19 | getGlobalModel(): Float32Array[] | null;
20 | getRoundStatus(roundId: number): TrainingRound | undefined;
21 | }
22 | ```
23 |
24 | ### DistributedTrainer
25 |
26 | ```typescript
27 | class DistributedTrainer {
28 | constructor(config: DistributedConfig);
29 |
30 | async train(
31 | model: tf.LayersModel,
32 | data: number[][],
33 | labels: number[][],
34 | epochs: number
35 | ): Promise;
36 | }
37 | ```
38 |
39 | ### ModelCompressor
40 |
41 | ```typescript
42 | class ModelCompressor {
43 | constructor(config: CompressionConfig);
44 |
45 | async compress(model: tf.LayersModel): Promise;
46 | async quantize(model: tf.LayersModel): Promise;
47 | async prune(model: tf.LayersModel): Promise;
48 | }
49 | ```
50 |
51 | ### DataProcessor
52 |
53 | ```typescript
54 | class DataProcessor {
55 | static normalizeData(data: number[][]): number[][];
56 | static standardizeData(data: number[][]): number[][];
57 | static oneHotEncode(labels: number[], numClasses: number): number[][];
58 | static processOutput(output: number[], taskType: TaskType): any;
59 | }
60 | ```
61 |
62 | ## Configuration Types
63 |
64 | ### ModelConfig
65 |
66 | ```typescript
67 | interface ModelConfig {
68 | architecture: string;
69 | hyperparameters: {
70 | learningRate: number;
71 | batchSize: number;
72 | epochs: number;
73 | optimizer: string;
74 | };
75 | inputShape: number[];
76 | outputShape: number[];
77 | }
78 | ```
79 |
80 | ### FederatedConfig
81 |
82 | ```typescript
83 | interface FederatedConfig {
84 | minClients: number;
85 | roundTimeout: number;
86 | aggregationStrategy: 'FedAvg' | 'FedProx' | 'FedMA';
87 | clientSelectionStrategy: 'Random' | 'PowerOfChoice' | 'Reputation';
88 | privacyConfig: {
89 | differentialPrivacy: {
90 | enabled: boolean;
91 | epsilon: number;
92 | delta: number;
93 | };
94 | secureSummation: {
95 | enabled: boolean;
96 | threshold: number;
97 | };
98 | };
99 | }
100 | ```
101 |
102 | ### DistributedConfig
103 |
104 | ```typescript
105 | interface DistributedConfig {
106 | strategy: DistributedStrategy;
107 | numWorkers: number;
108 | batchSizePerWorker: number;
109 | }
110 | ```
111 |
112 | ### CompressionConfig
113 |
114 | ```typescript
115 | interface CompressionConfig {
116 | type: CompressionType;
117 | quantizationBits?: number;
118 | pruningThreshold?: number;
119 | accuracy?: number;
120 | }
121 | ```
122 |
123 | ## Events
124 |
125 | The FederatedLearningProtocol emits the following events:
126 |
127 | - `initialized`: When protocol is initialized
128 | - `clientRegistered`: When a new client is registered
129 | - `roundStarted`: When a training round begins
130 | - `updateReceived`: When a client update is received
131 | - `roundCompleted`: When a training round is completed
132 | - `error`: When an error occurs
133 |
134 | ## Usage Examples
135 |
136 | ### Initialize Federated Learning
137 |
138 | ```typescript
139 | const protocol = new FederatedLearningProtocol(modelConfig, fedConfig);
140 | await protocol.initialize();
141 | ```
142 |
143 | ### Start Training Round
144 |
145 | ```typescript
146 | await protocol.startTrainingRound();
147 | ```
148 |
149 | ### Submit Client Update
150 |
151 | ```typescript
152 | await protocol.submitUpdate(clientId, update);
153 | ```
154 |
155 | ### Compress Model
156 |
157 | ```typescript
158 | const compressor = new ModelCompressor({
159 | type: CompressionType.QUANTIZATION,
160 | quantizationBits: 8
161 | });
162 |
163 | const compressedModel = await compressor.compress(model);
164 | ```
165 |
166 | ### Process Data
167 |
168 | ```typescript
169 | const normalizedData = DataProcessor.normalizeData(data);
170 | const encodedLabels = DataProcessor.oneHotEncode(labels, numClasses);
171 | ```
--------------------------------------------------------------------------------
/packages/ai/examples/advanced-training.ts:
--------------------------------------------------------------------------------
1 | import { ModelFactory } from '../src/core/models/model-factory';
2 | import {
3 | ModelType,
4 | TaskType,
5 | AugmentationType,
6 | CompressionType,
7 | DistributedStrategy
8 | } from '../src/core/types';
9 | import { DataAugmentor } from '../src/utils/data-augmentor';
10 | import { ModelCompressor } from '../src/utils/model-compressor';
11 | import { DistributedTrainer } from '../src/utils/distributed-trainer';
12 | import { ModelInterpreter } from '../src/utils/model-interpreter';
13 | import * as fs from 'fs/promises';
14 | import * as path from 'path';
15 |
16 | // Data loading functions
17 | async function loadData(): Promise {
18 | try {
19 | const dataPath = path.join(__dirname, '../data/training-data.json');
20 | const rawData = await fs.readFile(dataPath, 'utf-8');
21 | return JSON.parse(rawData);
22 | } catch (error) {
23 | console.error('Error loading training data:', error);
24 | return [];
25 | }
26 | }
27 |
28 | async function loadLabels(): Promise {
29 | try {
30 | const labelsPath = path.join(__dirname, '../data/training-labels.json');
31 | const rawLabels = await fs.readFile(labelsPath, 'utf-8');
32 | const labels = JSON.parse(rawLabels);
33 | // Convert single labels to one-hot encoded arrays
34 | return labels.map((label: number) => {
35 | const oneHot = new Array(10).fill(0);
36 | oneHot[label] = 1;
37 | return oneHot;
38 | });
39 | } catch (error) {
40 | console.error('Error loading training labels:', error);
41 | return [];
42 | }
43 | }
44 |
45 | async function main() {
46 | // 1. Create and configure the model
47 | const model = await ModelFactory.createModel({
48 | type: ModelType.TENSORFLOW,
49 | path: 'models/classifier',
50 | inputShape: [28, 28, 1],
51 | outputShape: [10],
52 | taskType: TaskType.CLASSIFICATION,
53 | encryptionEnabled: true,
54 | compressionConfig: {
55 | type: CompressionType.QUANTIZATION,
56 | quantizationBits: 8
57 | },
58 | distributedConfig: {
59 | strategy: DistributedStrategy.DATA_PARALLEL,
60 | numWorkers: 4
61 | },
62 | interpretabilityConfig: {
63 | methods: ['gradientBased', 'layerActivation', 'featureImportance'],
64 | numSamples: 1000
65 | }
66 | });
67 |
68 | // 2. Load sample data
69 | const data = await loadData(); // Your data loading function
70 | const labels = await loadLabels(); // Your label loading function
71 |
72 | // 3. Configure data augmentation
73 | const augmentor = new DataAugmentor({
74 | noiseScale: 0.1,
75 | rotationRange: 30,
76 | flipProbability: 0.5,
77 | scaleRange: [0.8, 1.2],
78 | cropSize: 0.8,
79 | mixupAlpha: 0.2,
80 | cutoutSize: 0.2
81 | });
82 |
83 | // Apply data augmentation
84 | const augmentedData = augmentor.augment(data, [
85 | AugmentationType.NOISE,
86 | AugmentationType.ROTATION,
87 | AugmentationType.FLIP
88 | ]);
89 |
90 | // 4. Configure distributed training
91 | const trainer = new DistributedTrainer({
92 | strategy: DistributedStrategy.DATA_PARALLEL,
93 | numWorkers: 4,
94 | batchSizePerWorker: 32
95 | });
96 |
97 | // Train the model
98 | const trainingMetrics = await trainer.train(
99 | model,
100 | augmentedData,
101 | labels,
102 | 10 // epochs
103 | );
104 |
105 | console.log('Training metrics:', trainingMetrics);
106 |
107 | // 5. Compress the model
108 | const compressor = new ModelCompressor({
109 | type: CompressionType.QUANTIZATION,
110 | quantizationBits: 8,
111 | accuracy: 0.95
112 | });
113 |
114 | const compressedModel = await compressor.compress(model);
115 | console.log('Model compressed successfully');
116 |
117 | // 6. Interpret model predictions
118 | const interpreter = new ModelInterpreter({
119 | methods: ['gradientBased', 'layerActivation', 'featureImportance'],
120 | numSamples: 1000,
121 | targetLayers: ['conv1', 'conv2']
122 | });
123 |
124 | // Get interpretations for a sample input
125 | const sampleInput = data[0];
126 | const interpretations = await interpreter.interpret(
127 | compressedModel,
128 | sampleInput,
129 | labels[0]
130 | );
131 |
132 | console.log('Model interpretations:', interpretations);
133 |
134 | // Save the compressed model
135 | await compressedModel.save('models/compressed-classifier');
136 | }
137 |
138 | main().catch(console.error);
--------------------------------------------------------------------------------
/packages/ai/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@cipher-nexus/ai",
3 | "version": "1.0.0",
4 | "main": "dist/index.js",
5 | "types": "dist/index.d.ts",
6 | "scripts": {
7 | "build": "tsc",
8 | "test": "mocha -r ts-node/register 'test/**/*.test.ts'"
9 | },
10 | "dependencies": {
11 | "@cipher-nexus/protocol": "^1.0.0"
12 | },
13 | "devDependencies": {
14 | "@types/chai": "^4.3.0",
15 | "@types/mocha": "^9.1.0",
16 | "@types/node": "^17.0.21",
17 | "chai": "^4.3.6",
18 | "mocha": "^9.2.2",
19 | "ts-node": "^10.7.0",
20 | "typescript": "^4.6.2"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/packages/ai/src/core/privacy.ts:
--------------------------------------------------------------------------------
1 | export class DifferentialPrivacy {
2 | constructor(
3 | private epsilon: number,
4 | private delta: number,
5 | private sensitivity: number
6 | ) {}
7 |
8 | addLaplaceNoise(value: number): number {
9 | // TODO: Implement Laplace noise mechanism
10 | return value;
11 | }
12 |
13 | addGaussianNoise(value: number): number {
14 | // TODO: Implement Gaussian noise mechanism
15 | return value;
16 | }
17 |
18 | computePrivacyBudget(epochs: number): number {
19 | // TODO: Implement privacy budget tracking
20 | return this.epsilon;
21 | }
22 | }
23 |
24 | export interface PrivacyConfig {
25 | encryptionLevel: 'basic' | 'medium' | 'high';
26 | useHomomorphicEncryption: boolean;
27 | useZeroKnowledgeProof: boolean;
28 | }
29 |
30 | export class PrivacyProtocol {
31 | private config: PrivacyConfig;
32 |
33 | constructor(config: PrivacyConfig) {
34 | this.config = config;
35 | }
36 |
37 | public getConfig(): PrivacyConfig {
38 | return { ...this.config };
39 | }
40 |
41 | public async encryptData(data: any): Promise {
42 | // TODO: Implement actual encryption logic
43 | return data;
44 | }
45 |
46 | public async decryptData(data: any): Promise {
47 | // TODO: Implement actual decryption logic
48 | return data;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/packages/ai/src/core/types.ts:
--------------------------------------------------------------------------------
1 | import { Buffer } from 'buffer';
2 |
3 | export enum ModelType {
4 | TENSORFLOW = 'tensorflow',
5 | ONNX = 'onnx',
6 | PYTORCH = 'pytorch',
7 | SCIKIT = 'scikit',
8 | XGBOOST = 'xgboost',
9 | LIGHTGBM = 'lightgbm'
10 | }
11 |
12 | export enum TaskType {
13 | CLASSIFICATION = 'classification',
14 | REGRESSION = 'regression',
15 | CLUSTERING = 'clustering',
16 | ANOMALY_DETECTION = 'anomaly_detection',
17 | OBJECT_DETECTION = 'object_detection',
18 | SEGMENTATION = 'segmentation',
19 | NLP = 'nlp'
20 | }
21 |
22 | export enum AugmentationType {
23 | NOISE = 'noise',
24 | ROTATION = 'rotation',
25 | FLIP = 'flip',
26 | SCALE = 'scale',
27 | CROP = 'crop',
28 | MIXUP = 'mixup',
29 | CUTOUT = 'cutout'
30 | }
31 |
32 | export enum CompressionType {
33 | QUANTIZATION = 'quantization',
34 | PRUNING = 'pruning',
35 | KNOWLEDGE_DISTILLATION = 'knowledge_distillation',
36 | WEIGHT_CLUSTERING = 'weight_clustering'
37 | }
38 |
39 | export enum DistributedStrategy {
40 | DATA_PARALLEL = 'data_parallel',
41 | MODEL_PARALLEL = 'model_parallel',
42 | PIPELINE_PARALLEL = 'pipeline_parallel',
43 | FEDERATED = 'federated'
44 | }
45 |
46 | export interface ModelConfig {
47 | layers: {
48 | units: number;
49 | inputDim: number;
50 | }[];
51 | }
52 |
53 | export interface TrainingConfig {
54 | batchSize: number;
55 | epochs: number;
56 | learningRate: number;
57 | optimizer: string;
58 | loss: string;
59 | metrics: string[];
60 | validationSplit?: number;
61 | augmentationTypes?: AugmentationType[];
62 | augmentationConfig?: AugmentationConfig;
63 | distributedStrategy?: DistributedStrategy;
64 | }
65 |
66 | export interface PredictionResult {
67 | output: number[] | number[][];
68 | confidence?: number;
69 | metadata?: Record;
70 | }
71 |
72 | export interface ModelMetrics {
73 | accuracy?: number;
74 | loss?: number;
75 | precision?: number;
76 | recall?: number;
77 | f1Score?: number;
78 | [key: string]: number | undefined;
79 | }
80 |
81 | export interface EncryptedData {
82 | data: Buffer;
83 | iv: Buffer;
84 | tag?: Buffer;
85 | }
86 |
87 | export interface SecureModelConfig extends ModelConfig {
88 | encryptionKey?: Buffer;
89 | threshold?: number;
90 | participants?: string[];
91 | }
92 |
93 | export interface ModelState {
94 | weights: number[][][];
95 | round: number;
96 | metrics: {
97 | accuracy: number;
98 | loss: number;
99 | timestamp: Date;
100 | };
101 | }
102 |
103 | export interface ModelUpdate {
104 | clientId: string;
105 | weights: number[][][];
106 | metrics?: {
107 | accuracy: number;
108 | loss: number;
109 | };
110 | }
111 |
112 | export interface CompressionConfig {
113 | type: CompressionType;
114 | targetSize?: number;
115 | accuracy?: number;
116 | sparsity?: number;
117 | quantizationBits?: number;
118 | teacherModel?: string;
119 | }
120 |
121 | export interface DistributedConfig {
122 | strategy: DistributedStrategy;
123 | numWorkers: number;
124 | workerEndpoints?: string[];
125 | batchSizePerWorker?: number;
126 | communicationProtocol?: string;
127 | }
128 |
129 | export interface InterpretabilityConfig {
130 | methods: string[];
131 | numSamples?: number;
132 | targetLayers?: string[];
133 | visualizationFormat?: string;
134 | }
135 |
136 | export interface AugmentationConfig {
137 | noiseScale?: number;
138 | rotationRange?: number;
139 | flipProbability?: number;
140 | scaleRange?: [number, number];
141 | cropSize?: number;
142 | mixupAlpha?: number;
143 | cutoutSize?: number;
144 | }
145 |
146 | export interface FederatedConfig {
147 | enablePrivacy: boolean;
148 | maxWeightMagnitude: number;
149 | minClientUpdates: number;
150 | }
--------------------------------------------------------------------------------
/packages/ai/src/index.ts:
--------------------------------------------------------------------------------
1 | // Core types
2 | export * from './core/types';
3 |
4 | // Models
5 | export { BaseModel } from './core/models/base-model';
6 | export { TensorFlowModel } from './core/models/tensorflow-model';
7 | export { ONNXModel } from './core/models/onnx-model';
8 | export { ModelFactory } from './core/models/model-factory';
9 |
10 | // Utils
11 | export { DataProcessor } from './utils/data-processor';
12 | export { DataAugmentor } from './utils/data-augmentor';
13 | export { ModelCompressor } from './utils/model-compressor';
14 | export { DistributedTrainer } from './utils/distributed-trainer';
15 | export { ModelInterpreter } from './utils/model-interpreter';
16 |
17 | export { FederatedLearning } from './core/federated';
18 | export * from './types';
19 |
--------------------------------------------------------------------------------
/packages/ai/src/models/base.ts:
--------------------------------------------------------------------------------
1 | import { ModelConfig } from '../types';
2 |
3 | export abstract class BaseModel {
4 | constructor(protected config: ModelConfig) {}
5 |
6 | abstract async train(data: any[], labels: any[]): Promise;
7 | abstract async predict(data: any[]): Promise;
8 | abstract async save(): Promise;
9 | abstract async load(path: string): Promise;
10 |
11 | protected validateConfig(): boolean {
12 | if (!this.config.layers || this.config.layers.length === 0) {
13 | throw new Error('Invalid model configuration: layers not specified');
14 | }
15 | if (this.config.layers.length !== this.config.activations.length + 1) {
16 | throw new Error('Invalid model configuration: mismatched layers and activations');
17 | }
18 | return true;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/packages/ai/src/types.ts:
--------------------------------------------------------------------------------
1 | export interface ModelConfig {
2 | layers: {
3 | units: number;
4 | inputDim: number;
5 | }[];
6 | }
7 |
8 | export interface FederatedConfig {
9 | enablePrivacy: boolean;
10 | maxWeightMagnitude: number;
11 | minClientUpdates: number;
12 | }
13 |
14 | export interface ModelState {
15 | weights: number[][][];
16 | round: number;
17 | metrics: {
18 | accuracy: number;
19 | loss: number;
20 | timestamp: Date;
21 | };
22 | }
23 |
24 | export interface ModelUpdate {
25 | clientId: string;
26 | weights: number[][][];
27 | metrics?: {
28 | accuracy: number;
29 | loss: number;
30 | };
31 | }
--------------------------------------------------------------------------------
/packages/ai/src/types/federated.ts:
--------------------------------------------------------------------------------
1 | export interface ModelConfig {
2 | architecture: string;
3 | hyperparameters: {
4 | learningRate: number;
5 | batchSize: number;
6 | epochs: number;
7 | optimizer: string;
8 | };
9 | inputShape: number[];
10 | outputShape: number[];
11 | }
12 |
13 | export interface FederatedConfig {
14 | minClients: number;
15 | roundTimeout: number;
16 | aggregationStrategy: 'FedAvg' | 'FedProx' | 'FedMA';
17 | clientSelectionStrategy: 'Random' | 'PowerOfChoice' | 'Reputation';
18 | privacyConfig: {
19 | differentialPrivacy: {
20 | enabled: boolean;
21 | epsilon: number;
22 | delta: number;
23 | };
24 | secureSummation: {
25 | enabled: boolean;
26 | threshold: number;
27 | };
28 | };
29 | }
30 |
31 | export interface ClientState {
32 | clientId: string;
33 | datasetSize: number;
34 | lastUpdate: Date;
35 | computeCapability: {
36 | flops: number;
37 | memory: number;
38 | bandwidth: number;
39 | };
40 | reputation: number;
41 | status: 'IDLE' | 'TRAINING' | 'AGGREGATING' | 'ERROR';
42 | }
43 |
44 | export interface ModelUpdate {
45 | clientId: string;
46 | round: number;
47 | weights: Float32Array[];
48 | metrics: {
49 | loss: number;
50 | accuracy: number;
51 | trainingDuration: number;
52 | };
53 | timestamp: Date;
54 | }
55 |
56 | export interface TrainingRound {
57 | roundId: number;
58 | startTime: Date;
59 | endTime?: Date;
60 | selectedClients: string[];
61 | status: 'INITIALIZING' | 'IN_PROGRESS' | 'AGGREGATING' | 'COMPLETED' | 'FAILED';
62 | updates: ModelUpdate[];
63 | aggregatedMetrics?: {
64 | globalLoss: number;
65 | globalAccuracy: number;
66 | participationRate: number;
67 | };
68 | }
69 |
70 | export interface PrivacyMetrics {
71 | epsilon: number;
72 | delta: number;
73 | clipNorm: number;
74 | noiseScale: number;
75 | gradientNorm: number;
76 | }
--------------------------------------------------------------------------------
/packages/ai/src/types/index.ts:
--------------------------------------------------------------------------------
1 | export interface ModelConfig {
2 | architecture: string;
3 | layers: number[];
4 | activations: string[];
5 | optimizer: string;
6 | learningRate: number;
7 | }
8 |
9 | export interface FederatedConfig {
10 | roundsPerEpoch: number;
11 | minClients: number;
12 | clientsPerRound: number;
13 | localEpochs: number;
14 | localBatchSize: number;
15 | }
16 |
17 | export interface PrivateTrainingConfig {
18 | modelConfig: ModelConfig;
19 | federatedConfig: FederatedConfig;
20 | privacyBudget: number;
21 | noiseScale: number;
22 | }
23 |
--------------------------------------------------------------------------------
/packages/ai/test/federated.test.ts:
--------------------------------------------------------------------------------
1 | import { expect, use } from 'chai';
2 | import chaiAsPromised from 'chai-as-promised';
3 | import { FederatedLearning } from '../src/core/federated';
4 | import { ModelConfig, FederatedConfig } from '../src/types';
5 | import { PrivacyProtocol } from '../src/core/privacy';
6 |
7 | use(chaiAsPromised);
8 |
9 | describe('FederatedLearning', () => {
10 | const modelConfig: ModelConfig = {
11 | layers: [
12 | { units: 10, inputDim: 5 },
13 | { units: 5, inputDim: 10 },
14 | { units: 1, inputDim: 5 }
15 | ]
16 | };
17 |
18 | const fedConfig: FederatedConfig = {
19 | enablePrivacy: true,
20 | maxWeightMagnitude: 10,
21 | minClientUpdates: 2
22 | };
23 |
24 | let privacyProtocol: PrivacyProtocol;
25 | let federated: FederatedLearning;
26 |
27 | beforeEach(() => {
28 | privacyProtocol = new PrivacyProtocol({
29 | encryptionLevel: 'basic',
30 | useHomomorphicEncryption: false,
31 | useZeroKnowledgeProof: false
32 | });
33 | federated = new FederatedLearning(modelConfig, fedConfig, privacyProtocol);
34 | });
35 |
36 | describe('Model Initialization', () => {
37 | it('should initialize model with random weights', async () => {
38 | await federated.initializeModel();
39 | const model = await federated.distributeModel();
40 |
41 | expect(model.weights).to.be.an('array');
42 | expect(model.weights).to.have.lengthOf(modelConfig.layers.length);
43 | expect(model.round).to.equal(0);
44 | expect(model.metrics).to.have.all.keys(['accuracy', 'loss', 'timestamp']);
45 | });
46 | });
47 |
48 | describe('Update Aggregation', () => {
49 | beforeEach(async () => {
50 | await federated.initializeModel();
51 | });
52 |
53 | it('should aggregate valid client updates', async () => {
54 | const clientUpdates = [
55 | {
56 | clientId: 'client1',
57 | weights: [
58 | [[0.1, 0.2], [0.3, 0.4]],
59 | [[0.5, 0.6]]
60 | ],
61 | metrics: { accuracy: 0.8, loss: 0.2 }
62 | },
63 | {
64 | clientId: 'client2',
65 | weights: [
66 | [[0.2, 0.3], [0.4, 0.5]],
67 | [[0.6, 0.7]]
68 | ],
69 | metrics: { accuracy: 0.9, loss: 0.1 }
70 | }
71 | ];
72 |
73 | const result = await federated.aggregateUpdates(clientUpdates);
74 | expect(result.round).to.equal(1);
75 | expect(result.metrics.accuracy).to.be.closeTo(0.85, 0.01);
76 | expect(result.metrics.loss).to.be.closeTo(0.15, 0.01);
77 | });
78 |
79 | it('should reject invalid updates', async () => {
80 | const invalidUpdates = [
81 | {
82 | clientId: 'client1',
83 | weights: [
84 | [[NaN, 0.2], [0.3, 0.4]],
85 | [[0.5, 0.6]]
86 | ],
87 | metrics: { accuracy: 0.8, loss: 0.2 }
88 | }
89 | ];
90 |
91 | await expect(federated.aggregateUpdates(invalidUpdates))
92 | .to.be.rejectedWith(Error);
93 | });
94 | });
95 |
96 | describe('Model Distribution', () => {
97 | it('should throw error if model not initialized', async () => {
98 | await expect(federated.distributeModel())
99 | .to.be.rejectedWith('Global model not initialized');
100 | });
101 |
102 | it('should distribute initialized model', async () => {
103 | await federated.initializeModel();
104 | const model = await federated.distributeModel();
105 |
106 | expect(model).to.have.all.keys(['weights', 'round', 'metrics']);
107 | expect(model.round).to.equal(0);
108 | });
109 | });
110 | });
--------------------------------------------------------------------------------
/packages/ai/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "./dist",
5 | "rootDir": "./src",
6 | "composite": true
7 | },
8 | "include": ["src"],
9 | "exclude": ["node_modules", "dist", "test"],
10 | "references": [
11 | { "path": "../protocol" }
12 | ]
13 | }
--------------------------------------------------------------------------------
/packages/crypto/docs/api.md:
--------------------------------------------------------------------------------
1 | # Crypto Package API Documentation
2 |
3 | ## Overview
4 |
5 | The Crypto package provides cryptographic primitives and protocols for secure computation and privacy protection.
6 |
7 | ## Core Components
8 |
9 | ### HomomorphicEncryption
10 |
11 | ```typescript
12 | class HomomorphicEncryption {
13 | constructor(config: HomomorphicConfig);
14 |
15 | async initialize(): Promise;
16 | async encrypt(data: number[]): Promise;
17 | async decrypt(data: EncryptedData): Promise;
18 | async add(a: EncryptedData, b: EncryptedData): Promise;
19 | async multiply(a: EncryptedData, b: EncryptedData): Promise;
20 | }
21 | ```
22 |
23 | ### ZeroKnowledgeProof
24 |
25 | ```typescript
26 | class ZeroKnowledgeProof {
27 | constructor(config: ZKPConfig);
28 |
29 | async generateProof(
30 | statement: any,
31 | witness: any,
32 | context: ProofContext
33 | ): Promise;
34 |
35 | async verifyProof(
36 | proof: Proof,
37 | context: ProofContext
38 | ): Promise;
39 | }
40 | ```
41 |
42 | ### DifferentialPrivacy
43 |
44 | ```typescript
45 | class DifferentialPrivacy {
46 | constructor(config: DPConfig);
47 |
48 | async addNoise(data: number[]): Promise;
49 | async computeSensitivity(query: Query): Promise;
50 | async verifyPrivacy(epsilon: number, delta: number): Promise;
51 | }
52 | ```
53 |
54 | ### KeyManager
55 |
56 | ```typescript
57 | class KeyManager {
58 | constructor(config: KeyConfig);
59 |
60 | async generateKeyPair(): Promise;
61 | async storeKey(keyId: string, key: Key): Promise;
62 | async retrieveKey(keyId: string): Promise;
63 | async rotateKey(keyId: string): Promise;
64 | }
65 | ```
66 |
67 | ## Configuration Types
68 |
69 | ### HomomorphicConfig
70 |
71 | ```typescript
72 | interface HomomorphicConfig {
73 | polyModulusDegree: number;
74 | coeffModulusBits: number[];
75 | scaleBits: number;
76 | maxThreads?: number;
77 | useGPU?: boolean;
78 | securityLevel: number;
79 | }
80 | ```
81 |
82 | ### ZKPConfig
83 |
84 | ```typescript
85 | interface ZKPConfig {
86 | securityParameter: number;
87 | numIterations: number;
88 | hashFunction: string;
89 | proofTimeout: number;
90 | maxProofSize: number;
91 | maxConstraints: number;
92 | fieldSize: bigint;
93 | }
94 | ```
95 |
96 | ### DPConfig
97 |
98 | ```typescript
99 | interface DPConfig {
100 | epsilon: number;
101 | delta: number;
102 | maxGradientNorm: number;
103 | noiseMultiplier: number;
104 | minBatchSize: number;
105 | maxReservedBudget: number;
106 | }
107 | ```
108 |
109 | ### KeyConfig
110 |
111 | ```typescript
112 | interface KeyConfig {
113 | algorithm: string;
114 | keySize: number;
115 | storageType: 'memory' | 'file' | 'database';
116 | rotationPeriod: number;
117 | }
118 | ```
119 |
120 | ## Usage Examples
121 |
122 | ### Homomorphic Encryption
123 |
124 | ```typescript
125 | const encryption = new HomomorphicEncryption({
126 | polyModulusDegree: 8192,
127 | coeffModulusBits: [60, 40, 40, 60],
128 | scaleBits: 40,
129 | securityLevel: 128
130 | });
131 |
132 | const encrypted = await encryption.encrypt(data);
133 | const result = await encryption.add(encrypted, encrypted);
134 | const decrypted = await encryption.decrypt(result);
135 | ```
136 |
137 | ### Zero Knowledge Proof
138 |
139 | ```typescript
140 | const zkp = new ZeroKnowledgeProof({
141 | securityParameter: 128,
142 | numIterations: 10,
143 | hashFunction: 'sha256'
144 | });
145 |
146 | const proof = await zkp.generateProof(statement, witness, context);
147 | const isValid = await zkp.verifyProof(proof, context);
148 | ```
149 |
150 | ### Differential Privacy
151 |
152 | ```typescript
153 | const dp = new DifferentialPrivacy({
154 | epsilon: 0.1,
155 | delta: 1e-5,
156 | maxGradientNorm: 1.0
157 | });
158 |
159 | const privatized = await dp.addNoise(data);
160 | ```
161 |
162 | ### Key Management
163 |
164 | ```typescript
165 | const keyManager = new KeyManager({
166 | algorithm: 'RSA',
167 | keySize: 2048,
168 | storageType: 'database',
169 | rotationPeriod: 30 * 24 * 60 * 60 // 30 days
170 | });
171 |
172 | const keyPair = await keyManager.generateKeyPair();
173 | await keyManager.storeKey('key1', keyPair.publicKey);
174 | ```
--------------------------------------------------------------------------------
/packages/crypto/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | preset: 'ts-jest',
3 | testEnvironment: 'node',
4 | roots: ['/src'],
5 | testMatch: ['**/__tests__/**/*.test.ts'],
6 | collectCoverageFrom: [
7 | 'src/**/*.ts',
8 | '!src/**/*.d.ts',
9 | '!src/**/__tests__/**'
10 | ],
11 | coverageThreshold: {
12 | global: {
13 | branches: 80,
14 | functions: 80,
15 | lines: 80,
16 | statements: 80
17 | }
18 | }
19 | };
--------------------------------------------------------------------------------
/packages/crypto/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@cipher-nexus/crypto",
3 | "version": "1.0.0",
4 | "private": true,
5 | "main": "dist/index.js",
6 | "types": "dist/index.d.ts",
7 | "scripts": {
8 | "build": "tsc",
9 | "test": "mocha -r ts-node/register 'test/**/*.test.ts'",
10 | "test:watch": "jest --watch",
11 | "test:coverage": "jest --coverage",
12 | "lint": "eslint src --ext .ts"
13 | },
14 | "dependencies": {
15 | "crypto": "^1.0.1"
16 | },
17 | "devDependencies": {
18 | "@types/chai": "^4.3.0",
19 | "@types/mocha": "^9.1.0",
20 | "@types/node": "^17.0.21",
21 | "chai": "^4.3.6",
22 | "mocha": "^9.2.2",
23 | "ts-node": "^10.7.0",
24 | "typescript": "^4.6.2"
25 | },
26 | "keywords": [],
27 | "author": "",
28 | "license": "ISC",
29 | "description": ""
30 | }
31 |
--------------------------------------------------------------------------------
/packages/crypto/src/core/__tests__/asymmetric.test.ts:
--------------------------------------------------------------------------------
1 | import { RSA, KeyPair } from '../asymmetric';
2 |
3 | describe('RSA', () => {
4 | let keyPair: KeyPair;
5 | const testData = Buffer.from('Hello, World!');
6 |
7 | beforeAll(async () => {
8 | keyPair = await RSA.generateKeyPair();
9 | });
10 |
11 | it('should generate key pair with correct format', async () => {
12 | expect(keyPair.publicKey).toBeDefined();
13 | expect(keyPair.privateKey).toBeDefined();
14 | expect(typeof keyPair.publicKey).toBe('string');
15 | expect(typeof keyPair.privateKey).toBe('string');
16 | expect(keyPair.publicKey).toContain('-----BEGIN PUBLIC KEY-----');
17 | expect(keyPair.privateKey).toContain('-----BEGIN PRIVATE KEY-----');
18 | });
19 |
20 | it('should encrypt and decrypt data correctly', async () => {
21 | const encrypted = await RSA.encrypt(testData, keyPair.publicKey);
22 | const decrypted = await RSA.decrypt(encrypted, keyPair.privateKey);
23 |
24 | expect(decrypted.toString()).toBe(testData.toString());
25 | });
26 |
27 | it('should fail to decrypt with wrong private key', async () => {
28 | const encrypted = await RSA.encrypt(testData, keyPair.publicKey);
29 | const wrongKeyPair = await RSA.generateKeyPair();
30 |
31 | await expect(RSA.decrypt(encrypted, wrongKeyPair.privateKey)).rejects.toThrow();
32 | });
33 |
34 | it('should handle small data', async () => {
35 | const smallData = Buffer.from('A');
36 | const encrypted = await RSA.encrypt(smallData, keyPair.publicKey);
37 | const decrypted = await RSA.decrypt(encrypted, keyPair.privateKey);
38 |
39 | expect(decrypted.toString()).toBe(smallData.toString());
40 | });
41 |
42 | it('should fail to encrypt data larger than key size', async () => {
43 | const largeData = Buffer.alloc(RSA.KEY_SIZE / 8); // Data size equals key size
44 | largeData.fill('A');
45 |
46 | await expect(RSA.encrypt(largeData, keyPair.publicKey)).rejects.toThrow();
47 | });
48 | });
--------------------------------------------------------------------------------
/packages/crypto/src/core/__tests__/elgamal.test.ts:
--------------------------------------------------------------------------------
1 | import { ElGamal, ElGamalPublicKey, ElGamalPrivateKey } from '../elgamal';
2 | import { BigInteger } from 'jsbn';
3 |
4 | describe('ElGamal Encryption', () => {
5 | let publicKey: ElGamalPublicKey;
6 | let privateKey: ElGamalPrivateKey;
7 |
8 | beforeAll(async () => {
9 | // Generate a smaller key for testing (512 bits instead of 2048)
10 | const keyPair = await ElGamal.generateKeyPair(512);
11 | publicKey = keyPair.publicKey;
12 | privateKey = keyPair.privateKey;
13 | });
14 |
15 | it('should generate valid key pair', () => {
16 | expect(publicKey.p).toBeDefined();
17 | expect(publicKey.g).toBeDefined();
18 | expect(publicKey.h).toBeDefined();
19 | expect(privateKey.x).toBeDefined();
20 |
21 | // Verify that h = g^x mod p
22 | expect(publicKey.g.modPow(privateKey.x, publicKey.p).equals(publicKey.h)).toBe(true);
23 | });
24 |
25 | it('should encrypt and decrypt messages correctly', async () => {
26 | const message = new BigInteger('42');
27 | const ciphertext = await ElGamal.encrypt(message, publicKey);
28 | const decrypted = await ElGamal.decrypt(ciphertext, privateKey, publicKey);
29 |
30 | expect(decrypted.equals(message)).toBe(true);
31 | });
32 |
33 | it('should support homomorphic multiplication', () => {
34 | const m1 = new BigInteger('30');
35 | const m2 = new BigInteger('12');
36 |
37 | const c1 = ElGamal.encrypt(m1, publicKey);
38 | const c2 = ElGamal.encrypt(m2, publicKey);
39 |
40 | const cProduct = ElGamal.multiply(c1, c2, publicKey);
41 | const decryptedProduct = ElGamal.decrypt(cProduct, privateKey, publicKey);
42 |
43 | // m1 * m2 mod p
44 | const expectedProduct = m1.multiply(m2).mod(publicKey.p);
45 | expect(decryptedProduct.equals(expectedProduct)).toBe(true);
46 | });
47 |
48 | it('should support exponentiation of ciphertext', () => {
49 | const message = new BigInteger('10');
50 | const exponent = new BigInteger('3');
51 |
52 | const ciphertext = ElGamal.encrypt(message, publicKey);
53 | const cPower = ElGamal.power(ciphertext, exponent, publicKey);
54 | const decryptedPower = ElGamal.decrypt(cPower, privateKey, publicKey);
55 |
56 | // message^exponent mod p
57 | const expectedPower = message.modPow(exponent, publicKey.p);
58 | expect(decryptedPower.equals(expectedPower)).toBe(true);
59 | });
60 |
61 | it('should handle identity element (1) correctly', async () => {
62 | const message = new BigInteger('1');
63 | const ciphertext = await ElGamal.encrypt(message, publicKey);
64 | const decrypted = await ElGamal.decrypt(ciphertext, privateKey, publicKey);
65 |
66 | expect(decrypted.equals(message)).toBe(true);
67 | });
68 |
69 | it('should maintain homomorphic properties with multiple operations', () => {
70 | const m1 = new BigInteger('20');
71 | const m2 = new BigInteger('30');
72 | const exp = new BigInteger('2');
73 |
74 | const c1 = ElGamal.encrypt(m1, publicKey);
75 | const c2 = ElGamal.encrypt(m2, publicKey);
76 |
77 | // (m1 * m2)^exp mod p
78 | const cProduct = ElGamal.multiply(c1, c2, publicKey);
79 | const cResult = ElGamal.power(cProduct, exp, publicKey);
80 | const decryptedResult = ElGamal.decrypt(cResult, privateKey, publicKey);
81 |
82 | const expectedResult = m1.multiply(m2).modPow(exp, publicKey.p);
83 | expect(decryptedResult.equals(expectedResult)).toBe(true);
84 | });
85 |
86 | it('should throw error for invalid key sizes', async () => {
87 | await expect(ElGamal.generateKeyPair(256)).rejects.toThrow();
88 | });
89 |
90 | it('should throw error for messages larger than modulus', async () => {
91 | const largeMessage = publicKey.p.add(new BigInteger('1'));
92 | await expect(ElGamal.encrypt(largeMessage, publicKey)).rejects.toThrow();
93 | });
94 |
95 | it('should generate different ciphertexts for same message', async () => {
96 | const message = new BigInteger('42');
97 | const c1 = await ElGamal.encrypt(message, publicKey);
98 | const c2 = await ElGamal.encrypt(message, publicKey);
99 |
100 | // Due to randomization, c1 and c2 should be different
101 | expect(c1.c1.equals(c2.c1)).toBe(false);
102 | expect(c1.c2.equals(c2.c2)).toBe(false);
103 |
104 | // But they should decrypt to the same message
105 | const d1 = await ElGamal.decrypt(c1, privateKey, publicKey);
106 | const d2 = await ElGamal.decrypt(c2, privateKey, publicKey);
107 | expect(d1.equals(d2)).toBe(true);
108 | });
109 | });
--------------------------------------------------------------------------------
/packages/crypto/src/core/__tests__/hash.test.ts:
--------------------------------------------------------------------------------
1 | import { Hash, Signature } from '../hash';
2 | import { RSA } from '../asymmetric';
3 |
4 | describe('Hash', () => {
5 | const testData = Buffer.from('Hello, World!');
6 | const testKey = Buffer.from('secret-key');
7 |
8 | it('should generate consistent SHA-256 hashes', async () => {
9 | const hash1 = await Hash.sha256(testData);
10 | const hash2 = await Hash.sha256(testData);
11 |
12 | expect(hash1.equals(hash2)).toBe(true);
13 | });
14 |
15 | it('should generate different hashes for different data', async () => {
16 | const hash1 = await Hash.sha256(testData);
17 | const hash2 = await Hash.sha256(Buffer.from('Different data'));
18 |
19 | expect(hash1.equals(hash2)).toBe(false);
20 | });
21 |
22 | it('should generate consistent HMAC values', async () => {
23 | const hmac1 = await Hash.hmac(testData, testKey);
24 | const hmac2 = await Hash.hmac(testData, testKey);
25 |
26 | expect(hmac1.equals(hmac2)).toBe(true);
27 | });
28 |
29 | it('should generate different HMAC values for different keys', async () => {
30 | const hmac1 = await Hash.hmac(testData, testKey);
31 | const hmac2 = await Hash.hmac(testData, Buffer.from('different-key'));
32 |
33 | expect(hmac1.equals(hmac2)).toBe(false);
34 | });
35 | });
36 |
37 | describe('Signature', () => {
38 | const testData = Buffer.from('Hello, World!');
39 | let keyPair: Awaited>;
40 |
41 | beforeAll(async () => {
42 | keyPair = await RSA.generateKeyPair();
43 | });
44 |
45 | it('should sign and verify data correctly', async () => {
46 | const signature = await Signature.sign(testData, keyPair.privateKey);
47 | const isValid = await Signature.verify(testData, signature, keyPair.publicKey);
48 |
49 | expect(isValid).toBe(true);
50 | });
51 |
52 | it('should fail verification with wrong public key', async () => {
53 | const signature = await Signature.sign(testData, keyPair.privateKey);
54 | const wrongKeyPair = await RSA.generateKeyPair();
55 |
56 | const isValid = await Signature.verify(testData, signature, wrongKeyPair.publicKey);
57 | expect(isValid).toBe(false);
58 | });
59 |
60 | it('should fail verification with modified data', async () => {
61 | const signature = await Signature.sign(testData, keyPair.privateKey);
62 | const modifiedData = Buffer.from('Modified data');
63 |
64 | const isValid = await Signature.verify(modifiedData, signature, keyPair.publicKey);
65 | expect(isValid).toBe(false);
66 | });
67 |
68 | it('should fail verification with modified signature', async () => {
69 | const signature = await Signature.sign(testData, keyPair.privateKey);
70 | const modifiedSignature = Buffer.from(signature); // Create a copy
71 | modifiedSignature[0] ^= 1; // Modify one bit
72 |
73 | const isValid = await Signature.verify(testData, modifiedSignature, keyPair.publicKey);
74 | expect(isValid).toBe(false);
75 | });
76 | });
--------------------------------------------------------------------------------
/packages/crypto/src/core/__tests__/homomorphic.test.ts:
--------------------------------------------------------------------------------
1 | import { Paillier, PaillierKeyPair } from '../homomorphic';
2 |
3 | describe('Paillier Homomorphic Encryption', () => {
4 | let keyPair: PaillierKeyPair;
5 |
6 | beforeAll(async () => {
7 | // Generate a smaller key for testing (512 bits instead of 2048)
8 | keyPair = await Paillier.generateKeyPair(512);
9 | });
10 |
11 | it('should generate valid key pair', () => {
12 | expect(keyPair.publicKey.n).toBeDefined();
13 | expect(keyPair.publicKey.g).toBeDefined();
14 | expect(keyPair.privateKey.lambda).toBeDefined();
15 | expect(keyPair.privateKey.mu).toBeDefined();
16 | expect(keyPair.privateKey.p).toBeDefined();
17 | expect(keyPair.privateKey.q).toBeDefined();
18 | });
19 |
20 | it('should encrypt and decrypt numbers correctly', async () => {
21 | const message = 42;
22 | const ciphertext = await Paillier.encrypt(message, keyPair.publicKey);
23 | const decrypted = await Paillier.decrypt(ciphertext, keyPair);
24 |
25 | expect(decrypted).toBe(message);
26 | });
27 |
28 | it('should support homomorphic addition', async () => {
29 | const m1 = 30;
30 | const m2 = 12;
31 |
32 | const c1 = await Paillier.encrypt(m1, keyPair.publicKey);
33 | const c2 = await Paillier.encrypt(m2, keyPair.publicKey);
34 |
35 | const cSum = await Paillier.add(c1, c2, keyPair.publicKey);
36 | const decryptedSum = await Paillier.decrypt(cSum, keyPair);
37 |
38 | expect(decryptedSum).toBe(m1 + m2);
39 | });
40 |
41 | it('should support multiplication by constant', async () => {
42 | const message = 10;
43 | const multiplier = 5;
44 |
45 | const ciphertext = await Paillier.encrypt(message, keyPair.publicKey);
46 | const cProduct = await Paillier.multiplyByConstant(ciphertext, multiplier, keyPair.publicKey);
47 | const decryptedProduct = await Paillier.decrypt(cProduct, keyPair);
48 |
49 | expect(decryptedProduct).toBe(message * multiplier);
50 | });
51 |
52 | it('should handle zero correctly', async () => {
53 | const message = 0;
54 | const ciphertext = await Paillier.encrypt(message, keyPair.publicKey);
55 | const decrypted = await Paillier.decrypt(ciphertext, keyPair);
56 |
57 | expect(decrypted).toBe(0);
58 | });
59 |
60 | it('should handle negative numbers through modular arithmetic', async () => {
61 | const message = -15;
62 | const ciphertext = await Paillier.encrypt(message, keyPair.publicKey);
63 | const decrypted = await Paillier.decrypt(ciphertext, keyPair);
64 |
65 | expect(decrypted).toBe(message);
66 | });
67 |
68 | it('should maintain homomorphic properties with multiple operations', async () => {
69 | const m1 = 20;
70 | const m2 = 30;
71 | const m3 = 5;
72 |
73 | const c1 = await Paillier.encrypt(m1, keyPair.publicKey);
74 | const c2 = await Paillier.encrypt(m2, keyPair.publicKey);
75 | const c3 = await Paillier.encrypt(m3, keyPair.publicKey);
76 |
77 | // (m1 + m2) * m3
78 | const cSum = await Paillier.add(c1, c2, keyPair.publicKey);
79 | const cResult = await Paillier.multiplyByConstant(cSum, m3, keyPair.publicKey);
80 | const decryptedResult = await Paillier.decrypt(cResult, keyPair);
81 |
82 | expect(decryptedResult).toBe((m1 + m2) * m3);
83 | });
84 |
85 | it('should throw error for invalid key sizes', async () => {
86 | await expect(Paillier.generateKeyPair(256)).rejects.toThrow();
87 | });
88 |
89 | it('should throw error for invalid message range', async () => {
90 | const message = Number.MAX_SAFE_INTEGER + 1;
91 | await expect(Paillier.encrypt(message, keyPair.publicKey)).rejects.toThrow();
92 | });
93 | });
--------------------------------------------------------------------------------
/packages/crypto/src/core/__tests__/kdf.test.ts:
--------------------------------------------------------------------------------
1 | import { KDF } from '../kdf';
2 |
3 | describe('KDF', () => {
4 | it('should derive different keys for different passwords', async () => {
5 | const password1 = 'password1';
6 | const password2 = 'password2';
7 |
8 | const result1 = await KDF.deriveKey(password1);
9 | const result2 = await KDF.deriveKey(password2);
10 |
11 | // Keys should be different even with same parameters
12 | expect(result1.key.equals(result2.key)).toBe(false);
13 | // Salts should be different
14 | expect(result1.salt.equals(result2.salt)).toBe(false);
15 | });
16 |
17 | it('should derive same key for same password and salt', async () => {
18 | const password = 'testpassword';
19 | const { key, salt } = await KDF.deriveKey(password);
20 |
21 | // Verify the password
22 | const isValid = await KDF.verifyKey(password, key, salt);
23 | expect(isValid).toBe(true);
24 | });
25 |
26 | it('should reject incorrect passwords', async () => {
27 | const password = 'correctpassword';
28 | const wrongPassword = 'wrongpassword';
29 | const { key, salt } = await KDF.deriveKey(password);
30 |
31 | // Verify with wrong password
32 | const isValid = await KDF.verifyKey(wrongPassword, key, salt);
33 | expect(isValid).toBe(false);
34 | });
35 |
36 | it('should support custom key lengths', async () => {
37 | const password = 'testpassword';
38 | const keyLength = 64; // 512 bits
39 |
40 | const { key } = await KDF.deriveKey(password, keyLength);
41 | expect(key.length).toBe(keyLength);
42 | });
43 |
44 | it('should support custom iteration counts', async () => {
45 | const password = 'testpassword';
46 | const iterations = 1000;
47 |
48 | // This just verifies the function runs with custom iterations
49 | const { key, salt } = await KDF.deriveKey(password, undefined, iterations);
50 | const isValid = await KDF.verifyKey(password, key, salt, undefined, iterations);
51 | expect(isValid).toBe(true);
52 | });
53 |
54 | it('should reject keys of different lengths', async () => {
55 | const password = 'testpassword';
56 | const { key: key1 } = await KDF.deriveKey(password, 32);
57 | const { key: key2 } = await KDF.deriveKey(password, 64);
58 |
59 | // Verify with key of different length
60 | const isValid = await KDF.verifyKey(password, key1, key2);
61 | expect(isValid).toBe(false);
62 | });
63 | });
--------------------------------------------------------------------------------
/packages/crypto/src/core/__tests__/symmetric.test.ts:
--------------------------------------------------------------------------------
1 | import { AES, SymmetricKey } from '../symmetric';
2 |
3 | describe('AES', () => {
4 | let key: SymmetricKey;
5 | const testData = Buffer.from('Hello, World!');
6 |
7 | beforeAll(async () => {
8 | key = await AES.generateKey();
9 | });
10 |
11 | it('should generate key with correct sizes', async () => {
12 | expect(key.key.length).toBe(AES.KEY_SIZE);
13 | expect(key.iv.length).toBe(AES.IV_SIZE);
14 | });
15 |
16 | it('should encrypt and decrypt data correctly', async () => {
17 | const encrypted = await AES.encrypt(testData, key);
18 | const decrypted = await AES.decrypt(encrypted, key.key);
19 |
20 | expect(decrypted.toString()).toBe(testData.toString());
21 | });
22 |
23 | it('should fail to decrypt with wrong key', async () => {
24 | const encrypted = await AES.encrypt(testData, key);
25 | const wrongKey = Buffer.alloc(AES.KEY_SIZE);
26 |
27 | await expect(AES.decrypt(encrypted, wrongKey)).rejects.toThrow();
28 | });
29 |
30 | it('should handle empty data', async () => {
31 | const emptyData = Buffer.from('');
32 | const encrypted = await AES.encrypt(emptyData, key);
33 | const decrypted = await AES.decrypt(encrypted, key.key);
34 |
35 | expect(decrypted.length).toBe(0);
36 | });
37 |
38 | it('should handle large data', async () => {
39 | const largeData = Buffer.alloc(1024 * 1024); // 1MB
40 | largeData.fill('A');
41 |
42 | const encrypted = await AES.encrypt(largeData, key);
43 | const decrypted = await AES.decrypt(encrypted, key.key);
44 |
45 | expect(decrypted.toString()).toBe(largeData.toString());
46 | });
47 | });
--------------------------------------------------------------------------------
/packages/crypto/src/core/__tests__/zkp.test.ts:
--------------------------------------------------------------------------------
1 | import { Schnorr, SchnorrParams } from '../zkp';
2 | import { BigInteger } from 'jsbn';
3 |
4 | describe('Schnorr', () => {
5 | let params: SchnorrParams;
6 | const secretValue = new BigInteger('42'); // Secret discrete logarithm
7 |
8 | beforeAll(async () => {
9 | // Use smaller parameters for faster tests
10 | params = await Schnorr.generateParams(512);
11 | });
12 |
13 | it('should generate valid group parameters', () => {
14 | const { p, q, g } = params;
15 |
16 | // Check that p and q are defined
17 | expect(p).toBeDefined();
18 | expect(q).toBeDefined();
19 | expect(g).toBeDefined();
20 |
21 | // Check that p = 2q + 1
22 | expect(q.multiply(new BigInteger('2')).add(new BigInteger('1')).equals(p)).toBe(true);
23 |
24 | // Check that g^q mod p = 1
25 | expect(g.modPow(q, p).equals(new BigInteger('1'))).toBe(true);
26 | });
27 |
28 | it('should generate and verify valid proofs', async () => {
29 | const { p, g } = params;
30 |
31 | // Compute public value h = g^x mod p
32 | const h = g.modPow(secretValue, p);
33 |
34 | // Generate proof
35 | const proof = await Schnorr.prove(secretValue, params);
36 |
37 | // Verify proof
38 | const isValid = await Schnorr.verify(h, proof, params);
39 | expect(isValid).toBe(true);
40 | });
41 |
42 | it('should reject proofs with wrong secret', async () => {
43 | const { p, g } = params;
44 | const wrongSecret = new BigInteger('43');
45 |
46 | // Compute public value h = g^x mod p
47 | const h = g.modPow(secretValue, p);
48 |
49 | // Generate proof with wrong secret
50 | const proof = await Schnorr.prove(wrongSecret, params);
51 |
52 | // Verify proof
53 | const isValid = await Schnorr.verify(h, proof, params);
54 | expect(isValid).toBe(false);
55 | });
56 |
57 | it('should reject proofs with modified commitment', async () => {
58 | const { p, g } = params;
59 |
60 | // Compute public value h = g^x mod p
61 | const h = g.modPow(secretValue, p);
62 |
63 | // Generate proof
64 | const proof = await Schnorr.prove(secretValue, params);
65 |
66 | // Modify commitment
67 | const modifiedProof = {
68 | ...proof,
69 | commitment: proof.commitment.add(new BigInteger('1'))
70 | };
71 |
72 | // Verify modified proof
73 | const isValid = await Schnorr.verify(h, modifiedProof, params);
74 | expect(isValid).toBe(false);
75 | });
76 |
77 | it('should reject proofs with modified challenge', async () => {
78 | const { p, g } = params;
79 |
80 | // Compute public value h = g^x mod p
81 | const h = g.modPow(secretValue, p);
82 |
83 | // Generate proof
84 | const proof = await Schnorr.prove(secretValue, params);
85 |
86 | // Modify challenge
87 | const modifiedProof = {
88 | ...proof,
89 | challenge: proof.challenge.add(new BigInteger('1'))
90 | };
91 |
92 | // Verify modified proof
93 | const isValid = await Schnorr.verify(h, modifiedProof, params);
94 | expect(isValid).toBe(false);
95 | });
96 |
97 | it('should reject proofs with modified response', async () => {
98 | const { p, g } = params;
99 |
100 | // Compute public value h = g^x mod p
101 | const h = g.modPow(secretValue, p);
102 |
103 | // Generate proof
104 | const proof = await Schnorr.prove(secretValue, params);
105 |
106 | // Modify response
107 | const modifiedProof = {
108 | ...proof,
109 | response: proof.response.add(new BigInteger('1'))
110 | };
111 |
112 | // Verify modified proof
113 | const isValid = await Schnorr.verify(h, modifiedProof, params);
114 | expect(isValid).toBe(false);
115 | });
116 | });
--------------------------------------------------------------------------------
/packages/crypto/src/core/asymmetric.ts:
--------------------------------------------------------------------------------
1 | import { generateKeyPairSync, publicEncrypt, privateDecrypt, constants } from 'crypto';
2 |
3 | export interface KeyPair {
4 | publicKey: string;
5 | privateKey: string;
6 | }
7 |
8 | export class RSA {
9 | static readonly KEY_SIZE = 2048;
10 |
11 | /**
12 | * Generate a new RSA key pair
13 | * @returns {Promise} Generated public and private keys in PEM format
14 | */
15 | static async generateKeyPair(): Promise {
16 | const { publicKey, privateKey } = generateKeyPairSync('rsa', {
17 | modulusLength: RSA.KEY_SIZE,
18 | publicKeyEncoding: {
19 | type: 'spki',
20 | format: 'pem'
21 | },
22 | privateKeyEncoding: {
23 | type: 'pkcs8',
24 | format: 'pem'
25 | }
26 | });
27 |
28 | return {
29 | publicKey,
30 | privateKey
31 | };
32 | }
33 |
34 | /**
35 | * Encrypt data using RSA-OAEP
36 | * @param {Buffer} data - Data to encrypt
37 | * @param {string} publicKey - Public key in PEM format
38 | * @returns {Promise} Encrypted data
39 | */
40 | static async encrypt(data: Buffer, publicKey: string): Promise {
41 | return publicEncrypt(
42 | {
43 | key: publicKey,
44 | padding: constants.RSA_PKCS1_OAEP_PADDING,
45 | oaepHash: 'sha256'
46 | },
47 | data
48 | );
49 | }
50 |
51 | /**
52 | * Decrypt data using RSA-OAEP
53 | * @param {Buffer} encryptedData - Data to decrypt
54 | * @param {string} privateKey - Private key in PEM format
55 | * @returns {Promise} Decrypted data
56 | */
57 | static async decrypt(encryptedData: Buffer, privateKey: string): Promise {
58 | return privateDecrypt(
59 | {
60 | key: privateKey,
61 | padding: constants.RSA_PKCS1_OAEP_PADDING,
62 | oaepHash: 'sha256'
63 | },
64 | encryptedData
65 | );
66 | }
67 | }
--------------------------------------------------------------------------------
/packages/crypto/src/core/encryption.ts:
--------------------------------------------------------------------------------
1 | import { EncryptionConfig, EncryptionKey, EncryptedData } from '../types';
2 | import { randomBytes, createCipheriv, createDecipheriv, generateKeyPairSync } from 'crypto';
3 |
4 | export class Encryption {
5 | constructor(private config: EncryptionConfig) {}
6 |
7 | async generateKeys(): Promise {
8 | switch (this.config.algorithm) {
9 | case 'RSA':
10 | return this.generateRSAKeys();
11 | case 'AES':
12 | return this.generateAESKeys();
13 | case 'FHE':
14 | return this.generateFHEKeys();
15 | default:
16 | throw new Error(`Unsupported algorithm: ${this.config.algorithm}`);
17 | }
18 | }
19 |
20 | async encrypt(data: any, key: string): Promise {
21 | switch (this.config.algorithm) {
22 | case 'RSA':
23 | return this.encryptRSA(data, key);
24 | case 'AES':
25 | return this.encryptAES(data, key);
26 | case 'FHE':
27 | return this.encryptFHE(data, key);
28 | default:
29 | throw new Error(`Unsupported algorithm: ${this.config.algorithm}`);
30 | }
31 | }
32 |
33 | async decrypt(encryptedData: EncryptedData, key: string): Promise {
34 | switch (this.config.algorithm) {
35 | case 'RSA':
36 | return this.decryptRSA(encryptedData, key);
37 | case 'AES':
38 | return this.decryptAES(encryptedData, key);
39 | case 'FHE':
40 | return this.decryptFHE(encryptedData, key);
41 | default:
42 | throw new Error(`Unsupported algorithm: ${this.config.algorithm}`);
43 | }
44 | }
45 |
46 | private generateRSAKeys(): EncryptionKey {
47 | const { publicKey, privateKey } = generateKeyPairSync('rsa', {
48 | modulusLength: this.config.keySize,
49 | publicKeyEncoding: {
50 | type: 'spki',
51 | format: 'pem'
52 | },
53 | privateKeyEncoding: {
54 | type: 'pkcs8',
55 | format: 'pem'
56 | }
57 | });
58 |
59 | return {
60 | publicKey,
61 | privateKey
62 | };
63 | }
64 |
65 | private generateAESKeys(): EncryptionKey {
66 | const key = randomBytes(this.config.keySize / 8).toString('hex');
67 | return {
68 | publicKey: key,
69 | privateKey: key
70 | };
71 | }
72 |
73 | private generateFHEKeys(): EncryptionKey {
74 | // TODO: Implement FHE key generation
75 | throw new Error('FHE key generation not implemented yet');
76 | }
77 |
78 | private async encryptRSA(data: any, publicKey: string): Promise {
79 | const { publicEncrypt } = await import('crypto');
80 | const buffer = Buffer.from(JSON.stringify(data));
81 | const encrypted = publicEncrypt(publicKey, buffer);
82 |
83 | return {
84 | data: encrypted.toString('base64')
85 | };
86 | }
87 |
88 | private async encryptAES(data: any, key: string): Promise {
89 | const iv = randomBytes(16);
90 | const cipher = createCipheriv(
91 | `aes-${this.config.keySize}-${this.config.mode || 'gcm'}`,
92 | Buffer.from(key, 'hex'),
93 | iv
94 | );
95 |
96 | const buffer = Buffer.from(JSON.stringify(data));
97 | const encrypted = Buffer.concat([cipher.update(buffer), cipher.final()]);
98 | const tag = cipher.getAuthTag();
99 |
100 | return {
101 | data: encrypted.toString('base64'),
102 | iv: iv.toString('hex'),
103 | tag: tag.toString('hex')
104 | };
105 | }
106 |
107 | private async encryptFHE(data: any, key: string): Promise {
108 | // TODO: Implement FHE encryption
109 | throw new Error('FHE encryption not implemented yet');
110 | }
111 |
112 | private async decryptRSA(encryptedData: EncryptedData, privateKey: string): Promise {
113 | const { privateDecrypt } = await import('crypto');
114 | const buffer = Buffer.from(encryptedData.data, 'base64');
115 | const decrypted = privateDecrypt(privateKey, buffer);
116 |
117 | return JSON.parse(decrypted.toString());
118 | }
119 |
120 | private async decryptAES(encryptedData: EncryptedData, key: string): Promise {
121 | if (!encryptedData.iv || !encryptedData.tag) {
122 | throw new Error('Missing IV or authentication tag for AES decryption');
123 | }
124 |
125 | const decipher = createDecipheriv(
126 | `aes-${this.config.keySize}-${this.config.mode || 'gcm'}`,
127 | Buffer.from(key, 'hex'),
128 | Buffer.from(encryptedData.iv, 'hex')
129 | );
130 |
131 | decipher.setAuthTag(Buffer.from(encryptedData.tag, 'hex'));
132 |
133 | const buffer = Buffer.from(encryptedData.data, 'base64');
134 | const decrypted = Buffer.concat([decipher.update(buffer), decipher.final()]);
135 |
136 | return JSON.parse(decrypted.toString());
137 | }
138 |
139 | private async decryptFHE(encryptedData: EncryptedData, key: string): Promise {
140 | // TODO: Implement FHE decryption
141 | throw new Error('FHE decryption not implemented yet');
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/packages/crypto/src/core/hash.ts:
--------------------------------------------------------------------------------
1 | import { createHash, createHmac, createSign, createVerify } from 'crypto';
2 |
3 | export class Hash {
4 | /**
5 | * Compute SHA-256 hash of data
6 | * @param {Buffer} data - Data to hash
7 | * @returns {Promise} Hash value
8 | */
9 | static async sha256(data: Buffer): Promise {
10 | return createHash('sha256').update(data).digest();
11 | }
12 |
13 | /**
14 | * Compute HMAC using SHA-256
15 | * @param {Buffer} data - Data to authenticate
16 | * @param {Buffer} key - HMAC key
17 | * @returns {Promise} HMAC value
18 | */
19 | static async hmac(data: Buffer, key: Buffer): Promise {
20 | return createHmac('sha256', key).update(data).digest();
21 | }
22 | }
23 |
24 | export class Signature {
25 | /**
26 | * Sign data using RSA-SHA256
27 | * @param {Buffer} data - Data to sign
28 | * @param {string} privateKey - Private key in PEM format
29 | * @returns {Promise} Signature
30 | */
31 | static async sign(data: Buffer, privateKey: string): Promise {
32 | const signer = createSign('SHA256');
33 | signer.update(data);
34 | return signer.sign(privateKey);
35 | }
36 |
37 | /**
38 | * Verify RSA-SHA256 signature
39 | * @param {Buffer} data - Original data
40 | * @param {Buffer} signature - Signature to verify
41 | * @param {string} publicKey - Public key in PEM format
42 | * @returns {Promise} Whether signature is valid
43 | */
44 | static async verify(data: Buffer, signature: Buffer, publicKey: string): Promise {
45 | const verifier = createVerify('SHA256');
46 | verifier.update(data);
47 | return verifier.verify(publicKey, signature);
48 | }
49 | }
--------------------------------------------------------------------------------
/packages/crypto/src/core/homomorphic/crt.ts:
--------------------------------------------------------------------------------
1 | export class CRT {
2 | private primes: bigint[];
3 | private N: bigint;
4 | private Ni: bigint[];
5 | private yi: bigint[];
6 |
7 | constructor(primes: bigint[]) {
8 | this.primes = primes;
9 | this.N = primes.reduce((a, b) => a * b, 1n);
10 | this.Ni = primes.map(p => this.N / p);
11 | this.yi = this.Ni.map((Ni, i) => this.modInverse(Ni, this.primes[i]));
12 | }
13 |
14 | /**
15 | * Convert a number to its CRT representation
16 | */
17 | public toCRT(x: bigint): bigint[] {
18 | return this.primes.map(p => x % p);
19 | }
20 |
21 | /**
22 | * Convert from CRT representation back to normal form
23 | */
24 | public fromCRT(remainders: bigint[]): bigint {
25 | if (remainders.length !== this.primes.length) {
26 | throw new Error('Invalid number of remainders');
27 | }
28 |
29 | let result = 0n;
30 | for (let i = 0; i < this.primes.length; i++) {
31 | const term = (remainders[i] * this.Ni[i] * this.yi[i]) % this.N;
32 | result = (result + term) % this.N;
33 | }
34 | return result;
35 | }
36 |
37 | /**
38 | * Add two numbers in CRT representation
39 | */
40 | public addCRT(a: bigint[], b: bigint[]): bigint[] {
41 | return a.map((ai, i) => (ai + b[i]) % this.primes[i]);
42 | }
43 |
44 | /**
45 | * Multiply two numbers in CRT representation
46 | */
47 | public multiplyCRT(a: bigint[], b: bigint[]): bigint[] {
48 | return a.map((ai, i) => (ai * b[i]) % this.primes[i]);
49 | }
50 |
51 | /**
52 | * Convert a polynomial to CRT representation
53 | */
54 | public polyToCRT(poly: bigint[]): bigint[][] {
55 | return poly.map(coeff => this.toCRT(coeff));
56 | }
57 |
58 | /**
59 | * Convert a polynomial from CRT representation
60 | */
61 | public polyFromCRT(crtPoly: bigint[][]): bigint[] {
62 | return crtPoly.map(coeffCRT => this.fromCRT(coeffCRT));
63 | }
64 |
65 | /**
66 | * Multiply polynomials in CRT representation
67 | */
68 | public polyMultiplyCRT(a: bigint[][], b: bigint[][]): bigint[][] {
69 | const degree = a.length + b.length - 1;
70 | const result: bigint[][] = Array(degree).fill(0).map(() =>
71 | Array(this.primes.length).fill(0n)
72 | );
73 |
74 | for (let i = 0; i < a.length; i++) {
75 | for (let j = 0; j < b.length; j++) {
76 | const product = this.multiplyCRT(a[i], b[j]);
77 | for (let k = 0; k < this.primes.length; k++) {
78 | result[i + j][k] = (result[i + j][k] + product[k]) % this.primes[k];
79 | }
80 | }
81 | }
82 |
83 | return result;
84 | }
85 |
86 | private modInverse(a: bigint, m: bigint): bigint {
87 | let [old_r, r] = [a, m];
88 | let [old_s, s] = [1n, 0n];
89 |
90 | while (r !== 0n) {
91 | const quotient = old_r / r;
92 | [old_r, r] = [r, old_r - quotient * r];
93 | [old_s, s] = [s, old_s - quotient * s];
94 | }
95 |
96 | return (old_s % m + m) % m;
97 | }
98 | }
--------------------------------------------------------------------------------
/packages/crypto/src/core/homomorphic/ntt.ts:
--------------------------------------------------------------------------------
1 | import { randomBytes } from 'crypto';
2 |
3 | export class NTT {
4 | private n: number;
5 | private q: bigint;
6 | private w: bigint;
7 | private w_inv: bigint;
8 | private n_inv: bigint;
9 |
10 | constructor(n: number, q: bigint) {
11 | this.n = n;
12 | this.q = q;
13 | // Find primitive nth root of unity modulo q
14 | this.w = this.findPrimitiveRoot();
15 | this.w_inv = this.modInverse(this.w);
16 | this.n_inv = this.modInverse(BigInt(n));
17 | }
18 |
19 | // Forward NTT
20 | public transform(poly: bigint[]): bigint[] {
21 | const result = new Array(this.n).fill(0n);
22 | let w_pow = 1n;
23 |
24 | for (let k = 0; k < this.n; k++) {
25 | let sum = 0n;
26 | for (let i = 0; i < this.n; i++) {
27 | sum = (sum + poly[i] * this.modPow(this.w, BigInt(i * k))) % this.q;
28 | }
29 | result[k] = sum;
30 | }
31 |
32 | return result;
33 | }
34 |
35 | // Inverse NTT
36 | public inverseTransform(poly: bigint[]): bigint[] {
37 | const result = new Array(this.n).fill(0n);
38 |
39 | for (let k = 0; k < this.n; k++) {
40 | let sum = 0n;
41 | for (let i = 0; i < this.n; i++) {
42 | sum = (sum + poly[i] * this.modPow(this.w_inv, BigInt(i * k))) % this.q;
43 | }
44 | result[k] = (sum * this.n_inv) % this.q;
45 | }
46 |
47 | return result;
48 | }
49 |
50 | // Polynomial multiplication using NTT
51 | public multiply(a: bigint[], b: bigint[]): bigint[] {
52 | const a_ntt = this.transform(a);
53 | const b_ntt = this.transform(b);
54 |
55 | // Point-wise multiplication in NTT domain
56 | const prod_ntt = a_ntt.map((x, i) => (x * b_ntt[i]) % this.q);
57 |
58 | // Transform back
59 | return this.inverseTransform(prod_ntt);
60 | }
61 |
62 | // Helper methods
63 | private modPow(base: bigint, exp: bigint): bigint {
64 | let result = 1n;
65 | base = base % this.q;
66 | while (exp > 0n) {
67 | if (exp & 1n) {
68 | result = (result * base) % this.q;
69 | }
70 | base = (base * base) % this.q;
71 | exp >>= 1n;
72 | }
73 | return result;
74 | }
75 |
76 | private modInverse(a: bigint): bigint {
77 | return this.modPow(a, this.q - 2n); // Using Fermat's little theorem
78 | }
79 |
80 | private findPrimitiveRoot(): bigint {
81 | // Find a primitive nth root of unity
82 | // For simplicity, we assume q is a prime where q ≡ 1 (mod 2n)
83 | let w = 2n;
84 | while (this.modPow(w, BigInt(this.n)) !== 1n ||
85 | this.modPow(w, BigInt(this.n / 2)) === 1n) {
86 | w += 1n;
87 | }
88 | return w;
89 | }
90 | }
--------------------------------------------------------------------------------
/packages/crypto/src/core/kdf.ts:
--------------------------------------------------------------------------------
1 | import { pbkdf2, randomBytes } from 'crypto';
2 | import { promisify } from 'util';
3 |
4 | const pbkdf2Async = promisify(pbkdf2);
5 |
6 | export class KDF {
7 | private static readonly DEFAULT_ITERATIONS = 100000;
8 | private static readonly DEFAULT_KEY_LENGTH = 32; // 256 bits
9 | private static readonly SALT_LENGTH = 16; // 128 bits
10 |
11 | /**
12 | * Generate a cryptographic key from a password using PBKDF2
13 | * @param {string} password - The password to derive key from
14 | * @param {number} keyLength - Length of the derived key in bytes (default: 32)
15 | * @param {number} iterations - Number of iterations (default: 100000)
16 | * @returns {Promise<{key: Buffer, salt: Buffer}>} Derived key and salt
17 | */
18 | static async deriveKey(
19 | password: string,
20 | keyLength: number = this.DEFAULT_KEY_LENGTH,
21 | iterations: number = this.DEFAULT_ITERATIONS
22 | ): Promise<{ key: Buffer; salt: Buffer }> {
23 | // Generate random salt
24 | const salt = randomBytes(this.SALT_LENGTH);
25 |
26 | // Derive key using PBKDF2-SHA256
27 | const key = await pbkdf2Async(
28 | password,
29 | salt,
30 | iterations,
31 | keyLength,
32 | 'sha256'
33 | );
34 |
35 | return { key, salt };
36 | }
37 |
38 | /**
39 | * Verify a password against a known key and salt
40 | * @param {string} password - The password to verify
41 | * @param {Buffer} key - The known key to verify against
42 | * @param {Buffer} salt - The salt used to derive the known key
43 | * @param {number} keyLength - Length of the derived key in bytes (default: 32)
44 | * @param {number} iterations - Number of iterations (default: 100000)
45 | * @returns {Promise} Whether the password is correct
46 | */
47 | static async verifyKey(
48 | password: string,
49 | key: Buffer,
50 | salt: Buffer,
51 | keyLength: number = this.DEFAULT_KEY_LENGTH,
52 | iterations: number = this.DEFAULT_ITERATIONS
53 | ): Promise {
54 | // Derive key using the same parameters
55 | const derivedKey = await pbkdf2Async(
56 | password,
57 | salt,
58 | iterations,
59 | keyLength,
60 | 'sha256'
61 | );
62 |
63 | // Compare keys in constant time
64 | if (key.length !== derivedKey.length) {
65 | return false;
66 | }
67 |
68 | let diff = 0;
69 | for (let i = 0; i < key.length; i++) {
70 | diff |= key[i] ^ derivedKey[i];
71 | }
72 | return diff === 0;
73 | }
74 | }
--------------------------------------------------------------------------------
/packages/crypto/src/core/mac/hmac.ts:
--------------------------------------------------------------------------------
1 | import { createHmac } from 'crypto';
2 |
3 | export enum HashAlgorithm {
4 | SHA256 = 'sha256',
5 | SHA384 = 'sha384',
6 | SHA512 = 'sha512'
7 | }
8 |
9 | export class HMAC {
10 | private key: Buffer;
11 | private algorithm: HashAlgorithm;
12 | private hmac: any;
13 |
14 | constructor(key: Buffer, algorithm: HashAlgorithm = HashAlgorithm.SHA256) {
15 | this.key = key;
16 | this.algorithm = algorithm;
17 | this.hmac = createHmac(algorithm, key);
18 | }
19 |
20 | public static generate(data: Buffer, key: Buffer, algorithm: HashAlgorithm = HashAlgorithm.SHA256): Buffer {
21 | const hmac = createHmac(algorithm, key);
22 | hmac.update(data);
23 | return hmac.digest();
24 | }
25 |
26 | public static verify(data: Buffer, mac: Buffer, key: Buffer, algorithm: HashAlgorithm = HashAlgorithm.SHA256): boolean {
27 | const expectedMac = HMAC.generate(data, key, algorithm);
28 | return mac.length === expectedMac.length &&
29 | Buffer.compare(mac, expectedMac) === 0;
30 | }
31 |
32 | public update(data: Buffer): void {
33 | this.hmac.update(data);
34 | }
35 |
36 | public digest(): Buffer {
37 | return this.hmac.digest();
38 | }
39 |
40 | public static deriveKey(key: Buffer, salt: Buffer, info: Buffer, length: number): Buffer {
41 | const hmac = createHmac('sha256', key);
42 | hmac.update(salt);
43 | hmac.update(info);
44 | return hmac.digest().slice(0, length);
45 | }
46 | }
--------------------------------------------------------------------------------
/packages/crypto/src/core/symmetric.ts:
--------------------------------------------------------------------------------
1 | import { randomBytes, createCipheriv, createDecipheriv } from 'crypto';
2 |
3 | export interface SymmetricKey {
4 | key: Buffer;
5 | iv: Buffer;
6 | }
7 |
8 | export class AES {
9 | static readonly KEY_SIZE = 32; // 256 bits
10 | static readonly IV_SIZE = 16; // 128 bits
11 |
12 | /**
13 | * Generate a new AES key
14 | * @returns {Promise} Generated key and IV
15 | */
16 | static async generateKey(): Promise {
17 | return {
18 | key: randomBytes(AES.KEY_SIZE),
19 | iv: randomBytes(AES.IV_SIZE)
20 | };
21 | }
22 |
23 | /**
24 | * Encrypt data using AES-256-GCM
25 | * @param {Buffer} data - Data to encrypt
26 | * @param {SymmetricKey} key - Encryption key
27 | * @returns {Promise} Encrypted data
28 | */
29 | static async encrypt(data: Buffer, { key, iv }: SymmetricKey): Promise {
30 | const cipher = createCipheriv('aes-256-gcm', key, iv);
31 | const encrypted = Buffer.concat([cipher.update(data), cipher.final()]);
32 | const authTag = cipher.getAuthTag();
33 |
34 | // Combine IV, encrypted data, and auth tag
35 | return Buffer.concat([iv, encrypted, authTag]);
36 | }
37 |
38 | /**
39 | * Decrypt data using AES-256-GCM
40 | * @param {Buffer} encryptedData - Data to decrypt
41 | * @param {Buffer} key - Decryption key
42 | * @returns {Promise} Decrypted data
43 | */
44 | static async decrypt(encryptedData: Buffer, key: Buffer): Promise {
45 | const iv = encryptedData.subarray(0, AES.IV_SIZE);
46 | const authTag = encryptedData.subarray(encryptedData.length - 16);
47 | const data = encryptedData.subarray(AES.IV_SIZE, encryptedData.length - 16);
48 |
49 | const decipher = createDecipheriv('aes-256-gcm', key, iv);
50 | decipher.setAuthTag(authTag);
51 |
52 | return Buffer.concat([decipher.update(data), decipher.final()]);
53 | }
54 | }
--------------------------------------------------------------------------------
/packages/crypto/src/core/symmetric/aes.ts:
--------------------------------------------------------------------------------
1 | import { createCipheriv, createDecipheriv, CipherGCM, DecipherGCM } from 'crypto';
2 |
3 | export enum AESMode {
4 | CBC = 'aes-256-cbc',
5 | GCM = 'aes-256-gcm'
6 | }
7 |
8 | export interface AESParams {
9 | key: Buffer;
10 | iv: Buffer;
11 | mode: AESMode;
12 | }
13 |
14 | export class AES {
15 | private params: AESParams;
16 | private cipher: CipherGCM | any;
17 |
18 | constructor(params: AESParams) {
19 | this.validateParams(params);
20 | this.params = params;
21 | this.cipher = createCipheriv(params.mode, params.key, params.iv);
22 | }
23 |
24 | public static async encrypt(data: Buffer, params: AESParams): Promise {
25 | const aes = new AES(params);
26 | return Buffer.concat([aes.update(data), await aes.final()]);
27 | }
28 |
29 | public static async decrypt(ciphertext: Buffer, params: AESParams): Promise {
30 | const decipher = createDecipheriv(params.mode, params.key, params.iv);
31 | return Buffer.concat([decipher.update(ciphertext), decipher.final()]);
32 | }
33 |
34 | public static async encryptGCM(data: Buffer, params: AESParams): Promise<{ ciphertext: Buffer; tag: Buffer }> {
35 | if (params.mode !== AESMode.GCM) {
36 | throw new Error('GCM mode required');
37 | }
38 | const cipher = createCipheriv(params.mode, params.key, params.iv) as CipherGCM;
39 | const ciphertext = Buffer.concat([cipher.update(data), cipher.final()]);
40 | return { ciphertext, tag: cipher.getAuthTag() };
41 | }
42 |
43 | public static async decryptGCM(ciphertext: Buffer, tag: Buffer, params: AESParams): Promise {
44 | if (params.mode !== AESMode.GCM) {
45 | throw new Error('GCM mode required');
46 | }
47 | const decipher = createDecipheriv(params.mode, params.key, params.iv) as DecipherGCM;
48 | decipher.setAuthTag(tag);
49 | return Buffer.concat([decipher.update(ciphertext), decipher.final()]);
50 | }
51 |
52 | public update(data: Buffer): Buffer {
53 | return this.cipher.update(data);
54 | }
55 |
56 | public async final(): Promise {
57 | return this.cipher.final();
58 | }
59 |
60 | private validateParams(params: AESParams): void {
61 | if (![16, 24, 32].includes(params.key.length)) {
62 | throw new Error('Invalid key length');
63 | }
64 | if (params.iv.length !== 16) {
65 | throw new Error('Invalid IV length');
66 | }
67 | }
68 | }
--------------------------------------------------------------------------------
/packages/crypto/src/core/symmetric/chacha20-poly1305.ts:
--------------------------------------------------------------------------------
1 | import { createCipheriv, createDecipheriv, CipherCCM, DecipherCCM } from 'crypto';
2 |
3 | export interface ChaChaParams {
4 | key: Buffer;
5 | nonce: Buffer;
6 | }
7 |
8 | export class ChaCha20Poly1305 {
9 | private params: ChaChaParams;
10 | private cipher: CipherCCM;
11 |
12 | constructor(params: ChaChaParams) {
13 | this.validateParams(params);
14 | this.params = params;
15 | this.cipher = createCipheriv('chacha20-poly1305', params.key, params.nonce) as CipherCCM;
16 | }
17 |
18 | public static async encrypt(data: Buffer, params: ChaChaParams): Promise<{ ciphertext: Buffer; tag: Buffer }> {
19 | const cipher = createCipheriv('chacha20-poly1305', params.key, params.nonce) as CipherCCM;
20 | const ciphertext = Buffer.concat([cipher.update(data), cipher.final()]);
21 | return { ciphertext, tag: cipher.getAuthTag() };
22 | }
23 |
24 | public static async decrypt(ciphertext: Buffer, tag: Buffer, params: ChaChaParams): Promise {
25 | const decipher = createDecipheriv('chacha20-poly1305', params.key, params.nonce) as DecipherCCM;
26 | decipher.setAuthTag(tag);
27 | return Buffer.concat([decipher.update(ciphertext), decipher.final()]);
28 | }
29 |
30 | public update(data: Buffer): Buffer {
31 | return this.cipher.update(data);
32 | }
33 |
34 | public async final(): Promise<{ finalCiphertext: Buffer; tag: Buffer }> {
35 | const finalCiphertext = this.cipher.final();
36 | const tag = this.cipher.getAuthTag();
37 | return { finalCiphertext, tag };
38 | }
39 |
40 | private validateParams(params: ChaChaParams): void {
41 | if (params.key.length !== 32) {
42 | throw new Error('Invalid key length');
43 | }
44 | if (params.nonce.length !== 12) {
45 | throw new Error('Invalid nonce length');
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/packages/crypto/src/core/tls/constants.ts:
--------------------------------------------------------------------------------
1 | export enum HandshakeType {
2 | hello_request = 0,
3 | client_hello = 1,
4 | server_hello = 2,
5 | new_session_ticket = 4,
6 | end_of_early_data = 5,
7 | encrypted_extensions = 8,
8 | certificate = 11,
9 | server_key_exchange = 12,
10 | certificate_request = 13,
11 | server_hello_done = 14,
12 | certificate_verify = 15,
13 | client_key_exchange = 16,
14 | finished = 20,
15 | key_update = 24,
16 | message_hash = 254
17 | }
18 |
19 | export enum AlertLevel {
20 | warning = 1,
21 | fatal = 2
22 | }
23 |
24 | export enum AlertDescription {
25 | close_notify = 0,
26 | unexpected_message = 10,
27 | bad_record_mac = 20,
28 | record_overflow = 22,
29 | handshake_failure = 40,
30 | bad_certificate = 42,
31 | unsupported_certificate = 43,
32 | certificate_revoked = 44,
33 | certificate_expired = 45,
34 | certificate_unknown = 46,
35 | illegal_parameter = 47,
36 | unknown_ca = 48,
37 | access_denied = 49,
38 | decode_error = 50,
39 | decrypt_error = 51,
40 | protocol_version = 70,
41 | insufficient_security = 71,
42 | internal_error = 80,
43 | inappropriate_fallback = 86,
44 | user_canceled = 90,
45 | missing_extension = 109,
46 | unsupported_extension = 110,
47 | unrecognized_name = 112,
48 | bad_certificate_status_response = 113,
49 | unknown_psk_identity = 115,
50 | certificate_required = 116,
51 | no_application_protocol = 120
52 | }
--------------------------------------------------------------------------------
/packages/crypto/src/core/tls/handshake.ts:
--------------------------------------------------------------------------------
1 | import { HandshakeType } from './constants';
2 |
3 | export interface HandshakeMessage {
4 | msgType: HandshakeType;
5 | serialize(): Buffer;
6 | }
7 |
8 | export class TLSHandshake {
9 | public static createClientHello(params: any): HandshakeMessage {
10 | return {
11 | msgType: HandshakeType.client_hello,
12 | serialize: () => Buffer.alloc(0) // TODO: Implement actual serialization
13 | };
14 | }
15 |
16 | public static createServerHello(params: any): HandshakeMessage {
17 | return {
18 | msgType: HandshakeType.server_hello,
19 | serialize: () => Buffer.alloc(0)
20 | };
21 | }
22 |
23 | public static createEncryptedExtensions(extensions: Map): HandshakeMessage {
24 | return {
25 | msgType: HandshakeType.encrypted_extensions,
26 | serialize: () => Buffer.alloc(0)
27 | };
28 | }
29 |
30 | public static createCertificate(params: any): HandshakeMessage {
31 | return {
32 | msgType: HandshakeType.certificate,
33 | serialize: () => Buffer.alloc(0)
34 | };
35 | }
36 |
37 | public static createCertificateVerify(params: any): HandshakeMessage {
38 | return {
39 | msgType: HandshakeType.certificate_verify,
40 | serialize: () => Buffer.alloc(0)
41 | };
42 | }
43 |
44 | public static createFinished(verifyData: Buffer): HandshakeMessage {
45 | return {
46 | msgType: HandshakeType.finished,
47 | serialize: () => Buffer.alloc(0)
48 | };
49 | }
50 |
51 | public static parseClientHello(data: Buffer): any {
52 | // TODO: Implement actual parsing
53 | if (data.length === 0) {
54 | throw new Error('Invalid handshake message');
55 | }
56 | return {};
57 | }
58 |
59 | public static parseServerHello(data: Buffer): any {
60 | if (data.length === 0) {
61 | throw new Error('Invalid handshake message');
62 | }
63 | return {};
64 | }
65 |
66 | public static parseEncryptedExtensions(data: Buffer): any {
67 | if (data.length === 0) {
68 | throw new Error('Invalid handshake message');
69 | }
70 | return {};
71 | }
72 |
73 | public static parseCertificate(data: Buffer): any {
74 | if (data.length === 0) {
75 | throw new Error('Invalid handshake message');
76 | }
77 | return {};
78 | }
79 |
80 | public static parseCertificateVerify(data: Buffer): any {
81 | if (data.length === 0) {
82 | throw new Error('Invalid handshake message');
83 | }
84 | return {};
85 | }
86 |
87 | public static parseFinished(data: Buffer): any {
88 | if (data.length === 0) {
89 | throw new Error('Invalid handshake message');
90 | }
91 | return {};
92 | }
93 |
94 | public static parsePreSharedKeyExtension(data: Buffer): any {
95 | return {};
96 | }
97 |
98 | public static parseKeyShareExtension(data: Buffer): any {
99 | return {};
100 | }
101 |
102 | public static createPreSharedKeyExtension(identities: any[], binders: Buffer[]): Buffer {
103 | return Buffer.alloc(0);
104 | }
105 |
106 | public static createKeyShareExtension(shares: any[]): Buffer {
107 | return Buffer.alloc(0);
108 | }
109 |
110 | public static parseExtension(type: string, data: Buffer): any {
111 | if (!type) {
112 | throw new Error('Unknown extension type');
113 | }
114 | return {};
115 | }
116 |
117 | public static fragment(data: Buffer): Buffer[] {
118 | const maxFragmentSize = 16384;
119 | const fragments: Buffer[] = [];
120 |
121 | for (let i = 0; i < data.length; i += maxFragmentSize) {
122 | fragments.push(data.slice(i, i + maxFragmentSize));
123 | }
124 |
125 | return fragments;
126 | }
127 | }
--------------------------------------------------------------------------------
/packages/crypto/src/core/tls/key-schedule.ts:
--------------------------------------------------------------------------------
1 | import { createHmac } from 'crypto';
2 |
3 | export class TLSKeySchedule {
4 | private static readonly HASH_LENGTH = 32; // SHA-256
5 |
6 | public static deriveEarlySecret(psk: Buffer): Buffer {
7 | return this.extract(Buffer.alloc(this.HASH_LENGTH), psk);
8 | }
9 |
10 | public static deriveEarlyTrafficSecret(secret: Buffer, label: 'client' | 'server'): Buffer {
11 | return this.expandLabel(secret, `${label} early traffic secret`, Buffer.alloc(0), this.HASH_LENGTH);
12 | }
13 |
14 | public static deriveEarlyExporterSecret(secret: Buffer): Buffer {
15 | return this.expandLabel(secret, 'early exporter secret', Buffer.alloc(0), this.HASH_LENGTH);
16 | }
17 |
18 | public static deriveHandshakeSecret(earlySecret: Buffer, sharedSecret: Buffer): Buffer {
19 | const derivedSecret = this.expandLabel(earlySecret, 'derived', Buffer.alloc(0), this.HASH_LENGTH);
20 | return this.extract(derivedSecret, sharedSecret);
21 | }
22 |
23 | public static deriveHandshakeTrafficSecret(secret: Buffer, label: 'client' | 'server'): Buffer {
24 | return this.expandLabel(secret, `${label} handshake traffic secret`, Buffer.alloc(0), this.HASH_LENGTH);
25 | }
26 |
27 | public static deriveMasterSecret(handshakeSecret: Buffer): Buffer {
28 | const derivedSecret = this.expandLabel(handshakeSecret, 'derived', Buffer.alloc(0), this.HASH_LENGTH);
29 | return this.extract(derivedSecret, Buffer.alloc(0));
30 | }
31 |
32 | public static deriveApplicationTrafficSecret(secret: Buffer, label: 'client' | 'server'): Buffer {
33 | return this.expandLabel(secret, `${label} application traffic secret`, Buffer.alloc(0), this.HASH_LENGTH);
34 | }
35 |
36 | public static deriveExporterMasterSecret(secret: Buffer): Buffer {
37 | return this.expandLabel(secret, 'exporter master secret', Buffer.alloc(0), this.HASH_LENGTH);
38 | }
39 |
40 | public static deriveResumptionMasterSecret(secret: Buffer): Buffer {
41 | return this.expandLabel(secret, 'resumption master secret', Buffer.alloc(0), this.HASH_LENGTH);
42 | }
43 |
44 | public static updateTrafficSecret(secret: Buffer): Buffer {
45 | return this.expandLabel(secret, 'traffic upd', Buffer.alloc(0), this.HASH_LENGTH);
46 | }
47 |
48 | public static deriveKeyAndIV(secret: Buffer, cipherSuite: string): { key: Buffer; iv: Buffer } {
49 | const keyLength = cipherSuite.includes('256') ? 32 : 16;
50 | const ivLength = 12;
51 |
52 | const key = this.expandLabel(secret, 'key', Buffer.alloc(0), keyLength);
53 | const iv = this.expandLabel(secret, 'iv', Buffer.alloc(0), ivLength);
54 |
55 | return { key, iv };
56 | }
57 |
58 | public static expandLabel(secret: Buffer, label: string, context: Buffer, length: number): Buffer {
59 | const hkdfLabel = Buffer.concat([
60 | Buffer.from([0, length]),
61 | Buffer.from('tls13 ' + label),
62 | context
63 | ]);
64 | return this.expand(secret, hkdfLabel, length);
65 | }
66 |
67 | public static exportKeyingMaterial(secret: Buffer, label: string, context: Buffer, length: number): Buffer {
68 | return this.expandLabel(secret, label, context, length);
69 | }
70 |
71 | private static extract(salt: Buffer, ikm: Buffer): Buffer {
72 | const hmac = createHmac('sha256', salt);
73 | hmac.update(ikm);
74 | return hmac.digest();
75 | }
76 |
77 | private static expand(prk: Buffer, info: Buffer, length: number): Buffer {
78 | const hmac = createHmac('sha256', prk);
79 | let output = Buffer.alloc(0);
80 | let T = Buffer.alloc(0);
81 | let i = 1;
82 |
83 | while (output.length < length) {
84 | const input = Buffer.concat([T, info, Buffer.from([i])]);
85 | hmac.update(input);
86 | T = hmac.digest();
87 | output = Buffer.concat([output, T]);
88 | i++;
89 | }
90 |
91 | return output.slice(0, length);
92 | }
93 | }
--------------------------------------------------------------------------------
/packages/crypto/src/core/tls/record-layer.ts:
--------------------------------------------------------------------------------
1 | import { createCipheriv, createDecipheriv, randomBytes } from 'crypto';
2 |
3 | export interface RecordLayerOptions {
4 | maxRecordSize?: number;
5 | keySize?: number;
6 | ivSize?: number;
7 | }
8 |
9 | export class RecordLayer {
10 | private static readonly DEFAULT_MAX_RECORD_SIZE = 16384;
11 | private static readonly DEFAULT_KEY_SIZE = 32;
12 | private static readonly DEFAULT_IV_SIZE = 12;
13 | private static readonly HEADER_SIZE = 5;
14 | private static readonly SEQUENCE_SIZE = 8;
15 |
16 | private readonly maxRecordSize: number;
17 | private readonly keySize: number;
18 | private readonly ivSize: number;
19 | private sequenceNumber: bigint;
20 |
21 | constructor(options: RecordLayerOptions = {}) {
22 | this.maxRecordSize = options.maxRecordSize || RecordLayer.DEFAULT_MAX_RECORD_SIZE;
23 | this.keySize = options.keySize || RecordLayer.DEFAULT_KEY_SIZE;
24 | this.ivSize = options.ivSize || RecordLayer.DEFAULT_IV_SIZE;
25 | this.sequenceNumber = BigInt(0);
26 | }
27 |
28 | /**
29 | * Encrypt a record
30 | * @param data Data to encrypt
31 | * @param key Encryption key
32 | * @param iv Initial vector
33 | * @param additionalData Additional authenticated data
34 | * @returns Encrypted record
35 | */
36 | public encrypt(
37 | data: Buffer,
38 | key: Buffer,
39 | iv: Buffer,
40 | additionalData?: Buffer
41 | ): Buffer {
42 | this.validateInputs(key, iv);
43 |
44 | if (data.length > this.maxRecordSize) {
45 | throw new Error(`Record size exceeds maximum (${this.maxRecordSize} bytes)`);
46 | }
47 |
48 | // Construct nonce by XORing IV with sequence number
49 | const nonce = Buffer.alloc(this.ivSize);
50 | iv.copy(nonce);
51 | const sequenceBuffer = Buffer.alloc(8);
52 | sequenceBuffer.writeBigUInt64BE(this.sequenceNumber);
53 | for (let i = 0; i < 8; i++) {
54 | nonce[i + 4] ^= sequenceBuffer[i];
55 | }
56 |
57 | // Encrypt data
58 | const cipher = createCipheriv('aes-256-gcm', key, nonce);
59 | if (additionalData) {
60 | cipher.setAAD(additionalData);
61 | }
62 | const ciphertext = Buffer.concat([cipher.update(data), cipher.final()]);
63 | const tag = cipher.getAuthTag();
64 |
65 | // Increment sequence number
66 | this.sequenceNumber = (this.sequenceNumber + BigInt(1)) % (BigInt(1) << BigInt(64));
67 |
68 | // Construct record
69 | const record = Buffer.alloc(RecordLayer.HEADER_SIZE + ciphertext.length + 16);
70 | record.writeUInt16BE(ciphertext.length + 16, 3); // Record length
71 | ciphertext.copy(record, RecordLayer.HEADER_SIZE);
72 | tag.copy(record, RecordLayer.HEADER_SIZE + ciphertext.length);
73 |
74 | return record;
75 | }
76 |
77 | /**
78 | * Decrypt a record
79 | * @param record Record to decrypt
80 | * @param key Decryption key
81 | * @param iv Initial vector
82 | * @param additionalData Additional authenticated data
83 | * @returns Decrypted data
84 | */
85 | public decrypt(
86 | record: Buffer,
87 | key: Buffer,
88 | iv: Buffer,
89 | additionalData?: Buffer
90 | ): Buffer {
91 | this.validateInputs(key, iv);
92 |
93 | // Parse record
94 | const recordLength = record.readUInt16BE(3);
95 | if (recordLength > this.maxRecordSize + 16) {
96 | throw new Error(`Record size exceeds maximum (${this.maxRecordSize} bytes)`);
97 | }
98 |
99 | const ciphertext = record.slice(RecordLayer.HEADER_SIZE, RecordLayer.HEADER_SIZE + recordLength - 16);
100 | const tag = record.slice(RecordLayer.HEADER_SIZE + recordLength - 16, RecordLayer.HEADER_SIZE + recordLength);
101 |
102 | // Construct nonce by XORing IV with sequence number
103 | const nonce = Buffer.alloc(this.ivSize);
104 | iv.copy(nonce);
105 | const sequenceBuffer = Buffer.alloc(8);
106 | sequenceBuffer.writeBigUInt64BE(this.sequenceNumber);
107 | for (let i = 0; i < 8; i++) {
108 | nonce[i + 4] ^= sequenceBuffer[i];
109 | }
110 |
111 | // Decrypt data
112 | const decipher = createDecipheriv('aes-256-gcm', key, nonce);
113 | if (additionalData) {
114 | decipher.setAAD(additionalData);
115 | }
116 | decipher.setAuthTag(tag);
117 | const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
118 |
119 | // Increment sequence number
120 | this.sequenceNumber = (this.sequenceNumber + BigInt(1)) % (BigInt(1) << BigInt(64));
121 |
122 | return plaintext;
123 | }
124 |
125 | /**
126 | * Get current sequence number
127 | * @returns Current sequence number
128 | */
129 | public getSequenceNumber(): bigint {
130 | return this.sequenceNumber;
131 | }
132 |
133 | /**
134 | * Reset sequence number to 0
135 | */
136 | public resetSequenceNumber(): void {
137 | this.sequenceNumber = BigInt(0);
138 | }
139 |
140 | private validateInputs(key: Buffer, iv: Buffer): void {
141 | if (key.length !== this.keySize) {
142 | throw new Error(`Key must be ${this.keySize} bytes`);
143 | }
144 | if (iv.length !== this.ivSize) {
145 | throw new Error(`IV must be ${this.ivSize} bytes`);
146 | }
147 | }
148 | }
--------------------------------------------------------------------------------
/packages/crypto/src/core/xchacha20/xchacha20.ts:
--------------------------------------------------------------------------------
1 | import { createCipheriv, createDecipheriv, randomBytes, CipherGCM, DecipherGCM } from 'crypto';
2 |
3 | export class XChaCha20 {
4 | private static readonly KEY_SIZE = 32;
5 | private static readonly NONCE_SIZE = 24;
6 | private static readonly BLOCK_SIZE = 64;
7 |
8 | /**
9 | * Encrypt data using XChaCha20
10 | * @param plaintext Data to encrypt
11 | * @param key 32-byte key
12 | * @param nonce 24-byte nonce
13 | * @param counter Optional counter for seeking
14 | * @returns Encrypted data
15 | */
16 | public static encrypt(
17 | plaintext: Buffer,
18 | key: Buffer,
19 | nonce: Buffer,
20 | counter: bigint = BigInt(0)
21 | ): Buffer {
22 | this.validateInputs(key, nonce);
23 | const cipher = createCipheriv('chacha20', key, nonce);
24 | return Buffer.concat([cipher.update(plaintext), cipher.final()]);
25 | }
26 |
27 | /**
28 | * Decrypt data using XChaCha20
29 | * @param ciphertext Data to decrypt
30 | * @param key 32-byte key
31 | * @param nonce 24-byte nonce
32 | * @param counter Optional counter for seeking
33 | * @returns Decrypted data
34 | */
35 | public static decrypt(
36 | ciphertext: Buffer,
37 | key: Buffer,
38 | nonce: Buffer,
39 | counter: bigint = BigInt(0)
40 | ): Buffer {
41 | this.validateInputs(key, nonce);
42 | const decipher = createDecipheriv('chacha20', key, nonce);
43 | return Buffer.concat([decipher.update(ciphertext), decipher.final()]);
44 | }
45 |
46 | /**
47 | * Encrypt data using XChaCha20-Poly1305 AEAD
48 | * @param plaintext Data to encrypt
49 | * @param key 32-byte key
50 | * @param nonce 24-byte nonce
51 | * @param aad Additional authenticated data
52 | * @returns Object containing ciphertext and authentication tag
53 | */
54 | public static encryptWithAEAD(
55 | plaintext: Buffer,
56 | key: Buffer,
57 | nonce: Buffer,
58 | aad?: Buffer
59 | ): { ciphertext: Buffer; tag: Buffer } {
60 | this.validateInputs(key, nonce);
61 | const cipher = createCipheriv('chacha20-poly1305', key, nonce) as CipherGCM;
62 | if (aad) {
63 | cipher.setAAD(aad);
64 | }
65 | const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
66 | const tag = cipher.getAuthTag();
67 | return { ciphertext, tag };
68 | }
69 |
70 | /**
71 | * Decrypt data using XChaCha20-Poly1305 AEAD
72 | * @param ciphertext Data to decrypt
73 | * @param key 32-byte key
74 | * @param nonce 24-byte nonce
75 | * @param tag Authentication tag
76 | * @param aad Additional authenticated data
77 | * @returns Decrypted data
78 | */
79 | public static decryptWithAEAD(
80 | ciphertext: Buffer,
81 | key: Buffer,
82 | nonce: Buffer,
83 | tag: Buffer,
84 | aad?: Buffer
85 | ): Buffer {
86 | this.validateInputs(key, nonce);
87 | const decipher = createDecipheriv('chacha20-poly1305', key, nonce) as DecipherGCM;
88 | if (aad) {
89 | decipher.setAAD(aad);
90 | }
91 | decipher.setAuthTag(tag);
92 | return Buffer.concat([decipher.update(ciphertext), decipher.final()]);
93 | }
94 |
95 | /**
96 | * Derive a subkey using HChaCha20
97 | * @param key 32-byte key
98 | * @param nonce 24-byte nonce
99 | * @returns 32-byte subkey
100 | */
101 | public static deriveSubkey(key: Buffer, nonce: Buffer): Buffer {
102 | this.validateInputs(key, nonce);
103 | const cipher = createCipheriv('chacha20', key, nonce);
104 | const subkey = cipher.update(Buffer.alloc(32));
105 | cipher.final();
106 | return subkey;
107 | }
108 |
109 | private static validateInputs(key: Buffer, nonce: Buffer): void {
110 | if (key.length !== this.KEY_SIZE) {
111 | throw new Error(`Key must be ${this.KEY_SIZE} bytes`);
112 | }
113 | if (nonce.length !== this.NONCE_SIZE) {
114 | throw new Error(`Nonce must be ${this.NONCE_SIZE} bytes`);
115 | }
116 | }
117 | }
--------------------------------------------------------------------------------
/packages/crypto/src/core/zkp/__tests__/chaum-pedersen.test.ts:
--------------------------------------------------------------------------------
1 | import { expect } from 'chai';
2 | import { ChaumPedersen, ChaumPedersenParams, ChaumPedersenProof } from '../chaum-pedersen';
3 | import { BigInteger } from 'jsbn';
4 | import { randomBytes } from 'crypto';
5 |
6 | describe('ChaumPedersen', () => {
7 | let params: ChaumPedersenParams;
8 | let secret: BigInteger;
9 | let y1: BigInteger;
10 | let y2: BigInteger;
11 |
12 | before(async () => {
13 | params = await ChaumPedersen.generateParams(512);
14 | const randomBuffer = Buffer.from(randomBytes(32));
15 | secret = new BigInteger(randomBuffer.toString('hex'), 16);
16 | y1 = params.g.modPow(secret, params.p);
17 | y2 = params.h.modPow(secret, params.p);
18 | });
19 |
20 | it('should generate valid parameters', () => {
21 | expect(params.p).to.exist;
22 | expect(params.q).to.exist;
23 | expect(params.g).to.exist;
24 | expect(params.h).to.exist;
25 | expect(params.g.modPow(params.q, params.p).equals(new BigInteger('1'))).to.be.true;
26 | expect(params.h.modPow(params.q, params.p).equals(new BigInteger('1'))).to.be.true;
27 | });
28 |
29 | it('should generate and verify valid proofs', async () => {
30 | const proof = await ChaumPedersen.prove(secret, y1, y2, params);
31 | const isValid = await ChaumPedersen.verify(y1, y2, proof, params);
32 | expect(isValid).to.be.true;
33 | });
34 |
35 | it('should reject invalid proofs with wrong secret', async () => {
36 | const wrongSecret = new BigInteger(randomBytes(32).toString('hex'), 16);
37 | const proof = await ChaumPedersen.prove(wrongSecret, y1, y2, params);
38 | const isValid = await ChaumPedersen.verify(y1, y2, proof, params);
39 | expect(isValid).to.be.false;
40 | });
41 |
42 | it('should reject invalid proofs with wrong public values', async () => {
43 | const wrongY1 = params.g.modPow(new BigInteger('2'), params.p);
44 | const wrongY2 = params.h.modPow(new BigInteger('2'), params.p);
45 | const proof = await ChaumPedersen.prove(secret, y1, y2, params);
46 | const isValid = await ChaumPedersen.verify(wrongY1, wrongY2, proof, params);
47 | expect(isValid).to.be.false;
48 | });
49 |
50 | it('should generate different proofs for the same values', async () => {
51 | const proof1 = await ChaumPedersen.prove(secret, y1, y2, params);
52 | const proof2 = await ChaumPedersen.prove(secret, y1, y2, params);
53 |
54 | expect(proof1.t1.equals(proof2.t1)).to.be.false;
55 | expect(proof1.t2.equals(proof2.t2)).to.be.false;
56 |
57 | const isValid1 = await ChaumPedersen.verify(y1, y2, proof1, params);
58 | const isValid2 = await ChaumPedersen.verify(y1, y2, proof2, params);
59 | expect(isValid1).to.be.true;
60 | expect(isValid2).to.be.true;
61 | });
62 |
63 | it('should handle small values correctly', async () => {
64 | const smallSecret = new BigInteger('1');
65 | const y1Small = params.g.modPow(smallSecret, params.p);
66 | const y2Small = params.h.modPow(smallSecret, params.p);
67 | const proof = await ChaumPedersen.prove(smallSecret, y1Small, y2Small, params);
68 | const isValid1 = await ChaumPedersen.verify(y1Small, y2Small, proof, params);
69 | expect(isValid1).to.be.true;
70 | });
71 |
72 | it('should handle maximum values correctly', async () => {
73 | const maxSecret = params.q.subtract(BigInteger.ONE);
74 | const y1Max = params.g.modPow(maxSecret, params.p);
75 | const y2Max = params.h.modPow(maxSecret, params.p);
76 | const proof = await ChaumPedersen.prove(maxSecret, y1Max, y2Max, params);
77 | const isValidMax = await ChaumPedersen.verify(y1Max, y2Max, proof, params);
78 | expect(isValidMax).to.be.true;
79 | });
80 |
81 | it('should reject invalid parameter sizes', async () => {
82 | await expect(ChaumPedersen.generateParams(256)).to.be.rejectedWith(Error);
83 | });
84 |
85 | it('should reject invalid secrets', async () => {
86 | const invalidSecret = params.q;
87 | await expect(ChaumPedersen.prove(invalidSecret, y1, y2, params)).to.be.rejectedWith(Error);
88 | });
89 |
90 | it('should generate unique proofs', async () => {
91 | const proof1 = await ChaumPedersen.prove(secret, y1, y2, params);
92 | const proof2 = await ChaumPedersen.prove(secret, y1, y2, params);
93 |
94 | expect(proof1).to.not.deep.equal(proof2);
95 |
96 | expect(proof1.t1.equals(y1)).to.be.false;
97 | expect(proof1.t2.equals(y2)).to.be.false;
98 | expect(proof2.t1.equals(y1)).to.be.false;
99 | expect(proof2.t2.equals(y2)).to.be.false;
100 | });
101 | });
--------------------------------------------------------------------------------
/packages/crypto/src/core/zkp/__tests__/fiat-shamir.test.ts:
--------------------------------------------------------------------------------
1 | import { expect } from 'chai';
2 | import { FiatShamir, FiatShamirParams, FiatShamirProof } from '../fiat-shamir';
3 | import { BigInteger } from 'jsbn';
4 | import { randomBytes } from 'crypto';
5 |
6 | describe('FiatShamir', () => {
7 | let params: FiatShamirParams;
8 | let secret: BigInteger;
9 | let publicValue: BigInteger;
10 |
11 | before(async () => {
12 | params = await FiatShamir.generateParams(512);
13 | const randomBuffer = Buffer.from(randomBytes(32));
14 | secret = new BigInteger(randomBuffer.toString('hex'), 16);
15 | publicValue = secret.modPow(new BigInteger('2'), params.n);
16 | });
17 |
18 | it('should generate valid parameters', () => {
19 | expect(params.n).to.exist;
20 | expect(params.n.bitLength()).to.be.at.least(512);
21 | });
22 |
23 | it('should generate and verify valid proofs', async () => {
24 | const proof = await FiatShamir.prove(secret, params);
25 | const isValid = await FiatShamir.verify(proof, publicValue, params);
26 | expect(isValid).to.be.true;
27 | });
28 |
29 | it('should reject invalid proofs with wrong secret', async () => {
30 | const wrongSecret = new BigInteger(randomBytes(32).toString('hex'), 16);
31 | const proof = await FiatShamir.prove(wrongSecret, params);
32 | const isValid = await FiatShamir.verify(proof, publicValue, params);
33 | expect(isValid).to.be.false;
34 | });
35 |
36 | it('should reject invalid proofs with wrong public value', async () => {
37 | const wrongPublicValue = params.g.modPow(new BigInteger('2'), params.n);
38 | const proof = await FiatShamir.prove(secret, params);
39 | const isValid = await FiatShamir.verify(proof, wrongPublicValue, params);
40 | expect(isValid).to.be.false;
41 | });
42 |
43 | it('should generate different proofs for the same values', async () => {
44 | const proof1 = await FiatShamir.prove(secret, params);
45 | const proof2 = await FiatShamir.prove(secret, params);
46 |
47 | expect(proof1.commitment.equals(proof2.commitment)).to.be.false;
48 | expect(proof1.challenge.equals(proof2.challenge)).to.be.false;
49 | expect(proof1.response.equals(proof2.response)).to.be.false;
50 |
51 | const isValid1 = await FiatShamir.verify(proof1, publicValue, params);
52 | const isValid2 = await FiatShamir.verify(proof2, publicValue, params);
53 | expect(isValid1).to.be.true;
54 | expect(isValid2).to.be.true;
55 | });
56 |
57 | it('should handle small values correctly', async () => {
58 | const smallSecret = new BigInteger('1');
59 | const smallPublicValue = params.g.modPow(smallSecret, params.n);
60 | const proof = await FiatShamir.prove(smallSecret, params);
61 | const isValid1 = await FiatShamir.verify(proof, smallPublicValue, params);
62 | expect(isValid1).to.be.true;
63 | });
64 |
65 | it('should handle maximum values correctly', async () => {
66 | const maxSecret = params.n.subtract(BigInteger.ONE);
67 | const maxPublicValue = params.g.modPow(maxSecret, params.n);
68 | const proof = await FiatShamir.prove(maxSecret, params);
69 | const isValidMax = await FiatShamir.verify(proof, maxPublicValue, params);
70 | expect(isValidMax).to.be.true;
71 | });
72 |
73 | it('should reject invalid parameter sizes', async () => {
74 | await expect(FiatShamir.generateParams(256)).to.be.rejectedWith(Error);
75 | });
76 |
77 | it('should generate unique proofs', async () => {
78 | const proof1 = await FiatShamir.prove(secret, params);
79 | const proof2 = await FiatShamir.prove(secret, params);
80 |
81 | expect(proof1).to.not.deep.equal(proof2);
82 |
83 | expect(proof1.commitment.equals(publicValue)).to.be.false;
84 | expect(proof2.commitment.equals(publicValue)).to.be.false;
85 |
86 | expect(proof1.response.equals(secret)).to.be.false;
87 | expect(proof2.response.equals(secret)).to.be.false;
88 | });
89 |
90 | it('should maintain soundness property', async () => {
91 | const proof = await FiatShamir.prove(secret, params);
92 | const isValidOriginal = await FiatShamir.verify(proof, publicValue, params);
93 | expect(isValidOriginal).to.be.true;
94 |
95 | // Try to forge a proof without knowing the secret
96 | const fakeProof = {
97 | commitment: params.g.modPow(new BigInteger('123'), params.n),
98 | challenge: proof.challenge,
99 | response: proof.response
100 | };
101 |
102 | const isValidFake = await FiatShamir.verify(fakeProof, publicValue, params);
103 | expect(isValidFake).to.be.false;
104 | });
105 | });
--------------------------------------------------------------------------------
/packages/crypto/src/core/zkp/__tests__/range.test.ts:
--------------------------------------------------------------------------------
1 | import { expect } from 'chai';
2 | import { RangeProver, RangeProof } from '../range';
3 | import { Schnorr, SchnorrParams } from '../schnorr';
4 | import { BigInteger } from 'jsbn';
5 | import { randomBytes } from 'crypto';
6 |
7 | describe('RangeProver', () => {
8 | let params: SchnorrParams;
9 | let value: BigInteger;
10 | const bits = 8;
11 |
12 | before(async () => {
13 | params = await Schnorr.generateParams(512);
14 | const valueBuffer = Buffer.from(randomBytes(Math.ceil(bits / 8)));
15 | value = new BigInteger(valueBuffer.toString('hex'), 16).mod(new BigInteger('2').pow(bits));
16 | });
17 |
18 | it('should generate valid parameters', () => {
19 | expect(params.p).to.exist;
20 | expect(params.q).to.exist;
21 | expect(params.g).to.exist;
22 | });
23 |
24 | it('should generate and verify valid proofs', async () => {
25 | const proof = await RangeProver.prove(value, bits, params);
26 | const isValid = await RangeProver.verify(proof, bits, params);
27 | expect(isValid).to.be.true;
28 | });
29 |
30 | it('should reject proofs with invalid value size', async () => {
31 | const invalidValue = new BigInteger('2').pow(bits + 1);
32 | await expect(
33 | RangeProver.prove(invalidValue, bits, params)
34 | ).to.be.rejectedWith(Error);
35 | });
36 |
37 | it('should reject invalid proofs', async () => {
38 | const invalidProof = {
39 | commitments: [params.g],
40 | challenges: [new BigInteger('1')],
41 | responses: [new BigInteger('1')],
42 | finalCommitment: params.g
43 | };
44 |
45 | const isValid = await RangeProver.verify(invalidProof, bits, params);
46 | expect(isValid).to.be.false;
47 | });
48 |
49 | it('should handle zero value correctly', async () => {
50 | const zeroValue = new BigInteger('0');
51 | const proof = await RangeProver.prove(zeroValue, bits, params);
52 | const isValidZero = await RangeProver.verify(proof, bits, params);
53 | expect(isValidZero).to.be.true;
54 | });
55 |
56 | it('should handle maximum value correctly', async () => {
57 | const maxValue = new BigInteger('2').pow(bits).subtract(BigInteger.ONE);
58 | const proof = await RangeProver.prove(maxValue, bits, params);
59 | const isValidMax = await RangeProver.verify(proof, bits, params);
60 | expect(isValidMax).to.be.true;
61 | });
62 |
63 | it('should generate different proofs for the same value', async () => {
64 | const proof1 = await RangeProver.prove(value, bits, params);
65 | const proof2 = await RangeProver.prove(value, bits, params);
66 |
67 | expect(proof1.commitments).to.not.deep.equal(proof2.commitments);
68 | expect(proof1.challenges).to.not.deep.equal(proof2.challenges);
69 | expect(proof1.responses).to.not.deep.equal(proof2.responses);
70 |
71 | const isValid1 = await RangeProver.verify(proof1, bits, params);
72 | const isValid2 = await RangeProver.verify(proof2, bits, params);
73 | expect(isValid1).to.be.true;
74 | expect(isValid2).to.be.true;
75 | });
76 |
77 | it('should maintain zero-knowledge property', async () => {
78 | const proof = await RangeProver.prove(value, bits, params);
79 |
80 | // Check that individual bit commitments don't reveal the bits
81 | for (let i = 0; i < bits; i++) {
82 | const bit = value.testBit(i);
83 | const commitment = proof.commitments[i];
84 | expect(commitment.equals(new BigInteger(bit ? '1' : '0'))).to.be.false;
85 | }
86 |
87 | // Check that final commitment doesn't reveal the value
88 | expect(proof.finalCommitment.equals(value)).to.be.false;
89 | });
90 |
91 | it('should handle different bit lengths', async () => {
92 | for (let testBits = 1; testBits <= 16; testBits++) {
93 | const testBuffer = Buffer.from(randomBytes(Math.ceil(testBits / 8)));
94 | const testValue = new BigInteger(testBuffer.toString('hex'), 16).mod(new BigInteger('2').pow(testBits));
95 | const proof = await RangeProver.prove(testValue, testBits, params);
96 | const isValid = await RangeProver.verify(proof, testBits, params);
97 | expect(isValid).to.be.true;
98 | expect(proof.commitments.length).to.equal(testBits);
99 | expect(proof.challenges.length).to.equal(testBits);
100 | expect(proof.responses.length).to.equal(testBits);
101 | }
102 | });
103 |
104 | it('should reject values outside the range', async () => {
105 | const outsideValue = new BigInteger('2').pow(bits);
106 | const proof = await RangeProver.prove(value, bits, params);
107 | const isValid = await RangeProver.verify(proof, bits, params);
108 | expect(isValid).to.be.false;
109 | });
110 |
111 | it('should reject invalid parameter sizes', async () => {
112 | await expect(
113 | RangeProver.generateParameters(256)
114 | ).to.be.rejectedWith(Error);
115 | });
116 | });
--------------------------------------------------------------------------------
/packages/crypto/src/core/zkp/__tests__/schnorr.test.ts:
--------------------------------------------------------------------------------
1 | import { expect } from 'chai';
2 | import { BigInteger } from 'jsbn';
3 | import { SchnorrProtocol, SchnorrParams } from '../schnorr';
4 |
5 | describe('Schnorr Protocol', () => {
6 | let protocol: SchnorrProtocol;
7 | let params: SchnorrParams;
8 | let secret: BigInteger;
9 |
10 | before(async () => {
11 | protocol = new SchnorrProtocol();
12 | params = await SchnorrProtocol.generateParams(512); // Use smaller parameters for testing
13 | secret = new BigInteger(32, 1, crypto.getRandomValues(new Uint8Array(32)));
14 | });
15 |
16 | it('should generate valid parameters', () => {
17 | expect(params.p).to.exist;
18 | expect(params.q).to.exist;
19 | expect(params.g).to.exist;
20 | expect(params.p.bitLength()).to.be.at.least(512);
21 | expect(params.g.compareTo(BigInteger.ONE)).to.be.above(0);
22 | expect(params.g.compareTo(params.p)).to.be.below(0);
23 | });
24 |
25 | it('should generate and verify valid proofs', async () => {
26 | // Generate proof
27 | const proof = await protocol.prove(secret, params);
28 | expect(proof.commitment).to.exist;
29 | expect(proof.challenge).to.exist;
30 | expect(proof.response).to.exist;
31 |
32 | // Compute public value
33 | const publicValue = params.g.modPow(secret, params.p);
34 |
35 | // Verify proof
36 | const isValid = await protocol.verify(proof, publicValue, params);
37 | expect(isValid).to.be.true;
38 | });
39 |
40 | it('should reject invalid proofs', async () => {
41 | // Generate valid proof
42 | const proof = await protocol.prove(secret, params);
43 | const publicValue = params.g.modPow(secret, params.p);
44 |
45 | // Modify proof to make it invalid
46 | const invalidProof = {
47 | ...proof,
48 | response: proof.response.add(BigInteger.ONE)
49 | };
50 |
51 | // Verify invalid proof
52 | const isValid = await protocol.verify(invalidProof, publicValue, params);
53 | expect(isValid).to.be.false;
54 | });
55 |
56 | it('should generate different proofs for same secret', async () => {
57 | // Generate two proofs for same secret
58 | const proof1 = await protocol.prove(secret, params);
59 | const proof2 = await protocol.prove(secret, params);
60 |
61 | // Verify proofs are different but both valid
62 | expect(proof1.commitment.equals(proof2.commitment)).to.be.false;
63 | expect(proof1.challenge.equals(proof2.challenge)).to.be.false;
64 | expect(proof1.response.equals(proof2.response)).to.be.false;
65 |
66 | const publicValue = params.g.modPow(secret, params.p);
67 | const isValid1 = await protocol.verify(proof1, publicValue, params);
68 | const isValid2 = await protocol.verify(proof2, publicValue, params);
69 | expect(isValid1).to.be.true;
70 | expect(isValid2).to.be.true;
71 | });
72 |
73 | it('should reject proofs with invalid parameters', async () => {
74 | // Try to prove with invalid parameters
75 | const invalidParams = {
76 | ...params,
77 | p: params.p.add(BigInteger.ONE) // Make p not prime
78 | };
79 |
80 | await expect(protocol.prove(secret, invalidParams)).to.be.rejectedWith(
81 | 'Parameter p must be prime'
82 | );
83 | });
84 |
85 | it('should maintain zero-knowledge property', async () => {
86 | // Generate proof
87 | const proof = await protocol.prove(secret, params);
88 | const publicValue = params.g.modPow(secret, params.p);
89 |
90 | // Verify proof components don't reveal secret
91 | expect(proof.commitment.modPow(secret, params.p).equals(publicValue)).to.be.false;
92 | expect(proof.challenge.multiply(secret).equals(secret)).to.be.false;
93 | expect(proof.response.equals(secret)).to.be.false;
94 |
95 | // Verify proof is still valid
96 | const isValid = await protocol.verify(proof, publicValue, params);
97 | expect(isValid).to.be.true;
98 | });
99 | });
--------------------------------------------------------------------------------
/packages/crypto/src/core/zkp/index.ts:
--------------------------------------------------------------------------------
1 | export * from './schnorr';
2 | export * from './range';
--------------------------------------------------------------------------------
/packages/crypto/src/core/zkp/range.ts:
--------------------------------------------------------------------------------
1 | import { randomBytes } from 'crypto';
2 | import { BigInteger } from 'jsbn';
3 | import { Hash } from '../hash';
4 | import { Schnorr, SchnorrParams } from './schnorr';
5 |
6 | export interface RangeProof {
7 | commitments: BigInteger[]; // Pedersen commitments for each bit
8 | challenges: BigInteger[]; // Challenges for each bit
9 | responses: BigInteger[]; // Responses for each bit
10 | finalCommitment: BigInteger; // Commitment to the actual value
11 | }
12 |
13 | export class RangeProver {
14 | private static ONE = new BigInteger('1');
15 | private static TWO = new BigInteger('2');
16 | private static ZERO = new BigInteger('0');
17 |
18 | /**
19 | * Generate a proof that a value lies in the range [0, 2^n - 1]
20 | * @param {BigInteger} value - The value to prove
21 | * @param {number} bitLength - The number of bits in the range
22 | * @param {SchnorrParams} params - Group parameters
23 | * @returns {Promise} Generated range proof
24 | */
25 | static async prove(value: BigInteger, bitLength: number, params: SchnorrParams): Promise {
26 | // Ensure value is non-negative and within range
27 | if (value.compareTo(this.ZERO) < 0 || value.compareTo(this.TWO.pow(bitLength)) >= 0) {
28 | throw new Error('Value out of range');
29 | }
30 |
31 | const bits = value.toString(2).padStart(bitLength, '0').split('').map(Number);
32 | const commitments: BigInteger[] = [];
33 | const challenges: BigInteger[] = [];
34 | const responses: BigInteger[] = [];
35 | const randoms: BigInteger[] = [];
36 |
37 | // Generate second base point h
38 | const h = await this.generateH(params);
39 |
40 | // Generate commitments for each bit
41 | for (let i = 0; i < bitLength; i++) {
42 | const bit = bits[i];
43 | const r = this.generateRandom(params.q);
44 | randoms.push(r);
45 |
46 | // C = g^b * h^r mod p
47 | const commitment = params.g.modPow(new BigInteger(bit.toString()), params.p)
48 | .multiply(h.modPow(r, params.p))
49 | .mod(params.p);
50 | commitments.push(commitment);
51 |
52 | // Generate challenge
53 | const challenge = await Hash.sha256(
54 | Buffer.from(commitment.toString() + i.toString())
55 | );
56 | challenges.push(new BigInteger(challenge.toString('hex'), 16).mod(params.q));
57 | }
58 |
59 | // Generate responses
60 | for (let i = 0; i < bitLength; i++) {
61 | const bit = bits[i];
62 | // s = r + c * b mod q
63 | const response = randoms[i].add(
64 | challenges[i].multiply(new BigInteger(bit.toString()))
65 | ).mod(params.q);
66 | responses.push(response);
67 | }
68 |
69 | // Calculate final commitment as product of bit commitments
70 | let finalCommitment = this.ONE;
71 | for (let i = 0; i < bitLength; i++) {
72 | const power = this.TWO.pow(i);
73 | finalCommitment = finalCommitment.multiply(
74 | commitments[i].modPow(power, params.p)
75 | ).mod(params.p);
76 | }
77 |
78 | return {
79 | commitments,
80 | challenges,
81 | responses,
82 | finalCommitment
83 | };
84 | }
85 |
86 | /**
87 | * Verify a range proof
88 | * @param {RangeProof} proof - The proof to verify
89 | * @param {number} bitLength - The number of bits in the range
90 | * @param {SchnorrParams} params - Group parameters
91 | * @returns {Promise} Whether the proof is valid
92 | */
93 | static async verify(proof: RangeProof, bitLength: number, params: SchnorrParams): Promise {
94 | const h = await this.generateH(params);
95 |
96 | // Verify each bit commitment
97 | for (let i = 0; i < bitLength; i++) {
98 | // Calculate g^s * h^c
99 | const lhs = params.g.modPow(proof.responses[i], params.p)
100 | .multiply(h.modPow(proof.challenges[i], params.p))
101 | .mod(params.p);
102 |
103 | // Compare with C
104 | const rhs = proof.commitments[i];
105 |
106 | if (!lhs.equals(rhs)) {
107 | return false;
108 | }
109 | }
110 |
111 | // Verify final commitment
112 | let product = this.ONE;
113 | for (let i = 0; i < bitLength; i++) {
114 | const power = this.TWO.pow(i);
115 | product = product.multiply(
116 | proof.commitments[i].modPow(power, params.p)
117 | ).mod(params.p);
118 | }
119 |
120 | return proof.finalCommitment.equals(product);
121 | }
122 |
123 | private static generateRandom(max: BigInteger): BigInteger {
124 | const bytes = Math.ceil(max.bitLength() / 8);
125 | let r: BigInteger;
126 | do {
127 | const hex = randomBytes(bytes).toString('hex');
128 | r = new BigInteger(hex, 16).mod(max);
129 | } while (r.compareTo(this.ZERO) <= 0);
130 | return r;
131 | }
132 |
133 | private static async generateH(params: SchnorrParams): Promise {
134 | const hash = await Hash.sha256(
135 | Buffer.from(params.g.toString() + params.p.toString())
136 | );
137 | return new BigInteger(hash.toString('hex'), 16).mod(params.p);
138 | }
139 | }
--------------------------------------------------------------------------------
/packages/crypto/src/index.ts:
--------------------------------------------------------------------------------
1 | export { Encryption } from './core/encryption';
2 | export * from './types';
3 | export * from './core/encryption';
4 | export * from './core/homomorphic';
5 | export * from './core/zkp';
6 | export * from './utils/hash';
7 | export * from './core/symmetric';
8 | export * from './core/asymmetric';
9 | export * from './core/hash';
10 |
11 | // Version and package info
12 | export const VERSION = '0.1.0';
13 | export const PACKAGE_NAME = '@cipher-nexus/crypto';
14 |
--------------------------------------------------------------------------------
/packages/crypto/src/types.ts:
--------------------------------------------------------------------------------
1 | export interface EncryptionConfig {
2 | algorithm: 'RSA' | 'AES' | 'FHE';
3 | keySize: number;
4 | mode?: string;
5 | }
6 |
7 | export interface EncryptionKey {
8 | publicKey: string;
9 | privateKey: string;
10 | }
11 |
12 | export interface EncryptedData {
13 | data: string;
14 | iv?: string;
15 | tag?: string;
16 | }
--------------------------------------------------------------------------------
/packages/crypto/src/types/index.ts:
--------------------------------------------------------------------------------
1 | export interface EncryptionKey {
2 | publicKey: string;
3 | privateKey: string;
4 | }
5 |
6 | export interface EncryptionConfig {
7 | algorithm: 'AES' | 'RSA' | 'FHE';
8 | keySize: number;
9 | mode?: string;
10 | }
11 |
12 | export interface EncryptedData {
13 | data: string;
14 | iv?: string;
15 | tag?: string;
16 | }
17 |
--------------------------------------------------------------------------------
/packages/crypto/src/utils/hash.ts:
--------------------------------------------------------------------------------
1 | import crypto from 'crypto';
2 |
3 | export const hashData = (data: string): string => {
4 | return crypto.createHash('sha256').update(data).digest('hex');
5 | };
6 |
7 | export const generateSalt = (length: number = 16): string => {
8 | return crypto.randomBytes(length).toString('hex');
9 | };
10 |
11 | export const hashWithSalt = (data: string, salt: string): string => {
12 | return crypto.createHmac('sha256', salt).update(data).digest('hex');
13 | };
14 |
--------------------------------------------------------------------------------
/packages/crypto/test/encryption.test.ts:
--------------------------------------------------------------------------------
1 | import { expect, use } from 'chai';
2 | import chaiAsPromised from 'chai-as-promised';
3 | import { Encryption } from '../src/core/encryption';
4 | import { EncryptionConfig } from '../src/types';
5 |
6 | use(chaiAsPromised);
7 |
8 | describe('Encryption', () => {
9 | describe('RSA Encryption', () => {
10 | const config: EncryptionConfig = {
11 | algorithm: 'RSA',
12 | keySize: 2048
13 | };
14 | let encryption: Encryption;
15 |
16 | beforeEach(() => {
17 | encryption = new Encryption(config);
18 | });
19 |
20 | it('should generate RSA key pair', async () => {
21 | const keys = await encryption.generateKeys();
22 | expect(keys.publicKey).to.be.a('string');
23 | expect(keys.privateKey).to.be.a('string');
24 | expect(keys.publicKey).to.include('BEGIN PUBLIC KEY');
25 | expect(keys.privateKey).to.include('BEGIN PRIVATE KEY');
26 | });
27 |
28 | it('should encrypt and decrypt data correctly', async () => {
29 | const testData = { message: 'test message' };
30 | const keys = await encryption.generateKeys();
31 |
32 | const encrypted = await encryption.encrypt(testData, keys.publicKey);
33 | expect(encrypted.data).to.be.a('string');
34 |
35 | const decrypted = await encryption.decrypt(encrypted, keys.privateKey);
36 | expect(decrypted).to.deep.equal(testData);
37 | });
38 | });
39 |
40 | describe('AES Encryption', () => {
41 | const config: EncryptionConfig = {
42 | algorithm: 'AES',
43 | keySize: 256,
44 | mode: 'gcm'
45 | };
46 | let encryption: Encryption;
47 |
48 | beforeEach(() => {
49 | encryption = new Encryption(config);
50 | });
51 |
52 | it('should generate AES key', async () => {
53 | const keys = await encryption.generateKeys();
54 | expect(keys.publicKey).to.be.a('string');
55 | expect(keys.privateKey).to.be.a('string');
56 | expect(keys.publicKey).to.have.lengthOf(64); // 256 bits = 64 hex chars
57 | });
58 |
59 | it('should encrypt and decrypt data correctly', async () => {
60 | const testData = { message: 'test message' };
61 | const keys = await encryption.generateKeys();
62 |
63 | const encrypted = await encryption.encrypt(testData, keys.publicKey);
64 | expect(encrypted.data).to.be.a('string');
65 | expect(encrypted.iv).to.be.a('string');
66 | expect(encrypted.tag).to.be.a('string');
67 |
68 | const decrypted = await encryption.decrypt(encrypted, keys.privateKey);
69 | expect(decrypted).to.deep.equal(testData);
70 | });
71 |
72 | it('should throw error for invalid data', async () => {
73 | const keys = await encryption.generateKeys();
74 | const invalidData = { data: 'invalid', iv: 'invalid', tag: 'invalid' };
75 |
76 | await expect(encryption.decrypt(invalidData, keys.privateKey))
77 | .to.be.rejectedWith(Error);
78 | });
79 | });
80 | });
--------------------------------------------------------------------------------
/packages/crypto/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "./dist",
5 | "rootDir": "./src",
6 | "composite": true,
7 | // "noEmit": true,
8 |
9 | },
10 | "include": ["src"],
11 | "exclude": ["node_modules", "dist", "test"]
12 | }
--------------------------------------------------------------------------------
/packages/protocol/docs/api.md:
--------------------------------------------------------------------------------
1 | # API 文档
2 |
3 | ## 类
4 |
5 | ### MPCProtocol
6 |
7 | 安全多方计算协议的主要实现类。
8 |
9 | #### 构造函数
10 |
11 | ```typescript
12 | constructor()
13 | ```
14 |
15 | 创建新的MPCProtocol实例。
16 |
17 | #### 方法
18 |
19 | ##### 初始化和会话管理
20 |
21 | ```typescript
22 | async initialize(): Promise
23 | ```
24 | 初始化协议,必须在使用其他方法前调用。
25 |
26 | ```typescript
27 | async start(): Promise
28 | ```
29 | 启动协议,开始处理消息。
30 |
31 | ```typescript
32 | async stop(): Promise
33 | ```
34 | 停止协议,清理资源。
35 |
36 | ```typescript
37 | async createSession(participants: Participant[]): Promise
38 | ```
39 | 创建新的计算会话。
40 | - `participants`: 参与计算的成员列表
41 | - 返回: 创建的会话对象
42 |
43 | ```typescript
44 | async joinSession(sessionId: string): Promise
45 | ```
46 | 加入已存在的会话。
47 | - `sessionId`: 要加入的会话ID
48 |
49 | ```typescript
50 | async leaveSession(sessionId: string): Promise
51 | ```
52 | 离开当前会话。
53 | - `sessionId`: 要离开的会话ID
54 |
55 | ##### 计算操作
56 |
57 | ```typescript
58 | setLocalValue(value: Buffer): void
59 | ```
60 | 设置本地计算值。
61 | - `value`: 要参与计算的本地值
62 |
63 | ```typescript
64 | async startComputation(type: MPCComputationType): Promise
65 | ```
66 | 开始指定类型的计算。
67 | - `type`: 计算类型
68 |
69 | ```typescript
70 | isComplete(): boolean
71 | ```
72 | 检查计算是否完成。
73 | - 返回: 如果计算完成则为true
74 |
75 | ```typescript
76 | getResult(): Buffer | undefined
77 | ```
78 | 获取计算结果。
79 | - 返回: 计算结果,如果未完成则为undefined
80 |
81 | ##### 消息处理
82 |
83 | ```typescript
84 | onMessage(handler: (message: Message) => Promise): void
85 | ```
86 | 注册消息处理器。
87 | - `handler`: 处理接收到消息的回调函数
88 |
89 | ```typescript
90 | setBatchParameters(batchSize: number, batchTimeout: number): void
91 | ```
92 | 设置消息批处理参数。
93 | - `batchSize`: 每批处理的消息数量
94 | - `batchTimeout`: 批处理超时时间(毫秒)
95 |
96 | ### Message
97 |
98 | 表示协议中传输的消息。
99 |
100 | ```typescript
101 | interface Message {
102 | type: string; // 消息类型
103 | sender: string; // 发送者ID
104 | receiver: string; // 接收者ID
105 | content: Buffer; // 消息内容
106 | timestamp: Date; // 时间戳
107 | }
108 | ```
109 |
110 | ### Session
111 |
112 | 表示一个计算会话。
113 |
114 | ```typescript
115 | interface Session {
116 | id: string; // 会话ID
117 | participants: Participant[]; // 参与者列表
118 | state: any; // 会话状态
119 | startTime: Date; // 开始时间
120 | endTime?: Date; // 结束时间
121 | }
122 | ```
123 |
124 | ### Participant
125 |
126 | 表示参与计算的成员。
127 |
128 | ```typescript
129 | interface Participant {
130 | id: string; // 参与者ID
131 | publicKey: Buffer; // 公钥
132 | }
133 | ```
134 |
135 | ## 枚举
136 |
137 | ### MPCComputationType
138 |
139 | 支持的计算类型。
140 |
141 | ```typescript
142 | enum MPCComputationType {
143 | SUM = 'SUM', // 计算和
144 | AVERAGE = 'AVERAGE', // 计算平均值
145 | MAX = 'MAX', // 计算最大值
146 | MIN = 'MIN', // 计算最小值
147 | MEDIAN = 'MEDIAN', // 计算中位数
148 | VARIANCE = 'VARIANCE', // 计算方差
149 | MODE = 'MODE', // 计算众数
150 | STD_DEV = 'STD_DEV', // 计算标准差
151 | QUARTILE = 'QUARTILE',// 计算四分位数
152 | RANGE = 'RANGE' // 计算范围
153 | }
154 | ```
155 |
156 | ### MPCMessageType
157 |
158 | 协议中使用的消息类型。
159 |
160 | ```typescript
161 | enum MPCMessageType {
162 | SET_VALUE = 'SET_VALUE', // 设置值
163 | SHARE = 'SHARE', // 共享值
164 | RESULT = 'RESULT', // 结果
165 | RECOVERY = 'RECOVERY', // 恢复
166 | VERIFY = 'VERIFY', // 验证
167 | COMMITMENT = 'COMMITMENT' // 承诺
168 | }
169 | ```
170 |
171 | ## 错误处理
172 |
173 | ### ProtocolError
174 |
175 | 协议错误类型。
176 |
177 | ```typescript
178 | enum ProtocolErrorType {
179 | INVALID_STATE = 'INVALID_STATE', // 无效状态
180 | INVALID_MESSAGE = 'INVALID_MESSAGE', // 无效消息
181 | TIMEOUT = 'TIMEOUT', // 超时
182 | VERIFICATION_FAILED = 'VERIFICATION_FAILED' // 验证失败
183 | }
184 | ```
185 |
186 | ## 安全特性
187 |
188 | ### 值盲化
189 |
190 | ```typescript
191 | private blindValue(value: Buffer): Buffer
192 | ```
193 | 对值进行盲化处理。
194 | - `value`: 要盲化的值
195 | - 返回: 盲化后的值
196 |
197 | ### 审计日志
198 |
199 | ```typescript
200 | interface AuditLog {
201 | timestamp: Date; // 时间戳
202 | event: string; // 事件类型
203 | participantId: string;// 参与者ID
204 | sessionId: string; // 会话ID
205 | details: any; // 详细信息
206 | }
207 | ```
208 |
209 | ## 批处理
210 |
211 | ### MessageBatch
212 |
213 | 表示一批要处理的消息。
214 |
215 | ```typescript
216 | interface MessageBatch {
217 | messages: Message[]; // 消息列表
218 | timestamp: Date; // 时间戳
219 | }
220 | ```
221 |
222 | ## 使用建议
223 |
224 | 1. 初始化顺序:
225 | ```typescript
226 | const protocol = new MPCProtocol();
227 | await protocol.initialize();
228 | await protocol.start();
229 | ```
230 |
231 | 2. 错误处理:
232 | ```typescript
233 | try {
234 | await protocol.startComputation(MPCComputationType.SUM);
235 | } catch (error) {
236 | if (error.type === ProtocolErrorType.TIMEOUT) {
237 | // 处理超时
238 | }
239 | }
240 | ```
241 |
242 | 3. 性能优化:
243 | ```typescript
244 | // 根据网络条件调整批处理参数
245 | protocol.setBatchParameters(100, 50);
246 | ```
247 |
248 | 4. 安全性:
249 | - 使用足够长的密钥
250 | - 定期更换会话
251 | - 启用审计日志
252 | - 验证所有输入
--------------------------------------------------------------------------------
/packages/protocol/docs/deployment.md:
--------------------------------------------------------------------------------
1 | # 部署指南
2 |
3 | ## 系统要求
4 |
5 | ### 硬件要求
6 | - CPU: 2核或以上
7 | - 内存: 4GB或以上
8 | - 磁盘空间: 1GB或以上
9 |
10 | ### 软件要求
11 | - Node.js 16.x或更高版本
12 | - npm 7.x或更高版本
13 | - TypeScript 4.x或更高版本
14 |
15 | ## 安装
16 |
17 | ### 使用npm安装
18 | ```bash
19 | npm install @ciphernx/protocol
20 | ```
21 |
22 | ### 使用yarn安装
23 | ```bash
24 | yarn add @ciphernx/protocol
25 | ```
26 |
27 | ## 环境配置
28 |
29 | ### 开发环境
30 | ```bash
31 | # 安装依赖
32 | npm install
33 |
34 | # 编译TypeScript
35 | npm run build
36 |
37 | # 运行测试
38 | npm test
39 | ```
40 |
41 | ### 生产环境
42 | ```bash
43 | # 安装生产依赖
44 | npm install --production
45 |
46 | # 编译并压缩
47 | npm run build:prod
48 | ```
49 |
50 | ## 配置选项
51 |
52 | ### 环境变量
53 | ```bash
54 | # 日志级别
55 | LOG_LEVEL=info
56 |
57 | # 批处理大小
58 | BATCH_SIZE=100
59 |
60 | # 批处理超时(毫秒)
61 | BATCH_TIMEOUT=50
62 |
63 | # 会话超时(秒)
64 | SESSION_TIMEOUT=3600
65 | ```
66 |
67 | ### 配置文件示例
68 | ```json
69 | {
70 | "protocol": {
71 | "logLevel": "info",
72 | "batchSize": 100,
73 | "batchTimeout": 50,
74 | "sessionTimeout": 3600,
75 | "security": {
76 | "keyLength": 2048,
77 | "hashAlgorithm": "sha256",
78 | "enableAuditLog": true
79 | },
80 | "recovery": {
81 | "enabled": true,
82 | "backupCount": 3
83 | }
84 | }
85 | }
86 | ```
87 |
88 | ## 安全配置
89 |
90 | ### 密钥管理
91 | - 使用安全的密钥生成方法
92 | - 定期轮换密钥
93 | - 安全存储密钥
94 | - 使用密钥管理服务(推荐)
95 |
96 | ### 网络安全
97 | - 启用TLS/SSL
98 | - 配置防火墙规则
99 | - 限制访问IP
100 | - 使用安全的通信协议
101 |
102 | ### 审计日志
103 | - 配置日志存储位置
104 | - 设置日志轮转策略
105 | - 实现日志监控
106 | - 定期备份日志
107 |
108 | ## 性能优化
109 |
110 | ### 批处理配置
111 | ```typescript
112 | // 根据系统负载调整批处理参数
113 | protocol.setBatchParameters({
114 | batchSize: 100, // 每批消息数
115 | batchTimeout: 50, // 批处理超时时间
116 | maxBatchSize: 1000, // 最大批大小
117 | minBatchSize: 10 // 最小批大小
118 | });
119 | ```
120 |
121 | ### 内存管理
122 | - 定期清理过期会话
123 | - 监控内存使用
124 | - 实现资源限制
125 | - 优化大型计算
126 |
127 | ### 并发处理
128 | - 合理设置并发数
129 | - 使用连接池
130 | - 实现负载均衡
131 | - 错误重试机制
132 |
133 | ## 监控和维护
134 |
135 | ### 健康检查
136 | ```typescript
137 | // 实现健康检查接口
138 | app.get('/health', (req, res) => {
139 | const status = protocol.getStatus();
140 | res.json({
141 | status: status.isRunning ? 'UP' : 'DOWN',
142 | details: {
143 | activeSessions: status.sessionCount,
144 | pendingComputations: status.computationCount,
145 | memoryUsage: process.memoryUsage()
146 | }
147 | });
148 | });
149 | ```
150 |
151 | ### 指标收集
152 | - CPU使用率
153 | - 内存使用
154 | - 活动会话数
155 | - 消息处理延迟
156 | - 计算完成时间
157 |
158 | ### 告警配置
159 | - 设置资源使用阈值
160 | - 配置错误率告警
161 | - 监控响应时间
162 | - 异常行为检测
163 |
164 | ## 灾难恢复
165 |
166 | ### 备份策略
167 | - 定期备份配置
168 | - 备份会话状态
169 | - 存储审计日志
170 | - 实现快速恢复
171 |
172 | ### 故障转移
173 | - 配置备用节点
174 | - 实现自动切换
175 | - 数据同步机制
176 | - 恢复验证
177 |
178 | ## 扩展性
179 |
180 | ### 水平扩展
181 | - 添加新节点
182 | - 配置负载均衡
183 | - 会话同步
184 | - 状态一致性
185 |
186 | ### 垂直扩展
187 | - 增加系统资源
188 | - 优化性能配置
189 | - 调整内存分配
190 | - 提升处理能力
191 |
192 | ## 生产环境检查清单
193 |
194 | ### 部署前
195 | - [ ] 完成所有测试
196 | - [ ] 检查配置文件
197 | - [ ] 验证环境变量
198 | - [ ] 确认依赖版本
199 | - [ ] 检查安全设置
200 | - [ ] 准备回滚方案
201 |
202 | ### 部署后
203 | - [ ] 验证服务状态
204 | - [ ] 检查日志输出
205 | - [ ] 测试核心功能
206 | - [ ] 监控系统指标
207 | - [ ] 确认告警配置
208 | - [ ] 验证备份恢复
209 |
210 | ## 常见问题
211 |
212 | ### 性能问题
213 | 1. 消息处理延迟
214 | - 检查网络连接
215 | - 优化批处理参数
216 | - 增加系统资源
217 |
218 | 2. 内存泄漏
219 | - 及时清理会话
220 | - 优化资源使用
221 | - 监控内存占用
222 |
223 | ### 安全问题
224 | 1. 密钥泄露
225 | - 立即轮换密钥
226 | - 审计访问日志
227 | - 更新安全策略
228 |
229 | 2. 未授权访问
230 | - 检查访问控制
231 | - 更新防火墙规则
232 | - 加强认证机制
233 |
234 | ## 维护指南
235 |
236 | ### 日常维护
237 | - 监控系统状态
238 | - 检查错误日志
239 | - 清理过期数据
240 | - 更新安全补丁
241 |
242 | ### 版本升级
243 | - 备份当前版本
244 | - 测试新版本
245 | - 规划升级时间
246 | - 准备回滚方案
247 |
248 | ### 故障处理
249 | - 记录问题现象
250 | - 分析错误日志
251 | - 实施修复方案
252 | - 验证系统恢复
253 |
254 | ## 支持资源
255 |
256 | ### 文档
257 | - [API文档](./api.md)
258 | - [使用示例](./examples.md)
259 | - [更新日志](./CHANGELOG.md)
260 |
261 | ### 社区
262 | - GitHub Issues
263 | - Stack Overflow
264 | - 技术支持邮箱
265 |
266 | ### 工具
267 | - 监控面板
268 | - 日志分析
269 | - 性能测试
270 | - 安全扫描
--------------------------------------------------------------------------------
/packages/protocol/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@cipher-nexus/protocol",
3 | "version": "1.0.0",
4 | "description": "Privacy-preserving protocols for CipherNexus",
5 | "main": "dist/index.js",
6 | "types": "dist/index.d.ts",
7 | "scripts": {
8 | "build": "tsc",
9 | "test": "mocha -r ts-node/register 'test/**/*.test.ts'",
10 | "clean": "rimraf dist",
11 | "lint": "eslint src --ext .ts"
12 | },
13 | "dependencies": {
14 | "@cipher-nexus/crypto": "^1.0.0"
15 | },
16 | "devDependencies": {
17 | "@types/chai": "^4.3.0",
18 | "@types/mocha": "^9.1.0",
19 | "@types/node": "^17.0.21",
20 | "chai": "^4.3.6",
21 | "mocha": "^9.2.2",
22 | "ts-node": "^10.7.0",
23 | "typescript": "^4.6.2",
24 | "rimraf": "^5.0.1",
25 | "eslint": "^8.38.0",
26 | "@typescript-eslint/parser": "^5.59.0",
27 | "@typescript-eslint/eslint-plugin": "^5.59.0"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/packages/protocol/src/core/privacy.ts:
--------------------------------------------------------------------------------
1 | import { PrivacyConfig } from '../types';
2 | import { Encryption } from '@cipher-nexus/crypto';
3 |
4 | export class PrivacyProtocol {
5 | private encryption: Encryption;
6 |
7 | constructor(private config: PrivacyConfig) {
8 | this.encryption = new Encryption(this.getEncryptionConfig());
9 | }
10 |
11 | async encrypt(data: any): Promise {
12 | try {
13 | // Generate encryption keys
14 | const keys = await this.encryption.generateKeys();
15 |
16 | // Encrypt data
17 | const encryptedData = await this.encryption.encrypt(data, keys.publicKey);
18 |
19 | return encryptedData;
20 | } catch (error: any) {
21 | throw new Error(`Encryption failed: ${error.message}`);
22 | }
23 | }
24 |
25 | async decrypt(encryptedData: any): Promise {
26 | try {
27 | // Generate or retrieve decryption key
28 | const keys = await this.encryption.generateKeys();
29 |
30 | // Decrypt data
31 | return await this.encryption.decrypt(encryptedData, keys.privateKey);
32 | } catch (error: any) {
33 | throw new Error(`Decryption failed: ${error.message}`);
34 | }
35 | }
36 |
37 | private getEncryptionConfig() {
38 | switch (this.config.encryptionLevel) {
39 | case 'high':
40 | return {
41 | algorithm: 'FHE',
42 | keySize: 3072
43 | };
44 | case 'medium':
45 | return {
46 | algorithm: 'RSA',
47 | keySize: 2048
48 | };
49 | case 'basic':
50 | default:
51 | return {
52 | algorithm: 'AES',
53 | keySize: 256,
54 | mode: 'gcm'
55 | };
56 | }
57 | }
58 |
59 | private async applyHomomorphicEncryption(data: any): Promise {
60 | // TODO: Implement homomorphic encryption transformation
61 | if (this.config.useHomomorphicEncryption) {
62 | throw new Error('Homomorphic encryption not implemented yet');
63 | }
64 | return data;
65 | }
66 |
67 | private async reverseHomomorphicEncryption(data: any): Promise {
68 | // TODO: Implement homomorphic encryption reverse transformation
69 | if (this.config.useHomomorphicEncryption) {
70 | throw new Error('Homomorphic encryption reverse transformation not implemented yet');
71 | }
72 | return data;
73 | }
74 |
75 | private async generateZKProof(data: any): Promise {
76 | // TODO: Implement zero-knowledge proof generation
77 | if (this.config.useZeroKnowledgeProof) {
78 | throw new Error('Zero-knowledge proof generation not implemented yet');
79 | }
80 | return data;
81 | }
82 |
83 | private async verifyZKProof(data: any): Promise {
84 | // TODO: Implement zero-knowledge proof verification
85 | if (this.config.useZeroKnowledgeProof) {
86 | throw new Error('Zero-knowledge proof verification not implemented yet');
87 | }
88 | return true;
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/packages/protocol/src/core/training.ts:
--------------------------------------------------------------------------------
1 | import { TrainingConfig } from '../types';
2 | import { PrivacyProtocol } from './privacy';
3 |
4 | export class TrainingProtocol {
5 | private privacyProtocol: PrivacyProtocol;
6 |
7 | constructor(private config: TrainingConfig) {
8 | this.privacyProtocol = new PrivacyProtocol(config.privacyConfig);
9 | }
10 |
11 | async initializeTraining(): Promise {
12 | // TODO: Initialize training environment
13 | }
14 |
15 | async processDataBatch(data: any[]): Promise {
16 | const encryptedData = await this.privacyProtocol.encrypt(data);
17 | // TODO: Process encrypted data
18 | return encryptedData;
19 | }
20 |
21 | async validateResults(results: any): Promise {
22 | // TODO: Implement validation logic
23 | return true;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/packages/protocol/src/core/types.ts:
--------------------------------------------------------------------------------
1 | import { Buffer } from 'buffer';
2 |
3 | /**
4 | * Base interface for all protocol participants
5 | */
6 | export interface Participant {
7 | id: string;
8 | publicKey: Buffer;
9 | }
10 |
11 | /**
12 | * Protocol session interface
13 | */
14 | export interface Session {
15 | id: string;
16 | participants: string[];
17 | localParticipantId: string;
18 | startTime: Date;
19 | endTime?: Date;
20 | }
21 |
22 | /**
23 | * Protocol message interface
24 | */
25 | export interface Message {
26 | session: Session;
27 | type: string;
28 | data?: any;
29 | senderId: string;
30 | receiverId: string;
31 | timestamp: Date;
32 | }
33 |
34 | /**
35 | * Protocol error types
36 | */
37 | export enum ProtocolErrorType {
38 | INVALID_STATE = 'INVALID_STATE',
39 | INVALID_MESSAGE = 'INVALID_MESSAGE',
40 | INVALID_PARTICIPANT = 'INVALID_PARTICIPANT',
41 | INTERNAL_ERROR = 'INTERNAL_ERROR',
42 | NETWORK_ERROR = 'NETWORK_ERROR',
43 | TIMEOUT = 'TIMEOUT'
44 | }
45 |
46 | /**
47 | * Protocol error interface
48 | */
49 | export interface ProtocolError extends Error {
50 | type: ProtocolErrorType;
51 | details?: any;
52 | }
53 |
54 | /**
55 | * Protocol options interface
56 | */
57 | export interface ProtocolOptions {
58 | timeout?: number;
59 | retryCount?: number;
60 | verifySignatures?: boolean;
61 | logLevel?: 'debug' | 'info' | 'warn' | 'error';
62 | }
63 |
64 | /**
65 | * Base protocol interface
66 | */
67 | export interface Protocol {
68 | // Protocol lifecycle
69 | initialize(options?: ProtocolOptions): Promise;
70 | start(): Promise;
71 | stop(): Promise;
72 |
73 | // Session management
74 | createSession(participants: Participant[]): Promise;
75 | joinSession(sessionId: string): Promise;
76 | leaveSession(sessionId: string): Promise;
77 |
78 | // Message handling
79 | sendMessage(message: Message): Promise;
80 | onMessage(handler: (message: Message) => Promise): void;
81 |
82 | // Error handling
83 | onError(handler: (error: ProtocolError) => void): void;
84 | }
85 |
86 | /**
87 | * Protocol state interface
88 | */
89 | export interface ProtocolState {
90 | isInitialized: boolean;
91 | isRunning: boolean;
92 | currentSession?: Session;
93 | activeSessions: Map;
94 | messageHandlers: Set<(message: Message) => Promise>;
95 | errorHandlers: Set<(error: ProtocolError) => void>;
96 | }
--------------------------------------------------------------------------------
/packages/protocol/src/index.ts:
--------------------------------------------------------------------------------
1 | // Core protocols
2 | export * from './core/types';
3 | export * from './core/base';
4 | export * from './core/key-exchange';
5 |
6 | // Protocol utilities
7 | export * from './utils/logger';
8 | export * from './utils/validator';
9 |
10 | export { PrivacyProtocol } from './core/privacy';
11 | export * from './types';
12 |
--------------------------------------------------------------------------------
/packages/protocol/src/types.ts:
--------------------------------------------------------------------------------
1 | export interface PrivacyConfig {
2 | encryptionLevel: 'basic' | 'medium' | 'high';
3 | useHomomorphicEncryption: boolean;
4 | useZeroKnowledgeProof: boolean;
5 | }
--------------------------------------------------------------------------------
/packages/protocol/src/types/index.ts:
--------------------------------------------------------------------------------
1 | export interface PrivacyConfig {
2 | encryptionLevel: 'basic' | 'medium' | 'high';
3 | useHomomorphicEncryption: boolean;
4 | useZeroKnowledgeProof: boolean;
5 | }
6 |
7 | export interface TrainingConfig {
8 | batchSize: number;
9 | epochs: number;
10 | learningRate: number;
11 | privacyConfig: PrivacyConfig;
12 | }
13 |
--------------------------------------------------------------------------------
/packages/protocol/src/utils/logger.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Log levels
3 | */
4 | export enum LogLevel {
5 | DEBUG = 'debug',
6 | INFO = 'info',
7 | WARN = 'warn',
8 | ERROR = 'error'
9 | }
10 |
11 | /**
12 | * Logger interface
13 | */
14 | export interface Logger {
15 | debug(message: string, ...args: any[]): void;
16 | info(message: string, ...args: any[]): void;
17 | warn(message: string, ...args: any[]): void;
18 | error(message: string, ...args: any[]): void;
19 | }
20 |
21 | /**
22 | * Protocol logger implementation
23 | */
24 | export class ProtocolLogger implements Logger {
25 | private level: LogLevel;
26 |
27 | constructor(level: LogLevel = LogLevel.INFO) {
28 | this.level = level;
29 | }
30 |
31 | public setLevel(level: LogLevel): void {
32 | this.level = level;
33 | }
34 |
35 | public debug(message: string, ...args: any[]): void {
36 | if (this.shouldLog(LogLevel.DEBUG)) {
37 | console.debug(`[DEBUG] ${message}`, ...args);
38 | }
39 | }
40 |
41 | public info(message: string, ...args: any[]): void {
42 | if (this.shouldLog(LogLevel.INFO)) {
43 | console.info(`[INFO] ${message}`, ...args);
44 | }
45 | }
46 |
47 | public warn(message: string, ...args: any[]): void {
48 | if (this.shouldLog(LogLevel.WARN)) {
49 | console.warn(`[WARN] ${message}`, ...args);
50 | }
51 | }
52 |
53 | public error(message: string, ...args: any[]): void {
54 | if (this.shouldLog(LogLevel.ERROR)) {
55 | console.error(`[ERROR] ${message}`, ...args);
56 | }
57 | }
58 |
59 | private shouldLog(level: LogLevel): boolean {
60 | const levels = Object.values(LogLevel);
61 | const currentIndex = levels.indexOf(this.level);
62 | const messageIndex = levels.indexOf(level);
63 | return messageIndex >= currentIndex;
64 | }
65 | }
--------------------------------------------------------------------------------
/packages/protocol/src/utils/validation.ts:
--------------------------------------------------------------------------------
1 | import { PrivacyConfig, TrainingConfig } from '../types';
2 |
3 | export const validatePrivacyConfig = (config: PrivacyConfig): boolean => {
4 | const validLevels = ['basic', 'medium', 'high'];
5 | if (!validLevels.includes(config.encryptionLevel)) {
6 | throw new Error('Invalid encryption level');
7 | }
8 | return true;
9 | };
10 |
11 | export const validateTrainingConfig = (config: TrainingConfig): boolean => {
12 | if (config.batchSize <= 0 || config.epochs <= 0 || config.learningRate <= 0) {
13 | throw new Error('Invalid training parameters');
14 | }
15 | validatePrivacyConfig(config.privacyConfig);
16 | return true;
17 | };
18 |
--------------------------------------------------------------------------------
/packages/protocol/src/utils/validator.ts:
--------------------------------------------------------------------------------
1 | import { Buffer } from 'buffer';
2 | import { Message, Participant, Session } from '../core/types';
3 |
4 | /**
5 | * Protocol validator implementation
6 | */
7 | export class ProtocolValidator {
8 | /**
9 | * Validate participant
10 | */
11 | public static validateParticipant(participant: Participant): void {
12 | if (!participant) {
13 | throw new Error('Participant is required');
14 | }
15 |
16 | if (!participant.id) {
17 | throw new Error('Participant ID is required');
18 | }
19 |
20 | if (!participant.publicKey || !(participant.publicKey instanceof Buffer)) {
21 | throw new Error('Participant public key must be a Buffer');
22 | }
23 | }
24 |
25 | /**
26 | * Validate session
27 | */
28 | public static validateSession(session: Session): void {
29 | if (!session) {
30 | throw new Error('Session is required');
31 | }
32 |
33 | if (!session.id) {
34 | throw new Error('Session ID is required');
35 | }
36 |
37 | if (!session.participants || !Array.isArray(session.participants)) {
38 | throw new Error('Session participants must be an array');
39 | }
40 |
41 | if (session.participants.length < 2) {
42 | throw new Error('Session must have at least 2 participants');
43 | }
44 |
45 | session.participants.forEach(participant => {
46 | this.validateParticipant(participant);
47 | });
48 |
49 | if (!session.startTime || !(session.startTime instanceof Date)) {
50 | throw new Error('Session start time must be a Date');
51 | }
52 |
53 | if (session.endTime && !(session.endTime instanceof Date)) {
54 | throw new Error('Session end time must be a Date');
55 | }
56 | }
57 |
58 | /**
59 | * Validate message
60 | */
61 | public static validateMessage(message: Message): void {
62 | if (!message) {
63 | throw new Error('Message is required');
64 | }
65 |
66 | if (!message.type) {
67 | throw new Error('Message type is required');
68 | }
69 |
70 | if (!message.sender) {
71 | throw new Error('Message sender is required');
72 | }
73 |
74 | if (!message.receiver) {
75 | throw new Error('Message receiver is required');
76 | }
77 |
78 | if (!message.content || !(message.content instanceof Buffer)) {
79 | throw new Error('Message content must be a Buffer');
80 | }
81 |
82 | if (message.signature && !(message.signature instanceof Buffer)) {
83 | throw new Error('Message signature must be a Buffer');
84 | }
85 |
86 | if (!message.timestamp || !(message.timestamp instanceof Date)) {
87 | throw new Error('Message timestamp must be a Date');
88 | }
89 | }
90 |
91 | /**
92 | * Validate buffer size
93 | */
94 | public static validateBufferSize(buffer: Buffer, expectedSize: number, name: string): void {
95 | if (!buffer || !(buffer instanceof Buffer)) {
96 | throw new Error(`${name} must be a Buffer`);
97 | }
98 |
99 | if (buffer.length !== expectedSize) {
100 | throw new Error(`${name} must be ${expectedSize} bytes`);
101 | }
102 | }
103 |
104 | /**
105 | * Validate number range
106 | */
107 | public static validateNumberRange(value: number, min: number, max: number, name: string): void {
108 | if (typeof value !== 'number') {
109 | throw new Error(`${name} must be a number`);
110 | }
111 |
112 | if (value < min || value > max) {
113 | throw new Error(`${name} must be between ${min} and ${max}`);
114 | }
115 | }
116 |
117 | /**
118 | * Validate array length
119 | */
120 | public static validateArrayLength(array: any[], min: number, max: number, name: string): void {
121 | if (!array || !Array.isArray(array)) {
122 | throw new Error(`${name} must be an array`);
123 | }
124 |
125 | if (array.length < min || array.length > max) {
126 | throw new Error(`${name} must have between ${min} and ${max} elements`);
127 | }
128 | }
129 | }
--------------------------------------------------------------------------------
/packages/protocol/test/privacy.test.ts:
--------------------------------------------------------------------------------
1 | import { expect, use } from 'chai';
2 | import chaiAsPromised from 'chai-as-promised';
3 | import { PrivacyProtocol } from '../src/core/privacy';
4 | import { PrivacyConfig } from '../src/types';
5 |
6 | use(chaiAsPromised);
7 |
8 | describe('PrivacyProtocol', () => {
9 | describe('Basic Encryption', () => {
10 | const config: PrivacyConfig = {
11 | encryptionLevel: 'basic',
12 | useHomomorphicEncryption: false,
13 | useZeroKnowledgeProof: false
14 | };
15 | let protocol: PrivacyProtocol;
16 |
17 | beforeEach(() => {
18 | protocol = new PrivacyProtocol(config);
19 | });
20 |
21 | it('should encrypt and decrypt data correctly', async () => {
22 | const testData = { message: 'test message' };
23 |
24 | const encrypted = await protocol.encrypt(testData);
25 | expect(encrypted).to.be.an('object');
26 |
27 | const decrypted = await protocol.decrypt(encrypted);
28 | expect(decrypted).to.deep.equal(testData);
29 | });
30 | });
31 |
32 | describe('Medium Security', () => {
33 | const config: PrivacyConfig = {
34 | encryptionLevel: 'medium',
35 | useHomomorphicEncryption: false,
36 | useZeroKnowledgeProof: false
37 | };
38 | let protocol: PrivacyProtocol;
39 |
40 | beforeEach(() => {
41 | protocol = new PrivacyProtocol(config);
42 | });
43 |
44 | it('should use RSA encryption', async () => {
45 | const testData = { message: 'test message' };
46 |
47 | const encrypted = await protocol.encrypt(testData);
48 | expect(encrypted).to.be.an('object');
49 |
50 | const decrypted = await protocol.decrypt(encrypted);
51 | expect(decrypted).to.deep.equal(testData);
52 | });
53 | });
54 |
55 | describe('High Security', () => {
56 | const config: PrivacyConfig = {
57 | encryptionLevel: 'high',
58 | useHomomorphicEncryption: true,
59 | useZeroKnowledgeProof: true
60 | };
61 | let protocol: PrivacyProtocol;
62 |
63 | beforeEach(() => {
64 | protocol = new PrivacyProtocol(config);
65 | });
66 |
67 | it('should throw error for unimplemented FHE', async () => {
68 | const testData = { message: 'test message' };
69 |
70 | await expect(protocol.encrypt(testData))
71 | .to.be.rejectedWith('Homomorphic encryption not implemented yet');
72 | });
73 | });
74 |
75 | describe('Error Handling', () => {
76 | const config: PrivacyConfig = {
77 | encryptionLevel: 'basic',
78 | useHomomorphicEncryption: false,
79 | useZeroKnowledgeProof: false
80 | };
81 | let protocol: PrivacyProtocol;
82 |
83 | beforeEach(() => {
84 | protocol = new PrivacyProtocol(config);
85 | });
86 |
87 | it('should handle invalid data gracefully', async () => {
88 | const invalidData = undefined;
89 |
90 | await expect(protocol.encrypt(invalidData))
91 | .to.be.rejectedWith(Error);
92 | });
93 |
94 | it('should handle decryption of invalid data', async () => {
95 | const invalidEncrypted = { data: 'invalid' };
96 |
97 | await expect(protocol.decrypt(invalidEncrypted))
98 | .to.be.rejectedWith(Error);
99 | });
100 | });
101 | });
--------------------------------------------------------------------------------
/packages/protocol/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "./dist",
5 | "rootDir": "./src",
6 | "composite": true,
7 | },
8 | "include": ["src"],
9 | "exclude": ["node_modules", "dist", "test"],
10 | "references": [
11 | { "path": "../crypto" }
12 | ]
13 | }
--------------------------------------------------------------------------------
/packages/ui/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ui",
3 | "version": "1.0.0",
4 | "main": "index.js",
5 | "scripts": {
6 | "test": "echo \"Error: no test specified\" && exit 1"
7 | },
8 | "keywords": [],
9 | "author": "",
10 | "license": "ISC",
11 | "description": "",
12 | "dependencies": {
13 | "@auth0/auth0-react": "^2.3.0",
14 | "@mui/x-data-grid": "^7.24.0",
15 | "recharts": "^2.15.0",
16 | "socket.io-client": "^4.8.1"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
14 | Cipher Nexus
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/scripts/setup-dev.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Install dependencies
4 | npm install
5 |
6 | # Create necessary directories
7 | mkdir -p packages/core/dist
8 | mkdir -p packages/protocol/dist
9 | mkdir -p packages/crypto/dist
10 | mkdir -p packages/ai/dist
11 | mkdir -p packages/ui/dist
12 |
13 | # Copy environment configuration
14 | cp .env.example .env
15 |
16 | # Start Docker services
17 | docker-compose up -d
18 |
19 | echo "Development environment setup completed!"
20 |
--------------------------------------------------------------------------------
/src/App.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom';
3 | import { ThemeProvider, createTheme, CssBaseline } from '@mui/material';
4 | import { MainLayout } from './layouts/MainLayout';
5 | import { DatasetsPage } from './pages/DatasetsPage';
6 | import { TrainingPage } from './pages/TrainingPage';
7 |
8 | const theme = createTheme({
9 | palette: {
10 | mode: 'light',
11 | primary: {
12 | main: '#1976d2',
13 | },
14 | secondary: {
15 | main: '#dc004e',
16 | },
17 | },
18 | typography: {
19 | fontFamily: [
20 | '-apple-system',
21 | 'BlinkMacSystemFont',
22 | '"Segoe UI"',
23 | 'Roboto',
24 | '"Helvetica Neue"',
25 | 'Arial',
26 | 'sans-serif',
27 | ].join(','),
28 | },
29 | components: {
30 | MuiButton: {
31 | styleOverrides: {
32 | root: {
33 | textTransform: 'none',
34 | },
35 | },
36 | },
37 | },
38 | });
39 |
40 | export function App() {
41 | return (
42 |
43 |
44 |
45 |
46 |
47 | } />
48 | } />
49 | } />
50 |
51 |
52 |
53 |
54 | );
55 | }
--------------------------------------------------------------------------------
/src/api/client.ts:
--------------------------------------------------------------------------------
1 | import axios, { AxiosInstance, AxiosRequestConfig } from 'axios';
2 | import { ApiResponse } from '../types';
3 |
4 | class ApiClient {
5 | private client: AxiosInstance;
6 |
7 | constructor() {
8 | this.client = axios.create({
9 | baseURL: process.env.REACT_APP_API_URL || 'http://localhost:3000/api',
10 | headers: {
11 | 'Content-Type': 'application/json',
12 | },
13 | });
14 |
15 | // Add request interceptor for authentication
16 | this.client.interceptors.request.use(
17 | (config) => {
18 | const token = localStorage.getItem('token');
19 | if (token && config.headers) {
20 | config.headers.Authorization = `Bearer ${token}`;
21 | }
22 | return config;
23 | },
24 | (error) => {
25 | return Promise.reject(error);
26 | }
27 | );
28 |
29 | // Add response interceptor for error handling
30 | this.client.interceptors.response.use(
31 | (response) => response,
32 | (error) => {
33 | if (error.response?.status === 401) {
34 | // Handle unauthorized access
35 | localStorage.removeItem('token');
36 | window.location.href = '/login';
37 | }
38 | return Promise.reject(error);
39 | }
40 | );
41 | }
42 |
43 | async get(url: string, config?: AxiosRequestConfig): Promise> {
44 | try {
45 | const response = await this.client.get>(url, config);
46 | return response.data;
47 | } catch (error: any) {
48 | return {
49 | success: false,
50 | error: error.message,
51 | };
52 | }
53 | }
54 |
55 | async post(url: string, data?: any, config?: AxiosRequestConfig): Promise> {
56 | try {
57 | const response = await this.client.post>(url, data, config);
58 | return response.data;
59 | } catch (error: any) {
60 | return {
61 | success: false,
62 | error: error.message,
63 | };
64 | }
65 | }
66 |
67 | async put(url: string, data?: any, config?: AxiosRequestConfig): Promise> {
68 | try {
69 | const response = await this.client.put>(url, data, config);
70 | return response.data;
71 | } catch (error: any) {
72 | return {
73 | success: false,
74 | error: error.message,
75 | };
76 | }
77 | }
78 |
79 | async delete(url: string, config?: AxiosRequestConfig): Promise> {
80 | try {
81 | const response = await this.client.delete>(url, config);
82 | return response.data;
83 | } catch (error: any) {
84 | return {
85 | success: false,
86 | error: error.message,
87 | };
88 | }
89 | }
90 | }
91 |
92 | export const apiClient = new ApiClient();
--------------------------------------------------------------------------------
/src/api/services.ts:
--------------------------------------------------------------------------------
1 | import { apiClient } from './client';
2 | import { Dataset, TrainingTask, ApiResponse } from '../types';
3 |
4 | // Dataset services
5 | export const datasetService = {
6 | getAll: () => apiClient.get('/datasets'),
7 |
8 | getById: (id: string) => apiClient.get(`/datasets/${id}`),
9 |
10 | create: (data: Omit) =>
11 | apiClient.post('/datasets', data),
12 |
13 | update: (id: string, data: Partial) =>
14 | apiClient.put(`/datasets/${id}`, data),
15 |
16 | delete: (id: string) => apiClient.delete(`/datasets/${id}`),
17 |
18 | upload: (id: string, file: File) => {
19 | const formData = new FormData();
20 | formData.append('file', file);
21 | return apiClient.post(`/datasets/${id}/upload`, formData, {
22 | headers: {
23 | 'Content-Type': 'multipart/form-data',
24 | },
25 | });
26 | },
27 | };
28 |
29 | // Training task services
30 | export const trainingService = {
31 | getAll: () => apiClient.get('/training'),
32 |
33 | getById: (id: string) => apiClient.get(`/training/${id}`),
34 |
35 | create: (data: Omit) =>
36 | apiClient.post('/training', data),
37 |
38 | update: (id: string, data: Partial) =>
39 | apiClient.put(`/training/${id}`, data),
40 |
41 | delete: (id: string) => apiClient.delete(`/training/${id}`),
42 |
43 | start: (id: string) => apiClient.post(`/training/${id}/start`),
44 |
45 | stop: (id: string) => apiClient.post(`/training/${id}/stop`),
46 |
47 | getProgress: (id: string) => apiClient.get<{progress: number}>(`/training/${id}/progress`),
48 |
49 | getResults: (id: string) => apiClient.get>(`/training/${id}/results`),
50 | };
--------------------------------------------------------------------------------
/src/components/DataVisualization.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {
3 | Box,
4 | Card,
5 | CardContent,
6 | Typography,
7 | Grid,
8 | FormControl,
9 | InputLabel,
10 | Select,
11 | MenuItem,
12 | } from '@mui/material';
13 | import {
14 | LineChart,
15 | Line,
16 | XAxis,
17 | YAxis,
18 | CartesianGrid,
19 | Tooltip,
20 | Legend,
21 | ResponsiveContainer,
22 | BarChart,
23 | Bar,
24 | ScatterChart,
25 | Scatter,
26 | } from 'recharts';
27 |
28 | interface DataPoint {
29 | [key: string]: number | string;
30 | }
31 |
32 | interface DataVisualizationProps {
33 | data: DataPoint[];
34 | title: string;
35 | xAxis: string;
36 | yAxis: string;
37 | chartType?: 'line' | 'bar' | 'scatter';
38 | }
39 |
40 | export function DataVisualization({
41 | data,
42 | title,
43 | xAxis,
44 | yAxis,
45 | chartType = 'line',
46 | }: DataVisualizationProps) {
47 | const [selectedChart, setSelectedChart] = React.useState(chartType);
48 |
49 | const renderChart = () => {
50 | switch (selectedChart) {
51 | case 'line':
52 | return (
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 | );
62 | case 'bar':
63 | return (
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 | );
73 | case 'scatter':
74 | return (
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 | );
84 | default:
85 | return null;
86 | }
87 | };
88 |
89 | return (
90 |
91 |
92 |
93 |
94 | {title}
95 |
96 |
97 | Chart Type
98 |
107 |
108 |
109 |
110 |
111 | {renderChart()}
112 |
113 |
114 |
115 |
116 | );
117 | }
--------------------------------------------------------------------------------
/src/components/DatasetList.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {
3 | Card,
4 | CardContent,
5 | Typography,
6 | Grid,
7 | IconButton,
8 | Chip,
9 | Box,
10 | LinearProgress,
11 | Menu,
12 | MenuItem,
13 | } from '@mui/material';
14 | import {
15 | MoreVert as MoreVertIcon,
16 | CloudUpload as UploadIcon,
17 | Edit as EditIcon,
18 | Delete as DeleteIcon,
19 | } from '@mui/icons-material';
20 | import { Dataset } from '../types';
21 |
22 | interface DatasetListProps {
23 | datasets: Dataset[];
24 | onEdit: (dataset: Dataset) => void;
25 | onDelete: (dataset: Dataset) => void;
26 | onUpload: (dataset: Dataset) => void;
27 | }
28 |
29 | export function DatasetList({ datasets, onEdit, onDelete, onUpload }: DatasetListProps) {
30 | const [anchorEl, setAnchorEl] = React.useState(null);
31 | const [selectedDataset, setSelectedDataset] = React.useState(null);
32 |
33 | const handleMenuOpen = (event: React.MouseEvent, dataset: Dataset) => {
34 | setAnchorEl(event.currentTarget);
35 | setSelectedDataset(dataset);
36 | };
37 |
38 | const handleMenuClose = () => {
39 | setAnchorEl(null);
40 | setSelectedDataset(null);
41 | };
42 |
43 | const handleAction = (action: 'edit' | 'delete' | 'upload') => {
44 | if (selectedDataset) {
45 | switch (action) {
46 | case 'edit':
47 | onEdit(selectedDataset);
48 | break;
49 | case 'delete':
50 | onDelete(selectedDataset);
51 | break;
52 | case 'upload':
53 | onUpload(selectedDataset);
54 | break;
55 | }
56 | }
57 | handleMenuClose();
58 | };
59 |
60 | const getStatusColor = (status: Dataset['status']) => {
61 | switch (status) {
62 | case 'active':
63 | return 'success';
64 | case 'processing':
65 | return 'warning';
66 | case 'error':
67 | return 'error';
68 | default:
69 | return 'default';
70 | }
71 | };
72 |
73 | return (
74 |
75 | {datasets.map((dataset) => (
76 |
77 |
78 |
79 |
80 |
81 | {dataset.name}
82 |
83 | handleMenuOpen(e, dataset)}
86 | >
87 |
88 |
89 |
90 |
91 |
92 | {dataset.description}
93 |
94 |
95 |
96 |
101 |
106 |
107 |
108 |
109 | Size: {(dataset.size / 1024 / 1024).toFixed(2)} MB
110 |
111 |
112 | {dataset.status === 'processing' && (
113 |
114 |
115 |
116 | )}
117 |
118 |
119 |
120 | ))}
121 |
122 |
140 |
141 | );
142 | }
--------------------------------------------------------------------------------
/src/core/encryption.ts:
--------------------------------------------------------------------------------
1 | import { BigInteger } from 'jsbn';
2 | import { randomBytes } from 'crypto';
3 |
4 | interface KeyPair {
5 | publicKey: {
6 | n: BigInteger;
7 | e: BigInteger;
8 | };
9 | privateKey: {
10 | n: BigInteger;
11 | d: BigInteger;
12 | };
13 | }
14 |
15 | export class Encryption {
16 | private keyPair: KeyPair | null = null;
17 |
18 | // 生成RSA密钥对
19 | async generateKeys(bits: number = 2048): Promise {
20 | // 生成两个大素数
21 | const p = await this.generatePrime(bits / 2);
22 | const q = await this.generatePrime(bits / 2);
23 |
24 | // 计算n = p * q
25 | const n = p.multiply(q);
26 |
27 | // 计算欧拉函数φ(n) = (p-1)(q-1)
28 | const p1 = p.subtract(BigInteger.ONE);
29 | const q1 = q.subtract(BigInteger.ONE);
30 | const phi = p1.multiply(q1);
31 |
32 | // 选择公钥e,通常使用65537
33 | const e = new BigInteger('65537');
34 |
35 | // 计算私钥d,使得ed ≡ 1 (mod φ(n))
36 | const d = e.modInverse(phi);
37 |
38 | this.keyPair = {
39 | publicKey: { n, e },
40 | privateKey: { n, d }
41 | };
42 |
43 | return this.keyPair;
44 | }
45 |
46 | // 加密数据
47 | encrypt(data: string, publicKey: { n: BigInteger; e: BigInteger }): string {
48 | const m = new BigInteger(Buffer.from(data).toString('hex'), 16);
49 | if (m.compareTo(publicKey.n) >= 0) {
50 | throw new Error('Message too large');
51 | }
52 |
53 | // 使用公钥加密: c = m^e mod n
54 | const c = m.modPow(publicKey.e, publicKey.n);
55 | return c.toString(16);
56 | }
57 |
58 | // 解密数据
59 | decrypt(encryptedData: string, privateKey: { n: BigInteger; d: BigInteger }): string {
60 | const c = new BigInteger(encryptedData, 16);
61 |
62 | // 使用私钥解密: m = c^d mod n
63 | const m = c.modPow(privateKey.d, privateKey.n);
64 | const decryptedBuffer = Buffer.from(m.toString(16), 'hex');
65 | return decryptedBuffer.toString();
66 | }
67 |
68 | // 生成大素数
69 | private async generatePrime(bits: number): Promise {
70 | while (true) {
71 | const candidate = this.generateRandomBigInt(bits);
72 | if (await this.isProbablePrime(candidate, 20)) {
73 | return candidate;
74 | }
75 | }
76 | }
77 |
78 | // 生成指定位数的随机大整数
79 | private generateRandomBigInt(bits: number): BigInteger {
80 | const bytes = Math.ceil(bits / 8);
81 | const randomBuffer = randomBytes(bytes);
82 |
83 | // 确保最高位为1
84 | randomBuffer[0] |= 0x80;
85 |
86 | return new BigInteger(randomBuffer.toString('hex'), 16);
87 | }
88 |
89 | // Miller-Rabin素性测试
90 | private async isProbablePrime(n: BigInteger, k: number): Promise {
91 | if (n.equals(BigInteger.ONE)) return false;
92 | if (n.equals(new BigInteger('2'))) return true;
93 | if (n.mod(new BigInteger('2')).equals(BigInteger.ZERO)) return false;
94 |
95 | let s = 0;
96 | let d = n.subtract(BigInteger.ONE);
97 | while (d.mod(new BigInteger('2')).equals(BigInteger.ZERO)) {
98 | s++;
99 | d = d.divide(new BigInteger('2'));
100 | }
101 |
102 | witnessLoop: for (let i = 0; i < k; i++) {
103 | const a = this.generateRandomBigInt(n.bitLength() - 1);
104 | let x = a.modPow(d, n);
105 |
106 | if (x.equals(BigInteger.ONE) || x.equals(n.subtract(BigInteger.ONE))) {
107 | continue;
108 | }
109 |
110 | for (let r = 1; r < s; r++) {
111 | x = x.modPow(new BigInteger('2'), n);
112 | if (x.equals(BigInteger.ONE)) return false;
113 | if (x.equals(n.subtract(BigInteger.ONE))) continue witnessLoop;
114 | }
115 |
116 | return false;
117 | }
118 |
119 | return true;
120 | }
121 |
122 | // 同态加密支持
123 | encryptForHomomorphic(data: number, publicKey: { n: BigInteger; e: BigInteger }): string {
124 | const m = new BigInteger(data.toString());
125 | return this.encrypt(m.toString(), publicKey);
126 | }
127 |
128 | // 同态解密支持
129 | decryptForHomomorphic(encryptedData: string, privateKey: { n: BigInteger; d: BigInteger }): number {
130 | const decrypted = this.decrypt(encryptedData, privateKey);
131 | return parseInt(decrypted);
132 | }
133 |
134 | // 同态加法
135 | homomorphicAdd(
136 | enc1: string,
137 | enc2: string,
138 | publicKey: { n: BigInteger; e: BigInteger }
139 | ): string {
140 | const c1 = new BigInteger(enc1, 16);
141 | const c2 = new BigInteger(enc2, 16);
142 | const result = c1.multiply(c2).mod(publicKey.n);
143 | return result.toString(16);
144 | }
145 |
146 | // 同态乘法(标量)
147 | homomorphicMultiply(
148 | enc: string,
149 | scalar: number,
150 | publicKey: { n: BigInteger; e: BigInteger }
151 | ): string {
152 | const c = new BigInteger(enc, 16);
153 | const result = c.modPow(new BigInteger(scalar.toString()), publicKey.n);
154 | return result.toString(16);
155 | }
156 | }
--------------------------------------------------------------------------------
/src/core/model.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Configuration for model architecture
3 | */
4 | export interface ModelArchitecture {
5 | /** Array of layer configurations */
6 | layers: Array<{
7 | /** Type of the layer */
8 | type: 'dense' | 'conv2d' | 'maxpool2d';
9 | /** Number of units/filters in the layer */
10 | units?: number;
11 | /** Activation function for the layer */
12 | activation?: string;
13 | /** Kernel size for convolutional layers */
14 | kernelSize?: [number, number];
15 | /** Stride for convolutional layers */
16 | stride?: [number, number];
17 | /** Padding for convolutional layers */
18 | padding?: 'valid' | 'same';
19 | }>;
20 | }
21 |
22 | /**
23 | * Configuration for model training and architecture
24 | */
25 | export interface ModelConfig {
26 | /** Model architecture configuration */
27 | architecture: ModelArchitecture;
28 | /** Learning rate for training */
29 | learningRate: number;
30 | /** Batch size for training */
31 | batchSize: number;
32 | /** Number of training epochs */
33 | epochs: number;
34 | /** Optimizer type */
35 | optimizer: 'sgd' | 'adam';
36 | }
37 |
38 | /**
39 | * Training and evaluation metrics
40 | */
41 | export interface ModelMetrics {
42 | /** Loss value */
43 | loss: number;
44 | /** Accuracy value */
45 | accuracy: number;
46 | /** Current epoch */
47 | epoch: number;
48 | /** Current step within epoch */
49 | step: number;
50 | /** Total steps in epoch */
51 | totalSteps: number;
52 | /** Validation loss (optional) */
53 | validationLoss?: number;
54 | /** Validation accuracy (optional) */
55 | validationAccuracy?: number;
56 | }
57 |
58 | /**
59 | * Abstract base class for machine learning models
60 | * Provides common functionality and interface for different model implementations
61 | */
62 | export abstract class Model {
63 | /** Model configuration */
64 | protected config: ModelConfig;
65 | /** Model parameters */
66 | protected parameters: number[] = [];
67 | /** Current training metrics */
68 | protected metrics: ModelMetrics = {
69 | loss: 0,
70 | accuracy: 0,
71 | epoch: 0,
72 | step: 0,
73 | totalSteps: 0
74 | };
75 |
76 | /**
77 | * Creates a new model instance
78 | * @param config Model configuration
79 | */
80 | constructor(config: ModelConfig) {
81 | this.config = config;
82 | }
83 |
84 | /**
85 | * Initializes model parameters and state
86 | * Must be implemented by derived classes
87 | */
88 | abstract initialize(): Promise;
89 |
90 | /**
91 | * Trains the model on provided dataset
92 | * Must be implemented by derived classes
93 | * @param data Training data
94 | * @param labels Training labels
95 | * @returns Training metrics
96 | */
97 | abstract train(data: number[][], labels: number[][]): Promise;
98 |
99 | /**
100 | * Makes predictions using the trained model
101 | * Must be implemented by derived classes
102 | * @param data Input data
103 | * @returns Predicted outputs
104 | */
105 | abstract predict(data: number[][]): Promise;
106 |
107 | /**
108 | * Evaluates model performance on test dataset
109 | * Must be implemented by derived classes
110 | * @param data Test data
111 | * @param labels Test labels
112 | * @returns Evaluation metrics
113 | */
114 | abstract evaluate(data: number[][], labels: number[][]): Promise;
115 |
116 | /**
117 | * Gets current model parameters
118 | * @returns Array of model parameters
119 | */
120 | getParameters(): number[] {
121 | return this.parameters;
122 | }
123 |
124 | /**
125 | * Updates model parameters
126 | * @param parameters New parameter values
127 | */
128 | updateParameters(parameters: number[]): void {
129 | if (parameters.length !== this.parameters.length) {
130 | throw new Error('Parameter length mismatch');
131 | }
132 | this.parameters = [...parameters];
133 | }
134 |
135 | /**
136 | * Gets current training metrics
137 | * @returns Current metrics
138 | */
139 | getMetrics(): ModelMetrics {
140 | return { ...this.metrics };
141 | }
142 |
143 | /**
144 | * Gets model configuration
145 | * @returns Current configuration
146 | */
147 | getConfig(): ModelConfig {
148 | return { ...this.config };
149 | }
150 |
151 | /**
152 | * Computes gradients for parameter updates
153 | * Must be implemented by derived classes
154 | * @param data Input data
155 | * @param labels Target labels
156 | * @returns Computed gradients
157 | */
158 | protected abstract computeGradients(data: number[][], labels: number[][]): Promise;
159 |
160 | /**
161 | * Applies computed gradients to update parameters
162 | * Must be implemented by derived classes
163 | * @param gradients Computed gradients
164 | */
165 | protected abstract applyGradients(gradients: number[]): Promise;
166 | }
--------------------------------------------------------------------------------
/src/hooks/useDatasets.ts:
--------------------------------------------------------------------------------
1 | import { useState, useEffect, useCallback } from 'react';
2 | import { Dataset, ApiResponse } from '../types';
3 | import { datasetService } from '../api/services';
4 |
5 | export function useDatasets() {
6 | const [datasets, setDatasets] = useState([]);
7 | const [loading, setLoading] = useState(false);
8 | const [error, setError] = useState(null);
9 |
10 | const fetchDatasets = useCallback(async () => {
11 | setLoading(true);
12 | setError(null);
13 | try {
14 | const response = await datasetService.getAll();
15 | if (response.success && response.data) {
16 | setDatasets(response.data);
17 | } else {
18 | setError(response.error || 'Failed to fetch datasets');
19 | }
20 | } catch (err: any) {
21 | setError(err.message);
22 | } finally {
23 | setLoading(false);
24 | }
25 | }, []);
26 |
27 | const createDataset = useCallback(async (data: Omit) => {
28 | setLoading(true);
29 | setError(null);
30 | try {
31 | const response = await datasetService.create(data);
32 | if (response.success && response.data) {
33 | setDatasets(prev => [...prev, response.data]);
34 | return response.data;
35 | } else {
36 | setError(response.error || 'Failed to create dataset');
37 | return null;
38 | }
39 | } catch (err: any) {
40 | setError(err.message);
41 | return null;
42 | } finally {
43 | setLoading(false);
44 | }
45 | }, []);
46 |
47 | const updateDataset = useCallback(async (id: string, data: Partial) => {
48 | setLoading(true);
49 | setError(null);
50 | try {
51 | const response = await datasetService.update(id, data);
52 | if (response.success && response.data) {
53 | setDatasets(prev => prev.map(dataset =>
54 | dataset.id === id ? response.data : dataset
55 | ));
56 | return response.data;
57 | } else {
58 | setError(response.error || 'Failed to update dataset');
59 | return null;
60 | }
61 | } catch (err: any) {
62 | setError(err.message);
63 | return null;
64 | } finally {
65 | setLoading(false);
66 | }
67 | }, []);
68 |
69 | const deleteDataset = useCallback(async (id: string) => {
70 | setLoading(true);
71 | setError(null);
72 | try {
73 | const response = await datasetService.delete(id);
74 | if (response.success) {
75 | setDatasets(prev => prev.filter(dataset => dataset.id !== id));
76 | return true;
77 | } else {
78 | setError(response.error || 'Failed to delete dataset');
79 | return false;
80 | }
81 | } catch (err: any) {
82 | setError(err.message);
83 | return false;
84 | } finally {
85 | setLoading(false);
86 | }
87 | }, []);
88 |
89 | const uploadDataset = useCallback(async (id: string, file: File) => {
90 | setLoading(true);
91 | setError(null);
92 | try {
93 | const response = await datasetService.upload(id, file);
94 | if (response.success) {
95 | await fetchDatasets(); // Refresh the list
96 | return true;
97 | } else {
98 | setError(response.error || 'Failed to upload dataset');
99 | return false;
100 | }
101 | } catch (err: any) {
102 | setError(err.message);
103 | return false;
104 | } finally {
105 | setLoading(false);
106 | }
107 | }, [fetchDatasets]);
108 |
109 | useEffect(() => {
110 | fetchDatasets();
111 | }, [fetchDatasets]);
112 |
113 | return {
114 | datasets,
115 | loading,
116 | error,
117 | fetchDatasets,
118 | createDataset,
119 | updateDataset,
120 | deleteDataset,
121 | uploadDataset,
122 | };
123 | }
--------------------------------------------------------------------------------
/src/hooks/useTrainingProgress.ts:
--------------------------------------------------------------------------------
1 | import { useState, useEffect, useCallback } from 'react';
2 | import wsService from '../services/websocket';
3 |
4 | interface Metrics {
5 | loss: number;
6 | accuracy: number;
7 | epoch: number;
8 | step: number;
9 | totalSteps: number;
10 | learningRate: number;
11 | }
12 |
13 | interface TrainingEvent {
14 | type: 'info' | 'warning' | 'error' | 'success';
15 | message: string;
16 | timestamp: string;
17 | }
18 |
19 | interface TrainingUpdate {
20 | taskId: string;
21 | status: string;
22 | metrics: Metrics;
23 | event?: TrainingEvent;
24 | }
25 |
26 | interface TrainingProgress {
27 | status: 'running' | 'paused' | 'completed' | 'failed';
28 | metrics: Metrics;
29 | events: TrainingEvent[];
30 | }
31 |
32 | const initialMetrics: Metrics = {
33 | loss: 0,
34 | accuracy: 0,
35 | epoch: 0,
36 | step: 0,
37 | totalSteps: 0,
38 | learningRate: 0,
39 | };
40 |
41 | export function useTrainingProgress(taskId: string) {
42 | const [progress, setProgress] = useState({
43 | status: 'paused',
44 | metrics: initialMetrics,
45 | events: [],
46 | });
47 | const [error, setError] = useState(null);
48 | const [isConnected, setIsConnected] = useState(false);
49 |
50 | useEffect(() => {
51 | // Connect to WebSocket when the hook is first used
52 | wsService.connect();
53 |
54 | // Handle WebSocket connection errors
55 | const handleError = (error: Error) => {
56 | setError('WebSocket connection error');
57 | setIsConnected(false);
58 | };
59 |
60 | // Handle max reconnection attempts reached
61 | const handleMaxReconnect = () => {
62 | setError('Unable to connect to server. Please refresh the page.');
63 | setIsConnected(false);
64 | };
65 |
66 | wsService.on('error', handleError);
67 | wsService.on('max_reconnect_attempts', handleMaxReconnect);
68 |
69 | return () => {
70 | wsService.off('error', handleError);
71 | wsService.off('max_reconnect_attempts', handleMaxReconnect);
72 | };
73 | }, []);
74 |
75 | useEffect(() => {
76 | // Subscribe to training updates for the specific task
77 | const handleUpdate = (update: TrainingUpdate) => {
78 | setProgress((prev) => {
79 | const newEvents = update.event
80 | ? [...prev.events, update.event]
81 | : prev.events;
82 |
83 | return {
84 | status: update.status as TrainingProgress['status'],
85 | metrics: update.metrics,
86 | events: newEvents,
87 | };
88 | });
89 | setIsConnected(true);
90 | setError(null);
91 | };
92 |
93 | const updateEventName = `training_update:${taskId}`;
94 | wsService.on(updateEventName, handleUpdate);
95 | wsService.subscribeToTrainingUpdates(taskId);
96 |
97 | return () => {
98 | wsService.off(updateEventName, handleUpdate);
99 | wsService.unsubscribeFromTrainingUpdates(taskId);
100 | };
101 | }, [taskId]);
102 |
103 | const startTraining = useCallback(async () => {
104 | try {
105 | await fetch(`/api/training/${taskId}/start`, {
106 | method: 'POST',
107 | });
108 | } catch (err) {
109 | setError('Failed to start training');
110 | }
111 | }, [taskId]);
112 |
113 | const stopTraining = useCallback(async () => {
114 | try {
115 | await fetch(`/api/training/${taskId}/stop`, {
116 | method: 'POST',
117 | });
118 | } catch (err) {
119 | setError('Failed to stop training');
120 | }
121 | }, [taskId]);
122 |
123 | const refreshProgress = useCallback(async () => {
124 | try {
125 | const response = await fetch(`/api/training/${taskId}/progress`);
126 | const data: TrainingUpdate = await response.json();
127 |
128 | setProgress((prev) => ({
129 | status: data.status as TrainingProgress['status'],
130 | metrics: data.metrics,
131 | events: data.event ? [...prev.events, data.event] : prev.events,
132 | }));
133 | } catch (err) {
134 | setError('Failed to refresh training progress');
135 | }
136 | }, [taskId]);
137 |
138 | return {
139 | ...progress,
140 | error,
141 | isConnected,
142 | startTraining,
143 | stopTraining,
144 | refreshProgress,
145 | };
146 | }
--------------------------------------------------------------------------------
/src/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { createRoot } from 'react-dom/client';
3 | import { App } from './App';
4 |
5 | const container = document.getElementById('root');
6 | if (!container) {
7 | throw new Error('Failed to find the root element');
8 | }
9 |
10 | const root = createRoot(container);
11 | root.render(
12 |
13 |
14 |
15 | );
--------------------------------------------------------------------------------
/src/layouts/MainLayout.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Box, AppBar, Toolbar, Typography, Drawer, List, ListItem, ListItemIcon, ListItemText, IconButton } from '@mui/material';
3 | import { styled } from '@mui/material/styles';
4 | import { useNavigate, useLocation } from 'react-router-dom';
5 | import {
6 | Menu as MenuIcon,
7 | Dataset as DatasetIcon,
8 | Psychology as TrainingIcon,
9 | Dashboard as DashboardIcon,
10 | } from '@mui/icons-material';
11 |
12 | const drawerWidth = 240;
13 |
14 | const Root = styled('div')({
15 | display: 'flex',
16 | });
17 |
18 | const StyledAppBar = styled(AppBar)(({ theme }) => ({
19 | zIndex: theme.zIndex.drawer + 1,
20 | }));
21 |
22 | const StyledDrawer = styled(Drawer)({
23 | width: drawerWidth,
24 | flexShrink: 0,
25 | '& .MuiDrawer-paper': {
26 | width: drawerWidth,
27 | boxSizing: 'border-box',
28 | },
29 | });
30 |
31 | const MainContent = styled('main')(({ theme }) => ({
32 | flexGrow: 1,
33 | padding: theme.spacing(3),
34 | marginTop: 64,
35 | }));
36 |
37 | interface MainLayoutProps {
38 | children: React.ReactNode;
39 | }
40 |
41 | export function MainLayout({ children }: MainLayoutProps) {
42 | const navigate = useNavigate();
43 | const location = useLocation();
44 | const [mobileOpen, setMobileOpen] = React.useState(false);
45 |
46 | const menuItems = [
47 | { text: 'Dashboard', icon: , path: '/' },
48 | { text: 'Datasets', icon: , path: '/datasets' },
49 | { text: 'Training Tasks', icon: , path: '/training' },
50 | ];
51 |
52 | const handleDrawerToggle = () => {
53 | setMobileOpen(!mobileOpen);
54 | };
55 |
56 | const drawer = (
57 |
58 |
59 |
60 | {menuItems.map((item) => (
61 | {
66 | navigate(item.path);
67 | setMobileOpen(false);
68 | }}
69 | >
70 | {item.icon}
71 |
72 |
73 | ))}
74 |
75 |
76 | );
77 |
78 | return (
79 |
80 |
81 |
82 |
89 |
90 |
91 |
92 | Cipher Nexus
93 |
94 |
95 |
96 |
97 |
98 |
109 | {drawer}
110 |
111 |
112 |
119 | {drawer}
120 |
121 |
122 |
123 |
124 | {children}
125 |
126 |
127 | );
128 | }
--------------------------------------------------------------------------------
/src/pages/auth/LoginPage.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { Link as RouterLink } from 'react-router-dom';
3 | import {
4 | Container,
5 | Box,
6 | Typography,
7 | TextField,
8 | Button,
9 | Link,
10 | Alert,
11 | Paper,
12 | } from '@mui/material';
13 | import { useAuth } from '../../components/auth/AuthProvider';
14 |
15 | export function LoginPage() {
16 | const { login, error } = useAuth();
17 | const [email, setEmail] = useState('');
18 | const [password, setPassword] = useState('');
19 | const [isSubmitting, setIsSubmitting] = useState(false);
20 |
21 | const handleSubmit = async (e: React.FormEvent) => {
22 | e.preventDefault();
23 | setIsSubmitting(true);
24 | try {
25 | await login(email, password);
26 | } catch (err) {
27 | // Error is handled by AuthProvider
28 | } finally {
29 | setIsSubmitting(false);
30 | }
31 | };
32 |
33 | return (
34 |
35 |
43 |
53 |
54 | Sign in
55 |
56 | {error && (
57 |
58 | {error}
59 |
60 | )}
61 |
62 | setEmail(e.target.value)}
73 | />
74 | setPassword(e.target.value)}
85 | />
86 |
95 |
96 |
97 | {"Don't have an account? Sign Up"}
98 |
99 |
100 |
101 |
102 |
103 |
104 | );
105 | }
--------------------------------------------------------------------------------
/src/pages/auth/RegisterPage.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { Link as RouterLink } from 'react-router-dom';
3 | import {
4 | Container,
5 | Box,
6 | Typography,
7 | TextField,
8 | Button,
9 | Link,
10 | Alert,
11 | Paper,
12 | } from '@mui/material';
13 | import { useAuth } from '../../components/auth/AuthProvider';
14 |
15 | export function RegisterPage() {
16 | const { register, error } = useAuth();
17 | const [username, setUsername] = useState('');
18 | const [email, setEmail] = useState('');
19 | const [password, setPassword] = useState('');
20 | const [confirmPassword, setConfirmPassword] = useState('');
21 | const [isSubmitting, setIsSubmitting] = useState(false);
22 | const [validationError, setValidationError] = useState(null);
23 |
24 | const validateForm = () => {
25 | if (password !== confirmPassword) {
26 | setValidationError('Passwords do not match');
27 | return false;
28 | }
29 | if (password.length < 8) {
30 | setValidationError('Password must be at least 8 characters long');
31 | return false;
32 | }
33 | setValidationError(null);
34 | return true;
35 | };
36 |
37 | const handleSubmit = async (e: React.FormEvent) => {
38 | e.preventDefault();
39 | if (!validateForm()) return;
40 |
41 | setIsSubmitting(true);
42 | try {
43 | await register(username, email, password);
44 | } catch (err) {
45 | // Error is handled by AuthProvider
46 | } finally {
47 | setIsSubmitting(false);
48 | }
49 | };
50 |
51 | return (
52 |
53 |
61 |
71 |
72 | Sign up
73 |
74 | {(error || validationError) && (
75 |
76 | {error || validationError}
77 |
78 | )}
79 |
80 | setUsername(e.target.value)}
91 | />
92 | setEmail(e.target.value)}
102 | />
103 | setPassword(e.target.value)}
114 | />
115 | setConfirmPassword(e.target.value)}
126 | />
127 |
136 |
137 |
138 | {'Already have an account? Sign in'}
139 |
140 |
141 |
142 |
143 |
144 |
145 | );
146 | }
--------------------------------------------------------------------------------
/src/services/websocket.ts:
--------------------------------------------------------------------------------
1 | import { EventEmitter } from 'events';
2 |
3 | interface WebSocketMessage {
4 | type: string;
5 | payload: any;
6 | }
7 |
8 | interface TrainingUpdate {
9 | taskId: string;
10 | status: string;
11 | metrics: {
12 | loss: number;
13 | accuracy: number;
14 | epoch: number;
15 | step: number;
16 | totalSteps: number;
17 | learningRate: number;
18 | };
19 | event?: {
20 | type: 'info' | 'warning' | 'error' | 'success';
21 | message: string;
22 | timestamp: string;
23 | };
24 | }
25 |
26 | class WebSocketService extends EventEmitter {
27 | private ws: WebSocket | null = null;
28 | private reconnectAttempts = 0;
29 | private maxReconnectAttempts = 5;
30 | private reconnectTimeout = 1000;
31 | private pingInterval: NodeJS.Timeout | null = null;
32 | private subscriptions: Set = new Set();
33 |
34 | constructor(private baseUrl: string) {
35 | super();
36 | }
37 |
38 | connect() {
39 | if (this.ws?.readyState === WebSocket.OPEN) return;
40 |
41 | this.ws = new WebSocket(this.baseUrl);
42 |
43 | this.ws.onopen = () => {
44 | console.log('WebSocket connected');
45 | this.reconnectAttempts = 0;
46 | this.startPingInterval();
47 | this.resubscribe();
48 | };
49 |
50 | this.ws.onclose = () => {
51 | console.log('WebSocket disconnected');
52 | this.cleanup();
53 | this.attemptReconnect();
54 | };
55 |
56 | this.ws.onerror = (error) => {
57 | console.error('WebSocket error:', error);
58 | this.emit('error', error);
59 | };
60 |
61 | this.ws.onmessage = (event) => {
62 | try {
63 | const message: WebSocketMessage = JSON.parse(event.data);
64 | this.handleMessage(message);
65 | } catch (error) {
66 | console.error('Error parsing WebSocket message:', error);
67 | }
68 | };
69 | }
70 |
71 | private handleMessage(message: WebSocketMessage) {
72 | switch (message.type) {
73 | case 'training_update':
74 | const update: TrainingUpdate = message.payload;
75 | this.emit(`training_update:${update.taskId}`, update);
76 | break;
77 | case 'pong':
78 | // Handle pong response
79 | break;
80 | default:
81 | console.warn('Unknown message type:', message.type);
82 | }
83 | }
84 |
85 | private startPingInterval() {
86 | this.pingInterval = setInterval(() => {
87 | this.send({ type: 'ping' });
88 | }, 30000);
89 | }
90 |
91 | private cleanup() {
92 | if (this.pingInterval) {
93 | clearInterval(this.pingInterval);
94 | this.pingInterval = null;
95 | }
96 | }
97 |
98 | private attemptReconnect() {
99 | if (this.reconnectAttempts >= this.maxReconnectAttempts) {
100 | console.error('Max reconnection attempts reached');
101 | this.emit('max_reconnect_attempts');
102 | return;
103 | }
104 |
105 | this.reconnectAttempts++;
106 | const timeout = this.reconnectTimeout * Math.pow(2, this.reconnectAttempts - 1);
107 |
108 | console.log(`Attempting to reconnect in ${timeout}ms (attempt ${this.reconnectAttempts})`);
109 | setTimeout(() => this.connect(), timeout);
110 | }
111 |
112 | private resubscribe() {
113 | this.subscriptions.forEach((taskId) => {
114 | this.send({
115 | type: 'subscribe',
116 | payload: { taskId },
117 | });
118 | });
119 | }
120 |
121 | subscribeToTrainingUpdates(taskId: string) {
122 | this.subscriptions.add(taskId);
123 | if (this.ws?.readyState === WebSocket.OPEN) {
124 | this.send({
125 | type: 'subscribe',
126 | payload: { taskId },
127 | });
128 | }
129 | }
130 |
131 | unsubscribeFromTrainingUpdates(taskId: string) {
132 | this.subscriptions.delete(taskId);
133 | if (this.ws?.readyState === WebSocket.OPEN) {
134 | this.send({
135 | type: 'unsubscribe',
136 | payload: { taskId },
137 | });
138 | }
139 | }
140 |
141 | private send(message: WebSocketMessage) {
142 | if (this.ws?.readyState === WebSocket.OPEN) {
143 | this.ws.send(JSON.stringify(message));
144 | } else {
145 | console.warn('WebSocket is not connected');
146 | }
147 | }
148 |
149 | disconnect() {
150 | this.cleanup();
151 | if (this.ws) {
152 | this.ws.close();
153 | this.ws = null;
154 | }
155 | }
156 | }
157 |
158 | // Create a singleton instance
159 | const wsService = new WebSocketService(process.env.REACT_APP_WS_URL || 'ws://localhost:8080/ws');
160 |
161 | export default wsService;
--------------------------------------------------------------------------------
/src/types/index.ts:
--------------------------------------------------------------------------------
1 | // Dataset types
2 | export interface Dataset {
3 | id: string;
4 | name: string;
5 | description: string;
6 | size: number;
7 | created: Date;
8 | updated: Date;
9 | status: 'active' | 'processing' | 'error';
10 | type: 'public' | 'private';
11 | owner: string;
12 | }
13 |
14 | // Training task types
15 | export interface TrainingTask {
16 | id: string;
17 | name: string;
18 | description: string;
19 | dataset: string;
20 | model: string;
21 | parameters: Record;
22 | status: 'pending' | 'running' | 'completed' | 'failed';
23 | progress: number;
24 | created: Date;
25 | updated: Date;
26 | owner: string;
27 | results?: Record;
28 | }
29 |
30 | // User types
31 | export interface User {
32 | id: string;
33 | username: string;
34 | email: string;
35 | role: 'admin' | 'user';
36 | created: Date;
37 | lastLogin: Date;
38 | }
39 |
40 | // API Response types
41 | export interface ApiResponse {
42 | success: boolean;
43 | data?: T;
44 | error?: string;
45 | message?: string;
46 | }
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": ["dom", "dom.iterable", "esnext"],
5 | "allowJs": true,
6 | "skipLibCheck": true,
7 | "esModuleInterop": true,
8 | "allowSyntheticDefaultImports": true,
9 | "strict": true,
10 | "forceConsistentCasingInFileNames": true,
11 | "noFallthroughCasesInSwitch": true,
12 | "module": "esnext",
13 | "moduleResolution": "node",
14 | "resolveJsonModule": true,
15 | "isolatedModules": true,
16 | "noEmit": true,
17 | "jsx": "react-jsx",
18 | "baseUrl": "src"
19 | },
20 | "include": ["src"]
21 | }
22 |
--------------------------------------------------------------------------------