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/
@@ -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
|
||||
@@ -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
|
||||
@@ -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 }}
|
||||
@@ -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 }}'
|
||||
}
|
||||
})
|
||||
@@ -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
|
||||
@@ -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"`.
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,9 +0,0 @@
|
||||
import { defineConfig } from 'vitest/config';
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
include: ['test/**/*.test.ts'],
|
||||
testTimeout: 30000,
|
||||
hookTimeout: 30000,
|
||||
},
|
||||
});
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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'] },
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -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` });
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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"]
|
||||
}
|
||||
@@ -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=
|
||||
|
||||
@@ -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
|
||||
```
|
||||
@@ -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);
|
||||
@@ -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:
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -1,5 +0,0 @@
|
||||
.artifacts
|
||||
.keys
|
||||
.ipynb_checkpoints
|
||||
.hypothesis
|
||||
**/__pycache__
|
||||
@@ -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
|
||||
@@ -1,8 +0,0 @@
|
||||
# Taplo is a TOML formater
|
||||
# https://taplo.tamasfe.dev/
|
||||
|
||||
exclude = []
|
||||
|
||||
[formatting]
|
||||
align_entries = true
|
||||
reorder_keys = true
|
||||
@@ -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.
|
||||
@@ -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
|
||||
|
||||

|
||||
|
||||
## 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)
|
||||
@@ -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"
|
||||
|
Before Width: | Height: | Size: 301 KiB |
|
Before Width: | Height: | Size: 301 KiB |
|
Before Width: | Height: | Size: 301 KiB |
|
Before Width: | Height: | Size: 301 KiB |
|
Before Width: | Height: | Size: 301 KiB |
|
Before Width: | Height: | Size: 301 KiB |
|
Before Width: | Height: | Size: 301 KiB |
|
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
|
||||
@@ -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
|
||||
@@ -1,2 +0,0 @@
|
||||
*
|
||||
!.gitignore
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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>'
|
||||
```
|
||||
|
Before Width: | Height: | Size: 38 KiB |
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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} ..."}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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 }}
|
||||
@@ -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
|
||||
@@ -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.
|
||||
@@ -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}
|
||||