refactor: convert to Go bindings only

Remove all submodules and non-Go content.
JS SDKs, plugins, templates, and examples live in their own repos.

Kept:
- Go FHE library (*.go)
- cmd/, pkg/, internal/
- docs/, bin/
This commit is contained in:
Zach Kelling
2026-01-27 14:41:31 -08:00
parent 83c0c3be91
commit 148b20c2c7
1355 changed files with 7 additions and 318455 deletions
-185
View File
@@ -1,185 +0,0 @@
name: CI
on:
push:
branches: [main, master]
pull_request:
branches: [main, master]
jobs:
build-wasm:
name: Build WASM
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
working-directory: packages/wasm
run: npm install
- name: Build
working-directory: packages/wasm
run: npm run build
build-kms:
name: Build KMS
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
working-directory: packages/kms
run: npm install
- name: Build
working-directory: packages/kms
run: npm run build
build-sdk:
name: Build SDK
runs-on: ubuntu-latest
needs: build-wasm
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
working-directory: js/v2-sdk
run: npm install --legacy-peer-deps
- name: Build
working-directory: js/v2-sdk
run: npm run build
- name: Run tests
working-directory: js/v2-sdk
run: npm test -- --reporter=verbose --testTimeout=60000 || true
env:
SKIP_LOCAL_ENV: true
build-permit:
name: Build Permit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
working-directory: js/permit
run: npm install
- name: Build
working-directory: js/permit
run: npm run build
build-relayer-sdk:
name: Build Relayer SDK
runs-on: ubuntu-latest
needs: [build-wasm, build-kms]
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
working-directory: relayer-sdk
run: npm install --legacy-peer-deps
- name: Build
working-directory: relayer-sdk
run: npm run build
build-hardhat-plugin:
name: Build Hardhat Plugin
runs-on: ubuntu-latest
needs: build-sdk
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
- name: Install forge-std
working-directory: plugins/hardhat
run: |
mkdir -p lib
forge install foundry-rs/forge-std --no-commit --root . || true
- name: Install dependencies
working-directory: plugins/hardhat
run: npm install --legacy-peer-deps
- name: Build
working-directory: plugins/hardhat
run: npm run build
build-mock-contracts:
name: Build Mock Contracts
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
- name: Install npm dependencies
working-directory: mocks/foundry
run: npm install
- name: Install forge dependencies
working-directory: mocks/foundry
run: |
forge install foundry-rs/forge-std --no-commit || true
- name: Build contracts
working-directory: mocks/foundry
run: forge build
- name: Run tests
working-directory: mocks/foundry
run: forge test || true
-101
View File
@@ -1,101 +0,0 @@
name: Deploy Docs
on:
push:
branches: [main, master]
paths:
- 'docs/**'
- '.github/workflows/docs.yml'
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: pages
cancel-in-progress: false
jobs:
build:
name: Build Documentation
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Setup Pages
uses: actions/configure-pages@v4
- name: Check for docs
id: check-docs
run: |
if [ -f "docs/package.json" ]; then
echo "has_docs=true" >> $GITHUB_OUTPUT
else
echo "has_docs=false" >> $GITHUB_OUTPUT
fi
- name: Install dependencies
if: steps.check-docs.outputs.has_docs == 'true'
working-directory: docs
run: npm install
- name: Build docs
if: steps.check-docs.outputs.has_docs == 'true'
working-directory: docs
run: npm run build
- name: Upload artifact
if: steps.check-docs.outputs.has_docs == 'true'
uses: actions/upload-pages-artifact@v3
with:
path: docs/out
deploy:
name: Deploy to GitHub Pages
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
# Generate API docs from TypeDoc
api-docs:
name: Generate API Documentation
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install TypeDoc
run: npm install -g typedoc
- name: Generate SDK docs
working-directory: js/v2-sdk
run: |
npm install
npx typedoc --out ../../docs/api/sdk src/index.ts || true
- name: Generate Permit docs
working-directory: js/permit
run: |
npm install
npx typedoc --out ../../docs/api/permit src/index.ts || true
-257
View File
@@ -1,257 +0,0 @@
name: Publish to NPM
on:
release:
types: [published]
workflow_dispatch:
inputs:
package:
description: 'Package to publish'
required: true
type: choice
options:
- all
- wasm
- kms
- sdk
- v2-sdk
- permit
- relayer-sdk
- hardhat-plugin
- mock-contracts
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
jobs:
publish-wasm:
name: Publish @luxfhe/wasm
runs-on: ubuntu-latest
if: github.event_name == 'release' || github.event.inputs.package == 'all' || github.event.inputs.package == 'wasm'
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies
working-directory: packages/wasm
run: npm install
- name: Build
working-directory: packages/wasm
run: npm run build
- name: Publish
working-directory: packages/wasm
run: npm publish --access public || echo "Version already exists"
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
publish-kms:
name: Publish @luxfhe/kms
runs-on: ubuntu-latest
if: github.event_name == 'release' || github.event.inputs.package == 'all' || github.event.inputs.package == 'kms'
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies
working-directory: packages/kms
run: npm install
- name: Build
working-directory: packages/kms
run: npm run build
- name: Publish
working-directory: packages/kms
run: npm publish --access public || echo "Version already exists"
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
publish-sdk:
name: Publish @luxfhe/sdk (v1)
runs-on: ubuntu-latest
needs: publish-wasm
if: always() && (github.event_name == 'release' || github.event.inputs.package == 'all' || github.event.inputs.package == 'sdk')
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies
working-directory: js/v1-sdk
run: npm install
- name: Build
working-directory: js/v1-sdk
run: npm run build
- name: Publish
working-directory: js/v1-sdk
run: npm publish --access public || echo "Version already exists"
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
publish-v2-sdk:
name: Publish @luxfhe/v2-sdk
runs-on: ubuntu-latest
needs: publish-wasm
if: always() && (github.event_name == 'release' || github.event.inputs.package == 'all' || github.event.inputs.package == 'v2-sdk')
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies
working-directory: js/v2-sdk
run: npm install
- name: Build
working-directory: js/v2-sdk
run: npm run build
- name: Publish
working-directory: js/v2-sdk
run: npm publish --access public || echo "Version already exists"
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
publish-permit:
name: Publish @luxfhe/permit
runs-on: ubuntu-latest
needs: publish-wasm
if: always() && (github.event_name == 'release' || github.event.inputs.package == 'all' || github.event.inputs.package == 'permit')
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies
working-directory: js/permit
run: npm install
- name: Build
working-directory: js/permit
run: npm run build
- name: Publish
working-directory: js/permit
run: npm publish --access public || echo "Version already exists"
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
publish-relayer-sdk:
name: Publish @luxfhe/relayer-sdk
runs-on: ubuntu-latest
needs: [publish-wasm, publish-kms]
if: always() && (github.event_name == 'release' || github.event.inputs.package == 'all' || github.event.inputs.package == 'relayer-sdk')
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies
working-directory: relayer-sdk
run: npm install
- name: Build
working-directory: relayer-sdk
run: npm run build
- name: Publish
working-directory: relayer-sdk
run: npm publish --access public || echo "Version already exists"
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
publish-mock-contracts:
name: Publish @luxfhe/mock-contracts
runs-on: ubuntu-latest
if: github.event_name == 'release' || github.event.inputs.package == 'all' || github.event.inputs.package == 'mock-contracts'
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
- name: Publish
working-directory: mocks/foundry
run: npm publish --access public || echo "Version already exists"
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
publish-hardhat-plugin:
name: Publish @luxfhe/hardhat-plugin
runs-on: ubuntu-latest
needs: [publish-v2-sdk, publish-mock-contracts]
if: always() && (github.event_name == 'release' || github.event.inputs.package == 'all' || github.event.inputs.package == 'hardhat-plugin')
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
- name: Install dependencies
working-directory: plugins/hardhat
run: npm install
- name: Build
working-directory: plugins/hardhat
run: npm run build
- name: Publish
working-directory: plugins/hardhat
run: npm publish --access public || echo "Version already exists"
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
-143
View File
@@ -1,143 +0,0 @@
name: Release
on:
workflow_dispatch:
inputs:
version:
description: 'Version bump type'
required: true
type: choice
options:
- patch
- minor
- major
package:
description: 'Package to release (or all)'
required: true
type: choice
options:
- all
- wasm
- kms
- sdk
- v2-sdk
- permit
- relayer-sdk
- hardhat-plugin
- mock-contracts
jobs:
release:
name: Create Release
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: recursive
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Configure Git
run: |
git config user.name "GitHub Actions"
git config user.email "actions@github.com"
- name: Bump version - WASM
if: github.event.inputs.package == 'all' || github.event.inputs.package == 'wasm'
working-directory: packages/wasm
run: |
npm version ${{ github.event.inputs.version }} --no-git-tag-version
echo "WASM_VERSION=$(node -p "require('./package.json').version")" >> $GITHUB_ENV
- name: Bump version - KMS
if: github.event.inputs.package == 'all' || github.event.inputs.package == 'kms'
working-directory: packages/kms
run: |
npm version ${{ github.event.inputs.version }} --no-git-tag-version
echo "KMS_VERSION=$(node -p "require('./package.json').version")" >> $GITHUB_ENV
- name: Bump version - SDK (v1)
if: github.event.inputs.package == 'all' || github.event.inputs.package == 'sdk'
working-directory: js/v1-sdk
run: |
npm version ${{ github.event.inputs.version }} --no-git-tag-version
echo "SDK_VERSION=$(node -p "require('./package.json').version")" >> $GITHUB_ENV
- name: Bump version - v2-sdk
if: github.event.inputs.package == 'all' || github.event.inputs.package == 'v2-sdk'
working-directory: js/v2-sdk
run: |
npm version ${{ github.event.inputs.version }} --no-git-tag-version
echo "V2SDK_VERSION=$(node -p "require('./package.json').version")" >> $GITHUB_ENV
- name: Bump version - Permit
if: github.event.inputs.package == 'all' || github.event.inputs.package == 'permit'
working-directory: js/permit
run: |
npm version ${{ github.event.inputs.version }} --no-git-tag-version
echo "PERMIT_VERSION=$(node -p "require('./package.json').version")" >> $GITHUB_ENV
- name: Bump version - Relayer SDK
if: github.event.inputs.package == 'all' || github.event.inputs.package == 'relayer-sdk'
working-directory: relayer-sdk
run: |
npm version ${{ github.event.inputs.version }} --no-git-tag-version
echo "RELAYER_VERSION=$(node -p "require('./package.json').version")" >> $GITHUB_ENV
- name: Bump version - Mock Contracts
if: github.event.inputs.package == 'all' || github.event.inputs.package == 'mock-contracts'
working-directory: mocks/foundry
run: |
npm version ${{ github.event.inputs.version }} --no-git-tag-version
echo "MOCKS_VERSION=$(node -p "require('./package.json').version")" >> $GITHUB_ENV
- name: Bump version - Hardhat Plugin
if: github.event.inputs.package == 'all' || github.event.inputs.package == 'hardhat-plugin'
working-directory: plugins/hardhat
run: |
npm version ${{ github.event.inputs.version }} --no-git-tag-version
echo "HARDHAT_VERSION=$(node -p "require('./package.json').version")" >> $GITHUB_ENV
- name: Generate changelog
id: changelog
run: |
echo "## Changes" > CHANGELOG_ENTRY.md
echo "" >> CHANGELOG_ENTRY.md
git log --oneline $(git describe --tags --abbrev=0 2>/dev/null || echo "HEAD~10")..HEAD >> CHANGELOG_ENTRY.md || echo "- Initial release" >> CHANGELOG_ENTRY.md
- name: Commit version bumps
run: |
git add -A
git commit -m "chore: bump versions for ${{ github.event.inputs.version }} release" || echo "No changes to commit"
git push
- name: Create Release
uses: softprops/action-gh-release@v1
with:
tag_name: v${{ env.WASM_VERSION || env.V2SDK_VERSION || 'latest' }}
name: Release v${{ env.WASM_VERSION || env.V2SDK_VERSION || 'latest' }}
body_path: CHANGELOG_ENTRY.md
draft: false
prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Trigger publish workflow
uses: actions/github-script@v7
with:
script: |
github.rest.actions.createWorkflowDispatch({
owner: context.repo.owner,
repo: context.repo.repo,
workflow_id: 'publish.yml',
ref: 'main',
inputs: {
package: '${{ github.event.inputs.package }}'
}
})
-141
View File
@@ -1,141 +0,0 @@
[submodule "js/permit"]
path = js/permit
url = https://github.com/luxfhe/permit.git
[submodule "js/v1-sdk"]
path = js/v1-sdk
url = https://github.com/luxfhe/v1-sdk.git
[submodule "js/v2-sdk"]
path = js/v2-sdk
url = https://github.com/luxfhe/v2-sdk.git
[submodule "plugins/hardhat"]
path = plugins/hardhat
url = https://github.com/luxfhe/hardhat-plugin.git
[submodule "plugins/remix"]
path = plugins/remix
url = https://github.com/luxfhe/remix-plugin.git
[submodule "packages/kms"]
path = packages/kms
url = https://github.com/luxfhe/kms.git
[submodule "packages/wasm"]
path = packages/wasm
url = https://github.com/luxfhe/wasm.git
[submodule "mocks/foundry"]
path = mocks/foundry
url = https://github.com/luxfhe/mocks-foundry.git
[submodule "relayer-sdk"]
path = relayer-sdk
url = https://github.com/luxfhe/relayer-sdk.git
[submodule "templates/fhevm-hardhat"]
path = templates/fhevm-hardhat
url = https://github.com/luxfhe/template-fhevm-hardhat.git
[submodule "templates/foundry"]
path = templates/foundry
url = https://github.com/luxfhe/template-foundry.git
[submodule "templates/hardhat"]
path = templates/hardhat
url = https://github.com/luxfhe/template-hardhat.git
[submodule "templates/hardhat-starter"]
path = templates/hardhat-starter
url = https://github.com/luxfhe/template-hardhat-starter.git
[submodule "templates/miniapp"]
path = templates/miniapp
url = https://github.com/luxfhe/template-miniapp.git
[submodule "templates/next"]
path = templates/next
url = https://github.com/luxfhe/template-next.git
[submodule "templates/nuxt"]
path = templates/nuxt
url = https://github.com/luxfhe/template-nuxt.git
[submodule "templates/react"]
path = templates/react
url = https://github.com/luxfhe/template-react.git
[submodule "templates/scaffold-eth"]
path = templates/scaffold-eth
url = https://github.com/luxfhe/template-scaffold-eth.git
[submodule "templates/ui"]
path = templates/ui
url = https://github.com/luxfhe/template-ui.git
[submodule "templates/vue"]
path = templates/vue
url = https://github.com/luxfhe/template-vue.git
[submodule "research/ocp-fhe"]
path = research/ocp-fhe
url = https://github.com/luxfhe/research-ocp-fhe.git
[submodule "research/threshold-paper"]
path = research/threshold-paper
url = https://github.com/luxfhe/research-threshold-paper.git
[submodule "research/verifiable-fhe"]
path = research/verifiable-fhe
url = https://github.com/luxfhe/research-verifiable-fhe.git
[submodule "examples/binary-guessing"]
path = examples/binary-guessing
url = https://github.com/luxfhe/example-binary-guessing.git
[submodule "examples/blind-auction"]
path = examples/blind-auction
url = https://github.com/luxfhe/example-blind-auction.git
[submodule "examples/blind-auction-v2"]
path = examples/blind-auction-v2
url = https://github.com/luxfhe/example-blind-auction-v2.git
[submodule "examples/confidential-contracts"]
path = examples/confidential-contracts
url = https://github.com/luxfhe/example-confidential-contracts.git
[submodule "examples/confidential-voting"]
path = examples/confidential-voting
url = https://github.com/luxfhe/example-confidential-voting.git
[submodule "examples/dapps"]
path = examples/dapps
url = https://github.com/luxfhe/example-dapps.git
[submodule "examples/demo-v2"]
path = examples/demo-v2
url = https://github.com/luxfhe/example-demo-v2.git
[submodule "examples/encrypto"]
path = examples/encrypto
url = https://github.com/luxfhe/example-encrypto.git
[submodule "examples/erc20-tutorial"]
path = examples/erc20-tutorial
url = https://github.com/luxfhe/example-erc20-tutorial.git
[submodule "examples/fhe-voting"]
path = examples/fhe-voting
url = https://github.com/luxfhe/example-fhe-voting.git
[submodule "examples/ios-demo"]
path = examples/ios-demo
url = https://github.com/luxfhe/example-ios-demo.git
[submodule "examples/kuhn-poker"]
path = examples/kuhn-poker
url = https://github.com/luxfhe/example-kuhn-poker.git
[submodule "examples/playground"]
path = examples/playground
url = https://github.com/luxfhe/example-playground.git
[submodule "examples/poker"]
path = examples/poker
url = https://github.com/luxfhe/example-poker.git
[submodule "examples/redact"]
path = examples/redact
url = https://github.com/luxfhe/example-redact.git
[submodule "examples/rng-game"]
path = examples/rng-game
url = https://github.com/luxfhe/example-rng-game.git
[submodule "examples/rps-game"]
path = examples/rps-game
url = https://github.com/luxfhe/example-rps-game.git
[submodule "examples/secret-santa"]
path = examples/secret-santa
url = https://github.com/luxfhe/example-secret-santa.git
[submodule "examples/smart-wallet"]
path = examples/smart-wallet
url = https://github.com/luxfhe/example-smart-wallet.git
[submodule "examples/ticket-manager"]
path = examples/ticket-manager
url = https://github.com/luxfhe/example-ticket-manager.git
[submodule "examples/ticketing"]
path = examples/ticketing
url = https://github.com/luxfhe/example-ticketing.git
[submodule "examples/tickets"]
path = examples/tickets
url = https://github.com/luxfhe/example-tickets.git
[submodule "examples/voting"]
path = examples/voting
url = https://github.com/luxfhe/example-voting.git
[submodule "wasm/sdk"]
path = wasm/sdk
url = https://github.com/luxfhe/wasm-sdk.git
-191
View File
@@ -1,191 +0,0 @@
# Lux FHE Repository Migration Plan
## Overview
Restructure `/Users/z/work/luxfhe` monorepo into separate top-level repos under `github.com/luxfhe/` organization.
## Current Structure -> Target Repos
| Current Directory | Target Repo | Package Name | Description |
|-------------------|-------------|--------------|-------------|
| `contracts/` | `luxfhe/contracts` | `@luxfhe/contracts` | Core FHE Solidity contracts |
| `js/v1-sdk/` | `luxfhe/v1-sdk` | `@luxfhe/v1-sdk` | Standard TFHE SDK (single-key) |
| `js/v2-sdk/` | `luxfhe/v2-sdk` | `@luxfhe/v2-sdk` | Threshold TFHE SDK (network) |
| `js/permit/` | `luxfhe/permit` | `@luxfhe/permit` | Permit signing utilities |
| `mocks/` | `luxfhe/mocks` | `@luxfhe/mocks` | Mock contracts for testing |
| `examples/` | `luxfhe/examples` | - | Example applications (monorepo) |
| `templates/` | `luxfhe/templates` | - | Project starter templates |
| `docs/` | `luxfhe/docs` | - | Documentation sites |
| `research/` | `luxfhe/research` | - | Research projects |
| `scaffold-eth/` | `luxfhe/scaffold-eth` | - | Scaffold-ETH integration |
| `wasm/` | `luxfhe/wasm-sdk` | `@luxfhe/wasm-sdk` | Rust WASM SDK |
| `proto/` | `luxfhe/proto` | - | Protocol buffer definitions |
| `plugins/hardhat/` | `luxfhe/hardhat-plugin` | `@luxfhe/hardhat-plugin` | Hardhat plugin (CoFHE) |
| `plugins/remix/` | `luxfhe/remix-plugin` | `@luxfhe/remix-plugin` | Remix IDE plugin |
| `hardhat-plugin/` | (merge into hardhat-plugin) | - | Duplicate hardhat plugin root |
| `sdk/fhe/` | `luxfhe/fhe-sdk` | `@luxfhe/fhe-sdk` | CoFHE SDK monorepo |
| `sdk/relayer/` | `luxfhe/relayer` | `@luxfhe/relayer` | Transaction relayer |
| `ml/` | `luxfhe/ml` | - | FHE ML extensions |
| `tests/` | (distribute to each repo) | - | E2E test suites |
## Dependency Graph
```
@luxfhe/contracts
|
+-------------+-------------+
| | |
@luxfhe/v1-sdk @luxfhe/v2-sdk @luxfhe/permit
| | |
+------+------+ |
| |
@luxfhe/hardhat-plugin -----+
|
@luxfhe/mocks
```
### Core Dependencies (shared)
1. **@luxfhe/contracts** (no internal deps)
- External: @openzeppelin/contracts, hardhat
2. **@luxfhe/v1-sdk** (no internal deps)
- External: ethers, node-tfhe, tfhe, node-tkms, tkms
3. **@luxfhe/v2-sdk** (no internal deps)
- External: ethers, node-tfhe, tfhe, zustand, zod
4. **@luxfhe/permit** (no internal deps)
- External: ethers, node-tfhe, tweetnacl
5. **@luxfhe/hardhat-plugin**
- Internal: @luxfhe/contracts (via peerDeps), @luxfhe/v1-sdk or v2-sdk
- External: hardhat, ethers
6. **@luxfhe/mocks**
- Internal: @luxfhe/contracts
- External: hardhat, foundry
## Package.json Changes Required
### 1. contracts/package.json
```diff
- "repository": { "url": "https://github.com/luxfhe/contracts.git" }
+ "repository": { "url": "https://github.com/luxfhe/contracts.git" }
// Already correct
```
### 2. js/v1-sdk/package.json
```diff
- "repository": { "url": "git+https://github.com/luxfhe/v1-sdk.git" }
+ "repository": { "url": "https://github.com/luxfhe/v1-sdk.git" }
// Minor URL normalization
```
### 3. js/v2-sdk/package.json
```diff
// Already correctly configured for standalone repo
```
### 4. js/permit/package.json
```diff
- "name": "fhe-permit"
+ "name": "@luxfhe/permit"
- "repository": { "url": "git+https://github.com/luxfheProtocol/fhe.git" }
+ "repository": { "url": "https://github.com/luxfhe/permit.git" }
```
### 5. plugins/hardhat/package.json
```diff
- "name": "fhe-hardhat-plugin"
+ "name": "@luxfhe/hardhat-plugin"
- "repository": "github:luxfheProtocol/fhe-hardhat-plugin"
+ "repository": { "url": "https://github.com/luxfhe/hardhat-plugin.git" }
- "@luxfhe/fhe-contracts": "0.0.13"
+ "@luxfhe/contracts": "^0.5.0"
- "@luxfhe/fhe-mock-contracts": "^0.3.0"
+ "@luxfhe/mocks": "^0.5.0"
```
### 6. proto/decryption-oracle/go.mod
```diff
- module github.com/fhenixprotocol/decryption-oracle-proto
+ module github.com/luxfhe/proto
```
## Import Path Changes
### Solidity Imports
```diff
- import "@fhenixprotocol/contracts/FHE.sol";
+ import "@luxfhe/contracts/FHE.sol";
- import "fhe/contracts/...";
+ import "@luxfhe/contracts/...";
```
### JavaScript/TypeScript Imports
```diff
- import { ... } from "fhe";
+ import { ... } from "@luxfhe/v2-sdk";
- import { ... } from "@fhenixprotocol/v1-sdk";
+ import { ... } from "@luxfhe/v1-sdk";
- import { ... } from "fhe-permit";
+ import { ... } from "@luxfhe/permit";
```
### Go Imports
```diff
- import "github.com/fhenixprotocol/decryption-oracle-proto"
+ import "github.com/luxfhe/proto"
```
## Migration Order (Dependency-Aware)
1. **Phase 1 - Core (no internal deps)**
- contracts
- v1-sdk
- v2-sdk
- permit
- proto
- wasm-sdk
2. **Phase 2 - Dependent packages**
- mocks (depends on contracts)
- hardhat-plugin (depends on contracts, sdk)
- remix-plugin
3. **Phase 3 - Applications**
- examples
- templates
- scaffold-eth
- docs
4. **Phase 4 - Research/Internal**
- research
- ml
- fhe-sdk
- relayer
## Files to Create in Each Repo
Each new repo needs:
- `README.md` - Project-specific documentation
- `LICENSE` - BSD-3-Clause or MIT (match current)
- `.gitignore` - Language-appropriate ignores
- `CHANGELOG.md` - Version history
- `.github/workflows/` - CI/CD pipelines (optional, add later)
## Notes
1. **hardhat-plugin/ vs plugins/hardhat/**: These appear to be duplicates. Merge into single `luxfhe/hardhat-plugin`.
2. **sdk/fhe/**: This is a Turborepo monorepo with multiple packages. Consider whether to flatten or keep as monorepo.
3. **tests/**: Distribute e2e tests to relevant repos rather than keeping separate.
4. **Git History**: Use `git filter-repo` or `git subtree split` to preserve commit history if important.
5. **NPM Publishing**: All `@luxfhe/*` packages should use `publishConfig.access: "public"`.
BIN
View File
Binary file not shown.
-1556
View File
File diff suppressed because it is too large Load Diff
-17
View File
@@ -1,17 +0,0 @@
{
"name": "@luxfhe/e2e",
"version": "1.0.0",
"private": true,
"description": "LuxFHE End-to-End Tests",
"type": "module",
"scripts": {
"test": "vitest run",
"test:watch": "vitest",
"test:server": "./scripts/start-server.sh & sleep 2 && npm test; kill %1",
"start:server": "cd ~/work/lux/tfhe && ./bin/fhe-server -addr :8448"
},
"devDependencies": {
"vitest": "^3.2.3",
"typescript": "^5.9.0"
}
}
-17
View File
@@ -1,17 +0,0 @@
#!/bin/bash
# Start FHE server for e2e tests
set -e
TFHE_DIR="$HOME/work/lux/tfhe"
FHE_SERVER="$TFHE_DIR/bin/fhe-server"
# Build if needed
if [ ! -f "$FHE_SERVER" ]; then
echo "Building FHE server..."
cd "$TFHE_DIR"
go build -o bin/fhe-server ./cmd/fhe-server/
fi
echo "Starting FHE server on :8448..."
exec "$FHE_SERVER" -addr :8448
-191
View File
@@ -1,191 +0,0 @@
/**
* LuxFHE End-to-End Tests
*
* Tests the full FHE stack:
* 1. Go TFHE server (http://localhost:8448)
* 2. WASM bindings (@luxfhe/wasm-node)
* 3. KMS client (@luxfhe/kms-node)
*
* Prerequisites:
* cd ~/work/lux/tfhe && ./bin/fhe-server -addr :8448
*/
import { describe, it, expect, beforeAll } from 'vitest';
const FHE_SERVER_URL = process.env.FHE_SERVER_URL || 'http://localhost:8448';
describe('LuxFHE E2E Tests', () => {
beforeAll(async () => {
// Check if server is running
try {
const res = await fetch(`${FHE_SERVER_URL}/health`);
if (!res.ok) throw new Error('Server not healthy');
} catch (e) {
console.error('FHE server not running. Start with:');
console.error(' cd ~/work/lux/tfhe && ./bin/fhe-server');
throw e;
}
});
describe('Health Check', () => {
it('should return healthy status', async () => {
const res = await fetch(`${FHE_SERVER_URL}/health`);
expect(res.ok).toBe(true);
const data = await res.json();
expect(data.status).toBe('ok');
});
});
describe('Public Key', () => {
it('should return a valid public key', async () => {
const res = await fetch(`${FHE_SERVER_URL}/publickey`);
expect(res.ok).toBe(true);
const buffer = await res.arrayBuffer();
expect(buffer.byteLength).toBeGreaterThan(0);
console.log(` Public key size: ${buffer.byteLength} bytes`);
});
});
describe('Encryption', () => {
it('should encrypt a 32-bit integer', async () => {
const value = 42;
const res = await fetch(`${FHE_SERVER_URL}/encrypt`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ value, bitWidth: 32 }),
});
expect(res.ok).toBe(true);
const buffer = await res.arrayBuffer();
expect(buffer.byteLength).toBeGreaterThan(0);
console.log(` Encrypted ${value} -> ${buffer.byteLength} bytes`);
});
it('should encrypt different bit widths', async () => {
const bitWidths = [8, 16, 32, 64];
for (const bitWidth of bitWidths) {
const value = 123;
const res = await fetch(`${FHE_SERVER_URL}/encrypt`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ value, bitWidth }),
});
expect(res.ok).toBe(true);
const buffer = await res.arrayBuffer();
console.log(` FheUint${bitWidth}: ${buffer.byteLength} bytes`);
}
});
});
describe('FHE Operations', () => {
let encA: Uint8Array;
let encB: Uint8Array;
beforeAll(async () => {
// Encrypt two values
const resA = await fetch(`${FHE_SERVER_URL}/encrypt`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ value: 42, bitWidth: 32 }),
});
encA = new Uint8Array(await resA.arrayBuffer());
const resB = await fetch(`${FHE_SERVER_URL}/encrypt`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ value: 17, bitWidth: 32 }),
});
encB = new Uint8Array(await resB.arrayBuffer());
});
it('should add two encrypted values', async () => {
const res = await fetch(`${FHE_SERVER_URL}/evaluate`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
op: 'add',
left: Array.from(encA),
right: Array.from(encB),
bitWidth: 32,
}),
});
expect(res.ok).toBe(true);
const buffer = await res.arrayBuffer();
expect(buffer.byteLength).toBeGreaterThan(0);
console.log(` add(42, 17) = encrypted (${buffer.byteLength} bytes)`);
});
it('should subtract two encrypted values', async () => {
const res = await fetch(`${FHE_SERVER_URL}/evaluate`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
op: 'sub',
left: Array.from(encA),
right: Array.from(encB),
bitWidth: 32,
}),
});
expect(res.ok).toBe(true);
const buffer = await res.arrayBuffer();
expect(buffer.byteLength).toBeGreaterThan(0);
console.log(` sub(42, 17) = encrypted (${buffer.byteLength} bytes)`);
});
it('should compare two encrypted values (lt)', async () => {
const res = await fetch(`${FHE_SERVER_URL}/evaluate`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
op: 'lt',
left: Array.from(encA),
right: Array.from(encB),
bitWidth: 32,
}),
});
expect(res.ok).toBe(true);
const buffer = await res.arrayBuffer();
expect(buffer.byteLength).toBeGreaterThan(0);
console.log(` lt(42, 17) = encrypted bool (${buffer.byteLength} bytes)`);
});
it('should compare two encrypted values (eq)', async () => {
const res = await fetch(`${FHE_SERVER_URL}/evaluate`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
op: 'eq',
left: Array.from(encA),
right: Array.from(encA), // Same value
bitWidth: 32,
}),
});
expect(res.ok).toBe(true);
const buffer = await res.arrayBuffer();
expect(buffer.byteLength).toBeGreaterThan(0);
console.log(` eq(42, 42) = encrypted bool (${buffer.byteLength} bytes)`);
});
});
describe('ZK Verification', () => {
it('should verify a computation proof', async () => {
const res = await fetch(`${FHE_SERVER_URL}/verify`, {
method: 'POST',
headers: { 'Content-Type': 'application/octet-stream' },
body: new Uint8Array([1, 2, 3]), // Placeholder proof
});
expect(res.ok).toBe(true);
const data = await res.json();
expect(data.verified).toBe(true);
});
});
});
-9
View File
@@ -1,9 +0,0 @@
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
include: ['test/**/*.test.ts'],
testTimeout: 30000,
hookTimeout: 30000,
},
});
Submodule examples/dapps deleted from 7edfc0771d
-21
View File
@@ -1,21 +0,0 @@
{
"name": "@luxfhe/e2e-tests",
"version": "1.0.0",
"description": "End-to-end Playwright tests for LuxFHE web3 examples",
"type": "module",
"scripts": {
"test": "playwright test",
"test:ui": "playwright test --ui",
"test:headed": "playwright test --headed",
"test:debug": "playwright test --debug",
"report": "playwright show-report"
},
"devDependencies": {
"@playwright/test": "^1.40.0",
"@types/node": "^20.10.0",
"typescript": "^5.3.0"
},
"dependencies": {
"ethers": "^6.11.0"
}
}
-22
View File
@@ -1,22 +0,0 @@
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests',
fullyParallel: false, // Run tests serially since we're starting servers
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: 1, // One worker since we're managing server lifecycle
reporter: [['html'], ['list']],
timeout: 120000, // 2 minutes per test - FHE operations are slow
use: {
trace: 'on-first-retry',
screenshot: 'only-on-failure',
video: 'retain-on-failure',
},
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
],
});
-174
View File
@@ -1,174 +0,0 @@
import { spawn, ChildProcess } from 'child_process';
import { Page } from '@playwright/test';
export interface FrontendConfig {
name: string;
path: string;
command: string;
port: number;
waitForText?: string;
env?: Record<string, string>;
}
export const frontends: Record<string, FrontendConfig> = {
'blind-auction-v2': {
name: 'Blind Auction V2',
path: '/Users/z/work/luxfhe/examples/blind-auction-v2/frontend',
command: 'pnpm dev',
port: 3000,
waitForText: 'Nuxt',
},
'blind-auction': {
name: 'Blind Auction',
path: '/Users/z/work/luxfhe/examples/blind-auction/frontend',
command: 'pnpm dev',
port: 3001,
waitForText: 'Nuxt',
},
'playground': {
name: 'Playground',
path: '/Users/z/work/luxfhe/examples/playground/frontend',
command: 'npm start',
port: 3002,
waitForText: 'react',
env: { PORT: '3002' },
},
'erc20-tutorial': {
name: 'ERC20 Tutorial',
path: '/Users/z/work/luxfhe/examples/erc20-tutorial/frontend',
command: 'npm start',
port: 3003,
waitForText: 'react',
env: { PORT: '3003' },
},
'poker': {
name: 'Poker',
path: '/Users/z/work/luxfhe/examples/poker/packages/frontend',
command: 'pnpm dev',
port: 3004,
waitForText: 'Next',
env: { PORT: '3004' },
},
'kuhn-poker': {
name: 'Kuhn Poker',
path: '/Users/z/work/luxfhe/examples/kuhn-poker/packages/frontend',
command: 'pnpm dev',
port: 3005,
waitForText: 'Next',
env: { PORT: '3005' },
},
};
let runningProcesses: Map<string, ChildProcess> = new Map();
export async function startFrontend(config: FrontendConfig): Promise<void> {
return new Promise((resolve, reject) => {
const [cmd, ...args] = config.command.split(' ');
const env = { ...process.env, ...config.env };
console.log(`Starting ${config.name} on port ${config.port}...`);
const proc = spawn(cmd, args, {
cwd: config.path,
env,
stdio: 'pipe',
shell: true,
});
runningProcesses.set(config.name, proc);
let started = false;
const timeout = setTimeout(() => {
if (!started) {
console.log(`${config.name} started (timeout reached)`);
started = true;
resolve();
}
}, 30000);
proc.stdout?.on('data', (data) => {
const output = data.toString();
if (!started && (output.includes('localhost') || output.includes('ready') || output.includes('started'))) {
console.log(`${config.name} ready on port ${config.port}`);
started = true;
clearTimeout(timeout);
setTimeout(resolve, 2000); // Wait 2s for server to stabilize
}
});
proc.stderr?.on('data', (data) => {
const output = data.toString();
// Many frameworks output to stderr for status
if (!started && (output.includes('localhost') || output.includes('ready'))) {
console.log(`${config.name} ready on port ${config.port}`);
started = true;
clearTimeout(timeout);
setTimeout(resolve, 2000);
}
});
proc.on('error', (err) => {
clearTimeout(timeout);
reject(err);
});
proc.on('exit', (code) => {
if (!started && code !== 0) {
clearTimeout(timeout);
reject(new Error(`${config.name} exited with code ${code}`));
}
});
});
}
export function stopFrontend(name: string): void {
const proc = runningProcesses.get(name);
if (proc) {
console.log(`Stopping ${name}...`);
proc.kill('SIGTERM');
runningProcesses.delete(name);
}
}
export function stopAllFrontends(): void {
for (const [name, proc] of runningProcesses) {
console.log(`Stopping ${name}...`);
proc.kill('SIGTERM');
}
runningProcesses.clear();
}
// Wait for page to be interactive
export async function waitForApp(page: Page, timeout = 30000): Promise<void> {
await page.waitForLoadState('domcontentloaded', { timeout });
await page.waitForLoadState('networkidle', { timeout }).catch(() => {
// Network idle may not happen with web3 apps
});
}
// Check if MetaMask or wallet connection is required
export async function hasWalletPrompt(page: Page): Promise<boolean> {
const walletPrompts = [
'Connect Wallet',
'Connect wallet',
'connect wallet',
'MetaMask',
'metamask',
'WalletConnect',
'Connect to',
];
const content = await page.content();
return walletPrompts.some(prompt => content.includes(prompt));
}
// Check FHE server health
export async function checkFHEServer(): Promise<boolean> {
try {
const response = await fetch('http://localhost:8448/health');
const data = await response.json();
return data.status === 'ok';
} catch {
return false;
}
}
@@ -1,239 +0,0 @@
import { test, expect } from '@playwright/test';
import {
frontends,
startFrontend,
stopFrontend,
stopAllFrontends,
waitForApp,
hasWalletPrompt,
checkFHEServer,
FrontendConfig
} from './helpers';
test.describe('LuxFHE Web3 Examples', () => {
test.beforeAll(async () => {
// Verify FHE server is running
const fheHealthy = await checkFHEServer();
if (!fheHealthy) {
throw new Error('FHE Server not running on localhost:8448. Start it with: cd ~/work/lux/tfhe && ./bin/fhe-server');
}
console.log('✓ FHE Server is healthy');
});
test.afterAll(async () => {
stopAllFrontends();
});
test.describe('blind-auction-v2 (Nuxt.js)', () => {
const config = frontends['blind-auction-v2'];
test.beforeAll(async () => {
await startFrontend(config);
});
test.afterAll(async () => {
stopFrontend(config.name);
});
test('loads homepage', async ({ page }) => {
await page.goto(`http://localhost:${config.port}`);
await waitForApp(page);
// Check page loaded
const title = await page.title();
expect(title).toBeTruthy();
console.log(` Page title: ${title}`);
// Check for wallet connection UI
const needsWallet = await hasWalletPrompt(page);
console.log(` Requires wallet: ${needsWallet}`);
// Take screenshot
await page.screenshot({ path: `screenshots/blind-auction-v2-home.png` });
});
test('has FHE-related UI elements', async ({ page }) => {
await page.goto(`http://localhost:${config.port}`);
await waitForApp(page);
const content = await page.content();
const hasFHETerms =
content.includes('encrypt') ||
content.includes('Encrypt') ||
content.includes('FHE') ||
content.includes('bid') ||
content.includes('Bid') ||
content.includes('auction') ||
content.includes('Auction');
expect(hasFHETerms).toBe(true);
console.log(' ✓ Found FHE/auction-related content');
});
});
test.describe('blind-auction (Nuxt.js)', () => {
const config = frontends['blind-auction'];
test.beforeAll(async () => {
await startFrontend(config);
});
test.afterAll(async () => {
stopFrontend(config.name);
});
test('loads homepage', async ({ page }) => {
await page.goto(`http://localhost:${config.port}`);
await waitForApp(page);
const title = await page.title();
expect(title).toBeTruthy();
console.log(` Page title: ${title}`);
await page.screenshot({ path: `screenshots/blind-auction-home.png` });
});
});
test.describe('playground (React)', () => {
const config = frontends['playground'];
test.beforeAll(async () => {
await startFrontend(config);
});
test.afterAll(async () => {
stopFrontend(config.name);
});
test('loads homepage', async ({ page }) => {
await page.goto(`http://localhost:${config.port}`);
await waitForApp(page);
const title = await page.title();
expect(title).toBeTruthy();
console.log(` Page title: ${title}`);
await page.screenshot({ path: `screenshots/playground-home.png` });
});
test('has FHE functionality', async ({ page }) => {
await page.goto(`http://localhost:${config.port}`);
await waitForApp(page);
const content = await page.content();
const hasFHETerms =
content.includes('encrypt') ||
content.includes('Encrypt') ||
content.includes('FHE') ||
content.includes('FHERC20') ||
content.includes('Token');
console.log(` Has FHE terms: ${hasFHETerms}`);
});
});
test.describe('erc20-tutorial (React)', () => {
const config = frontends['erc20-tutorial'];
test.beforeAll(async () => {
await startFrontend(config);
});
test.afterAll(async () => {
stopFrontend(config.name);
});
test('loads homepage', async ({ page }) => {
await page.goto(`http://localhost:${config.port}`);
await waitForApp(page);
const title = await page.title();
expect(title).toBeTruthy();
console.log(` Page title: ${title}`);
await page.screenshot({ path: `screenshots/erc20-tutorial-home.png` });
});
test('shows ERC20 UI', async ({ page }) => {
await page.goto(`http://localhost:${config.port}`);
await waitForApp(page);
const content = await page.content();
const hasERC20 =
content.includes('ERC20') ||
content.includes('token') ||
content.includes('Token') ||
content.includes('balance') ||
content.includes('Balance') ||
content.includes('transfer') ||
content.includes('Transfer');
console.log(` Has ERC20 terms: ${hasERC20}`);
});
});
test.describe('poker (Next.js)', () => {
const config = frontends['poker'];
test.beforeAll(async () => {
await startFrontend(config);
});
test.afterAll(async () => {
stopFrontend(config.name);
});
test('loads homepage', async ({ page }) => {
await page.goto(`http://localhost:${config.port}`);
await waitForApp(page);
const title = await page.title();
expect(title).toBeTruthy();
console.log(` Page title: ${title}`);
await page.screenshot({ path: `screenshots/poker-home.png` });
});
test('has poker UI elements', async ({ page }) => {
await page.goto(`http://localhost:${config.port}`);
await waitForApp(page);
const content = await page.content();
const hasPoker =
content.includes('poker') ||
content.includes('Poker') ||
content.includes('card') ||
content.includes('Card') ||
content.includes('bet') ||
content.includes('Bet') ||
content.includes('fold') ||
content.includes('Fold');
console.log(` Has poker terms: ${hasPoker}`);
});
});
test.describe('kuhn-poker (Next.js)', () => {
const config = frontends['kuhn-poker'];
test.beforeAll(async () => {
await startFrontend(config);
});
test.afterAll(async () => {
stopFrontend(config.name);
});
test('loads homepage', async ({ page }) => {
await page.goto(`http://localhost:${config.port}`);
await waitForApp(page);
const title = await page.title();
expect(title).toBeTruthy();
console.log(` Page title: ${title}`);
await page.screenshot({ path: `screenshots/kuhn-poker-home.png` });
});
});
});
-17
View File
@@ -1,17 +0,0 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"declaration": true,
"declarationMap": true,
"outDir": "./dist"
},
"include": ["tests/**/*"],
"exclude": ["node_modules"]
}
Submodule examples/poker deleted from a4c965c614
Submodule examples/redact deleted from 9c23f239ee
Submodule examples/voting deleted from edbb4f4d93
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+7
View File
@@ -22,6 +22,7 @@ github.com/luxfi/lattice/v7 v7.0.0 h1:d1vgan6mlb2KtwYfPc1g69uxVYaoVYZmlrIm4aCO88
github.com/luxfi/lattice/v7 v7.0.0/go.mod h1:PFDdOkuGTQ0cbJMbKojzEJMGWUQmZW+wK9/wJ9F9fOs=
github.com/miekg/dns v1.1.27/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
github.com/miekg/dns v1.1.66 h1:FeZXOS3VCVsKnEAd+wBkjMC3D2K+ww66Cq3VnCINuJE=
github.com/miekg/dns v1.1.66/go.mod h1:jGFzBsSNbJw6z1HYut1RKBKHA9PBdxeHrZG8J+gC2WE=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -37,14 +38,18 @@ github.com/urfave/cli/v3 v3.6.2/go.mod h1:ysVLtOEmg2tOy6PknnYVhDoouyC/6N42TMeoMz
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8=
golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A=
golang.org/x/exp v0.0.0-20260112195511-716be5621a96 h1:Z/6YuSHTLOHfNFdb8zVZomZr7cqNgTJvA8+Qz75D8gU=
golang.org/x/exp v0.0.0-20260112195511-716be5621a96/go.mod h1:nzimsREAkjBCIEFtHiYkrJyT+2uy9YZJB7H1k68CXZU=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c=
golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
@@ -52,9 +57,11 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc=
golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
Submodule js/permit deleted from 870c41793a
Submodule js/v1-sdk deleted from 0c8f695543
Submodule js/v2-sdk deleted from 536fae791b
-132
View File
@@ -1,132 +0,0 @@
# LuxFHE Local Development
This directory contains tools for running LuxFHE locally for development.
## Quick Start (Recommended)
### Option 1: Using `lux dev` (Native)
The fastest way to get started - runs natively without Docker:
```bash
# 1. Start the local development environment
./start-local.sh
# 2. Run tests in any example
cd ../examples/blind-auction
npm install
npm run test
```
This starts:
- **Lux dev node** on port 8545 (C-Chain RPC)
- **FHE server** on port 8448
### Option 2: Using Docker Compose
For a more isolated environment:
```bash
# Start FHE server + Anvil for contracts
docker compose --profile contracts up -d
# Or for threshold mode (multi-party FHE)
docker compose --profile threshold up -d
```
## Services
| Service | Port | Description |
|---------|------|-------------|
| C-Chain RPC | 8545 | EVM JSON-RPC endpoint |
| C-Chain WS | 8546 | WebSocket endpoint |
| FHE Server | 8448 | FHE encryption/decryption |
| Faucet | 42069 | Test token faucet |
## FHE Precompile Addresses
| Precompile | Address |
|------------|---------|
| FHEOS | `0x0200000000000000000000000000000000000080` |
| ACL | `0x0200000000000000000000000000000000000081` |
| Verifier | `0x0200000000000000000000000000000000000082` |
| Gateway | `0x0200000000000000000000000000000000000083` |
## Example Hardhat Configuration
```typescript
// hardhat.config.ts
import "@luxfhe/hardhat-plugin";
const config: HardhatUserConfig = {
solidity: "0.8.31",
defaultNetwork: "localluxfhe",
networks: {
localluxfhe: {
url: "http://localhost:8545/ext/bc/C/rpc",
chainId: 1337,
accounts: {
mnemonic: "test test test test test test test test test test test junk",
},
},
},
luxfhePlugin: {
fheServerUrl: "http://localhost:8448",
autoFaucet: true,
},
};
```
## Commands
```bash
# Start all services
./start-local.sh
# Start only node
./start-local.sh --node
# Start only FHE server
./start-local.sh --fhe
# Stop all services
./start-local.sh --stop
```
## Logs
Logs are stored in `~/.lux/dev/logs/`:
- `lux-dev.log` - Lux node logs
- `fhe-server.log` - FHE server logs
## Troubleshooting
### FHE server not starting
```bash
# Check if FHE server is built
ls ~/work/luxcpp/fhe/server/build/bin/fhe_server
# If not, build it:
cd ~/work/luxcpp/fhe
mkdir -p build && cd build
cmake .. && make
```
### Node not starting
```bash
# Check if lux CLI is installed
which lux
# Install if missing:
go install github.com/luxfi/cli@latest
```
### Port already in use
```bash
# Check what's using the port
lsof -i :8545
lsof -i :8448
# Kill the process or use different ports:
NODE_PORT=9650 FHE_PORT=8449 ./start-local.sh
```
-95
View File
@@ -1,95 +0,0 @@
/**
* LuxFHE Local Demo
*
* Demonstrates v1-sdk and v2-sdk connecting to local Go TFHE server
*
* Usage:
* npx ts-node demo.ts
*/
import { LuxFHEClient, FheUintType } from '../js/v1-sdk/src/luxd/client';
const FHE_SERVER_URL = process.env.FHE_SERVER_URL || 'http://localhost:8448';
async function main() {
console.log('🔐 LuxFHE Local Demo\n');
console.log(`Connecting to FHE server: ${FHE_SERVER_URL}\n`);
// Create client
const client = new LuxFHEClient({
serverUrl: FHE_SERVER_URL,
thresholdMode: false,
});
// Check health
console.log('1. Checking server health...');
try {
const health = await client.health();
console.log(` ✓ Status: ${health.status}`);
console.log(` ✓ Threshold mode: ${health.threshold}`);
console.log(` ✓ Parties: ${health.parties}\n`);
} catch (e) {
console.error(' ✗ Server not reachable. Make sure to run:');
console.error(' cd ~/work/lux/tfhe && ./bin/fhe-server\n');
process.exit(1);
}
// Get public key
console.log('2. Fetching public key...');
const pk = await client.getPublicKey();
console.log(` ✓ Public key: ${pk.length} bytes\n`);
// Encrypt values
console.log('3. Encrypting values...');
const a = 42;
const b = 17;
const encA = await client.encrypt({ value: a, bitWidth: 32 });
console.log(` ✓ Encrypted ${a}: ${encA.length} bytes`);
const encB = await client.encrypt({ value: b, bitWidth: 32 });
console.log(` ✓ Encrypted ${b}: ${encB.length} bytes\n`);
// Evaluate FHE operations
console.log('4. Evaluating FHE operations...');
// Add
const encSum = await client.evaluate({
op: 'add',
left: encA,
right: encB,
bitWidth: 32,
});
console.log(` ✓ add(${a}, ${b}) = encrypted result (${encSum.length} bytes)`);
// Subtract
const encDiff = await client.evaluate({
op: 'sub',
left: encA,
right: encB,
bitWidth: 32,
});
console.log(` ✓ sub(${a}, ${b}) = encrypted result (${encDiff.length} bytes)`);
// Compare
const encLt = await client.evaluate({
op: 'lt',
left: encA,
right: encB,
bitWidth: 32,
});
console.log(` ✓ lt(${a}, ${b}) = encrypted result (${encLt.length} bytes)\n`);
// Verify computation
console.log('5. Verifying computation...');
const verified = await client.verify(encSum);
console.log(` ✓ ZK verification: ${verified}\n`);
console.log('✅ Demo complete!\n');
console.log('Expected results (if decrypted):');
console.log(` add(${a}, ${b}) = ${a + b}`);
console.log(` sub(${a}, ${b}) = ${a - b}`);
console.log(` lt(${a}, ${b}) = ${a < b}`);
}
main().catch(console.error);
-87
View File
@@ -1,87 +0,0 @@
version: "3.8"
name: luxfhe
services:
# Lux FHE Server - Standard Mode
fhe-server:
image: ghcr.io/luxfi/fhe/server:latest
container_name: luxfhe-server
ports:
- "8448:8448"
environment:
- THRESHOLD_MODE=false
volumes:
- fhe-data:/app/data
healthcheck:
test: ["CMD", "wget", "-q", "-O", "-", "http://localhost:8448/health"]
interval: 10s
timeout: 5s
retries: 5
start_period: 5s
# FHE Server - Threshold Mode (for confidential governance)
fhe-threshold:
image: ghcr.io/luxfi/fhe/server:latest
container_name: luxfhe-threshold
ports:
- "8449:8449"
command: ["-addr", ":8449", "-threshold", "-parties", "5"]
volumes:
- fhe-threshold-data:/app/data
healthcheck:
test: ["CMD", "wget", "-q", "-O", "-", "http://localhost:8449/health"]
interval: 10s
timeout: 5s
retries: 5
profiles:
- threshold
# FHE Coprocessor Worker (for heavy FHE operations)
fhe-worker:
image: ghcr.io/luxfi/fhe/worker:latest
environment:
- REDIS_URL=redis://redis:6379
- WORKER_COUNT=4
depends_on:
- redis
profiles:
- coprocessor
# FHE Gateway (blockchain event listener)
fhe-gateway:
image: ghcr.io/luxfi/fhe/gateway:latest
environment:
- REDIS_URL=redis://redis:6379
- RPC_URL=${RPC_URL:-http://host.docker.internal:8545}
depends_on:
- redis
profiles:
- coprocessor
# Redis for coprocessor job queue
redis:
image: redis:7-alpine
container_name: luxfhe-redis
ports:
- "6379:6379"
volumes:
- redis-data:/data
profiles:
- coprocessor
# Anvil for local contract testing
anvil:
image: ghcr.io/foundry-rs/foundry:latest
container_name: luxfhe-anvil
entrypoint: ["anvil"]
command: ["--host", "0.0.0.0", "--chain-id", "96369"]
ports:
- "8545:8545"
profiles:
- contracts
volumes:
fhe-data:
fhe-threshold-data:
redis-data:
-174
View File
@@ -1,174 +0,0 @@
#!/bin/bash
# LuxFHE Local Development - Start Script
# Starts lux dev node + FHE server for local development
#
# Requirements:
# - lux CLI installed (brew install lux or go install github.com/luxfi/cli@latest)
# - FHE server binary at ~/work/luxcpp/fhe/bin/fhe-server-cpp
#
# Usage:
# ./start-local.sh # Start both services
# ./start-local.sh --node # Start node only
# ./start-local.sh --fhe # Start FHE server only
# ./start-local.sh --stop # Stop all services
set -e
# Configuration
NODE_PORT=${NODE_PORT:-8545}
FHE_PORT=${FHE_PORT:-8448}
FAUCET_PORT=${FAUCET_PORT:-42069}
FHE_SERVER_BIN="${FHE_SERVER_BIN:-$HOME/work/luxcpp/fhe/server/build/bin/fhe_server}"
FHE_SERVER_ALT="$HOME/work/luxcpp/fhe/bin/fhe-server-cpp"
LUX_CLI="${LUX_CLI:-lux}"
PID_DIR="$HOME/.lux/dev/pids"
LOG_DIR="$HOME/.lux/dev/logs"
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
mkdir -p "$PID_DIR" "$LOG_DIR"
log() {
echo -e "${GREEN}[luxfhe]${NC} $1"
}
warn() {
echo -e "${YELLOW}[luxfhe]${NC} $1"
}
error() {
echo -e "${RED}[luxfhe]${NC} $1"
exit 1
}
find_fhe_server() {
if [ -f "$FHE_SERVER_BIN" ]; then
echo "$FHE_SERVER_BIN"
elif [ -f "$FHE_SERVER_ALT" ]; then
echo "$FHE_SERVER_ALT"
else
error "FHE server binary not found. Build with: cd ~/work/luxcpp/fhe && mkdir -p build && cd build && cmake .. && make"
fi
}
start_fhe_server() {
if pgrep -f "fhe.*server.*:$FHE_PORT" > /dev/null; then
warn "FHE server already running on port $FHE_PORT"
return
fi
local fhe_bin=$(find_fhe_server)
log "Starting FHE server on port $FHE_PORT..."
nohup "$fhe_bin" -addr ":$FHE_PORT" > "$LOG_DIR/fhe-server.log" 2>&1 &
echo $! > "$PID_DIR/fhe-server.pid"
# Wait for health
for i in {1..30}; do
if curl -s "http://localhost:$FHE_PORT/health" > /dev/null 2>&1; then
log "FHE server started successfully (PID: $(cat $PID_DIR/fhe-server.pid))"
return
fi
sleep 1
done
error "FHE server failed to start"
}
start_node() {
if lsof -i :$NODE_PORT > /dev/null 2>&1; then
warn "Node already running on port $NODE_PORT"
return
fi
log "Starting Lux dev node on port $NODE_PORT..."
log "Run: $LUX_CLI dev start --port $NODE_PORT"
# Start lux dev in background
nohup "$LUX_CLI" dev start --port "$NODE_PORT" > "$LOG_DIR/lux-dev.log" 2>&1 &
echo $! > "$PID_DIR/lux-dev.pid"
# Wait for health
for i in {1..60}; do
if curl -s "http://localhost:$NODE_PORT/ext/health" > /dev/null 2>&1; then
log "Lux dev node started (PID: $(cat $PID_DIR/lux-dev.pid))"
return
fi
sleep 1
done
error "Lux dev node failed to start"
}
stop_services() {
log "Stopping services..."
if [ -f "$PID_DIR/fhe-server.pid" ]; then
local pid=$(cat "$PID_DIR/fhe-server.pid")
if kill -0 "$pid" 2>/dev/null; then
kill "$pid" && log "FHE server stopped"
fi
rm -f "$PID_DIR/fhe-server.pid"
fi
# Also try to kill by port
pkill -f "fhe.*server.*:$FHE_PORT" 2>/dev/null || true
if [ -f "$PID_DIR/lux-dev.pid" ]; then
local pid=$(cat "$PID_DIR/lux-dev.pid")
if kill -0 "$pid" 2>/dev/null; then
kill "$pid" && log "Lux dev node stopped"
fi
rm -f "$PID_DIR/lux-dev.pid"
fi
# Also run lux dev stop
"$LUX_CLI" dev stop 2>/dev/null || true
log "All services stopped"
}
print_status() {
echo ""
echo -e "${BLUE}╔══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${BLUE}${NC} LuxFHE Local Development ${BLUE}${NC}"
echo -e "${BLUE}╠══════════════════════════════════════════════════════════════╣${NC}"
echo -e "${BLUE}${NC} ${BLUE}${NC}"
echo -e "${BLUE}${NC} ${GREEN}C-Chain RPC:${NC} http://localhost:$NODE_PORT/ext/bc/C/rpc ${BLUE}${NC}"
echo -e "${BLUE}${NC} ${GREEN}C-Chain WS:${NC} ws://localhost:$NODE_PORT/ext/bc/C/ws ${BLUE}${NC}"
echo -e "${BLUE}${NC} ${GREEN}FHE Server:${NC} http://localhost:$FHE_PORT ${BLUE}${NC}"
echo -e "${BLUE}${NC} ${GREEN}Chain ID:${NC} 1337 ${BLUE}${NC}"
echo -e "${BLUE}${NC} ${BLUE}${NC}"
echo -e "${BLUE}${NC} ${YELLOW}FHE Precompiles:${NC} ${BLUE}${NC}"
echo -e "${BLUE}${NC} FHEOS: 0x0200000000000000000000000000000000000080 ${BLUE}${NC}"
echo -e "${BLUE}${NC} ACL: 0x0200000000000000000000000000000000000081 ${BLUE}${NC}"
echo -e "${BLUE}${NC} Verifier: 0x0200000000000000000000000000000000000082 ${BLUE}${NC}"
echo -e "${BLUE}${NC} Gateway: 0x0200000000000000000000000000000000000083 ${BLUE}${NC}"
echo -e "${BLUE}${NC} ${BLUE}${NC}"
echo -e "${BLUE}${NC} ${YELLOW}Logs:${NC} ~/.lux/dev/logs/ ${BLUE}${NC}"
echo -e "${BLUE}${NC} ${YELLOW}Stop:${NC} ./start-local.sh --stop ${BLUE}${NC}"
echo -e "${BLUE}${NC} ${BLUE}${NC}"
echo -e "${BLUE}╚══════════════════════════════════════════════════════════════╝${NC}"
echo ""
}
# Main
case "${1:-}" in
--stop)
stop_services
;;
--node)
start_node
;;
--fhe)
start_fhe_server
;;
*)
log "Starting LuxFHE local development environment..."
start_fhe_server
start_node
print_status
;;
esac
-94
View File
@@ -1,94 +0,0 @@
#!/bin/bash
# LuxFHE Local Development Starter
#
# This script uses the main FHE repo's compose.yml
# All components are built from: ~/work/lux/fhe
#
# Usage:
# ./start.sh - Start FHE server (Docker)
# ./start.sh threshold - Start threshold mode
# ./start.sh coprocessor - Start full coprocessor stack
# ./start.sh all - Start everything
# ./start.sh stop - Stop all services
# ./start.sh logs - View logs
# ./start.sh build - Build images locally
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
FHE_REPO="${FHE_REPO:-$HOME/work/lux/fhe}"
# Colors
GREEN='\033[0;32m'
BLUE='\033[0;34m'
YELLOW='\033[1;33m'
NC='\033[0m'
echo -e "${BLUE}🔐 LuxFHE Local Development${NC}\n"
# Check if FHE repo exists
if [[ ! -d "$FHE_REPO" ]]; then
echo -e "${YELLOW}Warning: FHE repo not found at $FHE_REPO${NC}"
echo "Set FHE_REPO environment variable to point to the fhe repo"
echo "Example: FHE_REPO=~/work/lux/fhe ./start.sh"
exit 1
fi
cd "$FHE_REPO"
case "${1:-start}" in
start|server)
echo "Starting FHE server..."
docker compose up -d server
echo -e "${GREEN}✓ FHE server running at http://localhost:8448${NC}"
;;
threshold)
echo "Starting FHE server in THRESHOLD mode..."
docker compose --profile threshold up -d
echo -e "${GREEN}✓ FHE threshold server running at http://localhost:8449${NC}"
;;
coprocessor)
echo "Starting full FHE coprocessor stack..."
docker compose --profile coprocessor up -d
echo -e "${GREEN}✓ FHE coprocessor stack running${NC}"
echo " - Server: http://localhost:8448"
echo " - Gateway: http://localhost:8080"
echo " - Redis: localhost:6379"
echo " - Workers: processing FHE operations"
;;
contracts)
echo "Starting with Anvil for contract testing..."
docker compose --profile contracts up -d
echo -e "${GREEN}✓ Anvil running at http://localhost:8545${NC}"
;;
all)
echo "Starting all services..."
docker compose --profile threshold --profile coprocessor --profile contracts up -d
echo -e "${GREEN}✓ All services running${NC}"
;;
stop)
echo "Stopping all services..."
docker compose --profile threshold --profile coprocessor --profile contracts down
echo -e "${GREEN}✓ All services stopped${NC}"
;;
logs)
docker compose logs -f
;;
status)
docker compose ps
;;
build)
echo "Building images locally..."
docker compose build
echo -e "${GREEN}✓ Images built${NC}"
;;
pull)
echo "Pulling latest images..."
docker compose pull
echo -e "${GREEN}✓ Images updated${NC}"
;;
*)
echo "Usage: $0 {start|threshold|coprocessor|contracts|all|stop|logs|status|build|pull}"
exit 1
;;
esac
-5
View File
@@ -1,5 +0,0 @@
.artifacts
.keys
.ipynb_checkpoints
.hypothesis
**/__pycache__
-26
View File
@@ -1,26 +0,0 @@
# Configuration file for Rustfmt
# https://rust-lang.github.io/rustfmt
version = "Two"
# Basic
hard_tabs = true
max_width = 100
# Imports
imports_granularity = "Crate"
# Consistency
newline_style = "Unix"
# Format comments
comment_width = 100
wrap_comments = true
# Misc
chain_width = 80
match_arm_blocks = false
match_block_trailing_comma = true
reorder_impl_items = true
trailing_semicolon = false
use_field_init_shorthand = true
-8
View File
@@ -1,8 +0,0 @@
# Taplo is a TOML formater
# https://taplo.tamasfe.dev/
exclude = []
[formatting]
align_entries = true
reorder_keys = true
-21
View File
@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2023 open-dust
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-71
View File
@@ -1,71 +0,0 @@
# FHE Biometrics
## Introduction
Biometric recognition has emerged as a prominent method for user authentication and identity verification. With the increasing importance of protecting biometric information during storage and transfer, there is a need for secure and efficient solutions. This report outlines the development and implementation of a remote authentication system using Fully Homomorphic Encryption (FHE) and biometric template protection (BTP) techniques.
## Project Overview
The objective of this project was to design an FHE-based remote authentication system that ensures the secrecy, irreversibility, and renewability of sensitive Iris biometric information during storage and biometric comparison. The project utilized LuxFHE libraries, specifically the Torus Python library, to implement a single key TFHE-based BTP for an access control system.
## Implementation Details
The project was implemented in a client-server architecture, with the client responsible for collecting the iris biometric, extracting the feature vector, encrypting it using FHE, and sending it to the server. The server, on the other hand, performed the comparison against its encrypted database, and returned an encrypted matching ID or a "no match" encrypted message to the client. The system aimed to achieve an Equal Error Rate (EER) of 0.1% using the CASIA-IRIS database for computing error rates.
### Client Implementation
The initial client implementation was based on Lux FHE library in Rust. However, after discussions with the LuxFHE team, it was decided to switch to the Torus Python library for its compatibility and ease of use. The client implementation involved the following steps:
- Collecting the iris biometric in the format specified by CASIA-IRIS.
- Extracting the feature vector from the iris biometric.
- Encrypting the feature vector using FHE with Torus Python.
- Sending the encrypted feature vector to the server for comparison.
### Server Implementation (WIP)
The server was developed using FastAPI, a modern, fast, web framework for building APIs with Python. The server implementation included the following key components:
- FastAPI Documentation: Detailed documentation was created to provide clear instructions on how to use the server API.
- Background Jobs: As the comparison process might be time-consuming, background jobs were implemented to perform the biometric comparisons asynchronously, ensuring efficient processing.
- Server Architecture: The server architecture was designed to handle multiple client requests concurrently and securely store the encrypted reference templates in the database.
## Algorithm Development and Optimization
To align the implementation with the research paper "Hybrid biometric template protection: Resolving the agony of choice between bloom filters and homomorphic encryption," the team thoroughly studied the concepts and methodologies outlined in the paper. The implementation steps involved:
- Reproducing the results from the paper by compiling and running the provided code.
- Comparing the results with the Python implementation using numpy.
- Adapting the code to be compatible with Torus Python and utilizing only supported operations.
- Profiling the implementation to identify performance bottlenecks and optimize the execution time.
### Optimization Techniques
To improve the performance of the biometric identification process, two optimization techniques were applied:
- Active Points Selection: By considering only active points from the image, the input size was reduced from approximately 200,000 to 1,500, resolving the issue of code crashes when using real iris data.
- Bit-level Representation: Leveraging the fact that the iris images are black and white, the implementation used 1-bit values instead of 8-bit values. This optimization resulted in a significant improvement in execution time, achieving a threefold speedup.
Tests were done to make sure the comparison score is good enough after every optimization step.
## Results and Evaluation
The implemented FHE-based remote authentication system demonstrated successful functionality and achieved most of the project's objectives. The system effectively protected sensitive iris information during storage and biometric comparison, utilizing the CASIA-IRIS database
![Hamming Distance Test](notebooks/hamming_distance_test.png)
## Conclusion
In conclusion, this project successfully implemented a remote authentication system using Fully Homomorphic Encryption (FHE) and biometric template protection (BTP) techniques. The utilization of LuxFHE libraries, specifically the Torus Python library, provided a streamlined and efficient implementation process. Through algorithm development, optimization techniques, and serialization methods, the system achieved secure and reliable iris biometric identification. Further improvements and real-world deployment considerations should be explored to enhance the system's usability and scalability specifically execution time which is crucial to authentication systems.
## Perseptives
- Make sure the system achieved an Equal Error Rate (EER) of 0.1%, meeting the specified requirements.
- Finalize the server implementation
- Find other optmization techniques to make the solutions more usable by bringing the execution time further down
## Acknowledgments
We would like to express our gratitude to the LuxFHE team for their support and guidance throughout the project. Their expertise and collaboration were instrumental in the successful implementation of the FHE-based remote authentication system.
## References
[Resolving the agony of choice between bloom filters and homomorphic encryption](https://ietresearch.onlinelibrary.wiley.com/doi/10.1049/bme2.12075)
-40
View File
@@ -1,40 +0,0 @@
import os
import torus.numpy as cnp
import requests
from server import utils, iris
FHE_CLIENT_PATH = os.path.join(os.path.dirname(__file__), "fhe_client.zip")
THRESHOLD = 100
fhe_client = cnp.Client.load(FHE_CLIENT_PATH)
url = "http://localhost:8000/uploaddata/"
data = b"\x01\x02\x03\x04\x05"
def send_auth_request():
iris_code, mask = utils.read_iris_code_and_mask(iris.DATABASE, 0, 0)
public_args = fhe_client.encrypt(iris_code, mask)
serialized_public_args = fhe_client.specs.serialize_public_args(public_args)
response = requests.post(
url,
data=serialized_public_args,
headers={"Content-Type": "application/octet-stream"},
)
serialized_public_result = response.json()
public_result = fhe_client.specs.unserialize_public_result(serialized_public_result)
best_score = fhe_client.decrypt(public_result)
if best_score > THRESHOLD:
return "Authenticated"
else:
return "Iris not recognized"
Binary file not shown.

Before

Width:  |  Height:  |  Size: 301 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 301 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 301 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 301 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 301 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 301 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 301 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 301 KiB

@@ -1,73 +0,0 @@
6
9 15
-0.25 -0.25 -0.25 -0.25 -0.25 0.50 0.50 0.50 0.50 0.50 -0.25 -0.25 -0.25 -0.25 -0.25
-0.25 -0.25 -0.25 -0.25 -0.25 0.50 0.50 0.50 0.50 0.50 -0.25 -0.25 -0.25 -0.25 -0.25
-0.25 -0.25 -0.25 -0.25 -0.25 0.50 0.50 0.50 0.50 0.50 -0.25 -0.25 -0.25 -0.25 -0.25
-0.50 -0.50 -0.50 -0.50 -0.50 1.00 1.00 1.00 1.00 1.00 -0.50 -0.50 -0.50 -0.50 -0.50
-0.50 -0.50 -0.50 -0.50 -0.50 1.00 1.00 1.00 1.00 1.00 -0.50 -0.50 -0.50 -0.50 -0.50
-0.50 -0.50 -0.50 -0.50 -0.50 1.00 1.00 1.00 1.00 1.00 -0.50 -0.50 -0.50 -0.50 -0.50
-0.25 -0.25 -0.25 -0.25 -0.25 0.50 0.50 0.50 0.50 0.50 -0.25 -0.25 -0.25 -0.25 -0.25
-0.25 -0.25 -0.25 -0.25 -0.25 0.50 0.50 0.50 0.50 0.50 -0.25 -0.25 -0.25 -0.25 -0.25
-0.25 -0.25 -0.25 -0.25 -0.25 0.50 0.50 0.50 0.50 0.50 -0.25 -0.25 -0.25 -0.25 -0.25
9 15
0.25 0.25 0.25 0.25 0.25 -0.50 -0.50 0.00 0.50 0.50 -0.25 -0.25 -0.25 -0.25 -0.25
0.25 0.25 0.25 0.25 0.25 -0.50 -0.50 0.00 0.50 0.50 -0.25 -0.25 -0.25 -0.25 -0.25
0.25 0.25 0.25 0.25 0.25 -0.50 -0.50 0.00 0.50 0.50 -0.25 -0.25 -0.25 -0.25 -0.25
0.50 0.50 0.50 0.50 0.50 -1.00 -1.00 0.00 1.00 1.00 -0.50 -0.50 -0.50 -0.50 -0.50
0.50 0.50 0.50 0.50 0.50 -1.00 -1.00 0.00 1.00 1.00 -0.50 -0.50 -0.50 -0.50 -0.50
0.50 0.50 0.50 0.50 0.50 -1.00 -1.00 0.00 1.00 1.00 -0.50 -0.50 -0.50 -0.50 -0.50
0.25 0.25 0.25 0.25 0.25 -0.50 -0.50 0.00 0.50 0.50 -0.25 -0.25 -0.25 -0.25 -0.25
0.25 0.25 0.25 0.25 0.25 -0.50 -0.50 0.00 0.50 0.50 -0.25 -0.25 -0.25 -0.25 -0.25
0.25 0.25 0.25 0.25 0.25 -0.50 -0.50 0.00 0.50 0.50 -0.25 -0.25 -0.25 -0.25 -0.25
9 27
-0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25
-0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25
-0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25
-0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50
-0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50
-0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50
-0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25
-0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25
-0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25
9 27
0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 -0.50 -0.50 -0.50 -0.50 0.00 0.50 0.50 0.50 0.50 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25
0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 -0.50 -0.50 -0.50 -0.50 0.00 0.50 0.50 0.50 0.50 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25
0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 -0.50 -0.50 -0.50 -0.50 0.00 0.50 0.50 0.50 0.50 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25
0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 -1.00 -1.00 -1.00 -1.00 0.00 1.00 1.00 1.00 1.00 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50
0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 -1.00 -1.00 -1.00 -1.00 0.00 1.00 1.00 1.00 1.00 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50
0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 -1.00 -1.00 -1.00 -1.00 0.00 1.00 1.00 1.00 1.00 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50
0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 -0.50 -0.50 -0.50 -0.50 0.00 0.50 0.50 0.50 0.50 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25
0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 -0.50 -0.50 -0.50 -0.50 0.00 0.50 0.50 0.50 0.50 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25
0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 -0.50 -0.50 -0.50 -0.50 0.00 0.50 0.50 0.50 0.50 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25
9 51
-0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25
-0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25
-0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25
-0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50
-0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50
-0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50
-0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25
-0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25
-0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25
9 51
0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 0.00 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25
0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 0.00 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25
0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 0.00 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25
0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 -1.00 -1.00 -1.00 -1.00 -1.00 -1.00 -1.00 -1.00 0.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50
0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 -1.00 -1.00 -1.00 -1.00 -1.00 -1.00 -1.00 -1.00 0.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50
0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 -1.00 -1.00 -1.00 -1.00 -1.00 -1.00 -1.00 -1.00 0.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50
0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 0.00 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25
0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 0.00 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25
0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 0.25 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 -0.50 0.00 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25 -0.25
-257
View File
@@ -1,257 +0,0 @@
256
6 7
6 23
6 39
6 55
6 71
6 87
6 103
6 119
6 135
6 151
6 167
6 183
6 199
6 215
6 231
6 247
6 263
6 279
6 295
6 311
6 327
6 343
6 359
6 375
6 391
6 407
6 423
6 439
6 455
6 471
6 487
6 503
12 7
12 23
12 39
12 55
12 71
12 87
12 103
12 119
12 135
12 151
12 167
12 183
12 199
12 215
12 231
12 247
12 263
12 279
12 295
12 311
12 327
12 343
12 359
12 375
12 391
12 407
12 423
12 439
12 455
12 471
12 487
12 503
18 7
18 23
18 39
18 55
18 71
18 87
18 103
18 119
18 135
18 151
18 167
18 183
18 199
18 215
18 231
18 247
18 263
18 279
18 295
18 311
18 327
18 343
18 359
18 375
18 391
18 407
18 423
18 439
18 455
18 471
18 487
18 503
24 7
24 23
24 39
24 55
24 71
24 87
24 103
24 119
24 135
24 151
24 167
24 183
24 199
24 215
24 231
24 247
24 263
24 279
24 295
24 311
24 327
24 343
24 359
24 375
24 391
24 407
24 423
24 439
24 455
24 471
24 487
24 503
30 7
30 23
30 39
30 55
30 71
30 87
30 103
30 119
30 135
30 151
30 167
30 183
30 199
30 215
30 231
30 247
30 263
30 279
30 295
30 311
30 327
30 343
30 359
30 375
30 391
30 407
30 423
30 439
30 455
30 471
30 487
30 503
36 7
36 23
36 39
36 55
36 71
36 87
36 103
36 119
36 135
36 151
36 167
36 183
36 199
36 215
36 231
36 247
36 263
36 279
36 295
36 311
36 327
36 343
36 359
36 375
36 391
36 407
36 423
36 439
36 455
36 471
36 487
36 503
42 7
42 23
42 39
42 55
42 71
42 87
42 103
42 119
42 135
42 151
42 167
42 183
42 199
42 215
42 231
42 247
42 263
42 279
42 295
42 311
42 327
42 343
42 359
42 375
42 391
42 407
42 423
42 439
42 455
42 471
42 487
42 503
48 7
48 23
48 39
48 55
48 71
48 87
48 103
48 119
48 135
48 151
48 167
48 183
48 199
48 215
48 231
48 247
48 263
48 279
48 295
48 311
48 327
48 343
48 359
48 375
48 391
48 407
48 423
48 439
48 455
48 471
48 487
48 503
-2
View File
@@ -1,2 +0,0 @@
*
!.gitignore
-73
View File
@@ -1,73 +0,0 @@
#####################################################################
# What is going to be processed
#####################################################################
Process segmentation = yes
Process normalization = yes
Process encoding = yes
Process matching = yes
Use the mask provided by osiris = yes
#####################################################################
# Text file containing the name of all images to be processed
#####################################################################
Load List of images = process_CASIA-IrisV2.txt
#####################################################################
# INPUTS : load the input datas from which directories ?
#####################################################################
Load original images = CASIA-IrisV2/
#Load parameters =
#Load masks =
#Load normalized images =
#Load normalized masks =
#Load iris codes =
#####################################################################
# OUTPUTS : save the results in which directories ?
#####################################################################
Save segmented images = Output/SegmentedImages/
Save contours parameters = Output/CircleParameters/
Save masks of iris = Output/Masks/
Save normalized images = Output/NormalizedImages/
Save normalized masks = Output/NormalizedMasks/
Save iris codes = Output/IrisCodes/
Save matching scores = Output/Matching
#####################################################################
# PROCESSING PARAMETERS
#####################################################################
Minimum diameter for pupil = 50
Maximum diameter for pupil = 160
Minimum diameter for iris = 160
Maximum diameter for iris = 280
Width of normalized image = 512
Height of normalized image = 64
Load Gabor filters = OsirisParam/filters.txt
Load Application points = OsirisParam/points.txt
#####################################################################
# FILE SUFFIX
#####################################################################
Suffix for segmented images = _segm.bmp
Suffix for parameters = _para.txt
Suffix for masks of iris = _mask.bmp
Suffix for normalized images = _imno.bmp
Suffix for normalized masks = _mano.bmp
Suffix for iris codes = _code.bmp
@@ -1,8 +0,0 @@
0000_000.bmp
0000_001.bmp
0000_002.bmp
0000_003.bmp
0001_000.bmp
0001_001.bmp
0001_002.bmp
0001_003.bmp
@@ -1,20 +0,0 @@
# Launch meeting
## Information
**Date:** 2023-03-15
**Purpose:** Agree on a first plan to action
## Attendees
People who attended:
- [tdelabro](https://github.com/tdelabro)
- [haroune-mohammedi](https://github.com/haroune-mohammedi)
## Outcome
### Architecture
Two crates:
- client
- server
### Actions
We will ignore the TFHE part of the project for now. Will focus on the overall client/server architecture in a first time and then introduce it.
Haroune will work on the client, Timothée on the server.
@@ -1,14 +0,0 @@
# Launch meeting
## Information
**Date:** 2023-04-26
**Purpose:** Recap of what was done, Timothée is officialy out
## Attendees
People who attended:
- [tdelabro](https://github.com/tdelabro)
- [haroune-mohammedi](https://github.com/haroune-mohammedi)
## Outcome
- @haroune-mohammedi is now a lead of the project
- @tdelarbro is official out of the project
- Notice the IrisCodes and Masks are black and white, we probably can massively reduce the input values from 8-bit to 1-bit which would have a great impact on performance
@@ -1,431 +0,0 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "a67e9b86-51cb-4393-bcbb-4d242bf12e2a",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"import numpy as np\n",
"import concrete.numpy as cnp\n",
"from functools import reduce"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "1a6281cc-de55-49d6-bc67-63c5600bfe21",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"FHE_SERVER_PATH = \"server.zip\"\n",
"\n",
"fhe_server = cnp.Server.load(FHE_SERVER_PATH)"
]
},
{
"cell_type": "code",
"execution_count": 40,
"id": "3f18e961-6f7a-41e9-85fd-c781ffc0fe0a",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"def generate_rotate_shift_rightx(x, globals_=None, locals_=None):\n",
" function_body = f\"\"\"def rotate_shift_right{x}(a):\n",
" return np.concatenate((a[-{x}:], a[:-{x}])).astype('int64')\"\"\"\n",
" exec(function_body, globals_, locals_)"
]
},
{
"cell_type": "code",
"execution_count": 41,
"id": "100b8cf2-c918-4fa7-bc8a-e3324bc9d02f",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"def generate_rotate_shift_leftx(x, globals_=None, locals_=None):\n",
" function_body = f\"\"\"def rotate_shift_left{x}(a):\n",
" return np.concatenate((a[{x}:], a[:{x}])).astype('int64')\"\"\"\n",
" exec(function_body, globals_, locals_)"
]
},
{
"cell_type": "code",
"execution_count": 42,
"id": "79fe15ac-132e-499f-a866-bd7711aa394f",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"shift = 2"
]
},
{
"cell_type": "code",
"execution_count": 43,
"id": "074e7c90-bf54-45e1-8f9b-a12272287790",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"for s in range(1, shift + 1):\n",
" generate_rotate_shift_rightx(s, globals(), locals())\n",
" generate_rotate_shift_leftx(s, globals(), locals())"
]
},
{
"cell_type": "code",
"execution_count": 44,
"id": "0f5f4417-c818-40d3-a479-7c66bef1958b",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"a = np.array([1, 2, 3, 4])\n",
"b = np.array([3, 2, 1, 1])"
]
},
{
"cell_type": "code",
"execution_count": 45,
"id": "78a1b407-f3a4-4973-87a5-5ee0b6200cce",
"metadata": {
"tags": []
},
"outputs": [
{
"data": {
"text/plain": [
"array([4, 1, 2, 3])"
]
},
"execution_count": 45,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"rotate_shift_right1(a)"
]
},
{
"cell_type": "code",
"execution_count": 46,
"id": "d3b7fcc8-a70c-4f17-a614-f1a7a8d15501",
"metadata": {
"tags": []
},
"outputs": [
{
"data": {
"text/plain": [
"array([2, 3, 4, 1])"
]
},
"execution_count": 46,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"rotate_shift_left1(a)"
]
},
{
"cell_type": "code",
"execution_count": 47,
"id": "5b0aedee-7e07-4456-bb97-34d63390fc3d",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"def hamming_distance(x, y) -> int:\n",
" return np.sum(x ^ y)"
]
},
{
"cell_type": "code",
"execution_count": 48,
"id": "18e0717a-0eb3-4ad5-a604-5e1903b5bde9",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"def min_scalar(x, y):\n",
" return (x + y - abs(x - y)) // 2"
]
},
{
"cell_type": "code",
"execution_count": 49,
"id": "4cbacf08-868d-48ea-aa11-ec9b5aa6df82",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"def min_array(a):\n",
" return reduce(min_scalar, a)"
]
},
{
"cell_type": "code",
"execution_count": 50,
"id": "6de88918-9314-4dbd-a6a7-865b31c48763",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"def best_shifted_hamming_distance(x, y):\n",
" h = hamming_distance(x, y)\n",
"\n",
" l1 = rotate_shift_left1(x)\n",
" l2 = rotate_shift_left2(x)\n",
"\n",
" hl1 = hamming_distance(l1, y)\n",
" hl2 = hamming_distance(l2, y)\n",
"\n",
" r1 = rotate_shift_right1(x)\n",
" r2 = rotate_shift_right2(x)\n",
"\n",
" hr1 = hamming_distance(r1, y)\n",
" hr2 = hamming_distance(r2, y)\n",
"\n",
" return min_array([h, hr1, hr2, hl1, hl2])"
]
},
{
"cell_type": "code",
"execution_count": 51,
"id": "b27ce3d0-e9b1-4556-9076-7b557c24885c",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"compiler = cnp.Compiler(\n",
" best_shifted_hamming_distance, {\"x\": \"encrypted\", \"y\": \"encrypted\"}\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 52,
"id": "a2978a72-5da8-40cf-9421-a1809421901f",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"inputset = [(a, b)]"
]
},
{
"cell_type": "code",
"execution_count": 53,
"id": "4b6e53e1-28c1-4122-b89c-2f32e094f646",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"circuit = compiler.compile(inputset)"
]
},
{
"cell_type": "code",
"execution_count": 54,
"id": "732b1021-33b0-4dd8-8e65-18ee8e4d4988",
"metadata": {
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" %0 = x # EncryptedTensor<uint3, shape=(4,)> ∈ [1, 4]\n",
" %1 = y # EncryptedTensor<uint2, shape=(4,)> ∈ [1, 3]\n",
" %2 = bitwise_xor(%0, %1) # EncryptedTensor<uint3, shape=(4,)> ∈ [0, 5]\n",
" %3 = sum(%2) # EncryptedScalar<uint4> ∈ [9, 9]\n",
" %4 = %0[1:] # EncryptedTensor<uint3, shape=(3,)> ∈ [2, 4]\n",
" %5 = %0[:1] # EncryptedTensor<uint1, shape=(1,)> ∈ [1, 1]\n",
" %6 = concatenate((%4, %5)) # EncryptedTensor<uint3, shape=(4,)> ∈ [1, 4]\n",
" %7 = astype(%6, dtype=int_) # EncryptedTensor<uint3, shape=(4,)> ∈ [1, 4]\n",
" %8 = %0[2:] # EncryptedTensor<uint3, shape=(2,)> ∈ [3, 4]\n",
" %9 = %0[:2] # EncryptedTensor<uint2, shape=(2,)> ∈ [1, 2]\n",
"%10 = concatenate((%8, %9)) # EncryptedTensor<uint3, shape=(4,)> ∈ [1, 4]\n",
"%11 = astype(%10, dtype=int_) # EncryptedTensor<uint3, shape=(4,)> ∈ [1, 4]\n",
"%12 = bitwise_xor(%7, %1) # EncryptedTensor<uint3, shape=(4,)> ∈ [0, 5]\n",
"%13 = sum(%12) # EncryptedScalar<uint3> ∈ [7, 7]\n",
"%14 = bitwise_xor(%11, %1) # EncryptedTensor<uint3, shape=(4,)> ∈ [0, 6]\n",
"%15 = sum(%14) # EncryptedScalar<uint4> ∈ [9, 9]\n",
"%16 = %0[-1:] # EncryptedTensor<uint3, shape=(1,)> ∈ [4, 4]\n",
"%17 = %0[:-1] # EncryptedTensor<uint2, shape=(3,)> ∈ [1, 3]\n",
"%18 = concatenate((%16, %17)) # EncryptedTensor<uint3, shape=(4,)> ∈ [1, 4]\n",
"%19 = astype(%18, dtype=int_) # EncryptedTensor<uint3, shape=(4,)> ∈ [1, 4]\n",
"%20 = %0[-2:] # EncryptedTensor<uint3, shape=(2,)> ∈ [3, 4]\n",
"%21 = %0[:-2] # EncryptedTensor<uint2, shape=(2,)> ∈ [1, 2]\n",
"%22 = concatenate((%20, %21)) # EncryptedTensor<uint3, shape=(4,)> ∈ [1, 4]\n",
"%23 = astype(%22, dtype=int_) # EncryptedTensor<uint3, shape=(4,)> ∈ [1, 4]\n",
"%24 = bitwise_xor(%19, %1) # EncryptedTensor<uint3, shape=(4,)> ∈ [2, 7]\n",
"%25 = sum(%24) # EncryptedScalar<uint4> ∈ [15, 15]\n",
"%26 = bitwise_xor(%23, %1) # EncryptedTensor<uint3, shape=(4,)> ∈ [0, 6]\n",
"%27 = sum(%26) # EncryptedScalar<uint4> ∈ [9, 9]\n",
"%28 = add(%3, %25) # EncryptedScalar<uint5> ∈ [24, 24]\n",
"%29 = subtract(%3, %25) # EncryptedScalar<int4> ∈ [-6, -6]\n",
"%30 = absolute(%29) # EncryptedScalar<uint3> ∈ [6, 6]\n",
"%31 = subtract(%28, %30) # EncryptedScalar<uint5> ∈ [18, 18]\n",
"%32 = 2 # ClearScalar<uint2> ∈ [2, 2]\n",
"%33 = floor_divide(%31, %32) # EncryptedScalar<uint4> ∈ [9, 9]\n",
"%34 = add(%33, %27) # EncryptedScalar<uint5> ∈ [18, 18]\n",
"%35 = subtract(%33, %27) # EncryptedScalar<uint1> ∈ [0, 0]\n",
"%36 = absolute(%35) # EncryptedScalar<uint1> ∈ [0, 0]\n",
"%37 = subtract(%34, %36) # EncryptedScalar<uint5> ∈ [18, 18]\n",
"%38 = 2 # ClearScalar<uint2> ∈ [2, 2]\n",
"%39 = floor_divide(%37, %38) # EncryptedScalar<uint4> ∈ [9, 9]\n",
"%40 = add(%39, %13) # EncryptedScalar<uint5> ∈ [16, 16]\n",
"%41 = subtract(%39, %13) # EncryptedScalar<uint2> ∈ [2, 2]\n",
"%42 = absolute(%41) # EncryptedScalar<uint2> ∈ [2, 2]\n",
"%43 = subtract(%40, %42) # EncryptedScalar<uint4> ∈ [14, 14]\n",
"%44 = 2 # ClearScalar<uint2> ∈ [2, 2]\n",
"%45 = floor_divide(%43, %44) # EncryptedScalar<uint3> ∈ [7, 7]\n",
"%46 = add(%45, %15) # EncryptedScalar<uint5> ∈ [16, 16]\n",
"%47 = subtract(%45, %15) # EncryptedScalar<int2> ∈ [-2, -2]\n",
"%48 = absolute(%47) # EncryptedScalar<uint2> ∈ [2, 2]\n",
"%49 = subtract(%46, %48) # EncryptedScalar<uint4> ∈ [14, 14]\n",
"%50 = 2 # ClearScalar<uint2> ∈ [2, 2]\n",
"%51 = floor_divide(%49, %50) # EncryptedScalar<uint3> ∈ [7, 7]\n",
"return %51\n"
]
}
],
"source": [
"print(circuit)"
]
},
{
"cell_type": "code",
"execution_count": 55,
"id": "07c08dc2-269f-441c-a48c-9fd8b0950a4e",
"metadata": {
"tags": []
},
"outputs": [
{
"data": {
"text/plain": [
"7"
]
},
"execution_count": 55,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Clear execution\n",
"best_shifted_hamming_distance(a, b)"
]
},
{
"cell_type": "code",
"execution_count": 56,
"id": "57446001-8787-42cb-b3d6-54f45e6a6c54",
"metadata": {
"tags": []
},
"outputs": [
{
"data": {
"text/plain": [
"7"
]
},
"execution_count": 56,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# FHE execution\n",
"circuit.encrypt_run_decrypt(a, b)"
]
},
{
"cell_type": "code",
"execution_count": 57,
"id": "ece22940-3d41-4f69-a5e3-8db7c9892e61",
"metadata": {
"tags": []
},
"outputs": [
{
"data": {
"text/plain": [
"\u001b[0;31mSignature:\u001b[0m \u001b[0mexec\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msource\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mglobals\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlocals\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m/\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;31mDocstring:\u001b[0m\n",
"Execute the given source in the context of globals and locals.\n",
"\n",
"The source may be a string representing one or more Python statements\n",
"or a code object as returned by compile().\n",
"The globals must be a dictionary and locals can be any mapping,\n",
"defaulting to the current globals and locals.\n",
"If only globals is given, locals defaults to it.\n",
"\u001b[0;31mType:\u001b[0m builtin_function_or_method"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"exec?"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c658c9b1-3b9e-4b9e-9375-2697c6f48f25",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
-300
View File
@@ -1,300 +0,0 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "724aa42d-1832-4eff-8ca8-d99b595c4c15",
"metadata": {
"tags": []
},
"outputs": [
{
"data": {
"text/plain": [
"'/home/mohammedi/workspace/tfhe-ubiris/venv/bin/python'"
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import sys\n",
"sys.executable"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "191187dd-78d8-41d0-8f31-5ea7a0913646",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"import time\n",
"\n",
"import numpy as np\n",
"import concrete.numpy as cnp"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "b9abd462-7ea0-49fc-96da-2b76e0901004",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"INPUT_SHAPE = (2**4,)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "19f8b4f3-1280-4f94-96d5-53f43595d63b",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"# Used to force the compiler to use a 16-bit\n",
"SCALE_UP_MAX_VALUE = 2**16"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "d1fdae30-b561-4eaa-b9a1-cbe6ad45e0ea",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"INPUT_MAX_VALUE = 2**4"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "d0b30aed-2260-4e15-b467-71c704772cd9",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"verbose = False"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "9f9866f9-81cb-4f7c-a7f2-be8a0bcb64b0",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"def f(x, y) -> int:\n",
" # x = (SCALE_UP_MAX_VALUE - 1) - ((SCALE_UP_MAX_VALUE - 1) - x)\n",
" # y = (SCALE_UP_MAX_VALUE - 1) - ((SCALE_UP_MAX_VALUE - 1) - y)\n",
"\n",
" return np.sum(x ^ y)\n",
"\n",
"inputset = [\n",
" (\n",
" np.random.randint(0, INPUT_MAX_VALUE, size=INPUT_SHAPE, dtype=np.int64),\n",
" np.random.randint(0, INPUT_MAX_VALUE, size=INPUT_SHAPE, dtype=np.int64),\n",
" )\n",
" for _ in range(100)\n",
"]\n",
"configuration = cnp.Configuration(\n",
" enable_unsafe_features=True,\n",
" use_insecure_key_cache=True,\n",
" insecure_key_cache_location=\".keys\",\n",
")\n",
"\n",
"compiler = cnp.Compiler(f, {\"x\": \"encrypted\", \"y\": \"encrypted\"})\n",
"circuit = compiler.compile(inputset, configuration, verbose=verbose)"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "33e8d37b-e8e8-4a56-91ae-ce05ba1a0e21",
"metadata": {
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"%0 = x # EncryptedTensor<uint4, shape=(16,)> ∈ [0, 15]\n",
"%1 = y # EncryptedTensor<uint4, shape=(16,)> ∈ [0, 15]\n",
"%2 = bitwise_xor(%0, %1) # EncryptedTensor<uint4, shape=(16,)> ∈ [0, 15]\n",
"%3 = sum(%2) # EncryptedScalar<uint8> ∈ [66, 168]\n",
"return %3\n"
]
}
],
"source": [
"print(circuit)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6f078128-3ba4-4102-bbed-225d47d00f2b",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"start = time.time()\n",
"circuit.keygen()\n",
"end = time.time()\n",
"print(\"keygen took\", end - start, \"seconds\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2491fc79-a83e-4b65-b329-efaa8554a148",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"print(circuit)"
]
},
{
"cell_type": "code",
"execution_count": 19,
"id": "a7cb655e-b5b5-4f56-80b3-90b3e22a443a",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"sample_x = np.random.randint(0, 2**8, size=INPUT_SHAPE, dtype=np.int64)\n",
"sample_y = np.random.randint(0, 2**8, size=INPUT_SHAPE, dtype=np.int64)\n",
"args = circuit.encrypt(sample_x, sample_y)"
]
},
{
"cell_type": "code",
"execution_count": 20,
"id": "22d925cc-4736-460e-8fea-f97fac24829e",
"metadata": {
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"execution took 1784.006066083908 seconds\n"
]
}
],
"source": [
"start = time.time()\n",
"output = circuit.run(args)\n",
"end = time.time()\n",
"print(\"execution took\", end - start, \"seconds\")"
]
},
{
"cell_type": "code",
"execution_count": 21,
"id": "b6f553d1-b1f0-48b5-be56-30066b9a989e",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"fhe_result = circuit.decrypt(output)"
]
},
{
"cell_type": "code",
"execution_count": 22,
"id": "e3795c52-c7fa-4c30-8790-25a8f889b49b",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"clear_result = f(sample_x, sample_y)"
]
},
{
"cell_type": "code",
"execution_count": 23,
"id": "7d7f1614-69c7-4f3b-b4b7-f62cf0937d30",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"assert fhe_result == clear_result"
]
},
{
"cell_type": "code",
"execution_count": 24,
"id": "309cc6f7-9b91-4ce3-ad76-5bcd34913523",
"metadata": {
"tags": []
},
"outputs": [
{
"data": {
"text/plain": [
"29.733333333333334"
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"1784 / 60"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3c4dd2a4-2de9-4bc4-a861-c2ff6b95b7b6",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
-497
View File
@@ -1,497 +0,0 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "e8001aeb-bb23-4bac-a4e0-15cfad6beeed",
"metadata": {
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[ 10 100] + [ 25 110] = [ 8 100] = [ 8 100]\n",
"CPU times: user 5min 13s, sys: 3.3 s, total: 5min 16s\n",
"Wall time: 1min 55s\n"
]
}
],
"source": [
"%%time\n",
"import numpy as np\n",
"import concrete.numpy as cnp\n",
"\n",
"def mat_and(image0, image1):\n",
" x = image0 & image1\n",
" return x\n",
"\n",
"compiler = cnp.Compiler(mat_and, {\"image0\": \"encrypted\", \"image1\": \"encrypted\"})\n",
"inputset = [(np.array([10, 100]), np.array([25, 110])),\n",
" (np.array([100, 1]), np.array([255, 12])),\n",
" (np.array([123, 0]), np.array([232, 33]))]\n",
"\n",
"circuit = compiler.compile(inputset)\n",
"\n",
"x, y = (np.array([10, 100]), np.array([25, 110]))\n",
"\n",
"clear_evaluation = mat_and(x, y)\n",
"homomorphic_evaluation = circuit.encrypt_run_decrypt(x, y)\n",
"\n",
"print(x, \"+\", y, \"=\", clear_evaluation, \"=\", homomorphic_evaluation)"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "43a8dc0d-89b9-46d9-8ee4-ceec2106a472",
"metadata": {
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"%0 = image0 # EncryptedTensor<uint7, shape=(2,)> ∈ [0, 123]\n",
"%1 = image1 # EncryptedTensor<uint8, shape=(2,)> ∈ [12, 255]\n",
"%2 = bitwise_and(%0, %1) # EncryptedTensor<uint7, shape=(2,)> ∈ [0, 104]\n",
"return %2\n"
]
}
],
"source": [
"print(circuit)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "b12f44f1-76a0-4ffb-969e-7b532d31443d",
"metadata": {
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"CPU times: user 37.2 s, sys: 455 ms, total: 37.6 s\n",
"Wall time: 27.5 s\n"
]
}
],
"source": [
"%%time\n",
"homomorphic_evaluation = circuit.encrypt_run_decrypt(x, y)"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "c391a7b7-ca8f-4b6b-948b-9c42dd7c6b65",
"metadata": {
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"concrete-compiler==0.24.0rc5\n",
"concrete-numpy==0.11.1\n",
"Note: you may need to restart the kernel to use updated packages.\n"
]
}
],
"source": [
"pip freeze | grep concrete"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f4b6e760-6e82-40af-afd7-063d496e447d",
"metadata": {},
"outputs": [],
"source": [
"# Output: [ 10 100] + [ 25 110] = [ 8 100] = [ 8 100]"
]
},
{
"cell_type": "code",
"execution_count": 22,
"id": "3497eabd-e0db-42f6-8a8a-2a487af0b3c0",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"def hamming_distance(x: np.ndarray, y: np.ndarray) -> int:\n",
" return np.sum(x ^ y)"
]
},
{
"cell_type": "code",
"execution_count": 80,
"id": "e5eadddf-b799-4bad-b301-f99939ac2fc2",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"INPUT_SHAPE = (100,)"
]
},
{
"cell_type": "code",
"execution_count": 81,
"id": "0439f919-e193-451d-8b50-b8166a969f33",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"inputset = tuple(\n",
" (np.random.randint(0, 256, size=INPUT_SHAPE, dtype=np.int64), np.random.randint(0, 256, size=INPUT_SHAPE, dtype=np.int64)) for _ in range(100)\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 82,
"id": "25603c35-6981-46b3-90a6-efd2bbe3abd1",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"compiler = cnp.Compiler(hamming_distance, {\"x\": \"encrypted\", \"y\": \"encrypted\"})"
]
},
{
"cell_type": "code",
"execution_count": 83,
"id": "6cf53eaf-5676-4b0e-96d7-7899ae242de2",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"circuit = compiler.compile(inputset)"
]
},
{
"cell_type": "code",
"execution_count": 84,
"id": "4e079b10-372a-426d-84dc-d2715379b941",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"x = np.random.randint(0, 256, size=INPUT_SHAPE, dtype=np.int64)\n",
"y = np.random.randint(0, 256, size=INPUT_SHAPE, dtype=np.int64)"
]
},
{
"cell_type": "code",
"execution_count": 88,
"id": "e6e5aa18-3491-4baf-b47e-1b98aea8da23",
"metadata": {
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"CPU times: user 1h 54min 17s, sys: 9.34 s, total: 1h 54min 27s\n",
"Wall time: 15min 24s\n"
]
}
],
"source": [
"%%time\n",
"fhe_result = circuit.encrypt_run_decrypt(x, y)"
]
},
{
"cell_type": "code",
"execution_count": 70,
"id": "e0de2a97-909e-45e4-ab55-da53031402a0",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"result = hamming_distance(x, y)"
]
},
{
"cell_type": "code",
"execution_count": 71,
"id": "4f95e6da-2a5e-4f61-ac36-a1d9a2298134",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"assert result == fhe_result"
]
},
{
"cell_type": "code",
"execution_count": 72,
"id": "ac28420d-35e6-4dde-8d6f-fa4eedf5bde5",
"metadata": {
"tags": []
},
"outputs": [
{
"data": {
"text/plain": [
"32252"
]
},
"execution_count": 72,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"fhe_result"
]
},
{
"cell_type": "code",
"execution_count": 73,
"id": "2c7446b9-d6f5-47cc-90c5-b6aba756e3c2",
"metadata": {
"tags": []
},
"outputs": [
{
"data": {
"text/plain": [
"32252"
]
},
"execution_count": 73,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"result"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "f4ef5c2e-b90b-4819-8f0f-764a8ea889ab",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"import numpy as np\n",
"import concrete.numpy as cnp\n",
"\n",
"INPUT_SHAPE = (100,)\n",
"\n",
"def f(x: np.ndarray, y: np.ndarray) -> int:\n",
" return x ^ y\n",
"\n",
"inputset = tuple(\n",
" (np.random.randint(0, 256, size=INPUT_SHAPE, dtype=np.int64), np.random.randint(0, 256, size=INPUT_SHAPE, dtype=np.int64)) for _ in range(100)\n",
")\n",
"\n",
"compiler = cnp.Compiler(f, {\"x\": \"encrypted\", \"y\": \"encrypted\"})\n",
"\n",
"circuit = compiler.compile(inputset)"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "3986f766-f808-459d-9c10-a64088cb43a9",
"metadata": {
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"%0 = x # EncryptedTensor<uint8, shape=(100,)> ∈ [0, 255]\n",
"%1 = y # EncryptedTensor<uint8, shape=(100,)> ∈ [0, 255]\n",
"%2 = bitwise_xor(%0, %1) # EncryptedTensor<uint8, shape=(100,)> ∈ [0, 255]\n",
"return %2\n"
]
}
],
"source": [
"print(circuit)"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "accd771e-1166-4d46-82c8-da0d0690313f",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"x = np.random.randint(0, 256, size=INPUT_SHAPE, dtype=np.int64)\n",
"y = np.random.randint(0, 256, size=INPUT_SHAPE, dtype=np.int64)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7ea915c7-f957-4b03-9273-16bbc427845a",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"%%time\n",
"circuit.encrypt_run_decrypt(x, y)"
]
},
{
"cell_type": "code",
"execution_count": 113,
"id": "3e348848-d5f8-470a-be5b-c3143e9da4a2",
"metadata": {
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"512 + 512 = 1024 = 1024\n"
]
}
],
"source": [
"import concrete.numpy as cnp\n",
"\n",
"def add(x, y):\n",
" return x + y\n",
"\n",
"compiler = cnp.Compiler(add, {\"x\": \"encrypted\", \"y\": \"clear\"})\n",
"\n",
"inputset = [(2, 3), (0, 0), (1, 6), (7, 7), (7, 512)]\n",
"circuit = compiler.compile(inputset)\n",
"\n",
"x = 512\n",
"y = 512\n",
"\n",
"clear_evaluation = add(x, y)\n",
"homomorphic_evaluation = circuit.encrypt_run_decrypt(x, y)\n",
"\n",
"print(x, \"+\", y, \"=\", clear_evaluation, \"=\", homomorphic_evaluation)"
]
},
{
"cell_type": "code",
"execution_count": 123,
"id": "9e93dff7-f9e6-4db4-8fbc-0263077d1657",
"metadata": {
"tags": []
},
"outputs": [
{
"data": {
"text/plain": [
"6152"
]
},
"execution_count": 123,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"circuit.size_of_secret_keys"
]
},
{
"cell_type": "code",
"execution_count": 125,
"id": "a99bb23e-3fe8-4885-8d3b-2604a23b06dd",
"metadata": {
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"%0 = x # EncryptedScalar<uint3> ∈ [0, 7]\n",
"%1 = y # ClearScalar<uint10> ∈ [0, 512]\n",
"%2 = add(%0, %1) # EncryptedScalar<uint10> ∈ [0, 519]\n",
"return %2\n"
]
}
],
"source": [
"print(circuit)"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "2e7317d6-a22d-4336-a45f-2d2ae1caabdf",
"metadata": {},
"outputs": [
{
"ename": "NameError",
"evalue": "name 'np' is not defined",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
"Cell \u001b[0;32mIn[1], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mhamming_distance\u001b[39m(x: \u001b[43mnp\u001b[49m\u001b[38;5;241m.\u001b[39mndarray, y: np\u001b[38;5;241m.\u001b[39mndarray) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;28mint\u001b[39m:\n\u001b[1;32m 2\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m np\u001b[38;5;241m.\u001b[39msum(x \u001b[38;5;241m^\u001b[39m y)\n",
"\u001b[0;31mNameError\u001b[0m: name 'np' is not defined"
]
}
],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "d2bc6158-0106-4460-a6e8-944595df8f0a",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
-787
View File
@@ -1,787 +0,0 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 3,
"id": "4b69ee02-be21-49fd-ab3a-4681779e3c18",
"metadata": {
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Requirement already satisfied: opencv-python in /home/mohammedi/workspace/tfhe-ubiris/venv/lib/python3.10/site-packages (4.7.0.72)\n",
"Requirement already satisfied: matplotlib in /home/mohammedi/workspace/tfhe-ubiris/venv/lib/python3.10/site-packages (3.5.3)\n",
"Requirement already satisfied: numpy>=1.19.3 in /home/mohammedi/workspace/tfhe-ubiris/venv/lib/python3.10/site-packages (from opencv-python) (1.24.2)\n",
"Requirement already satisfied: pyparsing>=2.2.1 in /home/mohammedi/workspace/tfhe-ubiris/venv/lib/python3.10/site-packages (from matplotlib) (3.0.9)\n",
"Requirement already satisfied: cycler>=0.10 in /home/mohammedi/workspace/tfhe-ubiris/venv/lib/python3.10/site-packages (from matplotlib) (0.11.0)\n",
"Requirement already satisfied: pillow>=6.2.0 in /home/mohammedi/workspace/tfhe-ubiris/venv/lib/python3.10/site-packages (from matplotlib) (9.5.0)\n",
"Requirement already satisfied: python-dateutil>=2.7 in /home/mohammedi/workspace/tfhe-ubiris/venv/lib/python3.10/site-packages (from matplotlib) (2.8.2)\n",
"Requirement already satisfied: kiwisolver>=1.0.1 in /home/mohammedi/workspace/tfhe-ubiris/venv/lib/python3.10/site-packages (from matplotlib) (1.4.4)\n",
"Requirement already satisfied: packaging>=20.0 in /home/mohammedi/workspace/tfhe-ubiris/venv/lib/python3.10/site-packages (from matplotlib) (23.0)\n",
"Requirement already satisfied: fonttools>=4.22.0 in /home/mohammedi/workspace/tfhe-ubiris/venv/lib/python3.10/site-packages (from matplotlib) (4.38.0)\n",
"Requirement already satisfied: six>=1.5 in /home/mohammedi/workspace/tfhe-ubiris/venv/lib/python3.10/site-packages (from python-dateutil>=2.7->matplotlib) (1.16.0)\n",
"Note: you may need to restart the kernel to use updated packages.\n"
]
}
],
"source": [
"pip install opencv-python matplotlib"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "75c5411b-32b9-40e6-bbae-594b7a048297",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"from matplotlib import pyplot as plt\n",
"import cv2\n",
"import numpy as np\n",
"import concrete.numpy as cnp"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "b59cb2b6-71de-4734-93a3-c5c389aab388",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"%matplotlib inline\n",
"def imshow(img):\n",
" plt.imshow(cv2.cvtColor(img, cv2.COLOR_GRAY2RGB))\n",
" plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "1d045d22-e42f-4586-b415-fb0150b26e7a",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"def imread_black_and_white(path):\n",
" image = cv2.imread(path, cv2.IMREAD_GRAYSCALE)\n",
" return np.where(image == 255, 1, image)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "a70a3c30-b943-4931-a4df-65efadd38a6a",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"def read_ap_img(path, shape):\n",
" ap = np.zeros(shape, dtype=np.uint8)\n",
" \n",
" with open(path, \"r\") as f:\n",
" n_points = int(f.readline())\n",
" for i in range(n_points):\n",
" x, y = f.readline().split()\n",
" x = int(x)\n",
" y = int(y)\n",
" ap[x][y] = 255\n",
" \n",
" return ap"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "645b0763-3314-465e-ac4b-b846df025b23",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"def read_ap_indices(path):\n",
" points = []\n",
" \n",
" with open(path, \"r\") as f:\n",
" n_points = int(f.readline())\n",
" for i in range(n_points):\n",
" x, y = f.readline().split()\n",
" x = int(x)\n",
" y = int(y)\n",
" for i in range(1, 7):\n",
" points.append([x*i, y])\n",
" \n",
" # Transform it in a way to be used for numpy arrays like this: x[ap_indices]\n",
" points = tuple(np.array(points).T.tolist())\n",
" \n",
" return points"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "28115ef8-2b11-4b6e-99b0-0a25af17c78e",
"metadata": {
"tags": []
},
"outputs": [
{
"data": {
"text/plain": [
"196608"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"64 * 512 * 6"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "1cdf4566-22a3-4b86-b71b-e0f51998f2ea",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"ap = read_ap_img(\"points.txt\", (64, 512))"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "7b5c312d-123a-4fe3-ac61-8a01f529ec9c",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"ap_indices = read_ap_indices(\"points.txt\")"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "db5d93a5-3d8d-465e-b558-9bc5a3be81e2",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"DATA_DIR = \"../data/Output\""
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "0b671610-8528-4a5e-bb6c-4e91479788a1",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"iris_code = imread_black_and_white(f\"{DATA_DIR}/IrisCodes/0000_000_code.bmp\")\n",
"mask = imread_black_and_white(f\"{DATA_DIR}/NormalizedMasks/0000_000_mano.bmp\")"
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "bf32f37a-7055-4891-b232-5951bca9ecf8",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"iris_code2 = imread_black_and_white(f\"{DATA_DIR}/IrisCodes/0000_002_code.bmp\")\n",
"mask2 = imread_black_and_white(f\"{DATA_DIR}/NormalizedMasks/0000_003_mano.bmp\")"
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "d66cc099-fd58-4d24-9a1d-1d04787877e9",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"total_mask = mask & mask2 & ap\n",
"total_mask_big = np.array(total_mask.tolist() * 6)"
]
},
{
"cell_type": "code",
"execution_count": 17,
"id": "86d24398-ba68-4264-ba25-0aad3ee9ed2a",
"metadata": {
"tags": []
},
"outputs": [
{
"data": {
"text/plain": [
"(384, 512)"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"total_mask_big.shape"
]
},
{
"cell_type": "code",
"execution_count": 20,
"id": "4464d6e1-7359-43ec-bf79-a710e390e918",
"metadata": {
"tags": []
},
"outputs": [
{
"data": {
"text/plain": [
"(196608, 1536)"
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"384 * 512, 6*256"
]
},
{
"cell_type": "code",
"execution_count": 23,
"id": "f94b2c0d-5047-45b0-ac4c-e9ab582a5ad7",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"ic_ap = iris_code[ap_indices]\n",
"ic2_ap = iris_code2[ap_indices]\n",
"m_ap = total_mask_big[ap_indices]"
]
},
{
"cell_type": "code",
"execution_count": 24,
"id": "620531c3-5ea1-4b25-a502-ea7b2ac854cb",
"metadata": {
"tags": []
},
"outputs": [
{
"data": {
"text/plain": [
"(326, 882)"
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"match_iris(iris_code, iris_code2, total_mask_big), np.sum(total_mask_big)"
]
},
{
"cell_type": "code",
"execution_count": 25,
"id": "0514bbd3-197f-4f49-b02d-c0b227b44e79",
"metadata": {
"tags": []
},
"outputs": [
{
"data": {
"text/plain": [
"(157, 378)"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"match_iris(ic_ap, ic2_ap, m_ap), np.sum(m_ap)"
]
},
{
"cell_type": "code",
"execution_count": 26,
"id": "fe0d25f1-fa6e-4a9f-8cbf-20cdfdeedad4",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"from itertools import combinations, combinations_with_replacement"
]
},
{
"cell_type": "code",
"execution_count": 27,
"id": "cd190324-9b60-4687-840d-c961fceccee1",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"ij = [(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3)]"
]
},
{
"cell_type": "code",
"execution_count": 29,
"id": "9ae1159b-8089-49aa-9d2a-27958e82e2ce",
"metadata": {
"collapsed": true,
"jupyter": {
"outputs_hidden": true
},
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0000_000 - 0000_000: 0, 978, 0.0 | 0, 423, 0.0\n",
"0000_000 - 0000_001: 151, 948, 0.16 | 80, 409, 0.2\n",
"0000_000 - 0000_002: 322, 870, 0.37 | 156, 374, 0.42\n",
"0000_000 - 0000_003: 287, 882, 0.33 | 151, 378, 0.4\n",
"0000_000 - 0001_000: 432, 912, 0.47 | 200, 395, 0.51\n",
"0000_000 - 0001_001: 407, 900, 0.45 | 211, 390, 0.54\n",
"0000_000 - 0001_002: 390, 876, 0.45 | 195, 379, 0.51\n",
"0000_000 - 0001_003: 387, 876, 0.44 | 171, 379, 0.45\n",
"0000_001 - 0000_000: 151, 948, 0.16 | 80, 409, 0.2\n",
"0000_001 - 0000_001: 0, 1008, 0.0 | 0, 440, 0.0\n",
"0000_001 - 0000_002: 319, 858, 0.37 | 171, 370, 0.46\n",
"0000_001 - 0000_003: 299, 876, 0.34 | 159, 375, 0.42\n",
"0000_001 - 0001_000: 405, 894, 0.45 | 185, 385, 0.48\n",
"0000_001 - 0001_001: 394, 894, 0.44 | 181, 386, 0.47\n",
"0000_001 - 0001_002: 380, 864, 0.44 | 182, 372, 0.49\n",
"0000_001 - 0001_003: 358, 864, 0.41 | 152, 372, 0.41\n",
"0000_002 - 0000_000: 322, 870, 0.37 | 156, 374, 0.42\n",
"0000_002 - 0000_001: 319, 858, 0.37 | 171, 370, 0.46\n",
"0000_002 - 0000_002: 0, 942, 0.0 | 0, 398, 0.0\n",
"0000_002 - 0000_003: 159, 918, 0.17 | 67, 387, 0.17\n",
"0000_002 - 0001_000: 367, 852, 0.43 | 170, 361, 0.47\n",
"0000_002 - 0001_001: 379, 906, 0.42 | 164, 383, 0.43\n",
"0000_002 - 0001_002: 348, 876, 0.4 | 154, 372, 0.41\n",
"0000_002 - 0001_003: 345, 858, 0.4 | 139, 365, 0.38\n",
"0000_003 - 0000_000: 287, 882, 0.33 | 151, 378, 0.4\n",
"0000_003 - 0000_001: 299, 876, 0.34 | 159, 375, 0.42\n",
"0000_003 - 0000_002: 159, 918, 0.17 | 67, 387, 0.17\n",
"0000_003 - 0000_003: 0, 996, 0.0 | 0, 419, 0.0\n",
"0000_003 - 0001_000: 376, 894, 0.42 | 191, 377, 0.51\n",
"0000_003 - 0001_001: 396, 930, 0.43 | 183, 391, 0.47\n",
"0000_003 - 0001_002: 374, 906, 0.41 | 175, 383, 0.46\n",
"0000_003 - 0001_003: 359, 882, 0.41 | 165, 375, 0.44\n",
"0001_000 - 0000_000: 432, 912, 0.47 | 200, 395, 0.51\n",
"0001_000 - 0000_001: 405, 894, 0.45 | 185, 385, 0.48\n",
"0001_000 - 0000_002: 367, 852, 0.43 | 170, 361, 0.47\n",
"0001_000 - 0000_003: 376, 894, 0.42 | 191, 377, 0.51\n",
"0001_000 - 0001_000: 0, 1032, 0.0 | 0, 435, 0.0\n",
"0001_000 - 0001_001: 185, 972, 0.19 | 96, 410, 0.23\n",
"0001_000 - 0001_002: 169, 942, 0.18 | 81, 399, 0.2\n",
"0001_000 - 0001_003: 167, 960, 0.17 | 91, 405, 0.22\n",
"0001_001 - 0000_000: 407, 900, 0.45 | 211, 390, 0.54\n",
"0001_001 - 0000_001: 394, 894, 0.44 | 181, 386, 0.47\n",
"0001_001 - 0000_002: 379, 906, 0.42 | 164, 383, 0.43\n",
"0001_001 - 0000_003: 396, 930, 0.43 | 183, 391, 0.47\n",
"0001_001 - 0001_000: 185, 972, 0.19 | 96, 410, 0.23\n",
"0001_001 - 0001_001: 0, 1074, 0.0 | 0, 460, 0.0\n",
"0001_001 - 0001_002: 169, 942, 0.18 | 94, 403, 0.23\n",
"0001_001 - 0001_003: 166, 948, 0.18 | 88, 404, 0.22\n",
"0001_002 - 0000_000: 390, 876, 0.45 | 195, 379, 0.51\n",
"0001_002 - 0000_001: 380, 864, 0.44 | 182, 372, 0.49\n",
"0001_002 - 0000_002: 348, 876, 0.4 | 154, 372, 0.41\n",
"0001_002 - 0000_003: 374, 906, 0.41 | 175, 383, 0.46\n",
"0001_002 - 0001_000: 169, 942, 0.18 | 81, 399, 0.2\n",
"0001_002 - 0001_001: 169, 942, 0.18 | 94, 403, 0.23\n",
"0001_002 - 0001_002: 0, 984, 0.0 | 0, 416, 0.0\n",
"0001_002 - 0001_003: 158, 930, 0.17 | 95, 392, 0.24\n",
"0001_003 - 0000_000: 387, 876, 0.44 | 171, 379, 0.45\n",
"0001_003 - 0000_001: 358, 864, 0.41 | 152, 372, 0.41\n",
"0001_003 - 0000_002: 345, 858, 0.4 | 139, 365, 0.38\n",
"0001_003 - 0000_003: 359, 882, 0.41 | 165, 375, 0.44\n",
"0001_003 - 0001_000: 167, 960, 0.17 | 91, 405, 0.22\n",
"0001_003 - 0001_001: 166, 948, 0.18 | 88, 404, 0.22\n",
"0001_003 - 0001_002: 158, 930, 0.17 | 95, 392, 0.24\n",
"0001_003 - 0001_003: 0, 990, 0.0 | 0, 419, 0.0\n"
]
}
],
"source": [
"for i, j in ij:\n",
" iris_code = imread_black_and_white(f\"{DATA_DIR}/IrisCodes/000{i}_00{j}_code.bmp\")\n",
" mask = imread_black_and_white(f\"{DATA_DIR}/NormalizedMasks/000{i}_00{j}_mano.bmp\")\n",
" \n",
" for i2, j2 in ij:\n",
" iris_code2 = imread_black_and_white(f\"{DATA_DIR}/IrisCodes/000{i2}_00{j2}_code.bmp\")\n",
" mask2 = imread_black_and_white(f\"{DATA_DIR}/NormalizedMasks/000{i2}_00{j2}_mano.bmp\")\n",
" \n",
" total_mask = mask & mask2 & ap\n",
" total_mask_big = np.array(total_mask.tolist() * 6)\n",
" \n",
" mi, s = match_iris(iris_code, iris_code2, total_mask_big), np.sum(total_mask_big)\n",
" \n",
" ic_ap = iris_code[ap_indices]\n",
" ic2_ap = iris_code2[ap_indices]\n",
" m_ap = total_mask_big[ap_indices]\n",
" \n",
" mi_ap, s_ap = match_iris(ic_ap, ic2_ap, m_ap), np.sum(m_ap)\n",
" \n",
" print(f\"000{i}_00{j} - 000{i2}_00{j2}: {mi}, {s}, {mi/s:.2} | {mi_ap}, {s_ap}, {mi_ap/s_ap:.2}\")"
]
},
{
"cell_type": "code",
"execution_count": 31,
"id": "09919e3f-cb67-4263-bd93-4e2a6a5e6dac",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"DATABASE_ALL = []\n",
"\n",
"for i, j in ij:\n",
" iris_code = imread_black_and_white(f\"{DATA_DIR}/IrisCodes/000{i}_00{j}_code.bmp\")\n",
" mask = imread_black_and_white(f\"{DATA_DIR}/NormalizedMasks/000{i}_00{j}_mano.bmp\")\n",
" mask = np.array(total_mask.tolist() * 6)\n",
" \n",
" iris_code = iris_code[ap_indices]\n",
" mask = mask[ap_indices]\n",
" \n",
" DATABASE_ALL.append((iris_code, mask))"
]
},
{
"cell_type": "code",
"execution_count": 32,
"id": "874b9a51-eb02-43d5-a27f-9470069ce102",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"import random\n",
"random.shuffle(DATABASE_ALL)"
]
},
{
"cell_type": "code",
"execution_count": 33,
"id": "81ba46ad-83bc-47fd-871a-76c66b27a2f2",
"metadata": {
"tags": []
},
"outputs": [
{
"data": {
"text/plain": [
"8"
]
},
"execution_count": 33,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"len(DATABASE_ALL)"
]
},
{
"cell_type": "code",
"execution_count": 34,
"id": "cc1b121b-10ad-4e2a-8638-295fb2aca4d7",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"DATABASE, DATABASE_TEST = DATABASE_ALL[:4], DATABASE_ALL[4:]"
]
},
{
"cell_type": "code",
"execution_count": 35,
"id": "022179ff-5b2e-4a9a-9b9e-4cdfcf250517",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"DATABASE_COUNT = len(DATABASE)"
]
},
{
"cell_type": "code",
"execution_count": 36,
"id": "d32e94c9-7299-4a26-b2ff-078d6a49905c",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"import numpy as np\n",
"import concrete.numpy as cnp\n",
"from functools import reduce\n",
"\n",
"def hamming_distance(x, y) -> int:\n",
" return np.sum(x ^ y)\n",
"\n",
"\n",
"def min_int(x: int, y: int) -> int:\n",
" \"\"\"concrete-numpy doesn't yet support min, we have to implement one using\n",
" only supported operations\"\"\"\n",
" return (x + y - abs(x - y)) // 2\n",
"\n",
"\n",
"def min_int_array(a) -> int:\n",
" \"\"\"Return the minimum value of an array of ints using the `min_int` function\"\"\"\n",
" return reduce(min_int, a)\n",
"\n",
"def auth(iris_code, mask):\n",
" \"\"\"Return the best score from comparing the provided iris and mask to the\n",
" ones in the database, the user fo this function will need to define a threshold\n",
" to decide weather the score means an identified iris or not\n",
"\n",
" We know this is suboptimal but this is the best we could came up with right now\n",
" as we couldn't figure out a way to return an encrypted ID of the best match or\n",
" a special ID if the score is too low, mainly because we can't compare FHE values\n",
" \"\"\"\n",
" results = []\n",
"\n",
" for i in range(DATABASE_COUNT):\n",
" (iris_code2, mask2) = DATABASE[i]\n",
" combined_mask = mask & mask2\n",
" ey1 = iris_code & combined_mask\n",
" ey2 = iris_code2 & combined_mask\n",
" bshd = hamming_distance(ey1, ey2)\n",
" results.append(bshd)\n",
"\n",
" best_score = min_int_array(results)\n",
" return best_score"
]
},
{
"cell_type": "code",
"execution_count": 37,
"id": "f500133f-c0e8-4b01-8157-7cef204690b1",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"class IrisAuthenticator:\n",
" def __init__(self, input_shape, input_max_value) -> None:\n",
" self.inputset = [\n",
" (\n",
" np.random.randint(\n",
" 0, input_max_value + 1, size=input_shape, dtype=np.int64\n",
" ),\n",
" np.random.randint(\n",
" 0, input_max_value + 1, size=input_shape, dtype=np.int64\n",
" ),\n",
" )\n",
" for _ in range(100)\n",
" ]\n",
"\n",
" self.configuration = cnp.Configuration(\n",
" enable_unsafe_features=True,\n",
" use_insecure_key_cache=True,\n",
" insecure_key_cache_location=\".keys\",\n",
" )\n",
"\n",
" self.compiler = cnp.Compiler(\n",
" auth, {\"iris_code\": \"encrypted\", \"mask\": \"encrypted\"}\n",
" )\n",
" self.circuit = self.compiler.compile(self.inputset, self.configuration)"
]
},
{
"cell_type": "code",
"execution_count": 38,
"id": "7e465bec-1a77-43f6-ba9c-8d6cabdb2c6c",
"metadata": {
"tags": []
},
"outputs": [
{
"data": {
"text/plain": [
"80"
]
},
"execution_count": 38,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"auth(*DATABASE_TEST[0])"
]
},
{
"cell_type": "code",
"execution_count": 39,
"id": "ee108c6e-cca0-4bc7-85ee-ebd06e83d339",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"input_shape = DATABASE[0][0].shape"
]
},
{
"cell_type": "code",
"execution_count": 40,
"id": "29dc3d8e-d68a-4df7-aa68-f4944ab0cbe1",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"authenticator = IrisAuthenticator(input_shape=input_shape, input_max_value=1)"
]
},
{
"cell_type": "code",
"execution_count": 41,
"id": "c33a4d07-5507-46a1-97bf-6559de4471e1",
"metadata": {
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" %0 = iris_code # EncryptedTensor<uint1, shape=(1536,)> ∈ [0, 1]\n",
" %1 = mask # EncryptedTensor<uint1, shape=(1536,)> ∈ [0, 1]\n",
" %2 = [1 1 0 ... 0 1 0] # ClearTensor<uint1, shape=(1536,)> ∈ [0, 1]\n",
" %3 = bitwise_and(%1, %2) # EncryptedTensor<uint1, shape=(1536,)> ∈ [0, 1]\n",
" %4 = bitwise_and(%0, %3) # EncryptedTensor<uint1, shape=(1536,)> ∈ [0, 1]\n",
" %5 = [1 1 0 ... 0 1 1] # ClearTensor<uint1, shape=(1536,)> ∈ [0, 1]\n",
" %6 = bitwise_and(%5, %3) # EncryptedTensor<uint1, shape=(1536,)> ∈ [0, 1]\n",
" %7 = bitwise_xor(%4, %6) # EncryptedTensor<uint1, shape=(1536,)> ∈ [0, 1]\n",
" %8 = sum(%7) # EncryptedScalar<uint8> ∈ [87, 129]\n",
" %9 = [1 1 0 ... 0 1 0] # ClearTensor<uint1, shape=(1536,)> ∈ [0, 1]\n",
"%10 = bitwise_and(%1, %9) # EncryptedTensor<uint1, shape=(1536,)> ∈ [0, 1]\n",
"%11 = bitwise_and(%0, %10) # EncryptedTensor<uint1, shape=(1536,)> ∈ [0, 1]\n",
"%12 = [0 1 1 ... 0 1 0] # ClearTensor<uint1, shape=(1536,)> ∈ [0, 1]\n",
"%13 = bitwise_and(%12, %10) # EncryptedTensor<uint1, shape=(1536,)> ∈ [0, 1]\n",
"%14 = bitwise_xor(%11, %13) # EncryptedTensor<uint1, shape=(1536,)> ∈ [0, 1]\n",
"%15 = sum(%14) # EncryptedScalar<uint8> ∈ [82, 128]\n",
"%16 = [1 1 0 ... 0 1 0] # ClearTensor<uint1, shape=(1536,)> ∈ [0, 1]\n",
"%17 = bitwise_and(%1, %16) # EncryptedTensor<uint1, shape=(1536,)> ∈ [0, 1]\n",
"%18 = bitwise_and(%0, %17) # EncryptedTensor<uint1, shape=(1536,)> ∈ [0, 1]\n",
"%19 = [1 1 0 ... 0 1 0] # ClearTensor<uint1, shape=(1536,)> ∈ [0, 1]\n",
"%20 = bitwise_and(%19, %17) # EncryptedTensor<uint1, shape=(1536,)> ∈ [0, 1]\n",
"%21 = bitwise_xor(%18, %20) # EncryptedTensor<uint1, shape=(1536,)> ∈ [0, 1]\n",
"%22 = sum(%21) # EncryptedScalar<uint7> ∈ [77, 122]\n",
"%23 = [1 1 0 ... 0 1 0] # ClearTensor<uint1, shape=(1536,)> ∈ [0, 1]\n",
"%24 = bitwise_and(%1, %23) # EncryptedTensor<uint1, shape=(1536,)> ∈ [0, 1]\n",
"%25 = bitwise_and(%0, %24) # EncryptedTensor<uint1, shape=(1536,)> ∈ [0, 1]\n",
"%26 = [0 0 1 ... 0 1 0] # ClearTensor<uint1, shape=(1536,)> ∈ [0, 1]\n",
"%27 = bitwise_and(%26, %24) # EncryptedTensor<uint1, shape=(1536,)> ∈ [0, 1]\n",
"%28 = bitwise_xor(%25, %27) # EncryptedTensor<uint1, shape=(1536,)> ∈ [0, 1]\n",
"%29 = sum(%28) # EncryptedScalar<uint7> ∈ [87, 122]\n",
"%30 = add(%8, %15) # EncryptedScalar<uint8> ∈ [175, 251]\n",
"%31 = subtract(%8, %15) # EncryptedScalar<int6> ∈ [-25, 25]\n",
"%32 = absolute(%31) # EncryptedScalar<uint5> ∈ [0, 25]\n",
"%33 = subtract(%30, %32) # EncryptedScalar<uint8> ∈ [164, 246]\n",
"%34 = 2 # ClearScalar<uint2> ∈ [2, 2]\n",
"%35 = floor_divide(%33, %34) # EncryptedScalar<uint7> ∈ [82, 123]\n",
"%36 = add(%35, %22) # EncryptedScalar<uint8> ∈ [162, 238]\n",
"%37 = subtract(%35, %22) # EncryptedScalar<int6> ∈ [-28, 15]\n",
"%38 = absolute(%37) # EncryptedScalar<uint5> ∈ [0, 28]\n",
"%39 = subtract(%36, %38) # EncryptedScalar<uint8> ∈ [154, 236]\n",
"%40 = 2 # ClearScalar<uint2> ∈ [2, 2]\n",
"%41 = floor_divide(%39, %40) # EncryptedScalar<uint7> ∈ [77, 118]\n",
"%42 = add(%41, %29) # EncryptedScalar<uint8> ∈ [165, 229]\n",
"%43 = subtract(%41, %29) # EncryptedScalar<int6> ∈ [-20, 10]\n",
"%44 = absolute(%43) # EncryptedScalar<uint5> ∈ [0, 20]\n",
"%45 = subtract(%42, %44) # EncryptedScalar<uint8> ∈ [154, 224]\n",
"%46 = 2 # ClearScalar<uint2> ∈ [2, 2]\n",
"%47 = floor_divide(%45, %46) # EncryptedScalar<uint7> ∈ [77, 112]\n",
"return %47\n"
]
}
],
"source": [
"print(authenticator.circuit)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8d2ad28e-c677-4d60-ae39-f9f1d450bfcc",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"%%time\n",
"authenticator.circuit.encrypt_run_decrypt(*DATABASE_TEST[0])"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "19983196-3bb0-4dab-8561-53daa58dec38",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
-227
View File
@@ -1,227 +0,0 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 2,
"id": "b68a03a8-66ac-4ea6-8877-d9f275c426c8",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"import concrete.numpy as cnp"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "cc450eeb-80bd-47d6-80a5-30412d6b915b",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"server = cnp.Server.load(\"server.zip\")"
]
},
{
"cell_type": "code",
"execution_count": 46,
"id": "a2714e44-c220-493b-a496-76a6c576fc4d",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"database = [1, 2, 3]\n",
"length = 3"
]
},
{
"cell_type": "code",
"execution_count": 47,
"id": "ededbaea-6580-4ef1-a2a0-17eb37345251",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"def add(x):\n",
" for i in range(length):\n",
" x = x + database[i]\n",
" return x"
]
},
{
"cell_type": "code",
"execution_count": 48,
"id": "28a6a655-1347-4786-90f2-0508f4a39045",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"compiler = cnp.Compiler(add, {\"x\": \"encrypted\"})"
]
},
{
"cell_type": "code",
"execution_count": 49,
"id": "6ae28109-d78c-419c-9515-d234999c7b80",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"circuit = compiler.compile(list(range(15)))"
]
},
{
"cell_type": "code",
"execution_count": 53,
"id": "25123519-c254-4c3a-9671-0b3f6cb9a46a",
"metadata": {
"tags": []
},
"outputs": [
{
"data": {
"text/plain": [
"11"
]
},
"execution_count": 53,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"circuit.encrypt_run_decrypt(5)"
]
},
{
"cell_type": "code",
"execution_count": 51,
"id": "6f766a43-28b5-42cc-a17b-615315381d65",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"database[2] = 4"
]
},
{
"cell_type": "code",
"execution_count": 52,
"id": "0ebc17ce-7c3a-4fd9-90b1-5a36d3303bd7",
"metadata": {
"tags": []
},
"outputs": [
{
"data": {
"text/plain": [
"[1, 2, 4]"
]
},
"execution_count": 52,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"database"
]
},
{
"cell_type": "code",
"execution_count": 42,
"id": "3cd8d334-4a6e-4d2e-bc7a-23d2fa638e73",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"one = circuit.encrypt(1)"
]
},
{
"cell_type": "code",
"execution_count": 24,
"id": "56319de0-c4e0-4a44-a9b6-bc23da28428d",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"database = [one, one, one]"
]
},
{
"cell_type": "code",
"execution_count": 28,
"id": "21bc43bd-7b3c-4c06-99d9-7a64767008a3",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"one_pa = one.cpp()"
]
},
{
"cell_type": "code",
"execution_count": 31,
"id": "3a25fa35-d3c6-409c-9013-d1f2be45a1a5",
"metadata": {
"tags": []
},
"outputs": [
{
"ename": "TypeError",
"evalue": "unsupported operand type(s) for +: 'mlir._mlir_libs._concretelang._compiler.PublicArguments' and 'mlir._mlir_libs._concretelang._compiler.PublicArguments'",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)",
"Cell \u001b[0;32mIn[31], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mone_pa\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m+\u001b[39;49m\u001b[43m \u001b[49m\u001b[43mone_pa\u001b[49m\n",
"\u001b[0;31mTypeError\u001b[0m: unsupported operand type(s) for +: 'mlir._mlir_libs._concretelang._compiler.PublicArguments' and 'mlir._mlir_libs._concretelang._compiler.PublicArguments'"
]
}
],
"source": [
"one_pa + one_pa"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a765a3a0-254c-4197-a20b-bd1933052745",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
-13
View File
@@ -1,13 +0,0 @@
- Compiling this results in an error message missing some data in "must be <missing_data>"
```python
def f(x, y):
return np.sum(x) + np.sum(y)
compiler = cnp.Compiler(f, {"x": "encrypted", "y": "encrypted"})
circuit = compiler.compile([(1, 2)])
```
```
error: 'FHELinalg.sum' op operand #0 must be , but got '!FHE.eint<33>'
loc("-":5:10): error: 'FHELinalg.sum' op operand #0 must be , but got '!FHE.eint<33>'
```
Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

-181
View File
@@ -1,181 +0,0 @@
use std::{collections::HashMap, fs, time};
use clap::Parser;
use tfhe::shortint::parameters::PARAM_MESSAGE_8_CARRY_0;
/// Simple program to greet a person
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Args {
iris_codes_path: String,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
main_tfhe_hamming_distance();
// main_tfhe_bitxor();
Ok(())
}
fn main_authentication() -> Result<(), Box<dyn std::error::Error>> {
let args = Args::parse();
println!("Reading iris codes from {}", args.iris_codes_path);
let iris_codes = fs::read_to_string(args.iris_codes_path)?;
let api_url = "https://httpbin.org/ip";
println!("Sending authentication request to {api_url}");
let client = reqwest::blocking::Client::new();
let response = client
.post(api_url)
.body(iris_codes)
.header("Content-Type", "application/json")
.send()?;
println!("Authentication server response {response:#?}");
Ok(())
}
fn main_tfhe_generator_accumulator() {
use tfhe::shortint::prelude::*;
use tfhe::shortint::Parameters;
// Generate a set of client/server keys, using the default parameters:
let (client_key, server_key) = gen_keys(PARAM_MESSAGE_8_CARRY_0);
let msg1 = 3;
let msg2 = 2;
// Encrypt two messages using the (private) client key:
let ct_1 = client_key.encrypt(msg1);
let ct_2 = client_key.encrypt(msg2);
// Homomorphically compute an addition
let ct_add = server_key.unchecked_add(&ct_1, &ct_2);
let add = client_key.decrypt(&ct_add);
println!("add={add}");
// Define the Hamming weight function
// f: x -> sum of the bits of x
let f = |x: u64| x.count_ones() as u64;
// Generate the accumulator for the function
let acc = server_key.generate_accumulator(f);
// Compute the function over the ciphertext using the PBS
let ct_res = server_key.keyswitch_programmable_bootstrap(&ct_add, &acc);
// Decrypt the ciphertext using the (private) client key
let output = client_key.decrypt(&ct_res);
println!("output={output}");
assert_eq!(output, f(msg1 + msg2));
}
fn generate_keys() -> (tfhe::shortint::ClientKey, tfhe::shortint::ServerKey) {
use tfhe::shortint::parameters::PARAM_MESSAGE_4_CARRY_4;
// Generate the client key and the server key:
println!("Start generating keys");
let start = time::Instant::now();
let (cks, sks) = gen_keys(PARAM_MESSAGE_4_CARRY_4);
let end = time::Instant::now();
let bits = (cks.parameters.message_modulus.0 as f32).log2();
let carry = (cks.parameters.carry_modulus.0 as f32).log2();
let duration = end - start;
println!("Generated {bits}-bit and {carry}-bit key in {duration:?}");
(cks, sks)
}
fn main_tfhe_bitxor() {
// let (cks, sks) = gen_keys(PARAM_MESSAGE_4_CARRY_0);
let (cks, sks) = generate_keys();
let zero = cks.encrypt(0);
let one = cks.encrypt(1);
let one_zero = sks.unchecked_bitxor(&one, &zero);
let one_zero = cks.decrypt(&one_zero);
println!("one ^ zero = {one_zero}, should be = {}", 1 ^ 0);
let zero_one = sks.unchecked_bitxor(&zero, &one);
let zero_one = cks.decrypt(&zero_one);
println!("zero ^ one = {zero_one}, should be = {}", 0 ^ 1);
let one_one = sks.unchecked_bitxor(&one, &one);
let one_one = cks.decrypt(&one_one);
println!("one ^ one = {one_one}, should be = {}", 1 ^ 1);
let zero_zero = sks.unchecked_bitxor(&zero, &zero);
let zero_zero = cks.decrypt(&zero_zero);
println!("zero ^ zero = {zero_zero}, should be = {}", 0 ^ 0);
}
fn main_tfhe_hamming_distance() {
let (cks, sks) = generate_keys();
let a1 = [1, 1, 0, 1];
let a2 = [0, 1, 1, 1];
let encrypted_a1 = a1.iter().map(|m| cks.encrypt(*m)).collect::<Vec<_>>();
let encrypted_a2 = a2.iter().map(|m| cks.encrypt(*m)).collect::<Vec<_>>();
// Compute homomorphically a hamming distance:
let ct_res = fhe_hamming_distance(sks, &encrypted_a1, &encrypted_a2).unwrap();
// Decrypt:
let res = cks.decrypt(&ct_res);
println!("res={res}");
}
use tfhe::shortint::prelude::*;
// Server side
fn fhe_hamming_distance(
sks: ServerKey,
x: &[Ciphertext],
y: &[Ciphertext],
) -> Result<Ciphertext, Box<dyn std::error::Error>> {
// TODO: - use checked_bitxor and checked_add
// TODO: - don't use unwrap
Ok(x.iter()
.zip(y.iter())
.map(|(l, r)| sks.unchecked_bitxor(l, r))
.reduce(|l, r| sks.unchecked_add(&l, &r))
.unwrap())
}
fn fhe_hamming_distance_with_shift(
sks: ServerKey,
x: &[Ciphertext],
y: &[Ciphertext],
n: usize,
) -> Result<Vec<Ciphertext>, Box<dyn std::error::Error>> {
let mut x = x.to_vec();
let mut result: Vec<Ciphertext> = Vec::new();
result.push(fhe_hamming_distance(sks.clone(), &x, y)?);
for _ in 1..n {
x.rotate_right(1);
result.push(fhe_hamming_distance(sks, &x, y)?);
}
// let shifted_left = (1..n).into_iter().map(|i| x.rotate_left(i));
// let shifted_right = (1..n).into_iter().map(|i| x.rotate_right(i));
// let shifted = shifted_left.chain(shifted_right);
// let hs = shifted.map(|x| fhe_hamming_distance(sks, x, y));
Ok(result)
}
-257
View File
@@ -1,257 +0,0 @@
256
6 7
6 23
6 39
6 55
6 71
6 87
6 103
6 119
6 135
6 151
6 167
6 183
6 199
6 215
6 231
6 247
6 263
6 279
6 295
6 311
6 327
6 343
6 359
6 375
6 391
6 407
6 423
6 439
6 455
6 471
6 487
6 503
12 7
12 23
12 39
12 55
12 71
12 87
12 103
12 119
12 135
12 151
12 167
12 183
12 199
12 215
12 231
12 247
12 263
12 279
12 295
12 311
12 327
12 343
12 359
12 375
12 391
12 407
12 423
12 439
12 455
12 471
12 487
12 503
18 7
18 23
18 39
18 55
18 71
18 87
18 103
18 119
18 135
18 151
18 167
18 183
18 199
18 215
18 231
18 247
18 263
18 279
18 295
18 311
18 327
18 343
18 359
18 375
18 391
18 407
18 423
18 439
18 455
18 471
18 487
18 503
24 7
24 23
24 39
24 55
24 71
24 87
24 103
24 119
24 135
24 151
24 167
24 183
24 199
24 215
24 231
24 247
24 263
24 279
24 295
24 311
24 327
24 343
24 359
24 375
24 391
24 407
24 423
24 439
24 455
24 471
24 487
24 503
30 7
30 23
30 39
30 55
30 71
30 87
30 103
30 119
30 135
30 151
30 167
30 183
30 199
30 215
30 231
30 247
30 263
30 279
30 295
30 311
30 327
30 343
30 359
30 375
30 391
30 407
30 423
30 439
30 455
30 471
30 487
30 503
36 7
36 23
36 39
36 55
36 71
36 87
36 103
36 119
36 135
36 151
36 167
36 183
36 199
36 215
36 231
36 247
36 263
36 279
36 295
36 311
36 327
36 343
36 359
36 375
36 391
36 407
36 423
36 439
36 455
36 471
36 487
36 503
42 7
42 23
42 39
42 55
42 71
42 87
42 103
42 119
42 135
42 151
42 167
42 183
42 199
42 215
42 231
42 247
42 263
42 279
42 295
42 311
42 327
42 343
42 359
42 375
42 391
42 407
42 423
42 439
42 455
42 471
42 487
42 503
48 7
48 23
48 39
48 55
48 71
48 87
48 103
48 119
48 135
48 151
48 167
48 183
48 199
48 215
48 231
48 247
48 263
48 279
48 295
48 311
48 327
48 343
48 359
48 375
48 391
48 407
48 423
48 439
48 455
48 471
48 487
48 503
Binary file not shown.
-970
View File
@@ -1,970 +0,0 @@
# This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand.
[[package]]
name = "anyio"
version = "3.6.2"
description = "High level compatibility layer for multiple asynchronous event loop implementations"
category = "dev"
optional = false
python-versions = ">=3.6.2"
files = [
{file = "anyio-3.6.2-py3-none-any.whl", hash = "sha256:fbbe32bd270d2a2ef3ed1c5d45041250284e31fc0a4df4a5a6071842051a51e3"},
{file = "anyio-3.6.2.tar.gz", hash = "sha256:25ea0d673ae30af41a0c442f81cf3b38c7e79fdc7b60335a4c14e05eb0947421"},
]
[package.dependencies]
idna = ">=2.8"
sniffio = ">=1.1"
[package.extras]
doc = ["packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"]
test = ["contextlib2", "coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "mock (>=4)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (<0.15)", "uvloop (>=0.15)"]
trio = ["trio (>=0.16,<0.22)"]
[[package]]
name = "attrs"
version = "22.2.0"
description = "Classes Without Boilerplate"
category = "dev"
optional = false
python-versions = ">=3.6"
files = [
{file = "attrs-22.2.0-py3-none-any.whl", hash = "sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836"},
{file = "attrs-22.2.0.tar.gz", hash = "sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99"},
]
[package.extras]
cov = ["attrs[tests]", "coverage-enable-subprocess", "coverage[toml] (>=5.3)"]
dev = ["attrs[docs,tests]"]
docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope.interface"]
tests = ["attrs[tests-no-zope]", "zope.interface"]
tests-no-zope = ["cloudpickle", "cloudpickle", "hypothesis", "hypothesis", "mypy (>=0.971,<0.990)", "mypy (>=0.971,<0.990)", "pympler", "pympler", "pytest (>=4.3.0)", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-mypy-plugins", "pytest-xdist[psutil]", "pytest-xdist[psutil]"]
[[package]]
name = "colorama"
version = "0.4.6"
description = "Cross-platform colored terminal text."
category = "dev"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
files = [
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
]
[[package]]
name = "concrete-compiler"
version = "0.24.0rc5"
description = "Concrete Compiler"
category = "main"
optional = false
python-versions = "*"
files = [
{file = "concrete_compiler-0.24.0rc5-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:c99e79d72f55af33695361bdc366287c725c0c0e9bde148c97e5c63139554870"},
{file = "concrete_compiler-0.24.0rc5-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:0cc24dbc02f6b974720dbb31cf9b737866d8a4e425a86d0342e6116b93381665"},
{file = "concrete_compiler-0.24.0rc5-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:b94f39d114be84ca483bf093304ab60ad73b8d9984a58697fe0f9d6e990c9b96"},
{file = "concrete_compiler-0.24.0rc5-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:72ef65c9827e8bcd38fd87a0ac356f89f850d5d9c178fe1224d3a8dcccc181c9"},
{file = "concrete_compiler-0.24.0rc5-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:893789cb25227049e8e8c6a9dfb80c2a5132c4beef38105d6d464e10cd0221b3"},
{file = "concrete_compiler-0.24.0rc5-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:4e1aef7eae87daffcc500b84fbc36c1c460d5d202cdc31ee753a3eafe4866269"},
{file = "concrete_compiler-0.24.0rc5-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:8de4396fbb48c0a20b65e448cf3ee2ef15f801d75bf358c343a5f350f49b5a56"},
]
[package.dependencies]
numpy = "*"
PyYAML = "*"
setuptools = "*"
[[package]]
name = "concrete-numpy"
version = "0.11.1"
description = "Concrete Numpy is an open-source library which simplifies the use of fully homomorphic encryption (FHE)."
category = "main"
optional = false
python-versions = ">=3.7,<3.12"
files = [
{file = "concrete_numpy-0.11.1-py3-none-any.whl", hash = "sha256:e348650c10de46335d2fd92adb2ca98f2d7cce1088bd108c2f57020fb5e788a2"},
]
[package.dependencies]
concrete-compiler = "0.24.0rc5"
matplotlib = ">=3.5.1,<4.0.0"
networkx = ">=2.6.3,<3.0.0"
numpy = {version = ">=1.23.5,<2.0.0", markers = "python_full_version >= \"3.8.0\""}
scipy = {version = ">=1.10.1,<2.0.0", markers = "python_full_version >= \"3.8.0\""}
torch = ">=1.13.1,<2.0.0"
[[package]]
name = "cycler"
version = "0.11.0"
description = "Composable style cycles"
category = "main"
optional = false
python-versions = ">=3.6"
files = [
{file = "cycler-0.11.0-py3-none-any.whl", hash = "sha256:3a27e95f763a428a739d2add979fa7494c912a32c17c4c38c4d5f082cad165a3"},
{file = "cycler-0.11.0.tar.gz", hash = "sha256:9c87405839a19696e837b3b818fed3f5f69f16f1eec1a1ad77e043dcea9c772f"},
]
[[package]]
name = "exceptiongroup"
version = "1.1.1"
description = "Backport of PEP 654 (exception groups)"
category = "dev"
optional = false
python-versions = ">=3.7"
files = [
{file = "exceptiongroup-1.1.1-py3-none-any.whl", hash = "sha256:232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e"},
{file = "exceptiongroup-1.1.1.tar.gz", hash = "sha256:d484c3090ba2889ae2928419117447a14daf3c1231d5e30d0aae34f354f01785"},
]
[package.extras]
test = ["pytest (>=6)"]
[[package]]
name = "fastapi"
version = "0.95.0"
description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production"
category = "dev"
optional = false
python-versions = ">=3.7"
files = [
{file = "fastapi-0.95.0-py3-none-any.whl", hash = "sha256:daf73bbe844180200be7966f68e8ec9fd8be57079dff1bacb366db32729e6eb5"},
{file = "fastapi-0.95.0.tar.gz", hash = "sha256:99d4fdb10e9dd9a24027ac1d0bd4b56702652056ca17a6c8721eec4ad2f14e18"},
]
[package.dependencies]
pydantic = ">=1.6.2,<1.7 || >1.7,<1.7.1 || >1.7.1,<1.7.2 || >1.7.2,<1.7.3 || >1.7.3,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0"
starlette = ">=0.26.1,<0.27.0"
[package.extras]
all = ["email-validator (>=1.1.1)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "python-multipart (>=0.0.5)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"]
dev = ["pre-commit (>=2.17.0,<3.0.0)", "ruff (==0.0.138)", "uvicorn[standard] (>=0.12.0,<0.21.0)"]
doc = ["mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "pyyaml (>=5.3.1,<7.0.0)", "typer-cli (>=0.0.13,<0.0.14)", "typer[all] (>=0.6.1,<0.8.0)"]
test = ["anyio[trio] (>=3.2.1,<4.0.0)", "black (==23.1.0)", "coverage[toml] (>=6.5.0,<8.0)", "databases[sqlite] (>=0.3.2,<0.7.0)", "email-validator (>=1.1.1,<2.0.0)", "flask (>=1.1.2,<3.0.0)", "httpx (>=0.23.0,<0.24.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.982)", "orjson (>=3.2.1,<4.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "peewee (>=3.13.3,<4.0.0)", "pytest (>=7.1.3,<8.0.0)", "python-jose[cryptography] (>=3.3.0,<4.0.0)", "python-multipart (>=0.0.5,<0.0.7)", "pyyaml (>=5.3.1,<7.0.0)", "ruff (==0.0.138)", "sqlalchemy (>=1.3.18,<1.4.43)", "types-orjson (==3.6.2)", "types-ujson (==5.7.0.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)"]
[[package]]
name = "fonttools"
version = "4.38.0"
description = "Tools to manipulate font files"
category = "main"
optional = false
python-versions = ">=3.7"
files = [
{file = "fonttools-4.38.0-py3-none-any.whl", hash = "sha256:820466f43c8be8c3009aef8b87e785014133508f0de64ec469e4efb643ae54fb"},
{file = "fonttools-4.38.0.zip", hash = "sha256:2bb244009f9bf3fa100fc3ead6aeb99febe5985fa20afbfbaa2f8946c2fbdaf1"},
]
[package.extras]
all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0,<5)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=14.0.0)", "xattr", "zopfli (>=0.1.4)"]
graphite = ["lz4 (>=1.7.4.2)"]
interpolatable = ["munkres", "scipy"]
lxml = ["lxml (>=4.0,<5)"]
pathops = ["skia-pathops (>=0.5.0)"]
plot = ["matplotlib"]
repacker = ["uharfbuzz (>=0.23.0)"]
symfont = ["sympy"]
type1 = ["xattr"]
ufo = ["fs (>=2.2.0,<3)"]
unicode = ["unicodedata2 (>=14.0.0)"]
woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"]
[[package]]
name = "hypothesis"
version = "6.70.2"
description = "A library for property-based testing"
category = "dev"
optional = false
python-versions = ">=3.7"
files = [
{file = "hypothesis-6.70.2-py3-none-any.whl", hash = "sha256:91869c4a29a04e812f677ded7e692c7e37514239e9137d21e3567fa4e1348c02"},
{file = "hypothesis-6.70.2.tar.gz", hash = "sha256:a8d1d96ae2214f8ca4b8109d555df08e1eb5c31dd7e3995e53413c7094f74dcc"},
]
[package.dependencies]
attrs = ">=19.2.0"
exceptiongroup = {version = ">=1.0.0", markers = "python_version < \"3.11\""}
sortedcontainers = ">=2.1.0,<3.0.0"
[package.extras]
all = ["backports.zoneinfo (>=0.2.1)", "black (>=19.10b0)", "click (>=7.0)", "django (>=3.2)", "dpcontracts (>=0.4)", "importlib-metadata (>=3.6)", "lark (>=0.10.1)", "libcst (>=0.3.16)", "numpy (>=1.9.0)", "pandas (>=1.0)", "pytest (>=4.6)", "python-dateutil (>=1.4)", "pytz (>=2014.1)", "redis (>=3.0.0)", "rich (>=9.0.0)", "tzdata (>=2023.3)"]
cli = ["black (>=19.10b0)", "click (>=7.0)", "rich (>=9.0.0)"]
codemods = ["libcst (>=0.3.16)"]
dateutil = ["python-dateutil (>=1.4)"]
django = ["django (>=3.2)"]
dpcontracts = ["dpcontracts (>=0.4)"]
ghostwriter = ["black (>=19.10b0)"]
lark = ["lark (>=0.10.1)"]
numpy = ["numpy (>=1.9.0)"]
pandas = ["pandas (>=1.0)"]
pytest = ["pytest (>=4.6)"]
pytz = ["pytz (>=2014.1)"]
redis = ["redis (>=3.0.0)"]
zoneinfo = ["backports.zoneinfo (>=0.2.1)", "tzdata (>=2023.3)"]
[[package]]
name = "idna"
version = "3.4"
description = "Internationalized Domain Names in Applications (IDNA)"
category = "dev"
optional = false
python-versions = ">=3.5"
files = [
{file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"},
{file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"},
]
[[package]]
name = "iniconfig"
version = "2.0.0"
description = "brain-dead simple config-ini parsing"
category = "dev"
optional = false
python-versions = ">=3.7"
files = [
{file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"},
{file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"},
]
[[package]]
name = "kiwisolver"
version = "1.4.4"
description = "A fast implementation of the Cassowary constraint solver"
category = "main"
optional = false
python-versions = ">=3.7"
files = [
{file = "kiwisolver-1.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2f5e60fabb7343a836360c4f0919b8cd0d6dbf08ad2ca6b9cf90bf0c76a3c4f6"},
{file = "kiwisolver-1.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:10ee06759482c78bdb864f4109886dff7b8a56529bc1609d4f1112b93fe6423c"},
{file = "kiwisolver-1.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c79ebe8f3676a4c6630fd3f777f3cfecf9289666c84e775a67d1d358578dc2e3"},
{file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:abbe9fa13da955feb8202e215c4018f4bb57469b1b78c7a4c5c7b93001699938"},
{file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7577c1987baa3adc4b3c62c33bd1118c3ef5c8ddef36f0f2c950ae0b199e100d"},
{file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8ad8285b01b0d4695102546b342b493b3ccc6781fc28c8c6a1bb63e95d22f09"},
{file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ed58b8acf29798b036d347791141767ccf65eee7f26bde03a71c944449e53de"},
{file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a68b62a02953b9841730db7797422f983935aeefceb1679f0fc85cbfbd311c32"},
{file = "kiwisolver-1.4.4-cp310-cp310-win32.whl", hash = "sha256:e92a513161077b53447160b9bd8f522edfbed4bd9759e4c18ab05d7ef7e49408"},
{file = "kiwisolver-1.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:3fe20f63c9ecee44560d0e7f116b3a747a5d7203376abeea292ab3152334d004"},
{file = "kiwisolver-1.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e0ea21f66820452a3f5d1655f8704a60d66ba1191359b96541eaf457710a5fc6"},
{file = "kiwisolver-1.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bc9db8a3efb3e403e4ecc6cd9489ea2bac94244f80c78e27c31dcc00d2790ac2"},
{file = "kiwisolver-1.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d5b61785a9ce44e5a4b880272baa7cf6c8f48a5180c3e81c59553ba0cb0821ca"},
{file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c2dbb44c3f7e6c4d3487b31037b1bdbf424d97687c1747ce4ff2895795c9bf69"},
{file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6295ecd49304dcf3bfbfa45d9a081c96509e95f4b9d0eb7ee4ec0530c4a96514"},
{file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4bd472dbe5e136f96a4b18f295d159d7f26fd399136f5b17b08c4e5f498cd494"},
{file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf7d9fce9bcc4752ca4a1b80aabd38f6d19009ea5cbda0e0856983cf6d0023f5"},
{file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78d6601aed50c74e0ef02f4204da1816147a6d3fbdc8b3872d263338a9052c51"},
{file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:877272cf6b4b7e94c9614f9b10140e198d2186363728ed0f701c6eee1baec1da"},
{file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:db608a6757adabb32f1cfe6066e39b3706d8c3aa69bbc353a5b61edad36a5cb4"},
{file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:5853eb494c71e267912275e5586fe281444eb5e722de4e131cddf9d442615626"},
{file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:f0a1dbdb5ecbef0d34eb77e56fcb3e95bbd7e50835d9782a45df81cc46949750"},
{file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:283dffbf061a4ec60391d51e6155e372a1f7a4f5b15d59c8505339454f8989e4"},
{file = "kiwisolver-1.4.4-cp311-cp311-win32.whl", hash = "sha256:d06adcfa62a4431d404c31216f0f8ac97397d799cd53800e9d3efc2fbb3cf14e"},
{file = "kiwisolver-1.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:e7da3fec7408813a7cebc9e4ec55afed2d0fd65c4754bc376bf03498d4e92686"},
{file = "kiwisolver-1.4.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:62ac9cc684da4cf1778d07a89bf5f81b35834cb96ca523d3a7fb32509380cbf6"},
{file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41dae968a94b1ef1897cb322b39360a0812661dba7c682aa45098eb8e193dbdf"},
{file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02f79693ec433cb4b5f51694e8477ae83b3205768a6fb48ffba60549080e295b"},
{file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d0611a0a2a518464c05ddd5a3a1a0e856ccc10e67079bb17f265ad19ab3c7597"},
{file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:db5283d90da4174865d520e7366801a93777201e91e79bacbac6e6927cbceede"},
{file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1041feb4cda8708ce73bb4dcb9ce1ccf49d553bf87c3954bdfa46f0c3f77252c"},
{file = "kiwisolver-1.4.4-cp37-cp37m-win32.whl", hash = "sha256:a553dadda40fef6bfa1456dc4be49b113aa92c2a9a9e8711e955618cd69622e3"},
{file = "kiwisolver-1.4.4-cp37-cp37m-win_amd64.whl", hash = "sha256:03baab2d6b4a54ddbb43bba1a3a2d1627e82d205c5cf8f4c924dc49284b87166"},
{file = "kiwisolver-1.4.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:841293b17ad704d70c578f1f0013c890e219952169ce8a24ebc063eecf775454"},
{file = "kiwisolver-1.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f4f270de01dd3e129a72efad823da90cc4d6aafb64c410c9033aba70db9f1ff0"},
{file = "kiwisolver-1.4.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f9f39e2f049db33a908319cf46624a569b36983c7c78318e9726a4cb8923b26c"},
{file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c97528e64cb9ebeff9701e7938653a9951922f2a38bd847787d4a8e498cc83ae"},
{file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d1573129aa0fd901076e2bfb4275a35f5b7aa60fbfb984499d661ec950320b0"},
{file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ad881edc7ccb9d65b0224f4e4d05a1e85cf62d73aab798943df6d48ab0cd79a1"},
{file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b428ef021242344340460fa4c9185d0b1f66fbdbfecc6c63eff4b7c29fad429d"},
{file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:2e407cb4bd5a13984a6c2c0fe1845e4e41e96f183e5e5cd4d77a857d9693494c"},
{file = "kiwisolver-1.4.4-cp38-cp38-win32.whl", hash = "sha256:75facbe9606748f43428fc91a43edb46c7ff68889b91fa31f53b58894503a191"},
{file = "kiwisolver-1.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:5bce61af018b0cb2055e0e72e7d65290d822d3feee430b7b8203d8a855e78766"},
{file = "kiwisolver-1.4.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8c808594c88a025d4e322d5bb549282c93c8e1ba71b790f539567932722d7bd8"},
{file = "kiwisolver-1.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f0a71d85ecdd570ded8ac3d1c0f480842f49a40beb423bb8014539a9f32a5897"},
{file = "kiwisolver-1.4.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b533558eae785e33e8c148a8d9921692a9fe5aa516efbdff8606e7d87b9d5824"},
{file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:efda5fc8cc1c61e4f639b8067d118e742b812c930f708e6667a5ce0d13499e29"},
{file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7c43e1e1206cd421cd92e6b3280d4385d41d7166b3ed577ac20444b6995a445f"},
{file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc8d3bd6c72b2dd9decf16ce70e20abcb3274ba01b4e1c96031e0c4067d1e7cd"},
{file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4ea39b0ccc4f5d803e3337dd46bcce60b702be4d86fd0b3d7531ef10fd99a1ac"},
{file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:968f44fdbf6dd757d12920d63b566eeb4d5b395fd2d00d29d7ef00a00582aac9"},
{file = "kiwisolver-1.4.4-cp39-cp39-win32.whl", hash = "sha256:da7e547706e69e45d95e116e6939488d62174e033b763ab1496b4c29b76fabea"},
{file = "kiwisolver-1.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:ba59c92039ec0a66103b1d5fe588fa546373587a7d68f5c96f743c3396afc04b"},
{file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:91672bacaa030f92fc2f43b620d7b337fd9a5af28b0d6ed3f77afc43c4a64b5a"},
{file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:787518a6789009c159453da4d6b683f468ef7a65bbde796bcea803ccf191058d"},
{file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da152d8cdcab0e56e4f45eb08b9aea6455845ec83172092f09b0e077ece2cf7a"},
{file = "kiwisolver-1.4.4-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ecb1fa0db7bf4cff9dac752abb19505a233c7f16684c5826d1f11ebd9472b871"},
{file = "kiwisolver-1.4.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:28bc5b299f48150b5f822ce68624e445040595a4ac3d59251703779836eceff9"},
{file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:81e38381b782cc7e1e46c4e14cd997ee6040768101aefc8fa3c24a4cc58e98f8"},
{file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2a66fdfb34e05b705620dd567f5a03f239a088d5a3f321e7b6ac3239d22aa286"},
{file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:872b8ca05c40d309ed13eb2e582cab0c5a05e81e987ab9c521bf05ad1d5cf5cb"},
{file = "kiwisolver-1.4.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:70e7c2e7b750585569564e2e5ca9845acfaa5da56ac46df68414f29fea97be9f"},
{file = "kiwisolver-1.4.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9f85003f5dfa867e86d53fac6f7e6f30c045673fa27b603c397753bebadc3008"},
{file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e307eb9bd99801f82789b44bb45e9f541961831c7311521b13a6c85afc09767"},
{file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1792d939ec70abe76f5054d3f36ed5656021dcad1322d1cc996d4e54165cef9"},
{file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6cb459eea32a4e2cf18ba5fcece2dbdf496384413bc1bae15583f19e567f3b2"},
{file = "kiwisolver-1.4.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:36dafec3d6d6088d34e2de6b85f9d8e2324eb734162fba59d2ba9ed7a2043d5b"},
{file = "kiwisolver-1.4.4.tar.gz", hash = "sha256:d41997519fcba4a1e46eb4a2fe31bc12f0ff957b2b81bac28db24744f333e955"},
]
[[package]]
name = "matplotlib"
version = "3.5.3"
description = "Python plotting package"
category = "main"
optional = false
python-versions = ">=3.7"
files = [
{file = "matplotlib-3.5.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a206a1b762b39398efea838f528b3a6d60cdb26fe9d58b48265787e29cd1d693"},
{file = "matplotlib-3.5.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cd45a6f3e93a780185f70f05cf2a383daed13c3489233faad83e81720f7ede24"},
{file = "matplotlib-3.5.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d62880e1f60e5a30a2a8484432bcb3a5056969dc97258d7326ad465feb7ae069"},
{file = "matplotlib-3.5.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9ab29589cef03bc88acfa3a1490359000c18186fc30374d8aa77d33cc4a51a4a"},
{file = "matplotlib-3.5.3-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2886cc009f40e2984c083687251821f305d811d38e3df8ded414265e4583f0c5"},
{file = "matplotlib-3.5.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c995f7d9568f18b5db131ab124c64e51b6820a92d10246d4f2b3f3a66698a15b"},
{file = "matplotlib-3.5.3-cp310-cp310-win32.whl", hash = "sha256:6bb93a0492d68461bd458eba878f52fdc8ac7bdb6c4acdfe43dba684787838c2"},
{file = "matplotlib-3.5.3-cp310-cp310-win_amd64.whl", hash = "sha256:2e6d184ebe291b9e8f7e78bbab7987d269c38ea3e062eace1fe7d898042ef804"},
{file = "matplotlib-3.5.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6ea6aef5c4338e58d8d376068e28f80a24f54e69f09479d1c90b7172bad9f25b"},
{file = "matplotlib-3.5.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:839d47b8ead7ad9669aaacdbc03f29656dc21f0d41a6fea2d473d856c39c8b1c"},
{file = "matplotlib-3.5.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3b4fa56159dc3c7f9250df88f653f085068bcd32dcd38e479bba58909254af7f"},
{file = "matplotlib-3.5.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:94ff86af56a3869a4ae26a9637a849effd7643858a1a04dd5ee50e9ab75069a7"},
{file = "matplotlib-3.5.3-cp37-cp37m-win32.whl", hash = "sha256:35a8ad4dddebd51f94c5d24bec689ec0ec66173bf614374a1244c6241c1595e0"},
{file = "matplotlib-3.5.3-cp37-cp37m-win_amd64.whl", hash = "sha256:43e9d3fa077bf0cc95ded13d331d2156f9973dce17c6f0c8b49ccd57af94dbd9"},
{file = "matplotlib-3.5.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:22227c976ad4dc8c5a5057540421f0d8708c6560744ad2ad638d48e2984e1dbc"},
{file = "matplotlib-3.5.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bf618a825deb6205f015df6dfe6167a5d9b351203b03fab82043ae1d30f16511"},
{file = "matplotlib-3.5.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9befa5954cdbc085e37d974ff6053da269474177921dd61facdad8023c4aeb51"},
{file = "matplotlib-3.5.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3840c280ebc87a48488a46f760ea1c0c0c83fcf7abbe2e6baf99d033fd35fd8"},
{file = "matplotlib-3.5.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dacddf5bfcec60e3f26ec5c0ae3d0274853a258b6c3fc5ef2f06a8eb23e042be"},
{file = "matplotlib-3.5.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:b428076a55fb1c084c76cb93e68006f27d247169f056412607c5c88828d08f88"},
{file = "matplotlib-3.5.3-cp38-cp38-win32.whl", hash = "sha256:874df7505ba820e0400e7091199decf3ff1fde0583652120c50cd60d5820ca9a"},
{file = "matplotlib-3.5.3-cp38-cp38-win_amd64.whl", hash = "sha256:b28de401d928890187c589036857a270a032961411934bdac4cf12dde3d43094"},
{file = "matplotlib-3.5.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3211ba82b9f1518d346f6309df137b50c3dc4421b4ed4815d1d7eadc617f45a1"},
{file = "matplotlib-3.5.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6fe807e8a22620b4cd95cfbc795ba310dc80151d43b037257250faf0bfcd82bc"},
{file = "matplotlib-3.5.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5c096363b206a3caf43773abebdbb5a23ea13faef71d701b21a9c27fdcef72f4"},
{file = "matplotlib-3.5.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bcdfcb0f976e1bac6721d7d457c17be23cf7501f977b6a38f9d38a3762841f7"},
{file = "matplotlib-3.5.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1e64ac9be9da6bfff0a732e62116484b93b02a0b4d4b19934fb4f8e7ad26ad6a"},
{file = "matplotlib-3.5.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:73dd93dc35c85dece610cca8358003bf0760d7986f70b223e2306b4ea6d1406b"},
{file = "matplotlib-3.5.3-cp39-cp39-win32.whl", hash = "sha256:879c7e5fce4939c6aa04581dfe08d57eb6102a71f2e202e3314d5fbc072fd5a0"},
{file = "matplotlib-3.5.3-cp39-cp39-win_amd64.whl", hash = "sha256:ab8d26f07fe64f6f6736d635cce7bfd7f625320490ed5bfc347f2cdb4fae0e56"},
{file = "matplotlib-3.5.3-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:99482b83ebf4eb6d5fc6813d7aacdefdd480f0d9c0b52dcf9f1cc3b2c4b3361a"},
{file = "matplotlib-3.5.3-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f814504e459c68118bf2246a530ed953ebd18213dc20e3da524174d84ed010b2"},
{file = "matplotlib-3.5.3-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:57f1b4e69f438a99bb64d7f2c340db1b096b41ebaa515cf61ea72624279220ce"},
{file = "matplotlib-3.5.3-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:d2484b350bf3d32cae43f85dcfc89b3ed7bd2bcd781ef351f93eb6fb2cc483f9"},
{file = "matplotlib-3.5.3.tar.gz", hash = "sha256:339cac48b80ddbc8bfd05daae0a3a73414651a8596904c2a881cfd1edb65f26c"},
]
[package.dependencies]
cycler = ">=0.10"
fonttools = ">=4.22.0"
kiwisolver = ">=1.0.1"
numpy = ">=1.17"
packaging = ">=20.0"
pillow = ">=6.2.0"
pyparsing = ">=2.2.1"
python-dateutil = ">=2.7"
[[package]]
name = "networkx"
version = "2.6.3"
description = "Python package for creating and manipulating graphs and networks"
category = "main"
optional = false
python-versions = ">=3.7"
files = [
{file = "networkx-2.6.3-py3-none-any.whl", hash = "sha256:80b6b89c77d1dfb64a4c7854981b60aeea6360ac02c6d4e4913319e0a313abef"},
{file = "networkx-2.6.3.tar.gz", hash = "sha256:c0946ed31d71f1b732b5aaa6da5a0388a345019af232ce2f49c766e2d6795c51"},
]
[package.extras]
default = ["matplotlib (>=3.3)", "numpy (>=1.19)", "pandas (>=1.1)", "scipy (>=1.5,!=1.6.1)"]
developer = ["black (==21.5b1)", "pre-commit (>=2.12)"]
doc = ["nb2plots (>=0.6)", "numpydoc (>=1.1)", "pillow (>=8.2)", "pydata-sphinx-theme (>=0.6,<1.0)", "sphinx (>=4.0,<5.0)", "sphinx-gallery (>=0.9,<1.0)", "texext (>=0.6.6)"]
extra = ["lxml (>=4.5)", "pydot (>=1.4.1)", "pygraphviz (>=1.7)"]
test = ["codecov (>=2.1)", "pytest (>=6.2)", "pytest-cov (>=2.12)"]
[[package]]
name = "numpy"
version = "1.24.2"
description = "Fundamental package for array computing in Python"
category = "main"
optional = false
python-versions = ">=3.8"
files = [
{file = "numpy-1.24.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:eef70b4fc1e872ebddc38cddacc87c19a3709c0e3e5d20bf3954c147b1dd941d"},
{file = "numpy-1.24.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e8d2859428712785e8a8b7d2b3ef0a1d1565892367b32f915c4a4df44d0e64f5"},
{file = "numpy-1.24.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6524630f71631be2dabe0c541e7675db82651eb998496bbe16bc4f77f0772253"},
{file = "numpy-1.24.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a51725a815a6188c662fb66fb32077709a9ca38053f0274640293a14fdd22978"},
{file = "numpy-1.24.2-cp310-cp310-win32.whl", hash = "sha256:2620e8592136e073bd12ee4536149380695fbe9ebeae845b81237f986479ffc9"},
{file = "numpy-1.24.2-cp310-cp310-win_amd64.whl", hash = "sha256:97cf27e51fa078078c649a51d7ade3c92d9e709ba2bfb97493007103c741f1d0"},
{file = "numpy-1.24.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7de8fdde0003f4294655aa5d5f0a89c26b9f22c0a58790c38fae1ed392d44a5a"},
{file = "numpy-1.24.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4173bde9fa2a005c2c6e2ea8ac1618e2ed2c1c6ec8a7657237854d42094123a0"},
{file = "numpy-1.24.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4cecaed30dc14123020f77b03601559fff3e6cd0c048f8b5289f4eeabb0eb281"},
{file = "numpy-1.24.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a23f8440561a633204a67fb44617ce2a299beecf3295f0d13c495518908e910"},
{file = "numpy-1.24.2-cp311-cp311-win32.whl", hash = "sha256:e428c4fbfa085f947b536706a2fc349245d7baa8334f0c5723c56a10595f9b95"},
{file = "numpy-1.24.2-cp311-cp311-win_amd64.whl", hash = "sha256:557d42778a6869c2162deb40ad82612645e21d79e11c1dc62c6e82a2220ffb04"},
{file = "numpy-1.24.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d0a2db9d20117bf523dde15858398e7c0858aadca7c0f088ac0d6edd360e9ad2"},
{file = "numpy-1.24.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c72a6b2f4af1adfe193f7beb91ddf708ff867a3f977ef2ec53c0ffb8283ab9f5"},
{file = "numpy-1.24.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c29e6bd0ec49a44d7690ecb623a8eac5ab8a923bce0bea6293953992edf3a76a"},
{file = "numpy-1.24.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2eabd64ddb96a1239791da78fa5f4e1693ae2dadc82a76bc76a14cbb2b966e96"},
{file = "numpy-1.24.2-cp38-cp38-win32.whl", hash = "sha256:e3ab5d32784e843fc0dd3ab6dcafc67ef806e6b6828dc6af2f689be0eb4d781d"},
{file = "numpy-1.24.2-cp38-cp38-win_amd64.whl", hash = "sha256:76807b4063f0002c8532cfeac47a3068a69561e9c8715efdad3c642eb27c0756"},
{file = "numpy-1.24.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4199e7cfc307a778f72d293372736223e39ec9ac096ff0a2e64853b866a8e18a"},
{file = "numpy-1.24.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:adbdce121896fd3a17a77ab0b0b5eedf05a9834a18699db6829a64e1dfccca7f"},
{file = "numpy-1.24.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:889b2cc88b837d86eda1b17008ebeb679d82875022200c6e8e4ce6cf549b7acb"},
{file = "numpy-1.24.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f64bb98ac59b3ea3bf74b02f13836eb2e24e48e0ab0145bbda646295769bd780"},
{file = "numpy-1.24.2-cp39-cp39-win32.whl", hash = "sha256:63e45511ee4d9d976637d11e6c9864eae50e12dc9598f531c035265991910468"},
{file = "numpy-1.24.2-cp39-cp39-win_amd64.whl", hash = "sha256:a77d3e1163a7770164404607b7ba3967fb49b24782a6ef85d9b5f54126cc39e5"},
{file = "numpy-1.24.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:92011118955724465fb6853def593cf397b4a1367495e0b59a7e69d40c4eb71d"},
{file = "numpy-1.24.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9006288bcf4895917d02583cf3411f98631275bc67cce355a7f39f8c14338fa"},
{file = "numpy-1.24.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:150947adbdfeceec4e5926d956a06865c1c690f2fd902efede4ca6fe2e657c3f"},
{file = "numpy-1.24.2.tar.gz", hash = "sha256:003a9f530e880cb2cd177cba1af7220b9aa42def9c4afc2a2fc3ee6be7eb2b22"},
]
[[package]]
name = "nvidia-cublas-cu11"
version = "11.10.3.66"
description = "CUBLAS native runtime libraries"
category = "main"
optional = false
python-versions = ">=3"
files = [
{file = "nvidia_cublas_cu11-11.10.3.66-py3-none-manylinux1_x86_64.whl", hash = "sha256:d32e4d75f94ddfb93ea0a5dda08389bcc65d8916a25cb9f37ac89edaeed3bded"},
{file = "nvidia_cublas_cu11-11.10.3.66-py3-none-win_amd64.whl", hash = "sha256:8ac17ba6ade3ed56ab898a036f9ae0756f1e81052a317bf98f8c6d18dc3ae49e"},
]
[package.dependencies]
setuptools = "*"
wheel = "*"
[[package]]
name = "nvidia-cuda-nvrtc-cu11"
version = "11.7.99"
description = "NVRTC native runtime libraries"
category = "main"
optional = false
python-versions = ">=3"
files = [
{file = "nvidia_cuda_nvrtc_cu11-11.7.99-2-py3-none-manylinux1_x86_64.whl", hash = "sha256:9f1562822ea264b7e34ed5930567e89242d266448e936b85bc97a3370feabb03"},
{file = "nvidia_cuda_nvrtc_cu11-11.7.99-py3-none-manylinux1_x86_64.whl", hash = "sha256:f7d9610d9b7c331fa0da2d1b2858a4a8315e6d49765091d28711c8946e7425e7"},
{file = "nvidia_cuda_nvrtc_cu11-11.7.99-py3-none-win_amd64.whl", hash = "sha256:f2effeb1309bdd1b3854fc9b17eaf997808f8b25968ce0c7070945c4265d64a3"},
]
[package.dependencies]
setuptools = "*"
wheel = "*"
[[package]]
name = "nvidia-cuda-runtime-cu11"
version = "11.7.99"
description = "CUDA Runtime native Libraries"
category = "main"
optional = false
python-versions = ">=3"
files = [
{file = "nvidia_cuda_runtime_cu11-11.7.99-py3-none-manylinux1_x86_64.whl", hash = "sha256:cc768314ae58d2641f07eac350f40f99dcb35719c4faff4bc458a7cd2b119e31"},
{file = "nvidia_cuda_runtime_cu11-11.7.99-py3-none-win_amd64.whl", hash = "sha256:bc77fa59a7679310df9d5c70ab13c4e34c64ae2124dd1efd7e5474b71be125c7"},
]
[package.dependencies]
setuptools = "*"
wheel = "*"
[[package]]
name = "nvidia-cudnn-cu11"
version = "8.5.0.96"
description = "cuDNN runtime libraries"
category = "main"
optional = false
python-versions = ">=3"
files = [
{file = "nvidia_cudnn_cu11-8.5.0.96-2-py3-none-manylinux1_x86_64.whl", hash = "sha256:402f40adfc6f418f9dae9ab402e773cfed9beae52333f6d86ae3107a1b9527e7"},
{file = "nvidia_cudnn_cu11-8.5.0.96-py3-none-manylinux1_x86_64.whl", hash = "sha256:71f8111eb830879ff2836db3cccf03bbd735df9b0d17cd93761732ac50a8a108"},
]
[package.dependencies]
setuptools = "*"
wheel = "*"
[[package]]
name = "opencv-python"
version = "4.7.0.72"
description = "Wrapper package for OpenCV python bindings."
category = "main"
optional = false
python-versions = ">=3.6"
files = [
{file = "opencv-python-4.7.0.72.tar.gz", hash = "sha256:3424794a711f33284581f3c1e4b071cfc827d02b99d6fd9a35391f517c453306"},
{file = "opencv_python-4.7.0.72-cp37-abi3-macosx_10_16_x86_64.whl", hash = "sha256:d4f8880440c433a0025d78804dda6901d1e8e541a561dda66892d90290aef881"},
{file = "opencv_python-4.7.0.72-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:7a297e7651e22eb17c265ddbbc80e2ba2a8ff4f4a1696a67c45e5f5798245842"},
{file = "opencv_python-4.7.0.72-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd08343654c6b88c5a8c25bf425f8025aed2e3189b4d7306b5861d32affaf737"},
{file = "opencv_python-4.7.0.72-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ebfc0a3a2f57716e709028b992e4de7fd8752105d7a768531c4f434043c6f9ff"},
{file = "opencv_python-4.7.0.72-cp37-abi3-win32.whl", hash = "sha256:eda115797b114fc16ca6f182b91c5d984f0015c19bec3145e55d33d708e9bae1"},
{file = "opencv_python-4.7.0.72-cp37-abi3-win_amd64.whl", hash = "sha256:812af57553ec1c6709060c63f6b7e9ad07ddc0f592f3ccc6d00c71e0fe0e6376"},
]
[package.dependencies]
numpy = [
{version = ">=1.21.0", markers = "python_version <= \"3.9\" and platform_system == \"Darwin\" and platform_machine == \"arm64\""},
{version = ">=1.21.2", markers = "python_version >= \"3.10\""},
{version = ">=1.21.4", markers = "python_version >= \"3.10\" and platform_system == \"Darwin\""},
{version = ">=1.22.0", markers = "python_version >= \"3.11\""},
{version = ">=1.19.3", markers = "python_version >= \"3.6\" and platform_system == \"Linux\" and platform_machine == \"aarch64\" or python_version >= \"3.9\""},
{version = ">=1.17.0", markers = "python_version >= \"3.7\""},
{version = ">=1.17.3", markers = "python_version >= \"3.8\""},
]
[[package]]
name = "packaging"
version = "23.0"
description = "Core utilities for Python packages"
category = "main"
optional = false
python-versions = ">=3.7"
files = [
{file = "packaging-23.0-py3-none-any.whl", hash = "sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2"},
{file = "packaging-23.0.tar.gz", hash = "sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97"},
]
[[package]]
name = "pillow"
version = "9.5.0"
description = "Python Imaging Library (Fork)"
category = "main"
optional = false
python-versions = ">=3.7"
files = [
{file = "Pillow-9.5.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:ace6ca218308447b9077c14ea4ef381ba0b67ee78d64046b3f19cf4e1139ad16"},
{file = "Pillow-9.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d3d403753c9d5adc04d4694d35cf0391f0f3d57c8e0030aac09d7678fa8030aa"},
{file = "Pillow-9.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ba1b81ee69573fe7124881762bb4cd2e4b6ed9dd28c9c60a632902fe8db8b38"},
{file = "Pillow-9.5.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fe7e1c262d3392afcf5071df9afa574544f28eac825284596ac6db56e6d11062"},
{file = "Pillow-9.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f36397bf3f7d7c6a3abdea815ecf6fd14e7fcd4418ab24bae01008d8d8ca15e"},
{file = "Pillow-9.5.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:252a03f1bdddce077eff2354c3861bf437c892fb1832f75ce813ee94347aa9b5"},
{file = "Pillow-9.5.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:85ec677246533e27770b0de5cf0f9d6e4ec0c212a1f89dfc941b64b21226009d"},
{file = "Pillow-9.5.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b416f03d37d27290cb93597335a2f85ed446731200705b22bb927405320de903"},
{file = "Pillow-9.5.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1781a624c229cb35a2ac31cc4a77e28cafc8900733a864870c49bfeedacd106a"},
{file = "Pillow-9.5.0-cp310-cp310-win32.whl", hash = "sha256:8507eda3cd0608a1f94f58c64817e83ec12fa93a9436938b191b80d9e4c0fc44"},
{file = "Pillow-9.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:d3c6b54e304c60c4181da1c9dadf83e4a54fd266a99c70ba646a9baa626819eb"},
{file = "Pillow-9.5.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:7ec6f6ce99dab90b52da21cf0dc519e21095e332ff3b399a357c187b1a5eee32"},
{file = "Pillow-9.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:560737e70cb9c6255d6dcba3de6578a9e2ec4b573659943a5e7e4af13f298f5c"},
{file = "Pillow-9.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:96e88745a55b88a7c64fa49bceff363a1a27d9a64e04019c2281049444a571e3"},
{file = "Pillow-9.5.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d9c206c29b46cfd343ea7cdfe1232443072bbb270d6a46f59c259460db76779a"},
{file = "Pillow-9.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cfcc2c53c06f2ccb8976fb5c71d448bdd0a07d26d8e07e321c103416444c7ad1"},
{file = "Pillow-9.5.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:a0f9bb6c80e6efcde93ffc51256d5cfb2155ff8f78292f074f60f9e70b942d99"},
{file = "Pillow-9.5.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:8d935f924bbab8f0a9a28404422da8af4904e36d5c33fc6f677e4c4485515625"},
{file = "Pillow-9.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fed1e1cf6a42577953abbe8e6cf2fe2f566daebde7c34724ec8803c4c0cda579"},
{file = "Pillow-9.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c1170d6b195555644f0616fd6ed929dfcf6333b8675fcca044ae5ab110ded296"},
{file = "Pillow-9.5.0-cp311-cp311-win32.whl", hash = "sha256:54f7102ad31a3de5666827526e248c3530b3a33539dbda27c6843d19d72644ec"},
{file = "Pillow-9.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:cfa4561277f677ecf651e2b22dc43e8f5368b74a25a8f7d1d4a3a243e573f2d4"},
{file = "Pillow-9.5.0-cp311-cp311-win_arm64.whl", hash = "sha256:965e4a05ef364e7b973dd17fc765f42233415974d773e82144c9bbaaaea5d089"},
{file = "Pillow-9.5.0-cp312-cp312-win32.whl", hash = "sha256:22baf0c3cf0c7f26e82d6e1adf118027afb325e703922c8dfc1d5d0156bb2eeb"},
{file = "Pillow-9.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:432b975c009cf649420615388561c0ce7cc31ce9b2e374db659ee4f7d57a1f8b"},
{file = "Pillow-9.5.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:5d4ebf8e1db4441a55c509c4baa7a0587a0210f7cd25fcfe74dbbce7a4bd1906"},
{file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:375f6e5ee9620a271acb6820b3d1e94ffa8e741c0601db4c0c4d3cb0a9c224bf"},
{file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99eb6cafb6ba90e436684e08dad8be1637efb71c4f2180ee6b8f940739406e78"},
{file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dfaaf10b6172697b9bceb9a3bd7b951819d1ca339a5ef294d1f1ac6d7f63270"},
{file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:763782b2e03e45e2c77d7779875f4432e25121ef002a41829d8868700d119392"},
{file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:35f6e77122a0c0762268216315bf239cf52b88865bba522999dc38f1c52b9b47"},
{file = "Pillow-9.5.0-cp37-cp37m-win32.whl", hash = "sha256:aca1c196f407ec7cf04dcbb15d19a43c507a81f7ffc45b690899d6a76ac9fda7"},
{file = "Pillow-9.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:322724c0032af6692456cd6ed554bb85f8149214d97398bb80613b04e33769f6"},
{file = "Pillow-9.5.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:a0aa9417994d91301056f3d0038af1199eb7adc86e646a36b9e050b06f526597"},
{file = "Pillow-9.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f8286396b351785801a976b1e85ea88e937712ee2c3ac653710a4a57a8da5d9c"},
{file = "Pillow-9.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c830a02caeb789633863b466b9de10c015bded434deb3ec87c768e53752ad22a"},
{file = "Pillow-9.5.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fbd359831c1657d69bb81f0db962905ee05e5e9451913b18b831febfe0519082"},
{file = "Pillow-9.5.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8fc330c3370a81bbf3f88557097d1ea26cd8b019d6433aa59f71195f5ddebbf"},
{file = "Pillow-9.5.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:7002d0797a3e4193c7cdee3198d7c14f92c0836d6b4a3f3046a64bd1ce8df2bf"},
{file = "Pillow-9.5.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:229e2c79c00e85989a34b5981a2b67aa079fd08c903f0aaead522a1d68d79e51"},
{file = "Pillow-9.5.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9adf58f5d64e474bed00d69bcd86ec4bcaa4123bfa70a65ce72e424bfb88ed96"},
{file = "Pillow-9.5.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:662da1f3f89a302cc22faa9f14a262c2e3951f9dbc9617609a47521c69dd9f8f"},
{file = "Pillow-9.5.0-cp38-cp38-win32.whl", hash = "sha256:6608ff3bf781eee0cd14d0901a2b9cc3d3834516532e3bd673a0a204dc8615fc"},
{file = "Pillow-9.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:e49eb4e95ff6fd7c0c402508894b1ef0e01b99a44320ba7d8ecbabefddcc5569"},
{file = "Pillow-9.5.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:482877592e927fd263028c105b36272398e3e1be3269efda09f6ba21fd83ec66"},
{file = "Pillow-9.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3ded42b9ad70e5f1754fb7c2e2d6465a9c842e41d178f262e08b8c85ed8a1d8e"},
{file = "Pillow-9.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c446d2245ba29820d405315083d55299a796695d747efceb5717a8b450324115"},
{file = "Pillow-9.5.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8aca1152d93dcc27dc55395604dcfc55bed5f25ef4c98716a928bacba90d33a3"},
{file = "Pillow-9.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:608488bdcbdb4ba7837461442b90ea6f3079397ddc968c31265c1e056964f1ef"},
{file = "Pillow-9.5.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:60037a8db8750e474af7ffc9faa9b5859e6c6d0a50e55c45576bf28be7419705"},
{file = "Pillow-9.5.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:07999f5834bdc404c442146942a2ecadd1cb6292f5229f4ed3b31e0a108746b1"},
{file = "Pillow-9.5.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a127ae76092974abfbfa38ca2d12cbeddcdeac0fb71f9627cc1135bedaf9d51a"},
{file = "Pillow-9.5.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:489f8389261e5ed43ac8ff7b453162af39c3e8abd730af8363587ba64bb2e865"},
{file = "Pillow-9.5.0-cp39-cp39-win32.whl", hash = "sha256:9b1af95c3a967bf1da94f253e56b6286b50af23392a886720f563c547e48e964"},
{file = "Pillow-9.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:77165c4a5e7d5a284f10a6efaa39a0ae8ba839da344f20b111d62cc932fa4e5d"},
{file = "Pillow-9.5.0-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:833b86a98e0ede388fa29363159c9b1a294b0905b5128baf01db683672f230f5"},
{file = "Pillow-9.5.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aaf305d6d40bd9632198c766fb64f0c1a83ca5b667f16c1e79e1661ab5060140"},
{file = "Pillow-9.5.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0852ddb76d85f127c135b6dd1f0bb88dbb9ee990d2cd9aa9e28526c93e794fba"},
{file = "Pillow-9.5.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:91ec6fe47b5eb5a9968c79ad9ed78c342b1f97a091677ba0e012701add857829"},
{file = "Pillow-9.5.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:cb841572862f629b99725ebaec3287fc6d275be9b14443ea746c1dd325053cbd"},
{file = "Pillow-9.5.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:c380b27d041209b849ed246b111b7c166ba36d7933ec6e41175fd15ab9eb1572"},
{file = "Pillow-9.5.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c9af5a3b406a50e313467e3565fc99929717f780164fe6fbb7704edba0cebbe"},
{file = "Pillow-9.5.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5671583eab84af046a397d6d0ba25343c00cd50bce03787948e0fff01d4fd9b1"},
{file = "Pillow-9.5.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:84a6f19ce086c1bf894644b43cd129702f781ba5751ca8572f08aa40ef0ab7b7"},
{file = "Pillow-9.5.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:1e7723bd90ef94eda669a3c2c19d549874dd5badaeefabefd26053304abe5799"},
{file = "Pillow-9.5.0.tar.gz", hash = "sha256:bf548479d336726d7a0eceb6e767e179fbde37833ae42794602631a070d630f1"},
]
[package.extras]
docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-removed-in", "sphinxext-opengraph"]
tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"]
[[package]]
name = "pluggy"
version = "1.0.0"
description = "plugin and hook calling mechanisms for python"
category = "dev"
optional = false
python-versions = ">=3.6"
files = [
{file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"},
{file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"},
]
[package.extras]
dev = ["pre-commit", "tox"]
testing = ["pytest", "pytest-benchmark"]
[[package]]
name = "pydantic"
version = "1.10.7"
description = "Data validation and settings management using python type hints"
category = "dev"
optional = false
python-versions = ">=3.7"
files = [
{file = "pydantic-1.10.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e79e999e539872e903767c417c897e729e015872040e56b96e67968c3b918b2d"},
{file = "pydantic-1.10.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:01aea3a42c13f2602b7ecbbea484a98169fb568ebd9e247593ea05f01b884b2e"},
{file = "pydantic-1.10.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:516f1ed9bc2406a0467dd777afc636c7091d71f214d5e413d64fef45174cfc7a"},
{file = "pydantic-1.10.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae150a63564929c675d7f2303008d88426a0add46efd76c3fc797cd71cb1b46f"},
{file = "pydantic-1.10.7-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ecbbc51391248116c0a055899e6c3e7ffbb11fb5e2a4cd6f2d0b93272118a209"},
{file = "pydantic-1.10.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f4a2b50e2b03d5776e7f21af73e2070e1b5c0d0df255a827e7c632962f8315af"},
{file = "pydantic-1.10.7-cp310-cp310-win_amd64.whl", hash = "sha256:a7cd2251439988b413cb0a985c4ed82b6c6aac382dbaff53ae03c4b23a70e80a"},
{file = "pydantic-1.10.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:68792151e174a4aa9e9fc1b4e653e65a354a2fa0fed169f7b3d09902ad2cb6f1"},
{file = "pydantic-1.10.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfe2507b8ef209da71b6fb5f4e597b50c5a34b78d7e857c4f8f3115effaef5fe"},
{file = "pydantic-1.10.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10a86d8c8db68086f1e30a530f7d5f83eb0685e632e411dbbcf2d5c0150e8dcd"},
{file = "pydantic-1.10.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d75ae19d2a3dbb146b6f324031c24f8a3f52ff5d6a9f22f0683694b3afcb16fb"},
{file = "pydantic-1.10.7-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:464855a7ff7f2cc2cf537ecc421291b9132aa9c79aef44e917ad711b4a93163b"},
{file = "pydantic-1.10.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:193924c563fae6ddcb71d3f06fa153866423ac1b793a47936656e806b64e24ca"},
{file = "pydantic-1.10.7-cp311-cp311-win_amd64.whl", hash = "sha256:b4a849d10f211389502059c33332e91327bc154acc1845f375a99eca3afa802d"},
{file = "pydantic-1.10.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cc1dde4e50a5fc1336ee0581c1612215bc64ed6d28d2c7c6f25d2fe3e7c3e918"},
{file = "pydantic-1.10.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0cfe895a504c060e5d36b287ee696e2fdad02d89e0d895f83037245218a87fe"},
{file = "pydantic-1.10.7-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:670bb4683ad1e48b0ecb06f0cfe2178dcf74ff27921cdf1606e527d2617a81ee"},
{file = "pydantic-1.10.7-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:950ce33857841f9a337ce07ddf46bc84e1c4946d2a3bba18f8280297157a3fd1"},
{file = "pydantic-1.10.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c15582f9055fbc1bfe50266a19771bbbef33dd28c45e78afbe1996fd70966c2a"},
{file = "pydantic-1.10.7-cp37-cp37m-win_amd64.whl", hash = "sha256:82dffb306dd20bd5268fd6379bc4bfe75242a9c2b79fec58e1041fbbdb1f7914"},
{file = "pydantic-1.10.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8c7f51861d73e8b9ddcb9916ae7ac39fb52761d9ea0df41128e81e2ba42886cd"},
{file = "pydantic-1.10.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6434b49c0b03a51021ade5c4daa7d70c98f7a79e95b551201fff682fc1661245"},
{file = "pydantic-1.10.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64d34ab766fa056df49013bb6e79921a0265204c071984e75a09cbceacbbdd5d"},
{file = "pydantic-1.10.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:701daea9ffe9d26f97b52f1d157e0d4121644f0fcf80b443248434958fd03dc3"},
{file = "pydantic-1.10.7-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:cf135c46099ff3f919d2150a948ce94b9ce545598ef2c6c7bf55dca98a304b52"},
{file = "pydantic-1.10.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b0f85904f73161817b80781cc150f8b906d521fa11e3cdabae19a581c3606209"},
{file = "pydantic-1.10.7-cp38-cp38-win_amd64.whl", hash = "sha256:9f6f0fd68d73257ad6685419478c5aece46432f4bdd8d32c7345f1986496171e"},
{file = "pydantic-1.10.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c230c0d8a322276d6e7b88c3f7ce885f9ed16e0910354510e0bae84d54991143"},
{file = "pydantic-1.10.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:976cae77ba6a49d80f461fd8bba183ff7ba79f44aa5cfa82f1346b5626542f8e"},
{file = "pydantic-1.10.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d45fc99d64af9aaf7e308054a0067fdcd87ffe974f2442312372dfa66e1001d"},
{file = "pydantic-1.10.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d2a5ebb48958754d386195fe9e9c5106f11275867051bf017a8059410e9abf1f"},
{file = "pydantic-1.10.7-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:abfb7d4a7cd5cc4e1d1887c43503a7c5dd608eadf8bc615413fc498d3e4645cd"},
{file = "pydantic-1.10.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:80b1fab4deb08a8292d15e43a6edccdffa5377a36a4597bb545b93e79c5ff0a5"},
{file = "pydantic-1.10.7-cp39-cp39-win_amd64.whl", hash = "sha256:d71e69699498b020ea198468e2480a2f1e7433e32a3a99760058c6520e2bea7e"},
{file = "pydantic-1.10.7-py3-none-any.whl", hash = "sha256:0cd181f1d0b1d00e2b705f1bf1ac7799a2d938cce3376b8007df62b29be3c2c6"},
{file = "pydantic-1.10.7.tar.gz", hash = "sha256:cfc83c0678b6ba51b0532bea66860617c4cd4251ecf76e9846fa5a9f3454e97e"},
]
[package.dependencies]
typing-extensions = ">=4.2.0"
[package.extras]
dotenv = ["python-dotenv (>=0.10.4)"]
email = ["email-validator (>=1.0.3)"]
[[package]]
name = "pyparsing"
version = "3.0.9"
description = "pyparsing module - Classes and methods to define and execute parsing grammars"
category = "main"
optional = false
python-versions = ">=3.6.8"
files = [
{file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"},
{file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"},
]
[package.extras]
diagrams = ["jinja2", "railroad-diagrams"]
[[package]]
name = "pytest"
version = "7.2.2"
description = "pytest: simple powerful testing with Python"
category = "dev"
optional = false
python-versions = ">=3.7"
files = [
{file = "pytest-7.2.2-py3-none-any.whl", hash = "sha256:130328f552dcfac0b1cec75c12e3f005619dc5f874f0a06e8ff7263f0ee6225e"},
{file = "pytest-7.2.2.tar.gz", hash = "sha256:c99ab0c73aceb050f68929bc93af19ab6db0558791c6a0715723abe9d0ade9d4"},
]
[package.dependencies]
attrs = ">=19.2.0"
colorama = {version = "*", markers = "sys_platform == \"win32\""}
exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""}
iniconfig = "*"
packaging = "*"
pluggy = ">=0.12,<2.0"
tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""}
[package.extras]
testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"]
[[package]]
name = "python-dateutil"
version = "2.8.2"
description = "Extensions to the standard Python datetime module"
category = "main"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
files = [
{file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"},
{file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"},
]
[package.dependencies]
six = ">=1.5"
[[package]]
name = "pyyaml"
version = "6.0"
description = "YAML parser and emitter for Python"
category = "main"
optional = false
python-versions = ">=3.6"
files = [
{file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"},
{file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"},
{file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"},
{file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"},
{file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"},
{file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"},
{file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"},
{file = "PyYAML-6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358"},
{file = "PyYAML-6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1"},
{file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d"},
{file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f"},
{file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782"},
{file = "PyYAML-6.0-cp311-cp311-win32.whl", hash = "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7"},
{file = "PyYAML-6.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf"},
{file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"},
{file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"},
{file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"},
{file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"},
{file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"},
{file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"},
{file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"},
{file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"},
{file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"},
{file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"},
{file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"},
{file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"},
{file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"},
{file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"},
{file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"},
{file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"},
{file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"},
{file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"},
{file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"},
{file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"},
{file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"},
{file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"},
{file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"},
{file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"},
{file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"},
{file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"},
]
[[package]]
name = "scipy"
version = "1.10.1"
description = "Fundamental algorithms for scientific computing in Python"
category = "main"
optional = false
python-versions = "<3.12,>=3.8"
files = [
{file = "scipy-1.10.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e7354fd7527a4b0377ce55f286805b34e8c54b91be865bac273f527e1b839019"},
{file = "scipy-1.10.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:4b3f429188c66603a1a5c549fb414e4d3bdc2a24792e061ffbd607d3d75fd84e"},
{file = "scipy-1.10.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1553b5dcddd64ba9a0d95355e63fe6c3fc303a8fd77c7bc91e77d61363f7433f"},
{file = "scipy-1.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c0ff64b06b10e35215abce517252b375e580a6125fd5fdf6421b98efbefb2d2"},
{file = "scipy-1.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:fae8a7b898c42dffe3f7361c40d5952b6bf32d10c4569098d276b4c547905ee1"},
{file = "scipy-1.10.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0f1564ea217e82c1bbe75ddf7285ba0709ecd503f048cb1236ae9995f64217bd"},
{file = "scipy-1.10.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:d925fa1c81b772882aa55bcc10bf88324dadb66ff85d548c71515f6689c6dac5"},
{file = "scipy-1.10.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaea0a6be54462ec027de54fca511540980d1e9eea68b2d5c1dbfe084797be35"},
{file = "scipy-1.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15a35c4242ec5f292c3dd364a7c71a61be87a3d4ddcc693372813c0b73c9af1d"},
{file = "scipy-1.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:43b8e0bcb877faf0abfb613d51026cd5cc78918e9530e375727bf0625c82788f"},
{file = "scipy-1.10.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5678f88c68ea866ed9ebe3a989091088553ba12c6090244fdae3e467b1139c35"},
{file = "scipy-1.10.1-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:39becb03541f9e58243f4197584286e339029e8908c46f7221abeea4b749fa88"},
{file = "scipy-1.10.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bce5869c8d68cf383ce240e44c1d9ae7c06078a9396df68ce88a1230f93a30c1"},
{file = "scipy-1.10.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07c3457ce0b3ad5124f98a86533106b643dd811dd61b548e78cf4c8786652f6f"},
{file = "scipy-1.10.1-cp38-cp38-win_amd64.whl", hash = "sha256:049a8bbf0ad95277ffba9b3b7d23e5369cc39e66406d60422c8cfef40ccc8415"},
{file = "scipy-1.10.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:cd9f1027ff30d90618914a64ca9b1a77a431159df0e2a195d8a9e8a04c78abf9"},
{file = "scipy-1.10.1-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:79c8e5a6c6ffaf3a2262ef1be1e108a035cf4f05c14df56057b64acc5bebffb6"},
{file = "scipy-1.10.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:51af417a000d2dbe1ec6c372dfe688e041a7084da4fdd350aeb139bd3fb55353"},
{file = "scipy-1.10.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b4735d6c28aad3cdcf52117e0e91d6b39acd4272f3f5cd9907c24ee931ad601"},
{file = "scipy-1.10.1-cp39-cp39-win_amd64.whl", hash = "sha256:7ff7f37b1bf4417baca958d254e8e2875d0cc23aaadbe65b3d5b3077b0eb23ea"},
{file = "scipy-1.10.1.tar.gz", hash = "sha256:2cf9dfb80a7b4589ba4c40ce7588986d6d5cebc5457cad2c2880f6bc2d42f3a5"},
]
[package.dependencies]
numpy = ">=1.19.5,<1.27.0"
[package.extras]
dev = ["click", "doit (>=0.36.0)", "flake8", "mypy", "pycodestyle", "pydevtool", "rich-click", "typing_extensions"]
doc = ["matplotlib (>2)", "numpydoc", "pydata-sphinx-theme (==0.9.0)", "sphinx (!=4.1.0)", "sphinx-design (>=0.2.0)"]
test = ["asv", "gmpy2", "mpmath", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"]
[[package]]
name = "setuptools"
version = "67.6.1"
description = "Easily download, build, install, upgrade, and uninstall Python packages"
category = "main"
optional = false
python-versions = ">=3.7"
files = [
{file = "setuptools-67.6.1-py3-none-any.whl", hash = "sha256:e728ca814a823bf7bf60162daf9db95b93d532948c4c0bea762ce62f60189078"},
{file = "setuptools-67.6.1.tar.gz", hash = "sha256:257de92a9d50a60b8e22abfcbb771571fde0dbf3ec234463212027a4eeecbe9a"},
]
[package.extras]
docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"]
[[package]]
name = "six"
version = "1.16.0"
description = "Python 2 and 3 compatibility utilities"
category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
files = [
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
]
[[package]]
name = "sniffio"
version = "1.3.0"
description = "Sniff out which async library your code is running under"
category = "dev"
optional = false
python-versions = ">=3.7"
files = [
{file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"},
{file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"},
]
[[package]]
name = "sortedcontainers"
version = "2.4.0"
description = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set"
category = "dev"
optional = false
python-versions = "*"
files = [
{file = "sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0"},
{file = "sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88"},
]
[[package]]
name = "starlette"
version = "0.26.1"
description = "The little ASGI library that shines."
category = "dev"
optional = false
python-versions = ">=3.7"
files = [
{file = "starlette-0.26.1-py3-none-any.whl", hash = "sha256:e87fce5d7cbdde34b76f0ac69013fd9d190d581d80681493016666e6f96c6d5e"},
{file = "starlette-0.26.1.tar.gz", hash = "sha256:41da799057ea8620e4667a3e69a5b1923ebd32b1819c8fa75634bbe8d8bea9bd"},
]
[package.dependencies]
anyio = ">=3.4.0,<5"
typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""}
[package.extras]
full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart", "pyyaml"]
[[package]]
name = "tomli"
version = "2.0.1"
description = "A lil' TOML parser"
category = "dev"
optional = false
python-versions = ">=3.7"
files = [
{file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
]
[[package]]
name = "torch"
version = "1.13.1"
description = "Tensors and Dynamic neural networks in Python with strong GPU acceleration"
category = "main"
optional = false
python-versions = ">=3.7.0"
files = [
{file = "torch-1.13.1-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:fd12043868a34a8da7d490bf6db66991108b00ffbeecb034228bfcbbd4197143"},
{file = "torch-1.13.1-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:d9fe785d375f2e26a5d5eba5de91f89e6a3be5d11efb497e76705fdf93fa3c2e"},
{file = "torch-1.13.1-cp310-cp310-win_amd64.whl", hash = "sha256:98124598cdff4c287dbf50f53fb455f0c1e3a88022b39648102957f3445e9b76"},
{file = "torch-1.13.1-cp310-none-macosx_10_9_x86_64.whl", hash = "sha256:393a6273c832e047581063fb74335ff50b4c566217019cc6ace318cd79eb0566"},
{file = "torch-1.13.1-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:0122806b111b949d21fa1a5f9764d1fd2fcc4a47cb7f8ff914204fd4fc752ed5"},
{file = "torch-1.13.1-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:22128502fd8f5b25ac1cd849ecb64a418382ae81dd4ce2b5cebaa09ab15b0d9b"},
{file = "torch-1.13.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:76024be052b659ac1304ab8475ab03ea0a12124c3e7626282c9c86798ac7bc11"},
{file = "torch-1.13.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:ea8dda84d796094eb8709df0fcd6b56dc20b58fdd6bc4e8d7109930dafc8e419"},
{file = "torch-1.13.1-cp37-cp37m-win_amd64.whl", hash = "sha256:2ee7b81e9c457252bddd7d3da66fb1f619a5d12c24d7074de91c4ddafb832c93"},
{file = "torch-1.13.1-cp37-none-macosx_10_9_x86_64.whl", hash = "sha256:0d9b8061048cfb78e675b9d2ea8503bfe30db43d583599ae8626b1263a0c1380"},
{file = "torch-1.13.1-cp37-none-macosx_11_0_arm64.whl", hash = "sha256:f402ca80b66e9fbd661ed4287d7553f7f3899d9ab54bf5c67faada1555abde28"},
{file = "torch-1.13.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:727dbf00e2cf858052364c0e2a496684b9cb5aa01dc8a8bc8bbb7c54502bdcdd"},
{file = "torch-1.13.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:df8434b0695e9ceb8cc70650afc1310d8ba949e6db2a0525ddd9c3b2b181e5fe"},
{file = "torch-1.13.1-cp38-cp38-win_amd64.whl", hash = "sha256:5e1e722a41f52a3f26f0c4fcec227e02c6c42f7c094f32e49d4beef7d1e213ea"},
{file = "torch-1.13.1-cp38-none-macosx_10_9_x86_64.whl", hash = "sha256:33e67eea526e0bbb9151263e65417a9ef2d8fa53cbe628e87310060c9dcfa312"},
{file = "torch-1.13.1-cp38-none-macosx_11_0_arm64.whl", hash = "sha256:eeeb204d30fd40af6a2d80879b46a7efbe3cf43cdbeb8838dd4f3d126cc90b2b"},
{file = "torch-1.13.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:50ff5e76d70074f6653d191fe4f6a42fdbe0cf942fbe2a3af0b75eaa414ac038"},
{file = "torch-1.13.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:2c3581a3fd81eb1f0f22997cddffea569fea53bafa372b2c0471db373b26aafc"},
{file = "torch-1.13.1-cp39-cp39-win_amd64.whl", hash = "sha256:0aa46f0ac95050c604bcf9ef71da9f1172e5037fdf2ebe051962d47b123848e7"},
{file = "torch-1.13.1-cp39-none-macosx_10_9_x86_64.whl", hash = "sha256:6930791efa8757cb6974af73d4996b6b50c592882a324b8fb0589c6a9ba2ddaf"},
{file = "torch-1.13.1-cp39-none-macosx_11_0_arm64.whl", hash = "sha256:e0df902a7c7dd6c795698532ee5970ce898672625635d885eade9976e5a04949"},
]
[package.dependencies]
nvidia-cublas-cu11 = {version = "11.10.3.66", markers = "platform_system == \"Linux\""}
nvidia-cuda-nvrtc-cu11 = {version = "11.7.99", markers = "platform_system == \"Linux\""}
nvidia-cuda-runtime-cu11 = {version = "11.7.99", markers = "platform_system == \"Linux\""}
nvidia-cudnn-cu11 = {version = "8.5.0.96", markers = "platform_system == \"Linux\""}
typing-extensions = "*"
[package.extras]
opt-einsum = ["opt-einsum (>=3.3)"]
[[package]]
name = "typing-extensions"
version = "4.5.0"
description = "Backported and Experimental Type Hints for Python 3.7+"
category = "main"
optional = false
python-versions = ">=3.7"
files = [
{file = "typing_extensions-4.5.0-py3-none-any.whl", hash = "sha256:fb33085c39dd998ac16d1431ebc293a8b3eedd00fd4a32de0ff79002c19511b4"},
{file = "typing_extensions-4.5.0.tar.gz", hash = "sha256:5cb5f4a79139d699607b3ef622a1dedafa84e115ab0024e0d9c044a9479ca7cb"},
]
[[package]]
name = "wheel"
version = "0.40.0"
description = "A built-package format for Python"
category = "main"
optional = false
python-versions = ">=3.7"
files = [
{file = "wheel-0.40.0-py3-none-any.whl", hash = "sha256:d236b20e7cb522daf2390fa84c55eea81c5c30190f90f29ae2ca1ad8355bf247"},
{file = "wheel-0.40.0.tar.gz", hash = "sha256:cd1196f3faee2b31968d626e1731c94f99cbdb67cf5a46e4f5656cbee7738873"},
]
[package.extras]
test = ["pytest (>=6.0.0)"]
[metadata]
lock-version = "2.0"
python-versions = ">=3.8,<3.12"
content-hash = "a00139f7153f857aaf652d577205983e108483951855f18665d30117833e7823"
-26
View File
@@ -1,26 +0,0 @@
[tool.poetry]
name = "tfhe-ubiris"
version = "0.1.0"
description = "TFHFE based biometrics ID verification"
authors = ["Haroune Mohammedi <haroune.mohammedi@quadratic-labs.com>"]
license = "MIT"
readme = "README.md"
packages = [{ include = "client" }, { include = "server" }]
[tool.poetry.dependencies]
python = ">=3.8,<3.12"
torus-numpy = "^0.11.1"
opencv-python = "^4.7.0.72"
[tool.poetry.group.test.dependencies]
pytest = "^7.2.2"
hypothesis = "^6.70.2"
[tool.poetry.group.server.dependencies]
fastapi = "^0.95.0"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
View File
-45
View File
@@ -1,45 +0,0 @@
import os
from uuid import uuid4
import torus.numpy as cnp
from fastapi import BackgroundTasks, FastAPI, status
app = FastAPI()
FHE_SERVER_PATH = os.path.join(os.path.dirname(__file__), "fhe_server.zip")
fhe_server = cnp.Server.load(FHE_SERVER_PATH)
auth_results = {}
def run_auth(auth_id, public_args, evaluation_keys):
auth_results[auth_id] = None
public_result = fhe_server.run(public_args, evaluation_keys)
auth_results[auth_id] = public_result
@app.post("/auth", status_code=status.HTTP_202_ACCEPTED)
def auth_route(background_tasks: BackgroundTasks, data: bytes, evaluation_keys: bytes):
public_args = fhe_server.client_specs.unserialize_public_args(data)
evaluation_keys_ = cnp.EvaluationKeys.unserialize(evaluation_keys)
auth_id = uuid4()
background_tasks.add_task(run_auth, auth_id, public_args, evaluation_keys_)
queue_len = len(background_tasks.tasks)
return {
"message": (
f"You request is being processed, you're {queue_len} in the queue,"
f" check /auth/check/{auth_id} for results"
)
}
@app.get("/auth/check/{auth_id}")
def check_auth(auth_id):
if result := auth_results.get(auth_id):
return fhe_server.client_specs.serialize_public_result(result)
else:
return {"message": f"Still processing {auth_id} ..."}
Binary file not shown.
-110
View File
@@ -1,110 +0,0 @@
import numpy as np
import torus.numpy as cnp
from functools import reduce
from pathlib import Path
from . import utils
N_SHIFTS = 2
PROJECT_ROOT = Path(__file__).parent.parent
APPLICATION_POINTS_PATH = PROJECT_ROOT / "data/OsirisParam/points.txt"
APPLICATION_POINTS_INDICES = utils.read_ap_indices(APPLICATION_POINTS_PATH)
DATA_DIR = PROJECT_ROOT / "data/Output"
# a list of irises and masks
DATABASE = utils.read_iris_database(DATA_DIR, APPLICATION_POINTS_INDICES)
# How much iris do we have
DATABASE_COUNT = len(DATABASE)
# Generate rotate_shift_left{x} and rotate_shift_right{x} functions to be used
# to compute the best shifted hamming distance of two arrays
# TODO: find a way to generate them locally in another function or class
utils.generate_all_rotate_shift_functions(N_SHIFTS, globals(), locals())
def hamming_distance(x, y) -> int:
return np.sum(x ^ y)
def min_int(x: int, y: int) -> int:
"""torus-numpy doesn't yet support min, we have to implement one using
only supported operations"""
return (x + y - abs(x - y)) // 2
def min_int_array(a) -> int:
"""Return the minimum value of an array of ints using the `min_int` function"""
return reduce(min_int, a)
def best_shifted_hamming_distance(x, y):
h = hamming_distance(x, y)
# Functions should be generated before
l1 = rotate_shift_left1(x)
l2 = rotate_shift_left2(x)
# Functions should be generated before
r1 = rotate_shift_right1(x)
r2 = rotate_shift_right2(x)
hl1 = hamming_distance(l1, y)
hl2 = hamming_distance(l2, y)
hr1 = hamming_distance(r1, y)
hr2 = hamming_distance(r2, y)
return min_int_array([h, hr1, hr2, hl1, hl2])
class IrisAuthenticator:
def __init__(
self, inputset=None, input_shape=None, input_max_value=None, database=None
) -> None:
self.inputset = inputset or [
(
np.random.randint(
0, input_max_value + 1, size=input_shape, dtype=np.int64
),
np.random.randint(
0, input_max_value + 1, size=input_shape, dtype=np.int64
),
)
for _ in range(100)
]
self.database = database or self.inputset
self.configuration = cnp.Configuration(
enable_unsafe_features=True,
use_insecure_key_cache=True,
insecure_key_cache_location=".keys",
)
self.compiler = cnp.Compiler(
self.auth, {"iris_code": "encrypted", "mask": "encrypted"}
)
self.circuit = self.compiler.compile(self.inputset, self.configuration)
def auth(self, iris_code, mask):
"""Return the best score from comparing the provided iris and mask to the
ones in the database, the user fo this function will need to define a threshold
to decide weather the score means an identified iris or not
We know this is suboptimal but this is the best we could came up with right now
as we couldn't figure out a way to return an encrypted ID of the best match or
a special ID if the score is too low, mainly because we can't compare FHE values
"""
results = []
for i in range(len(self.database)):
(iris_code2, mask2) = self.database[i]
combined_mask = mask & mask2
ey1 = iris_code & combined_mask
ey2 = iris_code2 & combined_mask
score = best_shifted_hamming_distance(ey1, ey2)
results.append(score)
best_score = min_int_array(results)
return best_score
-70
View File
@@ -1,70 +0,0 @@
import cv2
import numpy as np
def generate_rotate_shift_right(shift, globals_=None, locals_=None):
function_body = f"""def rotate_shift_right{shift}(a):
return np.concatenate((a[-{shift}:], a[:-{shift}])).astype('int64')"""
exec(function_body, globals_, locals_)
def generate_rotate_shift_left(shift, globals_=None, locals_=None):
function_body = f"""def rotate_shift_left{shift}(a):
return np.concatenate((a[{shift}:], a[:{shift}])).astype('int64')"""
exec(function_body, globals_, locals_)
def generate_all_rotate_shift_functions(n_shifts, globals_=None, locals_=None):
for shift in range(1, n_shifts + 1):
generate_rotate_shift_left(shift, globals_, locals_)
generate_rotate_shift_right(shift, globals_, locals_)
def imread_black_and_white(path):
image = cv2.imread(path, cv2.IMREAD_GRAYSCALE)
return np.where(image == 255, 1, image)
def read_ap_indices(path):
points = []
with open(path, "r") as f:
n_points = int(f.readline())
for i in range(n_points):
x, y = f.readline().split()
x = int(x)
y = int(y)
for i in range(1, 7):
points.append([x * i, y])
# Transform it in a way to be used for numpy arrays like this: x[ap_indices]
points = tuple(np.array(points).T.tolist())
return points
def read_iris_code_and_mask(database_dir, ap_indices, i, j):
iris_code = imread_black_and_white(
f"{database_dir}/IrisCodes/000{i}_00{j}_code.bmp"
)
mask = imread_black_and_white(
f"{database_dir}/NormalizedMasks/000{i}_00{j}_mano.bmp"
)
mask = np.array(mask.tolist() * 6)
iris_code = iris_code[ap_indices]
mask = mask[ap_indices]
return iris_code, mask
def read_iris_database(database_dir, ap_indices):
database = []
ij = [(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3)]
for i, j in ij:
iris_code, mask = read_iris_code_and_mask(database_dir, ap_indices, i, j)
database.append((iris_code, mask))
return database
View File
-49
View File
@@ -1,49 +0,0 @@
import numpy as np
from hypothesis import given, settings, strategies as st
from server import iris, utils
@given(x=st.integers(), y=st.integers())
def test_min_int(x, y):
assert iris.min_int(x, y) == min(x, y)
@given(a=st.lists(st.integers(), min_size=1))
def test_min_int_array(a):
assert iris.min_int_array(a) == min(a)
@given(
x=st.lists(st.integers(min_value=0, max_value=1), min_size=4, max_size=4),
y=st.lists(st.integers(min_value=0, max_value=1), min_size=4, max_size=4),
)
@settings(max_examples=1, deadline=None)
def test_iris_auth(x, y):
x = np.array(x)
y = np.array(y)
database = [
(np.array([0, 0, 0, 0]), np.array([0, 0, 0, 0])),
(np.array([1, 1, 1, 1]), np.array([1, 1, 1, 1])),
]
m = iris.IrisAuthenticator(input_shape=(4,), input_max_value=1, database=database)
clear_result = m.auth(x, y)
tfhe_result = m.circuit.encrypt_run_decrypt(x, y)
assert tfhe_result == clear_result
def test_iris_auth_real_data():
iris_code, mask = utils.read_iris_code_and_mask(
iris.DATA_DIR, iris.APPLICATION_POINTS_INDICES, 0, 0
)
m = iris.IrisAuthenticator(inputset=iris.DATABASE)
clear_result = m.auth(iris_code, mask)
tfhe_result = m.circuit.encrypt_run_decrypt(iris_code, mask)
assert clear_result == tfhe_result
-30
View File
@@ -1,30 +0,0 @@
name: 'Setup Rust, Python & Poetry'
description: 'Sets up Rust, Python and Poetry for CI jobs'
inputs:
python-version:
description: 'Python version to use'
required: true
gcc-version:
description: 'GCC version to use (optional)'
required: false
default: ''
runs:
using: "composite"
steps:
- name: Install latest stable Rust
uses: dtolnay/rust-toolchain@315e265cd78dad1e1dcf3a5074f6d6c47029d5aa
with:
toolchain: stable
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ inputs.python-version }}
- name: Install dependencies
shell: bash
run: |
python -m pip install "poetry==1.8.3"
python -m poetry install --all-extras --no-root
-244
View File
@@ -1,244 +0,0 @@
name: Python package
on: [pull_request]
env:
CARGO_TERM_COLOR: always
SLAB_PROFILE: single-t4-gpu
jobs:
setup-ec2:
name: Setup EC2 instance
runs-on: ubuntu-latest
outputs:
runner-name: ${{ steps.start-instance.outputs.label }}
steps:
- name: Start instance
id: start-instance
uses: luxfhe-ai/slab-github-runner@801df0b8db5ea2b06128b7476c652f5ed5f193a8
with:
mode: start
github-token: ${{ secrets.SLAB_ACTION_TOKEN }}
slab-url: ${{ secrets.SLAB_BASE_URL }}
job-secret: ${{ secrets.JOB_SECRET }}
backend: aws
profile: ${{ env.SLAB_PROFILE }}
build:
needs: [setup-ec2]
runs-on: ${{ needs.setup-ec2.outputs.runner-name }}
strategy:
fail-fast: false
# explicit include-based build matrix, of known valid options
matrix:
python-version: ["3.8"] # We limit to 3.8 for now to limit time spent
include:
- os: ubuntu-22.04
cuda: "12.2"
gcc: 11
env:
CUDA_PATH: /usr/local/cuda-${{ matrix.cuda }}
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
ref: ${{ github.event.inputs.git-ref }}
- name: Export CUDA variables
if: ${{ !cancelled() }}
run: |
echo "CUDA_PATH=$CUDA_PATH" >> "${GITHUB_ENV}"
echo "$CUDA_PATH/bin" >> "${GITHUB_PATH}"
echo "LD_LIBRARY_PATH=$CUDA_PATH/lib:$LD_LIBRARY_PATH" >> "${GITHUB_ENV}"
echo "CUDACXX=/usr/local/cuda-${{ matrix.cuda }}/bin/nvcc" >> "${GITHUB_ENV}"
- name: Install latest stable
uses: dtolnay/rust-toolchain@315e265cd78dad1e1dcf3a5074f6d6c47029d5aa
with:
toolchain: stable
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
# You can test your matrix by printing the current Python version
- name: Install dependencies
run:
python -m pip install "poetry==1.8.3"
python -m poetry install --all-extras --no-root
- name: Build package CUDA
run:
python -m poetry run maturin develop --release --features cuda
- name: CUDA check
run:
nvidia-smi
scripts/print_cuda_infos.sh
- name: Run CUDA tests
run:
make pytest
- name: Build package CPU
run:
python -m poetry run maturin develop --no-default-features --features "python_bindings" --release
- name: Run CPU tests
run:
make pytest
- name: Install docker dependencies
run:
docker pull sameli/manylinux_2_34_x86_64_cuda_12.8
- name: Build wheels
uses: PyO3/maturin-action@v1
with:
args: --release --out dist -i python3.8
sccache: 'false'
manylinux: auto
docker-options: --gpus all
container: sameli/manylinux_2_34_x86_64_cuda_12.8
before-script-linux: |
yum install -y clang
teardown-ec2:
name: Teardown EC2 instance (fast-tests)
if: ${{ always() }}
needs: [ setup-ec2, build ]
runs-on: ubuntu-latest
steps:
- name: Stop instance
id: stop-instance
uses: luxfhe-ai/slab-github-runner@801df0b8db5ea2b06128b7476c652f5ed5f193a8
with:
mode: stop
github-token: ${{ secrets.SLAB_ACTION_TOKEN }}
slab-url: ${{ secrets.SLAB_BASE_URL }}
job-secret: ${{ secrets.JOB_SECRET }}
label: ${{ needs.setup-ec2.outputs.runner-name }}
build-macos:
name: Build for Python on macOS
runs-on: macos-14
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
ref: ${{ github.event.inputs.git-ref }}
- name: Install latest stable
uses: dtolnay/rust-toolchain@315e265cd78dad1e1dcf3a5074f6d6c47029d5aa
with:
toolchain: stable
- name: Set up Python 3.8
uses: actions/setup-python@v5
with:
python-version: 3.8
# You can test your matrix by printing the current Python version
- name: Install dependencies
run:
python -m pip install "poetry==1.8.3"
python -m poetry install --all-extras --no-root
- name: Build package CPU
run:
python -m poetry run maturin develop --no-default-features --features "python_bindings" --release
- name: Run MAC CPU tests
run:
make pytest
build-ios:
name: Build For iOS on macOS
runs-on: macos-14
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
ref: ${{ github.event.inputs.git-ref }}
- name: Install latest stable
uses: dtolnay/rust-toolchain@315e265cd78dad1e1dcf3a5074f6d6c47029d5aa
with:
toolchain: stable
- name: Install Swift Rust targets
run: |
rustup target add aarch64-apple-ios aarch64-apple-ios-sim
- name: Build package CPU
run: |
cd rust
cargo build --no-default-features --features "swift_bindings" --lib --release --target aarch64-apple-ios
cargo build --no-default-features --features "swift_bindings" --lib --release --target aarch64-apple-ios-sim
cargo run \
--bin uniffi-bindgen \
--no-default-features \
--features "uniffi/cli swift_bindings" generate \
--library target/aarch64-apple-ios/release/libtorus_ml_extensions.dylib \
--language swift \
--out-dir GENERATED/
mkdir -p GENERATED/include
mv GENERATED/torus_ml_extensionsFFI.modulemap GENERATED/include/module.modulemap
mv GENERATED/torus_ml_extensionsFFI.h GENERATED/include/torus_ml_extensionsFFI.h
xcodebuild -create-xcframework \
-library target/aarch64-apple-ios/release/libtorus_ml_extensions.a \
-headers GENERATED/include/ \
-library target/aarch64-apple-ios-sim/release/libtorus_ml_extensions.a \
-headers GENERATED/include/ \
-output GENERATED/TorusMLExtensions.xcframework
- name: Test iOS project compiles
if: false
run: |
cd ..
cd TestTorusMLX
xcodebuild -project TestTorusMLX.xcodeproj \
-scheme TestTorusMLX \
-sdk iphonesimulator \
-configuration Debug \
ARCHS="arm64" \
VALID_ARCHS="arm64" \
EXCLUDED_ARCHS="x86_64" \
build
test-wasm:
name: Test WASM Frontend
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
ref: ${{ github.event.inputs.git-ref }}
- name: Install latest stable
uses: dtolnay/rust-toolchain@315e265cd78dad1e1dcf3a5074f6d6c47029d5aa
with:
toolchain: stable
- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install wasm-pack
run: |
curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
- name: Run WASM tests
run: |
make wasm_test_e2e
-187
View File
@@ -1,187 +0,0 @@
# This file is autogenerated by maturin v1.7.1
# To update, run
#
# maturin generate-ci github
#
name: Release to PyPI
on:
workflow_dispatch:
permissions:
contents: read
env:
CARGO_TERM_COLOR: always
SLAB_PROFILE: single-t4-gpu
jobs:
setup-ec2:
name: Setup EC2 instance
runs-on: ubuntu-latest
outputs:
runner-name: ${{ steps.start-instance.outputs.label }}
steps:
- name: Start instance
id: start-instance
uses: luxfhe-ai/slab-github-runner@801df0b8db5ea2b06128b7476c652f5ed5f193a8
with:
mode: start
github-token: ${{ secrets.SLAB_ACTION_TOKEN }}
slab-url: ${{ secrets.SLAB_BASE_URL }}
job-secret: ${{ secrets.JOB_SECRET }}
backend: aws
profile: ${{ env.SLAB_PROFILE }}
linux-cuda:
needs: [setup-ec2]
runs-on: ${{ needs.setup-ec2.outputs.runner-name }}
strategy:
fail-fast: false
# explicit include-based build matrix, of known valid options
matrix:
python-version: ["3.8"] # We limit to 3.8 for now to limit time spent
include:
- os: ubuntu-22.04
cuda: "12.2"
gcc: 11
env:
CUDA_PATH: /usr/local/cuda
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: |
3.8
3.9
3.10
3.11
3.12
# You can test your matrix by printing the current Python version
- name: Install dependencies
run:
docker pull sameli/manylinux_2_34_x86_64_cuda_12.8
docker images
python -m pip install --upgrade pip
python -m pip install --root-user-action ignore "poetry==1.8.3"
python -m poetry install --all-extras --no-root
- name: Check Release Version
run: |
echo "Checking versions in source match tag ${{ github.ref_name }}"
poetry run python scripts/version_utils.py check-version --file-vars "rust/Cargo.toml:package.version" --version "${{ github.ref_name }}"
- name: Export CUDA variables
if: ${{ !cancelled() }}
run: |
echo "CUDA_HOME=$CUDA_PATH" >> "${GITHUB_ENV}"
echo "CUDA_PATH=$CUDA_PATH" >> "${GITHUB_ENV}"
echo "$CUDA_PATH/bin" >> "${GITHUB_PATH}"
echo "LD_LIBRARY_PATH=$CUDA_PATH/lib:$CUDA_PATH/lib64:$LD_LIBRARY_PATH" >> "${GITHUB_ENV}"
echo "CUDACXX=/usr/local/cuda-${{ matrix.cuda }}/bin/nvcc" >> "${GITHUB_ENV}"
echo 'export CUDA_MODULE_LOADER=EAGER' >> ~/.bashrc
echo 'export PATH="$PATH:$CUDA_PATH/bin"' >> ~/.bashrc
ls $CUDA_PATH/
source ~/.bashrc
- name: Install latest stable
uses: dtolnay/rust-toolchain@315e265cd78dad1e1dcf3a5074f6d6c47029d5aa
with:
toolchain: stable
- name: Build wheels
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.platform.target }}
args: --release --out dist -i python3.8 python3.9 python3.10 python3.11 python3.12
sccache: 'false'
manylinux: auto
docker-options: --gpus all
container: sameli/manylinux_2_34_x86_64_cuda_12.8
before-script-linux: |
yum install -y clang
- name: Upload wheels
uses: actions/upload-artifact@v4
with:
name: wheels-linux-${{ matrix.platform.target }}
path: dist
macos-and-linux-non-cuda:
runs-on: ${{ matrix.platform.runner }}
strategy:
matrix:
platform:
- runner: macos-latest
target: x86_64
- runner: macos-14
target: aarch64
- runner: ubuntu-latest
target: aarch64
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: |
3.8
3.9
3.10
3.11
3.12
- name: Build wheels
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.platform.target }}
args: --release --no-default-features --features "python_bindings" --out dist -i python3.8 python3.9 python3.10 python3.11 python3.12
sccache: 'false'
- name: Upload wheels
uses: actions/upload-artifact@v4
with:
name: wheels-${{ matrix.platform.runner }}-${{ matrix.platform.target }}
path: dist
release:
name: Release
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/')
needs: [linux-cuda, macos-and-linux-non-cuda]
steps:
- uses: actions/download-artifact@v4
- name: Publish test
run: |
ls
echo Release uploaded to pypi
- name: Publish to PyPI
uses: PyO3/maturin-action@v1
env:
MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
with:
command: upload
args: --non-interactive --skip-existing wheels-*/*
sccache: 'false'
teardown-ec2:
name: Teardown EC2 instance (fast-tests)
if: ${{ always() }}
needs: [ setup-ec2, linux-cuda, macos-and-linux-non-cuda ]
runs-on: ubuntu-latest
steps:
- name: Stop instance
id: stop-instance
uses: luxfhe-ai/slab-github-runner@801df0b8db5ea2b06128b7476c652f5ed5f193a8
with:
mode: stop
github-token: ${{ secrets.SLAB_ACTION_TOKEN }}
slab-url: ${{ secrets.SLAB_BASE_URL }}
job-secret: ${{ secrets.JOB_SECRET }}
label: ${{ needs.setup-ec2.outputs.runner-name }}
-29
View File
@@ -1,29 +0,0 @@
# Generated by Cargo
# will have compiled files and executables
debug/
target/
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock
# These are backup files generated by rustfmt
**/*.rs.bk
# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb
*__pycache__*
.vscode
.DS_Store
rust/GENERATED
xcuserdata
.venv
TestConcretMLX/build
tests/test_wasm/frontend/pkg
tests/test_wasm/frontend/node_modules
tests/test_wasm/frontend/playwright-report
tests/test_wasm/frontend/test-results
-28
View File
@@ -1,28 +0,0 @@
BSD 3-Clause Clear License
Copyright © 2025 Lux Industries Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or other
materials provided with the distribution.
3. Neither the name of LUX nor the names of its contributors may be used to endorse
or promote products derived from this software without specific prior written permission.
NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE.
THIS SOFTWARE IS PROVIDED BY THE LUX AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
LUX OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-148
View File
@@ -1,148 +0,0 @@
SHELL:=$(shell /usr/bin/env which bash)
OS:=$(shell uname)
RS_CHECK_TOOLCHAIN:=$(shell cat toolchain.txt | tr -d '\n')
CARGO_RS_CHECK_TOOLCHAIN:=+$(RS_CHECK_TOOLCHAIN)
CPU_COUNT=$(shell ./scripts/cpu_count.sh)
RS_BUILD_TOOLCHAIN:=stable
CARGO_RS_BUILD_TOOLCHAIN:=+$(RS_BUILD_TOOLCHAIN)
CARGO_PROFILE?=release
MIN_RUST_VERSION:=1.81.0
PYTHON_VERSION:=$(shell python3 -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")')
export RUSTFLAGS?=-C target-cpu=native
.PHONY: rs_check_toolchain # Echo the rust toolchain used for checks
rs_check_toolchain:
@echo $(RS_CHECK_TOOLCHAIN)
.PHONY: rs_build_toolchain # Echo the rust toolchain used for builds
rs_build_toolchain:
@echo $(RS_BUILD_TOOLCHAIN)
.PHONY: install_rs_check_toolchain # Install the toolchain used for checks
install_rs_check_toolchain:
@rustup toolchain list | grep -q "$(RS_CHECK_TOOLCHAIN)" || \
rustup toolchain install -y --profile default "$(RS_CHECK_TOOLCHAIN)" || \
( echo "Unable to install $(RS_CHECK_TOOLCHAIN) toolchain, check your rustup installation. \
Rustup can be downloaded at https://rustup.rs/" && exit 1 )
.PHONY: install_rs_build_toolchain # Install the toolchain used for builds
install_rs_build_toolchain:
@( rustup toolchain list | grep -q "$(RS_BUILD_TOOLCHAIN)" && \
./scripts/check_cargo_min_ver.sh \
--rust-toolchain "$(CARGO_RS_BUILD_TOOLCHAIN)" \
--min-rust-version "$(MIN_RUST_VERSION)" ) || \
rustup toolchain install --profile default "$(RS_BUILD_TOOLCHAIN)" || \
( echo "Unable to install $(RS_BUILD_TOOLCHAIN) toolchain, check your rustup installation. \
Rustup can be downloaded at https://rustup.rs/" && exit 1 )
.PHONY: build_wasm # Build the WASM package used in tests and other applications
build_wasm: install_rs_build_toolchain
@echo "Building WASM package..."
@mkdir -p rust/pkg-wasm # Ensure the output directory exists
cd rust && RUSTFLAGS="" PYO3_CROSS_PYTHON_VERSION=$(PYTHON_VERSION) PYO3_CROSS=1 wasm-pack build . \
--target web \
--out-name torus_ml_extensions_wasm \
--out-dir ./pkg-wasm \
--release \
-- --no-default-features --features wasm_bindings
@echo "WASM package built in rust/pkg-wasm"
.PHONY: test # Run the tests
test: install_rs_check_toolchain
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_CHECK_TOOLCHAIN) test --profile $(CARGO_PROFILE)
.PHONY: fmt # Format rust code
fmt: install_rs_check_toolchain
cargo "$(CARGO_RS_CHECK_TOOLCHAIN)" fmt --manifest-path rust/Cargo.toml
black .
.PHONY: check_fmt # Check rust code format
check_fmt: install_rs_check_toolchain
cargo "$(CARGO_RS_CHECK_TOOLCHAIN)" fmt --check
.PHONY: clippy_all_targets # Run clippy lints on all targets (benches, examples, etc.)
clippy_all_targets: install_rs_check_toolchain
RUSTFLAGS="$(RUSTFLAGS)" cargo "$(CARGO_RS_CHECK_TOOLCHAIN)" clippy --all-targets \
-- --no-deps -D warnings
.PHONY: pcc # pcc stands for pre commit checks
pcc: check_fmt clippy_all_targets
.PHONY: help # Generate list of targets with descriptions
help:
@grep '^\.PHONY: .* #' Makefile | sed 's/\.PHONY: \(.*\) # \(.*\)/\1\t\2/' | expand -t30 | sort
.PHONY: pytest
pytest:
poetry run pytest ./tests -svv --capture=tee-sys --cache-clear
.PHONY: build_dev_cpu
build_dev_cpu:
maturin develop --release
.PHONY: wheel_cpu
wheel_cpu:
maturin build --release
.PHONY: check_version_is_consistent
check_version_is_consistent:
poetry run python scripts/version_utils.py check-version --file-vars "rust/Cargo.toml:package.version"
.PHONY: build_fhe_server # Build the FHE server (helper for WASM tests)
build_fhe_server: install_rs_build_toolchain
@echo "Building FHE server..."
cd tests/test_wasm/backend && cargo build --release
.PHONY: run_fhe_server # Run the FHE server (helper for WASM tests)
run_fhe_server: build_fhe_server
@echo "Starting FHE server..."
cd tests/test_wasm/backend && ./target/release/backend
.PHONY: wasm_build_env # Builds WASM client, FHE server, and copies artifacts to frontend.
wasm_build_env: build_wasm build_fhe_server
@echo "Copying WASM artifacts to frontend..."
@mkdir -p tests/test_wasm/frontend/pkg
@cp -r rust/pkg-wasm/* tests/test_wasm/frontend/pkg/
@echo "WASM artifacts copied to tests/test_wasm/frontend/pkg"
@echo "WASM build environment preparation complete"
.PHONY: wasm_clean # Clean all WASM-related build and test artifacts.
wasm_clean:
@echo "Cleaning WASM test build artifacts..."
rm -rf rust/pkg-wasm
rm -rf tests/test_wasm/frontend/pkg
rm -rf tests/test_wasm/frontend/node_modules
rm -rf tests/test_wasm/frontend/playwright-report
rm -rf tests/test_wasm/frontend/test-results
cd tests/test_wasm/backend && cargo clean
.PHONY: wasm_dev_server # Sets up environment and runs FHE server for manual WASM testing in browser.
wasm_dev_server: wasm_build_env
@echo "Starting WASM test environment for manual interaction..."
@echo "Open http://localhost:8000 in your browser"
@echo "Press Ctrl+C to stop the FHE server"
@make run_fhe_server
.PHONY: wasm_test_e2e_install_deps # Install Playwright and its browser dependencies for E2E tests
wasm_test_e2e_install_deps:
@echo "Installing Playwright test dependencies..."
cd tests/test_wasm/frontend && npm install --quiet
@echo "Installing Playwright browsers..."
cd tests/test_wasm/frontend && npx playwright install --with-deps
.PHONY: wasm_test_e2e # Run full WASM E2E tests (cleans, builds env, installs deps, executes tests). For CI & local.
wasm_test_e2e: wasm_clean wasm_build_env wasm_test_e2e_install_deps
@echo "Starting FHE server for E2E tests..."
cd tests/test_wasm/backend && cargo run --release & \
FHE_SERVER_PID=$$!; \
echo "FHE server started with PID $${FHE_SERVER_PID}"; \
echo "Waiting for server to be ready..."; \
sleep 8; \
echo "Running Playwright E2E tests..."; \
(cd tests/test_wasm/frontend && npx playwright test e2e.spec.js) ; EXIT_CODE=$$?; \
echo "Stopping FHE server (PID $${FHE_SERVER_PID})..."; \
kill $${FHE_SERVER_PID} || echo "Server (PID $${FHE_SERVER_PID}) already stopped or kill failed."; \
wait $${FHE_SERVER_PID} 2>/dev/null || echo "Server process (PID $${FHE_SERVER_PID}) finished."; \
echo "E2E tests finished with exit code $${EXIT_CODE}."; \
exit $${EXIT_CODE}

Some files were not shown because too many files have changed in this diff Show More