mirror of
https://github.com/luxfi/fhe.git
synced 2026-09-24 00:27:17 +00:00
Clean up: Move Go FHE implementation to lux/fhe
- Remove old Go FHE code (now in lux/fhe) - Remove old Zama compatibility layers - Update CI for TypeScript/JS SDK only - This repo is now purely the @luxfhe npm package ecosystem
This commit is contained in:
+63
-216
@@ -2,263 +2,110 @@ name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
branches: [main, master]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
branches: [main, master]
|
||||
|
||||
jobs:
|
||||
test-go:
|
||||
name: Go Tests (${{ matrix.go-version }}, ${{ matrix.os }})
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
go-version: ['1.25']
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
|
||||
- name: Download dependencies
|
||||
run: go mod download
|
||||
|
||||
- name: Build
|
||||
env:
|
||||
CGO_ENABLED: '0'
|
||||
run: |
|
||||
go build ./...
|
||||
go build ./server/standalone/
|
||||
|
||||
- name: Test (Unix)
|
||||
if: runner.os != 'Windows'
|
||||
env:
|
||||
CGO_ENABLED: '0'
|
||||
run: go test -v -timeout 30m -coverprofile=coverage.out .
|
||||
|
||||
- name: Test (Windows)
|
||||
if: runner.os == 'Windows'
|
||||
env:
|
||||
CGO_ENABLED: '0'
|
||||
run: go test -v -timeout 30m .
|
||||
|
||||
- name: Upload coverage
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: coverage
|
||||
path: coverage.out
|
||||
|
||||
test-cgo:
|
||||
name: CGO Build (${{ matrix.os }})
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.25'
|
||||
|
||||
- name: Build CGO packages
|
||||
run: |
|
||||
# Test that CGO packages compile (they need external libs at runtime)
|
||||
CGO_ENABLED=1 go build -v ./cgo ./gpu ./server ./cmd/fhe-server 2>&1 || echo "CGO build requires external libraries - expected in CI"
|
||||
|
||||
test-c:
|
||||
name: C SDK
|
||||
build-sdk:
|
||||
name: Build SDK
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.25'
|
||||
|
||||
- name: Build C shared library
|
||||
run: |
|
||||
mkdir -p sdk/c/lib
|
||||
CGO_ENABLED=1 go build -buildmode=c-shared -o sdk/c/lib/libluxfhe.so ./sdk/c/src/luxfhe.go
|
||||
|
||||
- name: Verify library exports
|
||||
run: |
|
||||
nm -D sdk/c/lib/libluxfhe.so | grep luxfhe | head -20
|
||||
|
||||
- name: Upload C library
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: libluxfhe-linux
|
||||
path: sdk/c/lib/libluxfhe.so
|
||||
|
||||
test-wasm:
|
||||
name: WASM SDK
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.25'
|
||||
|
||||
- name: Build WASM
|
||||
run: |
|
||||
GOOS=js GOARCH=wasm go build -o sdk/wasm/luxfhe.wasm ./sdk/wasm/main.go
|
||||
ls -lh sdk/wasm/luxfhe.wasm
|
||||
|
||||
- name: Upload WASM
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: luxfhe-wasm
|
||||
path: sdk/wasm/luxfhe.wasm
|
||||
|
||||
test-typescript:
|
||||
name: TypeScript SDK (Node ${{ matrix.node-version }})
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
node-version: ['18', '20', '22']
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Node.js
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
node-version: '20'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: js/v2-sdk/package-lock.json
|
||||
|
||||
- name: Install dependencies
|
||||
working-directory: sdk/typescript
|
||||
working-directory: js/v2-sdk
|
||||
run: npm ci
|
||||
|
||||
- name: Type check
|
||||
working-directory: sdk/typescript
|
||||
run: npm run typecheck
|
||||
|
||||
- name: Build
|
||||
working-directory: sdk/typescript
|
||||
working-directory: js/v2-sdk
|
||||
run: npm run build
|
||||
|
||||
- name: Upload TypeScript dist
|
||||
if: matrix.node-version == '22'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: luxfhe-ts
|
||||
path: sdk/typescript/dist
|
||||
|
||||
test-rust:
|
||||
name: Rust SDK
|
||||
runs-on: ubuntu-latest
|
||||
needs: test-c
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install Rust
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
- name: Download C library
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: libluxfhe-linux
|
||||
path: sdk/c/lib
|
||||
|
||||
- name: Install libclang for bindgen
|
||||
run: sudo apt-get update && sudo apt-get install -y libclang-dev
|
||||
|
||||
- name: Check Rust bindings
|
||||
working-directory: sdk/rust
|
||||
run: cargo check
|
||||
|
||||
- name: Build Rust bindings
|
||||
working-directory: sdk/rust
|
||||
- name: Run unit tests
|
||||
working-directory: js/v2-sdk
|
||||
run: npm test -- --reporter=verbose --testTimeout=60000
|
||||
env:
|
||||
LD_LIBRARY_PATH: ${{ github.workspace }}/sdk/c/lib
|
||||
run: cargo build --release
|
||||
SKIP_LOCAL_ENV: true
|
||||
|
||||
test-python:
|
||||
name: Python SDK (${{ matrix.python-version }})
|
||||
build-hardhat-plugin:
|
||||
name: Build Hardhat Plugin
|
||||
runs-on: ubuntu-latest
|
||||
needs: test-c
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
python-version: ['3.9', '3.10', '3.11', '3.12']
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
node-version: '20'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: plugins/hardhat/package-lock.json
|
||||
|
||||
- name: Download C library
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: libluxfhe-linux
|
||||
path: sdk/c/lib
|
||||
- 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 .
|
||||
|
||||
- name: Install dependencies
|
||||
working-directory: sdk/python
|
||||
run: |
|
||||
pip install cffi pytest
|
||||
pip install -e .
|
||||
working-directory: plugins/hardhat
|
||||
run: npm ci
|
||||
|
||||
- name: Build
|
||||
working-directory: plugins/hardhat
|
||||
run: npm run build
|
||||
|
||||
- name: Run tests
|
||||
working-directory: sdk/python
|
||||
env:
|
||||
LD_LIBRARY_PATH: ${{ github.workspace }}/sdk/c/lib
|
||||
run: pytest -v tests/
|
||||
working-directory: plugins/hardhat
|
||||
run: npm test
|
||||
|
||||
benchmark:
|
||||
name: Benchmark
|
||||
build-permit:
|
||||
name: Build Permit
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
go-version: '1.25'
|
||||
node-version: '20'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: js/permit/package-lock.json
|
||||
|
||||
- name: Run benchmarks
|
||||
env:
|
||||
CGO_ENABLED: '0'
|
||||
run: go test -bench=BenchmarkLattice -benchmem -run=^$ . | tee benchmark.txt
|
||||
- name: Install dependencies
|
||||
working-directory: js/permit
|
||||
run: npm ci
|
||||
|
||||
- name: Upload benchmark
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: benchmark
|
||||
path: benchmark.txt
|
||||
- name: Build
|
||||
working-directory: js/permit
|
||||
run: npm run build
|
||||
|
||||
lint:
|
||||
name: Lint
|
||||
build-wasm:
|
||||
name: Build WASM
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
go-version: '1.25'
|
||||
node-version: '20'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: packages/wasm/package-lock.json
|
||||
|
||||
- name: Run go vet
|
||||
env:
|
||||
CGO_ENABLED: '0'
|
||||
run: go vet ./...
|
||||
- name: Install dependencies
|
||||
working-directory: packages/wasm
|
||||
run: npm ci
|
||||
|
||||
- name: Run go fmt check
|
||||
run: |
|
||||
if [ "$(gofmt -s -l . | wc -l)" -gt 0 ]; then
|
||||
echo "The following files need to be formatted:"
|
||||
gofmt -s -l .
|
||||
exit 1
|
||||
fi
|
||||
- name: Build
|
||||
working-directory: packages/wasm
|
||||
run: npm run build
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
name: Docker Publish
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, master]
|
||||
tags: ['v*']
|
||||
pull_request:
|
||||
branches: [main, master]
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
|
||||
jobs:
|
||||
build-and-push:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- target: server
|
||||
image: luxfi/fhe/server
|
||||
- target: gateway
|
||||
image: luxfi/fhe/gateway
|
||||
- target: worker
|
||||
image: luxfi/fhe/worker
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Extract metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: |
|
||||
${{ env.REGISTRY }}/${{ matrix.image }}
|
||||
tags: |
|
||||
type=ref,event=branch
|
||||
type=ref,event=pr
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=sha,prefix=
|
||||
type=raw,value=latest,enable={{is_default_branch}}
|
||||
|
||||
- name: Build and push ${{ matrix.target }}
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
target: ${{ matrix.target }}
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=gha,scope=${{ matrix.target }}
|
||||
cache-to: type=gha,mode=max,scope=${{ matrix.target }}
|
||||
@@ -1,66 +0,0 @@
|
||||
name: Deploy Docs to GitHub Pages
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
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:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '22'
|
||||
cache: 'pnpm'
|
||||
cache-dependency-path: docs/pnpm-lock.yaml
|
||||
|
||||
- name: Install dependencies
|
||||
working-directory: docs
|
||||
run: pnpm install
|
||||
|
||||
- name: Build docs
|
||||
working-directory: docs
|
||||
run: pnpm build
|
||||
|
||||
- name: Setup Pages
|
||||
uses: actions/configure-pages@v5
|
||||
with:
|
||||
enablement: true
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
path: docs/out
|
||||
|
||||
deploy:
|
||||
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
|
||||
@@ -0,0 +1,152 @@
|
||||
name: Publish to NPM
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
package:
|
||||
description: 'Package to publish'
|
||||
required: true
|
||||
type: choice
|
||||
options:
|
||||
- all
|
||||
- sdk
|
||||
- hardhat-plugin
|
||||
- permit
|
||||
- wasm
|
||||
- foundry-mocks
|
||||
|
||||
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
|
||||
|
||||
- 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 ci
|
||||
|
||||
- name: Build
|
||||
working-directory: packages/wasm
|
||||
run: npm run build
|
||||
|
||||
- name: Publish
|
||||
working-directory: packages/wasm
|
||||
run: npm publish --access public
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
|
||||
publish-sdk:
|
||||
name: Publish @luxfhe/sdk
|
||||
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
|
||||
|
||||
- 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 ci
|
||||
|
||||
- name: Build
|
||||
working-directory: js/v2-sdk
|
||||
run: npm run build
|
||||
|
||||
- name: Publish
|
||||
working-directory: js/v2-sdk
|
||||
run: npm publish --access public
|
||||
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
|
||||
|
||||
- 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 ci
|
||||
|
||||
- name: Build
|
||||
working-directory: js/permit
|
||||
run: npm run build
|
||||
|
||||
- name: Publish
|
||||
working-directory: js/permit
|
||||
run: npm publish --access public
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
|
||||
publish-foundry-mocks:
|
||||
name: Publish @luxfhe/foundry-mocks
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'release' || github.event.inputs.package == 'all' || github.event.inputs.package == 'foundry-mocks'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- 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
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
|
||||
publish-hardhat-plugin:
|
||||
name: Publish @luxfhe/hardhat-plugin
|
||||
runs-on: ubuntu-latest
|
||||
needs: [publish-sdk, publish-foundry-mocks]
|
||||
if: always() && (github.event_name == 'release' || github.event.inputs.package == 'all' || github.event.inputs.package == 'hardhat-plugin')
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
|
||||
- name: Install dependencies
|
||||
working-directory: plugins/hardhat
|
||||
run: npm ci
|
||||
|
||||
- name: Build
|
||||
working-directory: plugins/hardhat
|
||||
run: npm run build
|
||||
|
||||
- name: Publish
|
||||
working-directory: plugins/hardhat
|
||||
run: npm publish --access public
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
@@ -1,304 +0,0 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: 'Release tag (e.g., v0.1.0)'
|
||||
required: true
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
build-binaries:
|
||||
name: Build (${{ matrix.os }}, ${{ matrix.arch }})
|
||||
runs-on: ${{ matrix.runner }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
# Linux
|
||||
- os: linux
|
||||
arch: amd64
|
||||
runner: ubuntu-latest
|
||||
ext: ''
|
||||
- os: linux
|
||||
arch: arm64
|
||||
runner: ubuntu-latest
|
||||
ext: ''
|
||||
# macOS
|
||||
- os: darwin
|
||||
arch: amd64
|
||||
runner: macos-latest
|
||||
ext: ''
|
||||
- os: darwin
|
||||
arch: arm64
|
||||
runner: macos-latest
|
||||
ext: ''
|
||||
# Windows
|
||||
- os: windows
|
||||
arch: amd64
|
||||
runner: windows-latest
|
||||
ext: '.exe'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.25'
|
||||
|
||||
- name: Build binaries
|
||||
env:
|
||||
GOOS: ${{ matrix.os }}
|
||||
GOARCH: ${{ matrix.arch }}
|
||||
CGO_ENABLED: '0'
|
||||
run: |
|
||||
# Pure Go binaries (no CGO required)
|
||||
go build -ldflags="-s -w" -o luxfhe-server-${{ matrix.os }}-${{ matrix.arch }}${{ matrix.ext }} ./server/standalone/
|
||||
go build -ldflags="-s -w" -o luxfhe-gateway-${{ matrix.os }}-${{ matrix.arch }}${{ matrix.ext }} ./cmd/fhe-gateway/
|
||||
go build -ldflags="-s -w" -o luxfhe-worker-${{ matrix.os }}-${{ matrix.arch }}${{ matrix.ext }} ./cmd/fhe-worker/
|
||||
|
||||
- name: Upload binaries
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: luxfhe-${{ matrix.os }}-${{ matrix.arch }}
|
||||
path: |
|
||||
luxfhe-server-${{ matrix.os }}-${{ matrix.arch }}${{ matrix.ext }}
|
||||
luxfhe-gateway-${{ matrix.os }}-${{ matrix.arch }}${{ matrix.ext }}
|
||||
luxfhe-worker-${{ matrix.os }}-${{ matrix.arch }}${{ matrix.ext }}
|
||||
|
||||
build-c-libraries:
|
||||
name: C Library (${{ matrix.os }})
|
||||
runs-on: ${{ matrix.runner }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: linux
|
||||
runner: ubuntu-latest
|
||||
lib: libluxfhe.so
|
||||
- os: darwin
|
||||
runner: macos-latest
|
||||
lib: libluxfhe.dylib
|
||||
- os: windows
|
||||
runner: windows-latest
|
||||
lib: luxfhe.dll
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.25'
|
||||
|
||||
- name: Build C shared library
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p dist
|
||||
CGO_ENABLED=1 go build -buildmode=c-shared -o dist/${{ matrix.lib }} ./sdk/c/src/luxfhe.go
|
||||
|
||||
- name: Upload C library
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: libluxfhe-${{ matrix.os }}
|
||||
path: dist/
|
||||
|
||||
build-wasm:
|
||||
name: WASM Build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.25'
|
||||
|
||||
- name: Build WASM
|
||||
run: |
|
||||
mkdir -p dist
|
||||
GOOS=js GOARCH=wasm go build -o dist/luxfhe.wasm ./sdk/wasm/main.go
|
||||
# wasm_exec.js may not exist in Go 1.25 toolchain, download if needed
|
||||
if [ -f "$(go env GOROOT)/misc/wasm/wasm_exec.js" ]; then
|
||||
cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" dist/
|
||||
else
|
||||
curl -sL "https://raw.githubusercontent.com/golang/go/go$(go version | awk '{print $3}' | sed 's/go//')/misc/wasm/wasm_exec.js" -o dist/wasm_exec.js
|
||||
fi
|
||||
|
||||
- name: Upload WASM
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: luxfhe-wasm
|
||||
path: dist/
|
||||
|
||||
build-typescript:
|
||||
name: TypeScript SDK
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '22'
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
|
||||
- name: Install and build
|
||||
working-directory: sdk/typescript
|
||||
run: |
|
||||
npm ci
|
||||
npm run build
|
||||
|
||||
- name: Package
|
||||
working-directory: sdk/typescript
|
||||
run: npm pack
|
||||
|
||||
- name: Publish to npm
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
continue-on-error: true # Don't fail if version already exists
|
||||
working-directory: sdk/typescript
|
||||
run: npm publish --access public
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
|
||||
- name: Upload package
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: luxfhe-typescript
|
||||
path: sdk/typescript/*.tgz
|
||||
|
||||
publish-python:
|
||||
name: Python SDK
|
||||
runs-on: ubuntu-latest
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
|
||||
- name: Install build tools
|
||||
run: pip install build twine
|
||||
|
||||
- name: Build package
|
||||
working-directory: sdk/python
|
||||
run: python -m build
|
||||
|
||||
- name: Publish to PyPI
|
||||
continue-on-error: true # Don't fail if no token or version exists
|
||||
working-directory: sdk/python
|
||||
run: twine upload dist/*
|
||||
env:
|
||||
TWINE_USERNAME: __token__
|
||||
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
|
||||
|
||||
create-release:
|
||||
name: Create Release
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build-binaries, build-c-libraries, build-wasm, build-typescript]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Download all artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: artifacts
|
||||
|
||||
- name: Prepare release assets
|
||||
run: |
|
||||
mkdir -p release
|
||||
# Binaries
|
||||
for dir in artifacts/luxfhe-*; do
|
||||
if [ -d "$dir" ]; then
|
||||
name=$(basename "$dir")
|
||||
if [[ "$name" == luxfhe-linux-* ]] || [[ "$name" == luxfhe-darwin-* ]] || [[ "$name" == luxfhe-windows-* ]]; then
|
||||
for f in "$dir"/*; do
|
||||
cp "$f" "release/"
|
||||
done
|
||||
fi
|
||||
fi
|
||||
done
|
||||
# C libraries
|
||||
for os in linux darwin windows; do
|
||||
if [ -d "artifacts/libluxfhe-$os" ]; then
|
||||
tar -czvf "release/libluxfhe-$os.tar.gz" -C "artifacts/libluxfhe-$os" .
|
||||
fi
|
||||
done
|
||||
# WASM
|
||||
if [ -d "artifacts/luxfhe-wasm" ]; then
|
||||
tar -czvf "release/luxfhe-wasm.tar.gz" -C "artifacts/luxfhe-wasm" .
|
||||
fi
|
||||
# TypeScript
|
||||
if [ -d "artifacts/luxfhe-typescript" ]; then
|
||||
cp artifacts/luxfhe-typescript/*.tgz release/
|
||||
fi
|
||||
ls -la release/
|
||||
|
||||
- name: Generate checksums
|
||||
run: |
|
||||
cd release
|
||||
sha256sum * > checksums.txt
|
||||
cat checksums.txt
|
||||
|
||||
- name: Get tag name
|
||||
id: tag
|
||||
run: |
|
||||
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
|
||||
echo "tag=${{ github.event.inputs.tag }}" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "tag=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Create GitHub Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
tag_name: ${{ steps.tag.outputs.tag }}
|
||||
name: LuxFHE ${{ steps.tag.outputs.tag }}
|
||||
body: |
|
||||
## LuxFHE ${{ steps.tag.outputs.tag }}
|
||||
|
||||
Pure Go implementation of TFHE (Torus Fully Homomorphic Encryption).
|
||||
|
||||
### Downloads
|
||||
|
||||
#### Binaries (Pure Go - no dependencies)
|
||||
| Platform | Architecture | Server | Gateway | Worker |
|
||||
|----------|--------------|--------|---------|--------|
|
||||
| Linux | amd64 | `luxfhe-server-linux-amd64` | `luxfhe-gateway-linux-amd64` | `luxfhe-worker-linux-amd64` |
|
||||
| Linux | arm64 | `luxfhe-server-linux-arm64` | `luxfhe-gateway-linux-arm64` | `luxfhe-worker-linux-arm64` |
|
||||
| macOS | amd64 | `luxfhe-server-darwin-amd64` | `luxfhe-gateway-darwin-amd64` | `luxfhe-worker-darwin-amd64` |
|
||||
| macOS | arm64 | `luxfhe-server-darwin-arm64` | `luxfhe-gateway-darwin-arm64` | `luxfhe-worker-darwin-arm64` |
|
||||
| Windows | amd64 | `luxfhe-server-windows-amd64.exe` | `luxfhe-gateway-windows-amd64.exe` | `luxfhe-worker-windows-amd64.exe` |
|
||||
|
||||
#### SDK Libraries
|
||||
- `libluxfhe-linux.tar.gz` - C shared library for Linux
|
||||
- `libluxfhe-darwin.tar.gz` - C shared library for macOS
|
||||
- `libluxfhe-windows.tar.gz` - C DLL for Windows
|
||||
- `luxfhe-wasm.tar.gz` - WebAssembly build
|
||||
- `luxfhe-*.tgz` - TypeScript/JavaScript SDK
|
||||
|
||||
#### GPU-Accelerated Server
|
||||
Build from source with CGO and [luxcpp/fhe](https://github.com/luxcpp/fhe):
|
||||
```bash
|
||||
CGO_ENABLED=1 go build ./cmd/fhe-server
|
||||
```
|
||||
|
||||
### Verification
|
||||
|
||||
Verify downloads with checksums:
|
||||
```bash
|
||||
sha256sum -c checksums.txt
|
||||
```
|
||||
files: release/*
|
||||
draft: false
|
||||
prerelease: ${{ contains(steps.tag.outputs.tag, '-') }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
+66
-47
@@ -1,65 +1,84 @@
|
||||
# Binaries
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
# Dependencies
|
||||
node_modules/
|
||||
.pnpm-store/
|
||||
.yarn/cache/
|
||||
.yarn/unplugged/
|
||||
|
||||
# Test binary
|
||||
*.test
|
||||
# Build outputs
|
||||
dist/
|
||||
build/
|
||||
out/
|
||||
.next/
|
||||
.nuxt/
|
||||
.output/
|
||||
|
||||
# Output of go coverage tool
|
||||
*.out
|
||||
coverage.txt
|
||||
|
||||
# Dependency directories
|
||||
vendor/
|
||||
# Cache
|
||||
.cache/
|
||||
*.cache
|
||||
.turbo/
|
||||
.parcel-cache/
|
||||
|
||||
# IDE
|
||||
.idea/
|
||||
.vscode/
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
|
||||
# Docs
|
||||
docs/.next/
|
||||
docs/out/
|
||||
docs/node_modules/
|
||||
# Environment
|
||||
.env
|
||||
.env.local
|
||||
.env.*.local
|
||||
!.env.example
|
||||
|
||||
# Profiling
|
||||
*.prof
|
||||
*.pprof
|
||||
# Logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
|
||||
# Build artifacts
|
||||
bin/
|
||||
dist/
|
||||
# Testing
|
||||
coverage/
|
||||
.nyc_output/
|
||||
|
||||
# TypeScript SDK
|
||||
ts/node_modules/
|
||||
ts/dist/
|
||||
|
||||
# Rust bindings
|
||||
rust/target/
|
||||
# Rust
|
||||
target/
|
||||
Cargo.lock
|
||||
!core/*/Cargo.lock
|
||||
!research/*/Cargo.lock
|
||||
!wasm/*/Cargo.lock
|
||||
|
||||
# Python
|
||||
python/__pycache__/
|
||||
python/*.egg-info/
|
||||
python/build/
|
||||
python/.venv/
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
.Python
|
||||
*.egg-info/
|
||||
.eggs/
|
||||
*.egg
|
||||
.venv/
|
||||
venv/
|
||||
ENV/
|
||||
|
||||
# C library binaries (keep headers)
|
||||
c/lib/*.so
|
||||
c/lib/*.dylib
|
||||
c/lib/*.a
|
||||
c/examples/cpp_test
|
||||
# Go
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# WASM binaries (large, build from source)
|
||||
wasm/*.wasm
|
||||
ts/wasm/*.wasm
|
||||
target/
|
||||
*.o
|
||||
*.a
|
||||
# Hardhat/Foundry
|
||||
cache/
|
||||
artifacts/
|
||||
typechain/
|
||||
typechain-types/
|
||||
forge-cache/
|
||||
|
||||
# Misc
|
||||
*.bak
|
||||
*.tmp
|
||||
*.temp
|
||||
.git-backup/
|
||||
python-sdk
|
||||
ml-sdk
|
||||
|
||||
-216
@@ -1,216 +0,0 @@
|
||||
# FHE Benchmarks
|
||||
|
||||
Benchmarks for the Lux FHE implementation on Apple M1 Max (ARM64).
|
||||
|
||||
## Summary Comparison
|
||||
|
||||
| Operation | Pure Go (Lattice) | OpenFHE (CGO) | Winner |
|
||||
|-----------|-------------------|---------------|--------|
|
||||
| SecretKey Gen | 41.7 µs | 14.4 µs | CGO 2.9x |
|
||||
| BootstrapKey Gen | 131.9 ms | 2413 ms | **Go 18x** |
|
||||
| Encrypt Bit | 20.8 µs | 27.7 µs | Go 1.3x |
|
||||
| Decrypt Bit | 4.5 µs | 1.4 µs | CGO 3.2x |
|
||||
| NOT | 1.2 µs | 1.4 µs | ~Same |
|
||||
| AND | 51.3 ms | 56.2 ms | Go 1.10x |
|
||||
| OR | 52.3 ms | 56.4 ms | Go 1.08x |
|
||||
| XOR | 51.2 ms | 56.3 ms | **Go 1.10x** |
|
||||
| NAND | 52.0 ms | 56.4 ms | Go 1.08x |
|
||||
| NOR | 52.2 ms | 56.3 ms | Go 1.08x |
|
||||
| XNOR | 51.0 ms | 57.6 ms | **Go 1.13x** |
|
||||
|
||||
**Key Findings:**
|
||||
- Pure Go bootstrap key gen is **18x faster** than OpenFHE (132ms vs 2.4s)
|
||||
- Pure Go is faster for ALL gates (~51ms vs ~56ms)
|
||||
- **XOR/XNOR optimized** to use single bootstrap (matching OpenFHE algorithm)
|
||||
- Decrypt is faster with OpenFHE (1.4µs vs 4.5µs)
|
||||
|
||||
---
|
||||
|
||||
## Pure Go (Lattice) Backend
|
||||
|
||||
### Key Operations
|
||||
|
||||
| Operation | Time | Memory | Allocs |
|
||||
|-----------|------|--------|--------|
|
||||
| SecretKey Gen | 41.7 µs | 15.6 KB | 21 |
|
||||
| PublicKey Gen | 17.4 µs | 11.9 KB | 22 |
|
||||
| BootstrapKey Gen | 131.9 ms | 82.4 MB | 151K |
|
||||
|
||||
### Boolean Gate Operations
|
||||
|
||||
| Operation | Time | Memory | Allocs |
|
||||
|-----------|------|--------|--------|
|
||||
| Encrypt Bit | 20.8 µs | 16.0 KB | 29 |
|
||||
| Decrypt Bit | 4.5 µs | 4.7 KB | 8 |
|
||||
| NOT | 1.2 µs | 8.9 KB | 11 |
|
||||
| AND | 51.3 ms | 1.2 MB | 38K |
|
||||
| OR | 52.3 ms | 1.2 MB | 38K |
|
||||
| NAND | 52.0 ms | 1.2 MB | 38K |
|
||||
| NOR | 52.2 ms | 1.2 MB | 38K |
|
||||
| XOR | 51.2 ms | 1.2 MB | 38K |
|
||||
| XNOR | 51.0 ms | 1.2 MB | 38K |
|
||||
| MUX | 158.4 ms | 3.6 MB | 114K |
|
||||
|
||||
### Multi-Input Gate Operations
|
||||
|
||||
| Operation | Time | Memory | Allocs | Notes |
|
||||
|-----------|------|--------|--------|-------|
|
||||
| AND3 | 117.2 ms | 2.4 MB | 76K | 2 bootstraps |
|
||||
| OR3 | 118.7 ms | 2.4 MB | 76K | 2 bootstraps |
|
||||
| MAJORITY | 58.6 ms | 1.2 MB | 38K | **1 bootstrap** |
|
||||
|
||||
**MAJORITY optimization:** Uses single bootstrap since threshold at 0 correctly
|
||||
separates 0-1 true inputs (negative sum) from 2-3 true inputs (positive sum).
|
||||
|
||||
### Integer Encryption/Decryption
|
||||
|
||||
| Operation | Time | Memory | Allocs |
|
||||
|-----------|------|--------|--------|
|
||||
| Encrypt 8-bit | 166.8 µs | 128 KB | 234 |
|
||||
| Encrypt 16-bit | 326.6 µs | 256 KB | 466 |
|
||||
| Encrypt 32-bit | 663.5 µs | 512 KB | 930 |
|
||||
| Decrypt 8-bit | 36.5 µs | 37.9 KB | 64 |
|
||||
| Decrypt 16-bit | 74.0 µs | 75.8 KB | 128 |
|
||||
|
||||
### Integer Arithmetic (8-bit)
|
||||
|
||||
| Operation | Time | Memory | Allocs |
|
||||
|-----------|------|--------|--------|
|
||||
| Add | 3.50 s | 81.2 MB | 2.6M |
|
||||
| Sub | 5.20 s | 115.1 MB | 3.6M |
|
||||
| ScalarAdd | 1.61 s | 36.2 MB | 1.1M |
|
||||
|
||||
### Integer Comparisons (8-bit)
|
||||
|
||||
| Operation | Time | Memory | Allocs |
|
||||
|-----------|------|--------|--------|
|
||||
| Eq | 1.74 s | 37.3 MB | 1.2M |
|
||||
| Lt | 2.91 s | 64.0 MB | 2.0M |
|
||||
| Le | 4.52 s | 102.8 MB | 3.2M |
|
||||
| Gt | 2.78 s | 64.1 MB | 2.0M |
|
||||
| Min | 4.00 s | 93.1 MB | 2.9M |
|
||||
| Max | 4.01 s | 93.0 MB | 2.9M |
|
||||
|
||||
### Bitwise Operations (8-bit)
|
||||
|
||||
| Operation | Time | Memory | Allocs |
|
||||
|-----------|------|--------|--------|
|
||||
| AND | 420.5 ms | 9.7 MB | 306K |
|
||||
| OR | 429.2 ms | 9.6 MB | 304K |
|
||||
| XOR | 1.45 s | 29.0 MB | 916K |
|
||||
| NOT | 10.5 µs | 71.0 KB | 90 |
|
||||
| Shl | 9.9 µs | 35.4 KB | 42 |
|
||||
| Shr | 9.6 µs | 35.4 KB | 42 |
|
||||
|
||||
### Other Operations
|
||||
|
||||
| Operation | Time | Memory | Allocs |
|
||||
|-----------|------|--------|--------|
|
||||
| Select (8-bit) | 1.27 s | 29.0 MB | 914K |
|
||||
| CastTo (8→16) | 40.1 µs | 141.4 KB | 162 |
|
||||
| PublicEncrypt 8-bit | 308.2 µs | 134.3 KB | 274 |
|
||||
| PublicEncrypt 16-bit | 597.9 µs | 268.6 KB | 546 |
|
||||
|
||||
### Serialization
|
||||
|
||||
| Operation | Time | Memory | Allocs |
|
||||
|-----------|------|--------|--------|
|
||||
| Serialize Ciphertext | 14.4 µs | 34.9 KB | 98 |
|
||||
| Deserialize Ciphertext | 20.3 µs | 28.6 KB | 255 |
|
||||
| Serialize 8-bit Int | 126.8 µs | 430.8 KB | 800 |
|
||||
| Serialize 16-bit Int | 255.9 µs | 873.8 KB | 1593 |
|
||||
|
||||
### RNG
|
||||
|
||||
| Operation | Time | Memory | Allocs |
|
||||
|-----------|------|--------|--------|
|
||||
| RandomUint 8-bit | 173.0 µs | 128.1 KB | 235 |
|
||||
| RandomUint 16-bit | 340.9 µs | 256.1 KB | 467 |
|
||||
|
||||
---
|
||||
|
||||
## OpenFHE (CGO) Backend
|
||||
|
||||
Benchmarks from OpenFHE 1.2.x with GINX bootstrapping method.
|
||||
|
||||
### Key Operations
|
||||
|
||||
| Operation | Time | Memory | Allocs |
|
||||
|-----------|------|--------|--------|
|
||||
| SecretKey Gen | 14.4 µs | 8 B | 1 |
|
||||
| BootstrapKey Gen | 2413 ms | 0 B | 0 |
|
||||
|
||||
### Boolean Gate Operations
|
||||
|
||||
| Operation | Time | Memory | Allocs |
|
||||
|-----------|------|--------|--------|
|
||||
| Encrypt Bit | 27.7 µs | 8 B | 1 |
|
||||
| Decrypt Bit | 1.4 µs | 0 B | 0 |
|
||||
| NOT | 1.4 µs | 8 B | 1 |
|
||||
| AND | 56.2 ms | 8 B | 1 |
|
||||
| OR | 56.4 ms | 8 B | 1 |
|
||||
| XOR | 56.3 ms | 8 B | 1 |
|
||||
| NAND | 56.4 ms | 8 B | 1 |
|
||||
| NOR | 56.3 ms | 8 B | 1 |
|
||||
| XNOR | 57.6 ms | 8 B | 1 |
|
||||
|
||||
---
|
||||
|
||||
## Running Benchmarks
|
||||
|
||||
### Pure Go Backend
|
||||
```bash
|
||||
cd /path/to/lux/tfhe
|
||||
|
||||
# All benchmarks
|
||||
go test -bench=. -benchmem -run=^$ .
|
||||
|
||||
# Only lattice benchmarks
|
||||
go test -bench=BenchmarkLattice -benchmem -run=^$ .
|
||||
|
||||
# With memory profiling
|
||||
go test -bench=BenchmarkLatticeAdd8 -benchmem -memprofile=mem.prof -run=^$ .
|
||||
```
|
||||
|
||||
### OpenFHE (CGO) Backend
|
||||
```bash
|
||||
cd /path/to/lux/fhe/go/tfhe
|
||||
|
||||
# Set OpenFHE paths
|
||||
export CGO_CXXFLAGS='-I/path/to/openfhe/include -I/path/to/openfhe/include/openfhe -I/path/to/openfhe/include/openfhe/core'
|
||||
export CGO_LDFLAGS='-L/path/to/openfhe/lib -lOPENFHEbinfhe -lOPENFHEcore -lOPENFHEpke -Wl,-rpath,/path/to/openfhe/lib'
|
||||
|
||||
go test -bench=. -benchmem -run=^$ .
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Performance Notes
|
||||
|
||||
1. **Bootstrap Key Generation**: Pure Go is 18x faster (132ms vs 2.4s). OpenFHE may use different parameter sets.
|
||||
2. **All Boolean gates**: Pure Go is ~10% faster (~51ms vs ~56ms)
|
||||
3. **XOR/XNOR optimized**: Now uses OpenFHE's `2*(ct1+ct2)` algorithm with single bootstrap
|
||||
4. **NOT** is essentially free in both implementations (~1.4µs) - no bootstrapping needed
|
||||
5. **Decrypt**: OpenFHE is faster (1.4µs vs 4.5µs)
|
||||
6. **Memory**: OpenFHE uses ~8 bytes per op (pointer only), Go tracks more allocations
|
||||
|
||||
## Recommendations
|
||||
|
||||
| Use Case | Recommended Backend |
|
||||
|----------|---------------------|
|
||||
| Startup-sensitive (key gen) | Pure Go |
|
||||
| All boolean circuits | Pure Go (faster) |
|
||||
| No C++ dependencies needed | Pure Go |
|
||||
| Maximum integer performance | OpenFHE (GPU future) |
|
||||
|
||||
## Hardware
|
||||
|
||||
- **CPU**: Apple M1 Max
|
||||
- **Architecture**: ARM64
|
||||
- **Cores**: 10 (8P + 2E)
|
||||
- **Go Version**: 1.22+
|
||||
- **OpenFHE Version**: 1.2.x
|
||||
|
||||
---
|
||||
|
||||
*Benchmarks run on December 27, 2024*
|
||||
@@ -1,50 +0,0 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Changed
|
||||
- Renamed module from `github.com/luxfi/tfhe` to `github.com/luxfi/fhe`
|
||||
- Updated Go version requirement to 1.23
|
||||
|
||||
### Fixed
|
||||
- AND/NAND gate test polynomials now use correct threshold comparison
|
||||
- Carry refresh in ScalarAdd prevents noise accumulation
|
||||
- WASM SDK build errors resolved
|
||||
- Code formatting with gofmt
|
||||
|
||||
### Added
|
||||
- Comprehensive test coverage for FHE operations
|
||||
- Pure Go mode tests (`CGO_ENABLED=0`)
|
||||
- CGO mode tests with GPU acceleration stubs
|
||||
- Integer arithmetic tests (Add, Sub, Mul)
|
||||
- BigInt type tests (uint128, uint160, uint256)
|
||||
- Serialization tests for keys
|
||||
- RNG tests for encrypted random number generation
|
||||
- Adversarial and fuzz tests
|
||||
|
||||
## [0.1.0] - 2025-01-01
|
||||
|
||||
### Added
|
||||
- Initial FHE implementation based on TFHE scheme
|
||||
- Boolean FHE operations (AND, OR, XOR, NOT, NAND, NOR, XNOR, MUX)
|
||||
- Integer FHE types (FheUint4 through FheUint256)
|
||||
- Bitwise integer operations with ripple-carry arithmetic
|
||||
- ShortInt operations with LUT-based evaluation
|
||||
- Key generation (SecretKey, PublicKey, BootstrapKey)
|
||||
- Serialization support for all key types
|
||||
- Multi-SDK support:
|
||||
- C shared library
|
||||
- Python bindings (via CFFI)
|
||||
- Rust bindings (via bindgen)
|
||||
- TypeScript/WASM support
|
||||
- GPU acceleration framework (CUDA via MLX)
|
||||
- Server mode for FHE-as-a-service
|
||||
- Comprehensive benchmarks and documentation
|
||||
|
||||
[Unreleased]: https://github.com/luxfi/fhe/compare/v0.1.0...HEAD
|
||||
[0.1.0]: https://github.com/luxfi/fhe/releases/tag/v0.1.0
|
||||
-80
@@ -1,80 +0,0 @@
|
||||
# Lux FHE - Multi-target Dockerfile
|
||||
# Builds: server (pure-go), gateway, worker
|
||||
|
||||
FROM golang:1.23-alpine AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Install build dependencies
|
||||
RUN apk add --no-cache git ca-certificates
|
||||
|
||||
# Enable toolchain auto-download for newer Go versions
|
||||
ENV GOTOOLCHAIN=auto
|
||||
|
||||
# Copy go mod files
|
||||
COPY go.mod go.sum ./
|
||||
RUN go mod download
|
||||
|
||||
# Copy source
|
||||
COPY . .
|
||||
|
||||
# Build binaries (pure Go, no CGO)
|
||||
RUN CGO_ENABLED=0 GOOS=linux go build -o /bin/fhe-gateway ./cmd/fhe-gateway/
|
||||
RUN CGO_ENABLED=0 GOOS=linux go build -o /bin/fhe-worker ./cmd/fhe-worker/
|
||||
|
||||
# Build pure-go server (creates standalone server without C acceleration)
|
||||
RUN CGO_ENABLED=0 GOOS=linux go build -tags purgo -o /bin/fhe-server ./server/standalone/
|
||||
|
||||
# =============================================================================
|
||||
# Server image (pure Go implementation)
|
||||
# =============================================================================
|
||||
FROM alpine:3.19 AS server
|
||||
|
||||
RUN apk add --no-cache ca-certificates curl
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY --from=builder /bin/fhe-server .
|
||||
|
||||
RUN mkdir -p /app/data
|
||||
|
||||
EXPOSE 8448
|
||||
|
||||
ENTRYPOINT ["./fhe-server"]
|
||||
CMD ["-addr", ":8448"]
|
||||
|
||||
# =============================================================================
|
||||
# Gateway image
|
||||
# =============================================================================
|
||||
FROM alpine:3.19 AS gateway
|
||||
|
||||
RUN apk add --no-cache ca-certificates curl
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY --from=builder /bin/fhe-gateway .
|
||||
|
||||
RUN mkdir -p /app/data
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
ENTRYPOINT ["./fhe-gateway"]
|
||||
CMD ["-http", ":8080"]
|
||||
|
||||
# =============================================================================
|
||||
# Worker image
|
||||
# =============================================================================
|
||||
FROM alpine:3.19 AS worker
|
||||
|
||||
RUN apk add --no-cache ca-certificates curl
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY --from=builder /bin/fhe-worker .
|
||||
|
||||
RUN mkdir -p /app/data
|
||||
|
||||
EXPOSE 9090
|
||||
|
||||
ENTRYPOINT ["./fhe-worker"]
|
||||
CMD ["-workers", "4"]
|
||||
@@ -0,0 +1,191 @@
|
||||
# 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,152 +0,0 @@
|
||||
# TFHE Makefile
|
||||
# Production-ready build system for multi-platform SDK
|
||||
|
||||
.PHONY: all build test bench clean profile c python wasm install help
|
||||
|
||||
# Default target
|
||||
all: build test
|
||||
|
||||
# Build all packages
|
||||
build:
|
||||
go build ./...
|
||||
|
||||
# Run all tests
|
||||
test:
|
||||
go test -v ./...
|
||||
|
||||
# Run benchmarks
|
||||
bench:
|
||||
go test -bench=. -benchmem ./...
|
||||
|
||||
# Run benchmarks with count for statistical significance
|
||||
bench-count:
|
||||
go test -bench=. -benchmem -count=5 ./... | tee bench.txt
|
||||
|
||||
# Clean build artifacts
|
||||
clean:
|
||||
rm -rf c/build python/dist python/build python/*.egg-info
|
||||
rm -f cpu.prof mem.prof block.prof mutex.prof trace.out
|
||||
rm -f profile
|
||||
|
||||
# Profile targets
|
||||
profile: profile-build
|
||||
./profile -cpu=cpu.prof -mem=mem.prof -iterations=100 -op=all
|
||||
|
||||
profile-build:
|
||||
go build -tags profile -o profile ./cmd/profile
|
||||
|
||||
profile-cpu: profile-build
|
||||
./profile -cpu=cpu.prof -iterations=1000 -op=gates
|
||||
go tool pprof -http=:8080 cpu.prof
|
||||
|
||||
profile-mem: profile-build
|
||||
./profile -mem=mem.prof -iterations=100 -op=keygen
|
||||
go tool pprof -http=:8080 mem.prof
|
||||
|
||||
# C/C++ bindings
|
||||
c:
|
||||
cd c && mkdir -p build && cd build && cmake .. && make
|
||||
|
||||
c-test: c
|
||||
cd c/build && ctest --output-on-failure
|
||||
|
||||
c-install: c
|
||||
cd c/build && make install
|
||||
|
||||
c-clean:
|
||||
rm -rf c/build
|
||||
|
||||
# Python bindings
|
||||
python: c
|
||||
cd python && pip install -e .
|
||||
|
||||
python-test: python
|
||||
cd python && python -m pytest tests/
|
||||
|
||||
python-build: c
|
||||
cd python && pip wheel . -w dist/
|
||||
|
||||
python-clean:
|
||||
rm -rf python/dist python/build python/*.egg-info
|
||||
|
||||
# WASM bindings
|
||||
wasm:
|
||||
cd ../tfhe-wasm && make wasm
|
||||
|
||||
wasm-release:
|
||||
cd ../tfhe-wasm && make wasm-release
|
||||
|
||||
wasm-small:
|
||||
cd ../tfhe-wasm && make wasm-small
|
||||
|
||||
wasm-size:
|
||||
cd ../tfhe-wasm && make size
|
||||
|
||||
# Install development dependencies
|
||||
deps:
|
||||
go mod download
|
||||
go mod tidy
|
||||
|
||||
# Format code
|
||||
fmt:
|
||||
go fmt ./...
|
||||
gofmt -s -w .
|
||||
|
||||
# Lint code
|
||||
lint:
|
||||
golangci-lint run
|
||||
|
||||
# Generate code coverage report
|
||||
coverage:
|
||||
go test -coverprofile=coverage.out ./...
|
||||
go tool cover -html=coverage.out -o coverage.html
|
||||
@echo "Coverage report: coverage.html"
|
||||
|
||||
# Run security analysis
|
||||
security:
|
||||
gosec ./...
|
||||
|
||||
# Static analysis
|
||||
vet:
|
||||
go vet ./...
|
||||
|
||||
# All quality checks
|
||||
check: fmt vet lint security test
|
||||
|
||||
# Help
|
||||
help:
|
||||
@echo "TFHE SDK Makefile"
|
||||
@echo ""
|
||||
@echo "Build targets:"
|
||||
@echo " all - Build and test (default)"
|
||||
@echo " build - Build all packages"
|
||||
@echo " test - Run all tests"
|
||||
@echo " bench - Run benchmarks"
|
||||
@echo " clean - Remove build artifacts"
|
||||
@echo ""
|
||||
@echo "Profile targets:"
|
||||
@echo " profile - Run full profiling suite"
|
||||
@echo " profile-cpu - CPU profiling with web UI"
|
||||
@echo " profile-mem - Memory profiling with web UI"
|
||||
@echo ""
|
||||
@echo "C/C++ bindings:"
|
||||
@echo " c - Build C bindings"
|
||||
@echo " c-test - Run C tests"
|
||||
@echo " c-install - Install C library"
|
||||
@echo ""
|
||||
@echo "Python bindings:"
|
||||
@echo " python - Install Python bindings (dev)"
|
||||
@echo " python-test - Run Python tests"
|
||||
@echo " python-build - Build Python wheel"
|
||||
@echo ""
|
||||
@echo "WASM bindings:"
|
||||
@echo " wasm - Build WASM module"
|
||||
@echo " wasm-release - Build optimized WASM"
|
||||
@echo " wasm-small - Build size-optimized WASM"
|
||||
@echo ""
|
||||
@echo "Quality checks:"
|
||||
@echo " fmt - Format code"
|
||||
@echo " lint - Run linter"
|
||||
@echo " vet - Run go vet"
|
||||
@echo " coverage - Generate coverage report"
|
||||
@echo " check - Run all quality checks"
|
||||
-233
@@ -1,233 +0,0 @@
|
||||
# FHE Optimization Guide
|
||||
|
||||
## Performance Optimization Strategies
|
||||
|
||||
This document describes the optimizations implemented in the Lux FHE library and provides guidance for achieving maximum performance.
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
```
|
||||
+-----------------------+
|
||||
| High-Level API |
|
||||
| (Boolean/Integer) |
|
||||
+-----------+-----------+
|
||||
|
|
||||
+-----------v-----------+
|
||||
| Evaluator |
|
||||
| (Gate Evaluation) |
|
||||
+-----------+-----------+
|
||||
|
|
||||
+-------------------+-------------------+
|
||||
| |
|
||||
+-----------v-----------+ +-------------v-------------+
|
||||
| CPU Backend | | GPU Backend (MLX) |
|
||||
| (lattice/v6) | | (Metal/CUDA/CPU) |
|
||||
+-----------+-----------+ +-------------+-------------+
|
||||
| |
|
||||
+-----------v-----------+ +-------------v-------------+
|
||||
| NTT Engine | | Batch Bootstrapping |
|
||||
| (SIMD-optimized) | | (Parallel PBS) |
|
||||
+-----------------------+ +---------------------------+
|
||||
```
|
||||
|
||||
## Key Optimizations
|
||||
|
||||
### 1. NTT Optimization
|
||||
|
||||
The Number Theoretic Transform is the core operation in FHE, used extensively in polynomial multiplication during bootstrapping.
|
||||
|
||||
**Cooley-Tukey NTT Algorithm**:
|
||||
- O(N log N) complexity
|
||||
- In-place computation with bit-reversal permutation
|
||||
- Butterfly operations are SIMD-vectorizable
|
||||
|
||||
**Barrett Reduction**:
|
||||
- Avoids expensive division in modular arithmetic
|
||||
- Precomputes mu = floor(2^64 / Q)
|
||||
- Reduces multiplication cost by 2-3x
|
||||
|
||||
```go
|
||||
// Barrett reduction for a * b mod Q
|
||||
func (e *NTTEngine) mulModBarrett(a, b uint64) uint64 {
|
||||
hi, lo := mul64(a, b)
|
||||
q := ((hi * e.barrettMu) >> 64) + ((lo * e.barrettMu) >> 32)
|
||||
r := lo - q*e.Q
|
||||
// At most 2 subtractions needed for correction
|
||||
if r >= e.Q { r -= e.Q }
|
||||
if r >= e.Q { r -= e.Q }
|
||||
return r
|
||||
}
|
||||
```
|
||||
|
||||
**Batch NTT**:
|
||||
- Process multiple polynomials in parallel
|
||||
- Optimal for GPU where batch size determines efficiency
|
||||
- CPU version uses goroutine parallelism
|
||||
|
||||
### 2. GPU Bootstrapping Pipeline
|
||||
|
||||
The GPU engine implements a complete bootstrapping pipeline:
|
||||
|
||||
```
|
||||
Input LWE → Batch NTT → External Products → Blind Rotation → INTT → Key Switch → Output LWE
|
||||
```
|
||||
|
||||
**Key optimizations**:
|
||||
|
||||
1. **Structure of Arrays (SoA)**: All data stored for coalesced memory access
|
||||
```
|
||||
// Bad: Array of Structures
|
||||
type LWE struct { a []uint64; b uint64 }
|
||||
ciphertexts []LWE // Poor memory locality
|
||||
|
||||
// Good: Structure of Arrays
|
||||
type LWEPool struct {
|
||||
A *gpulib.Array // [batch, n] - contiguous
|
||||
B *gpulib.Array // [batch] - contiguous
|
||||
}
|
||||
```
|
||||
|
||||
2. **Fused Kernels**: Combine multiple operations to reduce memory traffic
|
||||
- External product: decompose → multiply → accumulate in one pass
|
||||
- Blind rotation: all n external products batched
|
||||
|
||||
3. **Precomputed Data**: Twiddle factors and test polynomials computed once at initialization
|
||||
|
||||
### 3. Gate-Level Optimizations
|
||||
|
||||
**XOR/XNOR Optimization** (matching OpenFHE):
|
||||
```
|
||||
// Standard: 2 bootstraps for XOR
|
||||
result = Bootstrap(a + b, TestPolyPositive) XOR Bootstrap(a + b, TestPolyNegative)
|
||||
|
||||
// Optimized: 1 bootstrap with doubling trick
|
||||
doubled = 2 * (a + b) // Causes (1,1) case to wrap to negative
|
||||
result = Bootstrap(doubled, TestPolyXOR)
|
||||
```
|
||||
|
||||
**MAJORITY Gate** (single bootstrap):
|
||||
```
|
||||
// 3-input MAJORITY with 1 bootstrap
|
||||
sum = a + b + c
|
||||
// Threshold at 0 separates:
|
||||
// 0-1 true inputs (sum < 0) → FALSE
|
||||
// 2-3 true inputs (sum > 0) → TRUE
|
||||
result = Bootstrap(sum, TestPolyMAJORITY)
|
||||
```
|
||||
|
||||
**NOT Gate** (free operation):
|
||||
```
|
||||
// NOT requires no bootstrap - just negate coefficients
|
||||
NOT(ct) = -ct // O(N) polynomial negation
|
||||
```
|
||||
|
||||
### 4. Parameter Selection
|
||||
|
||||
| Parameter | PN10QP27 | PN11QP54 | Effect |
|
||||
|-----------|----------|----------|--------|
|
||||
| N (ring dimension) | 1024 | 2048 | Higher = more security, slower |
|
||||
| Q (modulus) | 2^27 | 2^54 | Higher = more precision |
|
||||
| n (LWE dimension) | 512 | 640 | Higher = more security |
|
||||
| L (decomposition) | 4 | 5 | Higher = less noise, more compute |
|
||||
| BaseLog | 7 | 10 | Higher = larger gadget, less noise |
|
||||
|
||||
**Choosing Parameters**:
|
||||
- Use **PN10QP27** for most applications (128-bit security, balanced)
|
||||
- Use **PN11QP54** when you need higher precision or longer circuits
|
||||
|
||||
**L (Decomposition Level) Tradeoff**:
|
||||
```
|
||||
L = 7 (original): Lower noise, but more computation
|
||||
L = 4 (optimized): ~1.75x faster, still secure
|
||||
|
||||
External product cost = O(L × N × log N)
|
||||
Reducing L from 7 to 4 gives ~1.75x speedup
|
||||
```
|
||||
|
||||
### 5. Memory Optimization
|
||||
|
||||
**Bootstrap Key Size**:
|
||||
```
|
||||
BSK size = n × 2 × L × 2 × N × 8 bytes
|
||||
= 512 × 2 × 4 × 2 × 1024 × 8
|
||||
= 134 MB per user (with L=4)
|
||||
```
|
||||
|
||||
**GPU Memory Budget** (per 8x H200 config):
|
||||
- Total: 1.1 TB (141 GB × 8)
|
||||
- Per GPU: 141 GB
|
||||
- Users per GPU: ~1000 (with 134 MB BSK each)
|
||||
- Total users: ~8000
|
||||
|
||||
### 6. Parallelization Strategies
|
||||
|
||||
**CPU**:
|
||||
- Batch NTT uses goroutines (16 workers max)
|
||||
- Gate evaluations can run in parallel with separate evaluators
|
||||
- No lock contention on read-only bootstrap keys
|
||||
|
||||
**GPU**:
|
||||
- Batch size determines efficiency (optimal: 4096+ for H200)
|
||||
- Operations grouped by gate type for same test polynomial
|
||||
- Multi-GPU with NVLink for user distribution
|
||||
|
||||
## Benchmarking
|
||||
|
||||
Run the full benchmark suite:
|
||||
|
||||
```bash
|
||||
# All benchmarks
|
||||
go test -bench=. -benchtime=5s ./...
|
||||
|
||||
# Specific benchmarks
|
||||
go test -bench=BenchmarkBootstrap -benchtime=10s
|
||||
go test -bench=BenchmarkNTT -benchtime=5s
|
||||
go test -bench=BenchmarkBatch -benchtime=5s
|
||||
|
||||
# Memory allocation analysis
|
||||
go test -bench=BenchmarkMemory -benchmem
|
||||
|
||||
# Generate performance report
|
||||
go test -run=TestPerformanceReport -v
|
||||
```
|
||||
|
||||
## Expected Performance (Apple M1 Max)
|
||||
|
||||
| Operation | Time | Notes |
|
||||
|-----------|------|-------|
|
||||
| Bootstrap Key Gen | 132 ms | 18x faster than OpenFHE |
|
||||
| AND/OR/NAND/NOR | ~51 ms | Single bootstrap |
|
||||
| XOR/XNOR | ~51 ms | Optimized single bootstrap |
|
||||
| MAJORITY | ~59 ms | Single bootstrap |
|
||||
| AND3/OR3 | ~117 ms | 2 bootstraps |
|
||||
| MUX | ~170 ms | 3 bootstraps |
|
||||
| NOT | 1.2 µs | Free (no bootstrap) |
|
||||
| NTT (N=1024) | ~30 µs | Per transform |
|
||||
| Batch NTT (32×) | ~14 µs/poly | Amortized |
|
||||
|
||||
## GPU Performance Targets
|
||||
|
||||
| Platform | Throughput | Latency |
|
||||
|----------|------------|---------|
|
||||
| M1 Max (Metal) | ~60K gates/sec | ~17 µs |
|
||||
| H100 (CUDA) | ~180K gates/sec | ~5.5 µs |
|
||||
| H200 (CUDA) | ~250K gates/sec | ~4 µs |
|
||||
| 8× H200 (NVLink) | ~1.5M gates/sec | ~0.7 µs |
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Batch Operations**: Always batch multiple gate operations together
|
||||
2. **Reuse Keys**: Generate bootstrap key once, use for many operations
|
||||
3. **Choose Right Parameters**: PN10QP27 for most use cases
|
||||
4. **Use NOT Freely**: NOT is essentially free (no bootstrap)
|
||||
5. **Minimize Circuit Depth**: Fewer sequential bootstraps = faster
|
||||
6. **Prefer MAJORITY**: Single bootstrap for 3-input majority vote
|
||||
7. **GPU for Batch**: GPU acceleration shines with 1000+ operations
|
||||
|
||||
## Future Optimizations
|
||||
|
||||
1. **AVX-512 NTT**: Assembly-optimized NTT for x86-64
|
||||
2. **NEON NTT**: Assembly-optimized NTT for ARM64
|
||||
3. **Metal Shaders**: Custom Metal kernels for NTT butterfly
|
||||
4. **CUDA Kernels**: Custom CUDA kernels for H100/H200
|
||||
5. **Circuit Compiler**: Automatic circuit optimization and batching
|
||||
@@ -1,221 +0,0 @@
|
||||
# Lux FHE
|
||||
|
||||
**Fully Homomorphic Encryption for the Lux Network** — Pure Go with optional C++/CUDA acceleration.
|
||||
|
||||
[](https://pkg.go.dev/github.com/luxfi/fhe)
|
||||
[](https://github.com/luxfi/fhe/actions/workflows/ci.yml)
|
||||
[](LICENSE)
|
||||
|
||||
## Overview
|
||||
|
||||
Lux FHE is a production-ready implementation of Fully Homomorphic Encryption (FHE) that enables computation on encrypted data without decryption. Ideal for privacy-preserving blockchain applications, confidential smart contracts, and secure multi-party computation.
|
||||
|
||||
## Implementations
|
||||
|
||||
| Mode | Build Flag | Description |
|
||||
|------|------------|-------------|
|
||||
| **Pure Go** | `CGO_ENABLED=0` | Zero dependencies, compiles anywhere Go runs |
|
||||
| **C++ Optimized** | `CGO_ENABLED=1` | High-performance [C++ backend](https://github.com/luxcpp/fhe) |
|
||||
| **GPU Accelerated** | `CGO_ENABLED=1` + GPU | Metal (macOS), CUDA (Linux/Windows) |
|
||||
|
||||
> **Enterprise:** Multi-GPU, cloud deployments, and advanced optimizations available through enterprise licensing.
|
||||
|
||||
### Pure Go Mode
|
||||
- **Zero external dependencies** — compiles anywhere Go runs
|
||||
- **Cross-platform** — Linux, macOS, Windows, ARM64
|
||||
- **Deterministic builds** — critical for blockchain consensus
|
||||
- **Easy deployment** — single static binary
|
||||
|
||||
### C++/GPU Mode
|
||||
For maximum performance, build with CGO enabled to use our optimized [C++ implementation](https://github.com/luxcpp/fhe):
|
||||
|
||||
```bash
|
||||
# macOS (Metal GPU automatic)
|
||||
CGO_ENABLED=1 go build ./...
|
||||
|
||||
# Linux/Windows with CUDA
|
||||
CGO_ENABLED=1 go build -tags cuda ./...
|
||||
|
||||
# Linux/Windows CPU-only
|
||||
CGO_ENABLED=1 go build ./...
|
||||
```
|
||||
|
||||
See [luxcpp/fhe](https://github.com/luxcpp/fhe) for C++/CUDA/MLX implementation details.
|
||||
|
||||
## Blockchain Optimized
|
||||
|
||||
- **Public key encryption** — users encrypt without secret key access
|
||||
- **Deterministic RNG** — blockchain-compatible random numbers
|
||||
- **Full serialization** — keys and ciphertexts
|
||||
- **FheUint160** — native Ethereum address support
|
||||
- **FheUint256** — native EVM word size support
|
||||
|
||||
## Performance (Apple M1 Max)
|
||||
|
||||
| Operation | Pure Go | C++ (CGO) | GPU |
|
||||
|-----------|---------|-----------|-----|
|
||||
| Bootstrap Key Gen | 132 ms | 68 ms | 12 ms |
|
||||
| Boolean Gate (AND) | 51 ms | 28 ms | 3 ms |
|
||||
| 8-bit Addition | 5.0 s | 2.1 s | 180 ms |
|
||||
|
||||
See [BENCHMARKS.md](BENCHMARKS.md) for complete performance data.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
go get github.com/luxfi/fhe
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
fhe "github.com/luxfi/fhe"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Setup
|
||||
params, _ := fhe.NewParametersFromLiteral(fhe.PN10QP27)
|
||||
kg := fhe.NewKeyGenerator(params)
|
||||
sk, pk := kg.GenKeyPair()
|
||||
bsk := kg.GenBootstrapKey(sk)
|
||||
|
||||
// Encrypt with public key (user side - no secret key needed!)
|
||||
pubEnc := fhe.NewBitwisePublicEncryptor(params, pk)
|
||||
ctA, _ := pubEnc.EncryptUint64(5, fhe.FheUint8)
|
||||
ctB, _ := pubEnc.EncryptUint64(3, fhe.FheUint8)
|
||||
|
||||
// Compute on encrypted data (server/blockchain side)
|
||||
eval := fhe.NewBitwiseEvaluator(params, bsk, sk)
|
||||
ctSum, _ := eval.Add(ctA, ctB)
|
||||
|
||||
// Decrypt result
|
||||
dec := fhe.NewBitwiseDecryptor(params, sk)
|
||||
result := dec.DecryptUint64(ctSum)
|
||||
fmt.Println("5 + 3 =", result) // Output: 5 + 3 = 8
|
||||
}
|
||||
```
|
||||
|
||||
## Supported Types
|
||||
|
||||
| Type | Bits | Use Case |
|
||||
|------|------|----------|
|
||||
| FheBool | 1 | Boolean flags, comparisons |
|
||||
| FheUint4 | 4 | Small counters, nibbles |
|
||||
| FheUint8 | 8 | Bytes, small values |
|
||||
| FheUint16 | 16 | Short integers |
|
||||
| FheUint32 | 32 | Standard integers |
|
||||
| FheUint64 | 64 | Large integers |
|
||||
| FheUint128 | 128 | UUIDs, large values |
|
||||
| FheUint160 | 160 | **Ethereum addresses** |
|
||||
| FheUint256 | 256 | **EVM word size** |
|
||||
|
||||
## Operations
|
||||
|
||||
**Arithmetic**: `Add`, `Sub`, `ScalarAdd`, `Neg`
|
||||
|
||||
**Comparison**: `Eq`, `Lt`, `Le`, `Gt`, `Ge`, `Min`, `Max`
|
||||
|
||||
**Bitwise**: `And`, `Or`, `Xor`, `Not`, `Shl`, `Shr`
|
||||
|
||||
**Selection**: `Select` (encrypted if-then-else), `CastTo`
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
github.com/luxfi/fhe/
|
||||
├── fhe.go # Parameters, key types, key generation
|
||||
├── encryptor.go # Boolean encryption (secret key)
|
||||
├── decryptor.go # Boolean decryption
|
||||
├── evaluator.go # Boolean gates (AND, OR, XOR, NOT, MUX)
|
||||
├── bitwise_integers.go # Integer operations + public key encryption
|
||||
├── integers.go # FheUintType definitions
|
||||
├── integer_ops.go # Comparison, bitwise operations
|
||||
├── serialization.go # Key/ciphertext serialization
|
||||
├── random.go # FHE random number generation
|
||||
├── server/ # HTTP server for benchmarking
|
||||
└── gpu/ # GPU acceleration stubs
|
||||
```
|
||||
|
||||
## Dependencies
|
||||
|
||||
- [`github.com/luxfi/lattice/v6`](https://github.com/luxfi/lattice) — Lattice cryptography primitives
|
||||
|
||||
## Running Tests
|
||||
|
||||
```bash
|
||||
# Pure Go tests (all core packages)
|
||||
CGO_ENABLED=0 go test -v ./...
|
||||
|
||||
# With C++ backend + GPU (requires luxcpp/fhe)
|
||||
CGO_ENABLED=1 go test -v ./...
|
||||
|
||||
# Benchmarks
|
||||
go test -bench=. -benchmem -run=^$
|
||||
```
|
||||
|
||||
## Package Structure
|
||||
|
||||
| Package | CGO Required | Description |
|
||||
|---------|--------------|-------------|
|
||||
| `github.com/luxfi/fhe` | No | Core FHE library (pure Go) |
|
||||
| `github.com/luxfi/fhe/cgo` | Yes | C++ bridge to OpenFHE |
|
||||
| `github.com/luxfi/fhe/gpu` | Yes | GPU acceleration (MLX) |
|
||||
| `github.com/luxfi/fhe/server` | Yes | HTTP server with GPU support |
|
||||
| `github.com/luxfi/fhe/cmd/fhe-server` | Yes | Standalone FHE server |
|
||||
| `github.com/luxfi/fhe/cmd/fhe-gateway` | No | Pure Go gateway |
|
||||
| `github.com/luxfi/fhe/cmd/fhe-worker` | No | Pure Go worker |
|
||||
|
||||
## HTTP Benchmark Server
|
||||
|
||||
GPU-accelerated server (requires CGO):
|
||||
|
||||
```bash
|
||||
# Build and run server
|
||||
CGO_ENABLED=1 go run ./cmd/fhe-server -addr :8448 -gpu
|
||||
|
||||
# C++ server (see luxcpp/fhe)
|
||||
./fhe-server --port 8081
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
**BSD-3-Clause**
|
||||
|
||||
Lux FHE is open source software. Patent rights for novel optimizations are reserved by Lux Partners Limited.
|
||||
|
||||
- **Lux Network**: Free to use on Lux mainnet and testnets
|
||||
- **Research/Academic**: Free for non-commercial use
|
||||
- **Commercial**: Contact licensing@lux.partners
|
||||
|
||||
See [LICENSE](LICENSE) for full terms.
|
||||
|
||||
## Implementation
|
||||
|
||||
Original implementation based on published academic research:
|
||||
|
||||
- Built on [`github.com/luxfi/lattice`](https://github.com/luxfi/lattice) (our cryptographic primitives)
|
||||
- Implements peer-reviewed algorithms from academic publications
|
||||
- Contains novel optimizations developed independently
|
||||
|
||||
**Academic References:**
|
||||
- Chillotti et al. "FHE: Fast Fully Homomorphic Encryption Over the Torus" (Journal of Cryptology, 2020)
|
||||
- Ducas & Micciancio "FHEW: Bootstrapping Homomorphic Encryption in Less Than a Second" (EUROCRYPT 2015)
|
||||
|
||||
## Related Projects
|
||||
|
||||
- [luxcpp/fhe](https://github.com/luxcpp/fhe) — C++/CUDA/MLX implementation
|
||||
- [luxfi/lattice](https://github.com/luxfi/lattice) — Lattice cryptography library
|
||||
- [luxfi/standard](https://github.com/luxfi/standard) — fhEVM smart contracts
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions welcome! Please ensure tests pass before submitting PRs:
|
||||
|
||||
```bash
|
||||
CGO_ENABLED=0 go test -v ./...
|
||||
go vet ./...
|
||||
```
|
||||
-1508
File diff suppressed because it is too large
Load Diff
@@ -1,531 +0,0 @@
|
||||
// Copyright (c) 2024 The Lux Authors
|
||||
// Use of this source code is governed by a BSD 3-Clause
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package fhe
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Comprehensive benchmarks for pure Go (lattice) backend
|
||||
// These mirror the CGO benchmarks for comparison
|
||||
|
||||
var (
|
||||
benchParams Parameters
|
||||
benchKGen *KeyGenerator
|
||||
benchSK *SecretKey
|
||||
benchPK *PublicKey
|
||||
benchBSK *BootstrapKey
|
||||
benchEnc *Encryptor
|
||||
benchDec *Decryptor
|
||||
benchEval *Evaluator
|
||||
benchBitEnc *BitwiseEncryptor
|
||||
benchBitDec *BitwiseDecryptor
|
||||
benchBitEval *BitwiseEvaluator
|
||||
)
|
||||
|
||||
func setupBenchmark(b *testing.B) {
|
||||
if benchKGen != nil {
|
||||
return
|
||||
}
|
||||
var err error
|
||||
benchParams, err = NewParametersFromLiteral(PN10QP27)
|
||||
if err != nil {
|
||||
b.Fatalf("failed to create params: %v", err)
|
||||
}
|
||||
benchKGen = NewKeyGenerator(benchParams)
|
||||
benchSK = benchKGen.GenSecretKey()
|
||||
benchPK = benchKGen.GenPublicKey(benchSK)
|
||||
benchBSK = benchKGen.GenBootstrapKey(benchSK)
|
||||
benchEnc = NewEncryptor(benchParams, benchSK)
|
||||
benchDec = NewDecryptor(benchParams, benchSK)
|
||||
benchEval = NewEvaluator(benchParams, benchBSK)
|
||||
benchBitEnc = NewBitwiseEncryptor(benchParams, benchSK)
|
||||
benchBitDec = NewBitwiseDecryptor(benchParams, benchSK)
|
||||
benchBitEval = NewBitwiseEvaluator(benchParams, benchBSK, benchSK)
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Key Generation Benchmarks
|
||||
// ============================================================================
|
||||
|
||||
func BenchmarkLatticeKeyGen(b *testing.B) {
|
||||
params, _ := NewParametersFromLiteral(PN10QP27)
|
||||
kgen := NewKeyGenerator(params)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = kgen.GenSecretKey()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLatticePublicKeyGen(b *testing.B) {
|
||||
setupBenchmark(b)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = benchKGen.GenPublicKey(benchSK)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLatticeBootstrapKeyGen(b *testing.B) {
|
||||
params, _ := NewParametersFromLiteral(PN10QP27)
|
||||
kgen := NewKeyGenerator(params)
|
||||
sk := kgen.GenSecretKey()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = kgen.GenBootstrapKey(sk)
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Boolean Encryption/Decryption Benchmarks
|
||||
// ============================================================================
|
||||
|
||||
func BenchmarkLatticeEncryptBit(b *testing.B) {
|
||||
setupBenchmark(b)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = benchEnc.Encrypt(true)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLatticeDecryptBit(b *testing.B) {
|
||||
setupBenchmark(b)
|
||||
ct := benchEnc.Encrypt(true)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = benchDec.Decrypt(ct)
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Boolean Gate Benchmarks
|
||||
// ============================================================================
|
||||
|
||||
func BenchmarkLatticeAND(b *testing.B) {
|
||||
setupBenchmark(b)
|
||||
ct1 := benchEnc.Encrypt(true)
|
||||
ct2 := benchEnc.Encrypt(false)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = benchEval.AND(ct1, ct2)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLatticeOR(b *testing.B) {
|
||||
setupBenchmark(b)
|
||||
ct1 := benchEnc.Encrypt(true)
|
||||
ct2 := benchEnc.Encrypt(false)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = benchEval.OR(ct1, ct2)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLatticeXOR(b *testing.B) {
|
||||
setupBenchmark(b)
|
||||
ct1 := benchEnc.Encrypt(true)
|
||||
ct2 := benchEnc.Encrypt(false)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = benchEval.XOR(ct1, ct2)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLatticeNOT(b *testing.B) {
|
||||
setupBenchmark(b)
|
||||
ct := benchEnc.Encrypt(true)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = benchEval.NOT(ct)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLatticeNAND(b *testing.B) {
|
||||
setupBenchmark(b)
|
||||
ct1 := benchEnc.Encrypt(true)
|
||||
ct2 := benchEnc.Encrypt(true)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = benchEval.NAND(ct1, ct2)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLatticeNOR(b *testing.B) {
|
||||
setupBenchmark(b)
|
||||
ct1 := benchEnc.Encrypt(true)
|
||||
ct2 := benchEnc.Encrypt(true)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = benchEval.NOR(ct1, ct2)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLatticeXNOR(b *testing.B) {
|
||||
setupBenchmark(b)
|
||||
ct1 := benchEnc.Encrypt(true)
|
||||
ct2 := benchEnc.Encrypt(false)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = benchEval.XNOR(ct1, ct2)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLatticeMUX(b *testing.B) {
|
||||
setupBenchmark(b)
|
||||
sel := benchEnc.Encrypt(true)
|
||||
ct1 := benchEnc.Encrypt(true)
|
||||
ct2 := benchEnc.Encrypt(false)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = benchEval.MUX(sel, ct1, ct2)
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Integer Encryption/Decryption Benchmarks
|
||||
// ============================================================================
|
||||
|
||||
func BenchmarkLatticeEncryptInt8(b *testing.B) {
|
||||
setupBenchmark(b)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = benchBitEnc.EncryptUint64(42, FheUint8)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLatticeEncryptInt16(b *testing.B) {
|
||||
setupBenchmark(b)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = benchBitEnc.EncryptUint64(12345, FheUint16)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLatticeEncryptInt32(b *testing.B) {
|
||||
setupBenchmark(b)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = benchBitEnc.EncryptUint64(123456789, FheUint32)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLatticeDecryptInt8(b *testing.B) {
|
||||
setupBenchmark(b)
|
||||
ct := benchBitEnc.EncryptUint64(42, FheUint8)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = benchBitDec.DecryptUint64(ct)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLatticeDecryptInt16(b *testing.B) {
|
||||
setupBenchmark(b)
|
||||
ct := benchBitEnc.EncryptUint64(12345, FheUint16)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = benchBitDec.DecryptUint64(ct)
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Integer Arithmetic Benchmarks
|
||||
// ============================================================================
|
||||
|
||||
func BenchmarkLatticeAdd8(b *testing.B) {
|
||||
setupBenchmark(b)
|
||||
a := benchBitEnc.EncryptUint64(10, FheUint8)
|
||||
c := benchBitEnc.EncryptUint64(20, FheUint8)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = benchBitEval.Add(a, c)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLatticeAdd16(b *testing.B) {
|
||||
setupBenchmark(b)
|
||||
a := benchBitEnc.EncryptUint64(1000, FheUint16)
|
||||
c := benchBitEnc.EncryptUint64(2000, FheUint16)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = benchBitEval.Add(a, c)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLatticeSub8(b *testing.B) {
|
||||
setupBenchmark(b)
|
||||
a := benchBitEnc.EncryptUint64(50, FheUint8)
|
||||
c := benchBitEnc.EncryptUint64(20, FheUint8)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = benchBitEval.Sub(a, c)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLatticeScalarAdd8(b *testing.B) {
|
||||
setupBenchmark(b)
|
||||
a := benchBitEnc.EncryptUint64(42, FheUint8)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = benchBitEval.ScalarAdd(a, 10)
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Comparison Benchmarks
|
||||
// ============================================================================
|
||||
|
||||
func BenchmarkLatticeEq8(b *testing.B) {
|
||||
setupBenchmark(b)
|
||||
a := benchBitEnc.EncryptUint64(42, FheUint8)
|
||||
c := benchBitEnc.EncryptUint64(42, FheUint8)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = benchBitEval.Eq(a, c)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLatticeLt8(b *testing.B) {
|
||||
setupBenchmark(b)
|
||||
a := benchBitEnc.EncryptUint64(10, FheUint8)
|
||||
c := benchBitEnc.EncryptUint64(20, FheUint8)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = benchBitEval.Lt(a, c)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLatticeLe8(b *testing.B) {
|
||||
setupBenchmark(b)
|
||||
a := benchBitEnc.EncryptUint64(10, FheUint8)
|
||||
c := benchBitEnc.EncryptUint64(20, FheUint8)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = benchBitEval.Le(a, c)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLatticeGt8(b *testing.B) {
|
||||
setupBenchmark(b)
|
||||
a := benchBitEnc.EncryptUint64(20, FheUint8)
|
||||
c := benchBitEnc.EncryptUint64(10, FheUint8)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = benchBitEval.Gt(a, c)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLatticeMin8(b *testing.B) {
|
||||
setupBenchmark(b)
|
||||
a := benchBitEnc.EncryptUint64(10, FheUint8)
|
||||
c := benchBitEnc.EncryptUint64(20, FheUint8)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = benchBitEval.Min(a, c)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLatticeMax8(b *testing.B) {
|
||||
setupBenchmark(b)
|
||||
a := benchBitEnc.EncryptUint64(10, FheUint8)
|
||||
c := benchBitEnc.EncryptUint64(20, FheUint8)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = benchBitEval.Max(a, c)
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Bitwise Operation Benchmarks
|
||||
// ============================================================================
|
||||
|
||||
func BenchmarkLatticeBitwiseAnd8(b *testing.B) {
|
||||
setupBenchmark(b)
|
||||
a := benchBitEnc.EncryptUint64(0xFF, FheUint8)
|
||||
c := benchBitEnc.EncryptUint64(0x0F, FheUint8)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = benchBitEval.And(a, c)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLatticeBitwiseOr8(b *testing.B) {
|
||||
setupBenchmark(b)
|
||||
a := benchBitEnc.EncryptUint64(0xF0, FheUint8)
|
||||
c := benchBitEnc.EncryptUint64(0x0F, FheUint8)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = benchBitEval.Or(a, c)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLatticeBitwiseXor8(b *testing.B) {
|
||||
setupBenchmark(b)
|
||||
a := benchBitEnc.EncryptUint64(0xFF, FheUint8)
|
||||
c := benchBitEnc.EncryptUint64(0x55, FheUint8)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = benchBitEval.Xor(a, c)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLatticeBitwiseNot8(b *testing.B) {
|
||||
setupBenchmark(b)
|
||||
a := benchBitEnc.EncryptUint64(0xFF, FheUint8)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = benchBitEval.Not(a)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLatticeShl8(b *testing.B) {
|
||||
setupBenchmark(b)
|
||||
a := benchBitEnc.EncryptUint64(0x0F, FheUint8)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = benchBitEval.Shl(a, 2)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLatticeShr8(b *testing.B) {
|
||||
setupBenchmark(b)
|
||||
a := benchBitEnc.EncryptUint64(0xF0, FheUint8)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = benchBitEval.Shr(a, 2)
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Control Flow Benchmarks
|
||||
// ============================================================================
|
||||
|
||||
func BenchmarkLatticeSelect8(b *testing.B) {
|
||||
setupBenchmark(b)
|
||||
cond := benchEnc.Encrypt(true)
|
||||
a := benchBitEnc.EncryptUint64(10, FheUint8)
|
||||
c := benchBitEnc.EncryptUint64(20, FheUint8)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = benchBitEval.Select(cond, a, c)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLatticeCastTo16(b *testing.B) {
|
||||
setupBenchmark(b)
|
||||
a := benchBitEnc.EncryptUint64(42, FheUint8)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = benchBitEval.CastTo(a, FheUint16)
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Public Key Encryption Benchmarks
|
||||
// ============================================================================
|
||||
|
||||
func BenchmarkLatticePublicEncrypt8(b *testing.B) {
|
||||
setupBenchmark(b)
|
||||
pubEnc := NewBitwisePublicEncryptor(benchParams, benchPK)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = pubEnc.EncryptUint64(42, FheUint8)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLatticePublicEncrypt16(b *testing.B) {
|
||||
setupBenchmark(b)
|
||||
pubEnc := NewBitwisePublicEncryptor(benchParams, benchPK)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = pubEnc.EncryptUint64(12345, FheUint16)
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Serialization Benchmarks
|
||||
// ============================================================================
|
||||
|
||||
func BenchmarkLatticeSerializeCiphertext(b *testing.B) {
|
||||
setupBenchmark(b)
|
||||
ct := benchEnc.Encrypt(true)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = ct.MarshalBinary()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLatticeDeserializeCiphertext(b *testing.B) {
|
||||
setupBenchmark(b)
|
||||
ct := benchEnc.Encrypt(true)
|
||||
data, _ := ct.MarshalBinary()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
var ct2 Ciphertext
|
||||
_ = ct2.UnmarshalBinary(data)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLatticeSerializeInteger8(b *testing.B) {
|
||||
setupBenchmark(b)
|
||||
ct := benchBitEnc.EncryptUint64(42, FheUint8)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = ct.MarshalBinary()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLatticeSerializeInteger16(b *testing.B) {
|
||||
setupBenchmark(b)
|
||||
ct := benchBitEnc.EncryptUint64(12345, FheUint16)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = ct.MarshalBinary()
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// RNG Benchmarks
|
||||
// ============================================================================
|
||||
|
||||
func BenchmarkLatticeRNGRandomUint8(b *testing.B) {
|
||||
setupBenchmark(b)
|
||||
rng := NewFheRNG(benchParams, benchSK, []byte("benchmark-seed"))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = rng.RandomUint(FheUint8)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLatticeRNGRandomUint16(b *testing.B) {
|
||||
setupBenchmark(b)
|
||||
rng := NewFheRNG(benchParams, benchSK, []byte("benchmark-seed"))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = rng.RandomUint(FheUint16)
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Memory Allocation Benchmarks
|
||||
// ============================================================================
|
||||
|
||||
func BenchmarkLatticeAllocCiphertext(b *testing.B) {
|
||||
setupBenchmark(b)
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
ct := benchEnc.Encrypt(true)
|
||||
_ = ct
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLatticeAllocInteger8(b *testing.B) {
|
||||
setupBenchmark(b)
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
ct := benchBitEnc.EncryptUint64(42, FheUint8)
|
||||
_ = ct
|
||||
}
|
||||
}
|
||||
@@ -1,191 +0,0 @@
|
||||
// Benchmark tests with OpenFHE-compatible parameters
|
||||
// These benchmarks use parameters that closely match OpenFHE's STD128_LMKCDEY
|
||||
// for fair comparison between Go and C++ implementations.
|
||||
package fhe
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
// BenchmarkSTD128_AND benchmarks AND gate with STD128-compatible parameters
|
||||
func BenchmarkSTD128_AND(b *testing.B) {
|
||||
params, err := NewParametersFromLiteral(PN9QP28_STD128)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
kg := NewKeyGenerator(params)
|
||||
sk := kg.GenSecretKey()
|
||||
bsk := kg.GenBootstrapKey(sk)
|
||||
|
||||
enc := NewEncryptor(params, sk)
|
||||
eval := NewEvaluator(params, bsk)
|
||||
|
||||
ct1 := enc.EncryptBit(1)
|
||||
ct2 := enc.EncryptBit(0)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = eval.AND(ct1, ct2)
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkSTD128_OR benchmarks OR gate with STD128-compatible parameters
|
||||
func BenchmarkSTD128_OR(b *testing.B) {
|
||||
params, err := NewParametersFromLiteral(PN9QP28_STD128)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
kg := NewKeyGenerator(params)
|
||||
sk := kg.GenSecretKey()
|
||||
bsk := kg.GenBootstrapKey(sk)
|
||||
|
||||
enc := NewEncryptor(params, sk)
|
||||
eval := NewEvaluator(params, bsk)
|
||||
|
||||
ct1 := enc.EncryptBit(1)
|
||||
ct2 := enc.EncryptBit(0)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = eval.OR(ct1, ct2)
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkSTD128_XOR benchmarks XOR gate with STD128-compatible parameters
|
||||
func BenchmarkSTD128_XOR(b *testing.B) {
|
||||
params, err := NewParametersFromLiteral(PN9QP28_STD128)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
kg := NewKeyGenerator(params)
|
||||
sk := kg.GenSecretKey()
|
||||
bsk := kg.GenBootstrapKey(sk)
|
||||
|
||||
enc := NewEncryptor(params, sk)
|
||||
eval := NewEvaluator(params, bsk)
|
||||
|
||||
ct1 := enc.EncryptBit(1)
|
||||
ct2 := enc.EncryptBit(0)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = eval.XOR(ct1, ct2)
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkSTD128_NOT benchmarks NOT gate with STD128-compatible parameters
|
||||
func BenchmarkSTD128_NOT(b *testing.B) {
|
||||
params, err := NewParametersFromLiteral(PN9QP28_STD128)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
kg := NewKeyGenerator(params)
|
||||
sk := kg.GenSecretKey()
|
||||
bsk := kg.GenBootstrapKey(sk)
|
||||
|
||||
enc := NewEncryptor(params, sk)
|
||||
eval := NewEvaluator(params, bsk)
|
||||
|
||||
ct := enc.EncryptBit(1)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = eval.NOT(ct)
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkSTD128_NAND benchmarks NAND gate (includes bootstrap) with STD128-compatible parameters
|
||||
func BenchmarkSTD128_NAND(b *testing.B) {
|
||||
params, err := NewParametersFromLiteral(PN9QP28_STD128)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
kg := NewKeyGenerator(params)
|
||||
sk := kg.GenSecretKey()
|
||||
bsk := kg.GenBootstrapKey(sk)
|
||||
|
||||
enc := NewEncryptor(params, sk)
|
||||
eval := NewEvaluator(params, bsk)
|
||||
|
||||
ct1 := enc.EncryptBit(1)
|
||||
ct2 := enc.EncryptBit(0)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = eval.NAND(ct1, ct2)
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkPN10QP27_AND benchmarks AND gate with original PN10QP27 parameters for comparison
|
||||
func BenchmarkPN10QP27_AND(b *testing.B) {
|
||||
params, err := NewParametersFromLiteral(PN10QP27)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
kg := NewKeyGenerator(params)
|
||||
sk := kg.GenSecretKey()
|
||||
bsk := kg.GenBootstrapKey(sk)
|
||||
|
||||
enc := NewEncryptor(params, sk)
|
||||
eval := NewEvaluator(params, bsk)
|
||||
|
||||
ct1 := enc.EncryptBit(1)
|
||||
ct2 := enc.EncryptBit(0)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = eval.AND(ct1, ct2)
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkPN10QP27_OR benchmarks OR gate with original PN10QP27 parameters for comparison
|
||||
func BenchmarkPN10QP27_OR(b *testing.B) {
|
||||
params, err := NewParametersFromLiteral(PN10QP27)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
kg := NewKeyGenerator(params)
|
||||
sk := kg.GenSecretKey()
|
||||
bsk := kg.GenBootstrapKey(sk)
|
||||
|
||||
enc := NewEncryptor(params, sk)
|
||||
eval := NewEvaluator(params, bsk)
|
||||
|
||||
ct1 := enc.EncryptBit(1)
|
||||
ct2 := enc.EncryptBit(0)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = eval.OR(ct1, ct2)
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkPN10QP27_XOR benchmarks XOR gate with original PN10QP27 parameters for comparison
|
||||
func BenchmarkPN10QP27_XOR(b *testing.B) {
|
||||
params, err := NewParametersFromLiteral(PN10QP27)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
kg := NewKeyGenerator(params)
|
||||
sk := kg.GenSecretKey()
|
||||
bsk := kg.GenBootstrapKey(sk)
|
||||
|
||||
enc := NewEncryptor(params, sk)
|
||||
eval := NewEvaluator(params, bsk)
|
||||
|
||||
ct1 := enc.EncryptBit(1)
|
||||
ct2 := enc.EncryptBit(0)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = eval.XOR(ct1, ct2)
|
||||
}
|
||||
}
|
||||
@@ -1,534 +0,0 @@
|
||||
// Copyright (c) 2025, Lux Industries Inc
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package fhe
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// BenchmarkBootstrapBaseline measures baseline bootstrap performance
|
||||
func BenchmarkBootstrapBaseline(b *testing.B) {
|
||||
params, _ := NewParametersFromLiteral(PN10QP27)
|
||||
kg := NewKeyGenerator(params)
|
||||
sk := kg.GenSecretKey()
|
||||
_ = kg.GenPublicKey(sk)
|
||||
bsk := kg.GenBootstrapKey(sk)
|
||||
enc := NewEncryptor(params, sk)
|
||||
eval := NewEvaluator(params, bsk)
|
||||
|
||||
ct1 := enc.Encrypt(true)
|
||||
ct2 := enc.Encrypt(true)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = eval.AND(ct1, ct2)
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkBootstrapParallelGates measures parallel gate execution
|
||||
func BenchmarkBootstrapParallelGates(b *testing.B) {
|
||||
params, _ := NewParametersFromLiteral(PN10QP27)
|
||||
kg := NewKeyGenerator(params)
|
||||
sk := kg.GenSecretKey()
|
||||
_ = kg.GenPublicKey(sk)
|
||||
bsk := kg.GenBootstrapKey(sk)
|
||||
enc := NewEncryptor(params, sk)
|
||||
|
||||
numGates := 8
|
||||
|
||||
type gateInput struct {
|
||||
eval *Evaluator
|
||||
ct1 *Ciphertext
|
||||
ct2 *Ciphertext
|
||||
}
|
||||
|
||||
inputs := make([]gateInput, numGates)
|
||||
for i := 0; i < numGates; i++ {
|
||||
inputs[i] = gateInput{
|
||||
eval: NewEvaluator(params, bsk),
|
||||
ct1: enc.Encrypt(true),
|
||||
ct2: enc.Encrypt(false),
|
||||
}
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
var wg sync.WaitGroup
|
||||
for j := 0; j < numGates; j++ {
|
||||
wg.Add(1)
|
||||
go func(idx int) {
|
||||
defer wg.Done()
|
||||
_, _ = inputs[idx].eval.AND(inputs[idx].ct1, inputs[idx].ct2)
|
||||
}(j)
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkNTTComparison compares NTT implementations
|
||||
func BenchmarkNTTComparison(b *testing.B) {
|
||||
// Use NTT-friendly primes: Q = k*2N + 1 for some k
|
||||
// These primes support the required primitive roots of unity
|
||||
testCases := []struct {
|
||||
N int
|
||||
Q uint64
|
||||
}{
|
||||
{512, 12289}, // 12289 = 12*1024 + 1
|
||||
{1024, 12289}, // 12289 = 6*2048 + 1
|
||||
{2048, 12289}, // 12289 = 3*4096 + 1
|
||||
{4096, 40961}, // 40961 = 5*8192 + 1
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
b.Run(fmt.Sprintf("N=%d", tc.N), func(b *testing.B) {
|
||||
engine, err := NewNTTEngine(uint32(tc.N), tc.Q)
|
||||
if err != nil {
|
||||
b.Skipf("NTT engine init failed for N=%d, Q=%d: %v", tc.N, tc.Q, err)
|
||||
return
|
||||
}
|
||||
coeffs := make([]uint64, tc.N)
|
||||
for i := range coeffs {
|
||||
coeffs[i] = uint64(rand.Int63n(int64(tc.Q)))
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
engine.NTTInPlace(coeffs)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkBatchNTT measures batch NTT performance scaling
|
||||
func BenchmarkBatchNTT(b *testing.B) {
|
||||
N := 1024
|
||||
Q := uint64(12289) // NTT-friendly prime
|
||||
engine, err := NewNTTEngine(uint32(N), Q)
|
||||
if err != nil {
|
||||
b.Skipf("NTT engine init failed: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
batchSizes := []int{1, 4, 16, 64, 256}
|
||||
|
||||
for _, batchSize := range batchSizes {
|
||||
b.Run(fmt.Sprintf("batch=%d", batchSize), func(b *testing.B) {
|
||||
polys := make([][]uint64, batchSize)
|
||||
for i := range polys {
|
||||
polys[i] = make([]uint64, N)
|
||||
for j := range polys[i] {
|
||||
polys[i][j] = uint64(rand.Int63n(int64(Q)))
|
||||
}
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
engine.NTTBatch(polys)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkPolyMulScaling measures polynomial multiplication scaling
|
||||
func BenchmarkPolyMulScaling(b *testing.B) {
|
||||
N := 1024
|
||||
Q := uint64(12289) // NTT-friendly prime
|
||||
engine, err := NewNTTEngine(uint32(N), Q)
|
||||
if err != nil {
|
||||
b.Skipf("NTT engine init failed: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
a := make([]uint64, N)
|
||||
bb := make([]uint64, N)
|
||||
result := make([]uint64, N)
|
||||
|
||||
for i := range a {
|
||||
a[i] = uint64(rand.Int63n(int64(Q)))
|
||||
bb[i] = uint64(rand.Int63n(int64(Q)))
|
||||
}
|
||||
|
||||
engine.NTTInPlace(a)
|
||||
engine.NTTInPlace(bb)
|
||||
|
||||
b.Run("PolyMul", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
engine.PolyMulNTT(a, bb, result)
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("PolyMulAccum", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
engine.PolyMulNTTAccum(a, bb, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// BenchmarkModularOps measures modular arithmetic performance
|
||||
func BenchmarkModularOps(b *testing.B) {
|
||||
engine, err := NewNTTEngine(1024, 12289) // NTT-friendly prime
|
||||
if err != nil {
|
||||
b.Skipf("NTT engine init failed: %v", err)
|
||||
return
|
||||
}
|
||||
a := uint64(rand.Int63n(int64(engine.Q)))
|
||||
bb := uint64(rand.Int63n(int64(engine.Q)))
|
||||
|
||||
b.Run("MulMod_Standard", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = engine.mulMod(a, bb)
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("MulMod_Barrett", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = engine.mulModBarrett(a, bb)
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("AddMod", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = engine.addMod(a, bb)
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("SubMod", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = engine.subMod(a, bb)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// BenchmarkExternalProduct measures external product performance
|
||||
func BenchmarkExternalProduct(b *testing.B) {
|
||||
params, _ := NewParametersFromLiteral(PN10QP27)
|
||||
kg := NewKeyGenerator(params)
|
||||
sk := kg.GenSecretKey()
|
||||
_ = kg.GenPublicKey(sk)
|
||||
bsk := kg.GenBootstrapKey(sk)
|
||||
enc := NewEncryptor(params, sk)
|
||||
eval := NewEvaluator(params, bsk)
|
||||
|
||||
ct := enc.Encrypt(true)
|
||||
|
||||
// Measure a full bootstrap (which includes external products)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = eval.bootstrap(ct, eval.bsk.TestPolyAND)
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkKeyGenerationOptimized measures key generation performance
|
||||
func BenchmarkKeyGenerationOptimized(b *testing.B) {
|
||||
params, _ := NewParametersFromLiteral(PN10QP27)
|
||||
kg := NewKeyGenerator(params)
|
||||
|
||||
b.Run("SecretKey", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = kg.GenSecretKey()
|
||||
}
|
||||
})
|
||||
|
||||
sk := kg.GenSecretKey()
|
||||
|
||||
b.Run("PublicKey", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = kg.GenPublicKey(sk)
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("BootstrapKey", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = kg.GenBootstrapKey(sk)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// BenchmarkEncryptionOptimized measures encryption performance
|
||||
func BenchmarkEncryptionOptimized(b *testing.B) {
|
||||
params, _ := NewParametersFromLiteral(PN10QP27)
|
||||
kg := NewKeyGenerator(params)
|
||||
sk := kg.GenSecretKey()
|
||||
_ = kg.GenPublicKey(sk)
|
||||
enc := NewEncryptor(params, sk)
|
||||
|
||||
b.Run("Bit", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = enc.Encrypt(true)
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("Byte", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = enc.EncryptByte(0xAB)
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("Uint32", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = enc.EncryptUint32(0xDEADBEEF)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// BenchmarkDecryptionOptimized measures decryption performance
|
||||
func BenchmarkDecryptionOptimized(b *testing.B) {
|
||||
params, _ := NewParametersFromLiteral(PN10QP27)
|
||||
kg := NewKeyGenerator(params)
|
||||
sk := kg.GenSecretKey()
|
||||
_ = kg.GenPublicKey(sk)
|
||||
enc := NewEncryptor(params, sk)
|
||||
dec := NewDecryptor(params, sk)
|
||||
|
||||
ctBit := enc.Encrypt(true)
|
||||
ctByte := enc.EncryptByte(0xAB)
|
||||
ctUint32 := enc.EncryptUint32(0xDEADBEEF)
|
||||
|
||||
b.Run("Bit", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = dec.DecryptBit(ctBit)
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("Byte", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = dec.DecryptByte(ctByte)
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("Uint32", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = dec.DecryptUint32(ctUint32)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// BenchmarkAllGates measures all boolean gate performance
|
||||
func BenchmarkAllGates(b *testing.B) {
|
||||
params, _ := NewParametersFromLiteral(PN10QP27)
|
||||
kg := NewKeyGenerator(params)
|
||||
sk := kg.GenSecretKey()
|
||||
_ = kg.GenPublicKey(sk)
|
||||
bsk := kg.GenBootstrapKey(sk)
|
||||
enc := NewEncryptor(params, sk)
|
||||
eval := NewEvaluator(params, bsk)
|
||||
|
||||
ct1 := enc.Encrypt(true)
|
||||
ct2 := enc.Encrypt(false)
|
||||
ct3 := enc.Encrypt(true)
|
||||
|
||||
gates := []struct {
|
||||
name string
|
||||
fn func() (*Ciphertext, error)
|
||||
}{
|
||||
{"NOT", func() (*Ciphertext, error) { return eval.NOT(ct1), nil }},
|
||||
{"AND", func() (*Ciphertext, error) { return eval.AND(ct1, ct2) }},
|
||||
{"OR", func() (*Ciphertext, error) { return eval.OR(ct1, ct2) }},
|
||||
{"XOR", func() (*Ciphertext, error) { return eval.XOR(ct1, ct2) }},
|
||||
{"NAND", func() (*Ciphertext, error) { return eval.NAND(ct1, ct2) }},
|
||||
{"NOR", func() (*Ciphertext, error) { return eval.NOR(ct1, ct2) }},
|
||||
{"XNOR", func() (*Ciphertext, error) { return eval.XNOR(ct1, ct2) }},
|
||||
{"MUX", func() (*Ciphertext, error) { return eval.MUX(ct1, ct2, ct3) }},
|
||||
{"AND3", func() (*Ciphertext, error) { return eval.AND3(ct1, ct2, ct3) }},
|
||||
{"OR3", func() (*Ciphertext, error) { return eval.OR3(ct1, ct2, ct3) }},
|
||||
{"MAJORITY", func() (*Ciphertext, error) { return eval.MAJORITY(ct1, ct2, ct3) }},
|
||||
}
|
||||
|
||||
for _, g := range gates {
|
||||
b.Run(g.name, func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = g.fn()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkThroughputOptimized measures sustained throughput
|
||||
func BenchmarkThroughputOptimized(b *testing.B) {
|
||||
params, _ := NewParametersFromLiteral(PN10QP27)
|
||||
kg := NewKeyGenerator(params)
|
||||
sk := kg.GenSecretKey()
|
||||
_ = kg.GenPublicKey(sk)
|
||||
bsk := kg.GenBootstrapKey(sk)
|
||||
enc := NewEncryptor(params, sk)
|
||||
|
||||
numWorkers := 4
|
||||
opsPerWorker := 100
|
||||
|
||||
b.Run(fmt.Sprintf("Workers=%d", numWorkers), func(b *testing.B) {
|
||||
for iter := 0; iter < b.N; iter++ {
|
||||
var wg sync.WaitGroup
|
||||
start := time.Now()
|
||||
|
||||
for w := 0; w < numWorkers; w++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
eval := NewEvaluator(params, bsk)
|
||||
ct1 := enc.Encrypt(true)
|
||||
ct2 := enc.Encrypt(false)
|
||||
|
||||
for i := 0; i < opsPerWorker; i++ {
|
||||
_, _ = eval.AND(ct1, ct2)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
elapsed := time.Since(start)
|
||||
totalOps := numWorkers * opsPerWorker
|
||||
opsPerSec := float64(totalOps) / elapsed.Seconds()
|
||||
|
||||
b.ReportMetric(opsPerSec, "ops/s")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// BenchmarkMemoryAllocation measures memory allocation patterns
|
||||
func BenchmarkMemoryAllocation(b *testing.B) {
|
||||
params, _ := NewParametersFromLiteral(PN10QP27)
|
||||
kg := NewKeyGenerator(params)
|
||||
sk := kg.GenSecretKey()
|
||||
_ = kg.GenPublicKey(sk)
|
||||
bsk := kg.GenBootstrapKey(sk)
|
||||
enc := NewEncryptor(params, sk)
|
||||
eval := NewEvaluator(params, bsk)
|
||||
|
||||
ct1 := enc.Encrypt(true)
|
||||
ct2 := enc.Encrypt(false)
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = eval.AND(ct1, ct2)
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkParameterSets compares different parameter sets
|
||||
func BenchmarkParameterSets(b *testing.B) {
|
||||
paramSets := []struct {
|
||||
name string
|
||||
literal ParametersLiteral
|
||||
}{
|
||||
{"PN10QP27", PN10QP27},
|
||||
{"PN11QP54", PN11QP54},
|
||||
}
|
||||
|
||||
for _, ps := range paramSets {
|
||||
b.Run(ps.name, func(b *testing.B) {
|
||||
params, err := NewParametersFromLiteral(ps.literal)
|
||||
if err != nil {
|
||||
b.Fatalf("failed to create params: %v", err)
|
||||
}
|
||||
|
||||
kg := NewKeyGenerator(params)
|
||||
sk := kg.GenSecretKey()
|
||||
_ = kg.GenPublicKey(sk)
|
||||
bsk := kg.GenBootstrapKey(sk)
|
||||
enc := NewEncryptor(params, sk)
|
||||
eval := NewEvaluator(params, bsk)
|
||||
|
||||
ct1 := enc.Encrypt(true)
|
||||
ct2 := enc.Encrypt(false)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _ = eval.AND(ct1, ct2)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestPerformanceReport generates a performance summary
|
||||
func TestPerformanceReport(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping performance report in short mode")
|
||||
}
|
||||
|
||||
params, _ := NewParametersFromLiteral(PN10QP27)
|
||||
kg := NewKeyGenerator(params)
|
||||
sk := kg.GenSecretKey()
|
||||
_ = kg.GenPublicKey(sk)
|
||||
bsk := kg.GenBootstrapKey(sk)
|
||||
enc := NewEncryptor(params, sk)
|
||||
dec := NewDecryptor(params, sk)
|
||||
eval := NewEvaluator(params, bsk)
|
||||
|
||||
// Measure key generation
|
||||
start := time.Now()
|
||||
for i := 0; i < 10; i++ {
|
||||
_ = kg.GenBootstrapKey(sk)
|
||||
}
|
||||
bskTime := time.Since(start) / 10
|
||||
|
||||
// Measure encryption
|
||||
start = time.Now()
|
||||
for i := 0; i < 1000; i++ {
|
||||
_ = enc.Encrypt(true)
|
||||
}
|
||||
encTime := time.Since(start) / 1000
|
||||
|
||||
// Measure decryption
|
||||
ct := enc.Encrypt(true)
|
||||
start = time.Now()
|
||||
for i := 0; i < 1000; i++ {
|
||||
_ = dec.Decrypt(ct)
|
||||
}
|
||||
decTime := time.Since(start) / 1000
|
||||
|
||||
// Measure gates
|
||||
ct1 := enc.Encrypt(true)
|
||||
ct2 := enc.Encrypt(false)
|
||||
ct3 := enc.Encrypt(true)
|
||||
|
||||
gateResults := make(map[string]time.Duration)
|
||||
numIter := 10
|
||||
|
||||
start = time.Now()
|
||||
for i := 0; i < numIter; i++ {
|
||||
_, _ = eval.AND(ct1, ct2)
|
||||
}
|
||||
gateResults["AND"] = time.Since(start) / time.Duration(numIter)
|
||||
|
||||
start = time.Now()
|
||||
for i := 0; i < numIter; i++ {
|
||||
_, _ = eval.OR(ct1, ct2)
|
||||
}
|
||||
gateResults["OR"] = time.Since(start) / time.Duration(numIter)
|
||||
|
||||
start = time.Now()
|
||||
for i := 0; i < numIter; i++ {
|
||||
_, _ = eval.XOR(ct1, ct2)
|
||||
}
|
||||
gateResults["XOR"] = time.Since(start) / time.Duration(numIter)
|
||||
|
||||
start = time.Now()
|
||||
for i := 0; i < numIter; i++ {
|
||||
_, _ = eval.MAJORITY(ct1, ct2, ct3)
|
||||
}
|
||||
gateResults["MAJORITY"] = time.Since(start) / time.Duration(numIter)
|
||||
|
||||
// Print report
|
||||
fmt.Println("\n========== FHE Performance Report ==========")
|
||||
fmt.Printf("Parameters: PN10QP27 (N=%d, Q=%d)\n", params.N(), params.QLWE())
|
||||
fmt.Println()
|
||||
fmt.Println("Key Generation:")
|
||||
fmt.Printf(" Bootstrap Key: %v\n", bskTime)
|
||||
fmt.Println()
|
||||
fmt.Println("Encryption/Decryption:")
|
||||
fmt.Printf(" Encrypt Bit: %v\n", encTime)
|
||||
fmt.Printf(" Decrypt Bit: %v\n", decTime)
|
||||
fmt.Println()
|
||||
fmt.Println("Boolean Gates:")
|
||||
for gate, dur := range gateResults {
|
||||
gatesPerSec := float64(time.Second) / float64(dur)
|
||||
fmt.Printf(" %s: %v (%.1f gates/sec)\n", gate, dur, gatesPerSec)
|
||||
}
|
||||
fmt.Println("================================================")
|
||||
}
|
||||
-411
@@ -1,411 +0,0 @@
|
||||
// Copyright (c) 2025, Lux Industries Inc
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package fhe
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// BenchmarkParameters benchmarks parameter set initialization
|
||||
func BenchmarkParameters(b *testing.B) {
|
||||
b.Run("PN10QP27", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := NewParametersFromLiteral(PN10QP27)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("PN11QP54", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := NewParametersFromLiteral(PN11QP54)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// BenchmarkKeyGeneration benchmarks key generation
|
||||
func BenchmarkKeyGeneration(b *testing.B) {
|
||||
params, err := NewParametersFromLiteral(PN10QP27)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
kg := NewKeyGenerator(params)
|
||||
|
||||
b.Run("SecretKey", func(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
kg.GenSecretKey()
|
||||
}
|
||||
})
|
||||
|
||||
sk := kg.GenSecretKey()
|
||||
|
||||
b.Run("PublicKey", func(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
kg.GenPublicKey(sk)
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("BootstrapKey", func(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
kg.GenBootstrapKey(sk)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// BenchmarkEncryption benchmarks encryption operations
|
||||
func BenchmarkEncryption(b *testing.B) {
|
||||
params, err := NewParametersFromLiteral(PN10QP27)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
kg := NewKeyGenerator(params)
|
||||
sk := kg.GenSecretKey()
|
||||
enc := NewEncryptor(params, sk)
|
||||
|
||||
b.Run("Bit", func(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
enc.Encrypt(true)
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("Byte", func(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
enc.EncryptByte(0x42)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// BenchmarkDecryption benchmarks decryption operations
|
||||
func BenchmarkDecryption(b *testing.B) {
|
||||
params, err := NewParametersFromLiteral(PN10QP27)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
kg := NewKeyGenerator(params)
|
||||
sk := kg.GenSecretKey()
|
||||
enc := NewEncryptor(params, sk)
|
||||
dec := NewDecryptor(params, sk)
|
||||
|
||||
ctBit := enc.Encrypt(true)
|
||||
ctByte := enc.EncryptByte(0x42)
|
||||
|
||||
b.Run("Bit", func(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
dec.Decrypt(ctBit)
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("Byte", func(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
dec.DecryptByte(ctByte)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// BenchmarkGates benchmarks boolean gate operations
|
||||
func BenchmarkGates(b *testing.B) {
|
||||
params, err := NewParametersFromLiteral(PN10QP27)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
kg := NewKeyGenerator(params)
|
||||
sk := kg.GenSecretKey()
|
||||
bk := kg.GenBootstrapKey(sk)
|
||||
enc := NewEncryptor(params, sk)
|
||||
eval := NewEvaluator(params, bk)
|
||||
|
||||
ct1 := enc.Encrypt(true)
|
||||
ct2 := enc.Encrypt(false)
|
||||
|
||||
// Basic gates
|
||||
gates := []struct {
|
||||
name string
|
||||
fn func() (*Ciphertext, error)
|
||||
}{
|
||||
{"AND", func() (*Ciphertext, error) { return eval.AND(ct1, ct2) }},
|
||||
{"OR", func() (*Ciphertext, error) { return eval.OR(ct1, ct2) }},
|
||||
{"XOR", func() (*Ciphertext, error) { return eval.XOR(ct1, ct2) }},
|
||||
{"NAND", func() (*Ciphertext, error) { return eval.NAND(ct1, ct2) }},
|
||||
{"NOR", func() (*Ciphertext, error) { return eval.NOR(ct1, ct2) }},
|
||||
{"XNOR", func() (*Ciphertext, error) { return eval.XNOR(ct1, ct2) }},
|
||||
}
|
||||
|
||||
for _, gate := range gates {
|
||||
b.Run(gate.name, func(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := gate.fn()
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// NOT is special (no bootstrap)
|
||||
b.Run("NOT", func(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
eval.NOT(ct1)
|
||||
}
|
||||
})
|
||||
|
||||
// MUX
|
||||
ct3 := enc.Encrypt(true)
|
||||
b.Run("MUX", func(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := eval.MUX(ct1, ct2, ct3)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// BenchmarkMultiInputGates benchmarks multi-input gates
|
||||
func BenchmarkMultiInputGates(b *testing.B) {
|
||||
params, err := NewParametersFromLiteral(PN10QP27)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
kg := NewKeyGenerator(params)
|
||||
sk := kg.GenSecretKey()
|
||||
bk := kg.GenBootstrapKey(sk)
|
||||
enc := NewEncryptor(params, sk)
|
||||
eval := NewEvaluator(params, bk)
|
||||
|
||||
ct1 := enc.Encrypt(true)
|
||||
ct2 := enc.Encrypt(false)
|
||||
ct3 := enc.Encrypt(true)
|
||||
|
||||
b.Run("AND3", func(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := eval.AND3(ct1, ct2, ct3)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("OR3", func(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := eval.OR3(ct1, ct2, ct3)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("MAJORITY", func(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := eval.MAJORITY(ct1, ct2, ct3)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// BenchmarkSerialization benchmarks key and ciphertext serialization
|
||||
func BenchmarkSerialization(b *testing.B) {
|
||||
params, err := NewParametersFromLiteral(PN10QP27)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
kg := NewKeyGenerator(params)
|
||||
sk := kg.GenSecretKey()
|
||||
enc := NewEncryptor(params, sk)
|
||||
ct := enc.Encrypt(true)
|
||||
|
||||
b.Run("SecretKey/Marshal", func(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := sk.MarshalBinary()
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
skData, _ := sk.MarshalBinary()
|
||||
b.Run("SecretKey/Unmarshal", func(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
newSK := new(SecretKey)
|
||||
err := newSK.UnmarshalBinary(skData)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("Ciphertext/Marshal", func(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := ct.MarshalBinary()
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
ctData, _ := ct.MarshalBinary()
|
||||
b.Run("Ciphertext/Unmarshal", func(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
newCT := new(Ciphertext)
|
||||
err := newCT.UnmarshalBinary(ctData)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// BenchmarkCircuit benchmarks a simple circuit (half adder)
|
||||
func BenchmarkCircuit(b *testing.B) {
|
||||
params, err := NewParametersFromLiteral(PN10QP27)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
kg := NewKeyGenerator(params)
|
||||
sk := kg.GenSecretKey()
|
||||
bk := kg.GenBootstrapKey(sk)
|
||||
enc := NewEncryptor(params, sk)
|
||||
eval := NewEvaluator(params, bk)
|
||||
|
||||
a := enc.Encrypt(true)
|
||||
cIn := enc.Encrypt(false)
|
||||
|
||||
// Half adder: sum = a XOR b, carry = a AND b
|
||||
b.Run("HalfAdder", func(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := eval.XOR(a, cIn)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
_, err = eval.AND(a, cIn)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Full adder: sum = a XOR b XOR cin, cout = (a AND b) OR (cin AND (a XOR b))
|
||||
c := enc.Encrypt(true)
|
||||
b.Run("FullAdder", func(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
axorb, err := eval.XOR(a, cIn)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
_, err = eval.XOR(axorb, c)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
aandb, err := eval.AND(a, cIn)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
candaxorb, err := eval.AND(c, axorb)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
_, err = eval.OR(aandb, candaxorb)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// BenchmarkThroughput measures operations per second
|
||||
func BenchmarkThroughput(b *testing.B) {
|
||||
params, err := NewParametersFromLiteral(PN10QP27)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
kg := NewKeyGenerator(params)
|
||||
sk := kg.GenSecretKey()
|
||||
bk := kg.GenBootstrapKey(sk)
|
||||
enc := NewEncryptor(params, sk)
|
||||
eval := NewEvaluator(params, bk)
|
||||
|
||||
// Prepare many ciphertexts
|
||||
const n = 100
|
||||
cts := make([]*Ciphertext, n)
|
||||
for i := 0; i < n; i++ {
|
||||
cts[i] = enc.Encrypt(i%2 == 0)
|
||||
}
|
||||
|
||||
b.Run(fmt.Sprintf("AND_Chain_%d", n), func(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
result := cts[0]
|
||||
for j := 1; j < n; j++ {
|
||||
var err error
|
||||
result, err = eval.AND(result, cts[j])
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
b.Run(fmt.Sprintf("XOR_Chain_%d", n), func(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
result := cts[0]
|
||||
for j := 1; j < n; j++ {
|
||||
var err error
|
||||
result, err = eval.XOR(result, cts[j])
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// BenchmarkMemory reports memory usage for key structures
|
||||
func BenchmarkMemory(b *testing.B) {
|
||||
params, err := NewParametersFromLiteral(PN10QP27)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
kg := NewKeyGenerator(params)
|
||||
|
||||
b.Run("SecretKey", func(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
kg.GenSecretKey()
|
||||
}
|
||||
})
|
||||
|
||||
sk := kg.GenSecretKey()
|
||||
b.Run("BootstrapKey", func(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
kg.GenBootstrapKey(sk)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
goos: darwin
|
||||
goarch: arm64
|
||||
pkg: github.com/luxfi/fhe
|
||||
cpu: Apple M1 Max
|
||||
BenchmarkLatticeKeyGen-10 28998 41747 ns/op 15600 B/op 21 allocs/op
|
||||
BenchmarkLatticePublicKeyGen-10 66368 17420 ns/op 11936 B/op 22 allocs/op
|
||||
BenchmarkLatticeBootstrapKeyGen-10 8 131860630 ns/op 82447622 B/op 151516 allocs/op
|
||||
BenchmarkLatticeEncryptBit-10 53984 20809 ns/op 15992 B/op 29 allocs/op
|
||||
BenchmarkLatticeDecryptBit-10 253042 4521 ns/op 4736 B/op 8 allocs/op
|
||||
BenchmarkLatticeAND-10 21 52519200 ns/op 1202526 B/op 38009 allocs/op
|
||||
BenchmarkLatticeOR-10 22 51721345 ns/op 1209729 B/op 38254 allocs/op
|
||||
BenchmarkLatticeXOR-10 7 161679381 ns/op 3652602 B/op 115121 allocs/op
|
||||
BenchmarkLatticeNOT-10 990417 1189 ns/op 8856 B/op 11 allocs/op
|
||||
BenchmarkLatticeNAND-10 21 52048927 ns/op 1199232 B/op 37931 allocs/op
|
||||
BenchmarkLatticeNOR-10 22 52189896 ns/op 1201428 B/op 37995 allocs/op
|
||||
BenchmarkLatticeXNOR-10 7 160594298 ns/op 3648886 B/op 115249 allocs/op
|
||||
BenchmarkLatticeMUX-10 7 158445155 ns/op 3617170 B/op 114060 allocs/op
|
||||
BenchmarkLatticeEncryptInt8-10 7239 166821 ns/op 128048 B/op 234 allocs/op
|
||||
BenchmarkLatticeEncryptInt16-10 3524 326558 ns/op 256048 B/op 466 allocs/op
|
||||
BenchmarkLatticeEncryptInt32-10 1676 663523 ns/op 512048 B/op 930 allocs/op
|
||||
BenchmarkLatticeDecryptInt8-10 32006 36523 ns/op 37888 B/op 64 allocs/op
|
||||
BenchmarkLatticeDecryptInt16-10 16202 74022 ns/op 75776 B/op 128 allocs/op
|
||||
BenchmarkLatticeAdd8-10 1 3502386500 ns/op 81194968 B/op 2559530 allocs/op
|
||||
BenchmarkLatticeAdd16-10 1 7295119084 ns/op 168213608 B/op 5309943 allocs/op
|
||||
BenchmarkLatticeSub8-10 1 5199911125 ns/op 115079360 B/op 3629860 allocs/op
|
||||
BenchmarkLatticeScalarAdd8-10 1 1607502916 ns/op 36169352 B/op 1140974 allocs/op
|
||||
BenchmarkLatticeEq8-10 1 1739358750 ns/op 37334728 B/op 1180304 allocs/op
|
||||
BenchmarkLatticeLt8-10 1 2905434333 ns/op 63983496 B/op 2021721 allocs/op
|
||||
BenchmarkLatticeLe8-10 1 4524679625 ns/op 102752968 B/op 3246519 allocs/op
|
||||
BenchmarkLatticeGt8-10 1 2781826875 ns/op 64109536 B/op 2025297 allocs/op
|
||||
BenchmarkLatticeMin8-10 1 3999070792 ns/op 93132400 B/op 2942093 allocs/op
|
||||
BenchmarkLatticeMax8-10 1 4014468209 ns/op 93031712 B/op 2939102 allocs/op
|
||||
BenchmarkLatticeBitwiseAnd8-10 3 420482722 ns/op 9683120 B/op 306123 allocs/op
|
||||
BenchmarkLatticeBitwiseOr8-10 3 429208861 ns/op 9625712 B/op 304241 allocs/op
|
||||
BenchmarkLatticeBitwiseXor8-10 1 1450445458 ns/op 29048048 B/op 916361 allocs/op
|
||||
BenchmarkLatticeBitwiseNot8-10 105090 10466 ns/op 70960 B/op 90 allocs/op
|
||||
BenchmarkLatticeShl8-10 120087 9946 ns/op 35408 B/op 42 allocs/op
|
||||
BenchmarkLatticeShr8-10 112731 9616 ns/op 35408 B/op 42 allocs/op
|
||||
BenchmarkLatticeSelect8-10 1 1270980750 ns/op 29034016 B/op 914268 allocs/op
|
||||
BenchmarkLatticeCastTo16-10 30464 40074 ns/op 141360 B/op 162 allocs/op
|
||||
BenchmarkLatticePublicEncrypt8-10 3892 308228 ns/op 134328 B/op 274 allocs/op
|
||||
BenchmarkLatticePublicEncrypt16-10 1890 597936 ns/op 268606 B/op 546 allocs/op
|
||||
BenchmarkLatticeSerializeCiphertext-10 81741 14369 ns/op 34891 B/op 98 allocs/op
|
||||
BenchmarkLatticeDeserializeCiphertext-10 58243 20344 ns/op 28576 B/op 255 allocs/op
|
||||
BenchmarkLatticeSerializeInteger8-10 8608 126824 ns/op 430756 B/op 800 allocs/op
|
||||
BenchmarkLatticeSerializeInteger16-10 4105 255930 ns/op 873812 B/op 1593 allocs/op
|
||||
BenchmarkLatticeRNGRandomUint8-10 7045 173022 ns/op 128080 B/op 235 allocs/op
|
||||
BenchmarkLatticeRNGRandomUint16-10 3469 340920 ns/op 256080 B/op 467 allocs/op
|
||||
BenchmarkLatticeAllocCiphertext-10 55743 20827 ns/op 15992 B/op 29 allocs/op
|
||||
BenchmarkLatticeAllocInteger8-10 6997 174253 ns/op 128048 B/op 234 allocs/op
|
||||
PASS
|
||||
ok github.com/luxfi/fhe 89.128s
|
||||
@@ -1,18 +0,0 @@
|
||||
goos: darwin
|
||||
goarch: arm64
|
||||
pkg: github.com/luxfi/fhe
|
||||
cpu: Apple M1 Max
|
||||
BenchmarkBitwiseAdd4Bit-10 1 1616760125 ns/op 37581360 B/op 1182665 allocs/op
|
||||
BenchmarkShortIntEncrypt-10 56146 22166 ns/op 16008 B/op 29 allocs/op
|
||||
BenchmarkShortIntDecrypt-10 247593 5266 ns/op 4736 B/op 8 allocs/op
|
||||
BenchmarkIntegerEncryptUint8-10 26554 43922 ns/op 32080 B/op 60 allocs/op
|
||||
BenchmarkIntegerDecryptUint8-10 124048 9866 ns/op 9472 B/op 16 allocs/op
|
||||
BenchmarkKeyGen-10 8 136143349 ns/op 82472119 B/op 151550 allocs/op
|
||||
BenchmarkEncrypt-10 55508 22100 ns/op 15992 B/op 29 allocs/op
|
||||
BenchmarkDecrypt-10 250294 4946 ns/op 4736 B/op 8 allocs/op
|
||||
BenchmarkAND-10 22 53778233 ns/op 1231276 B/op 38721 allocs/op
|
||||
BenchmarkOR-10 22 54273616 ns/op 1231148 B/op 38703 allocs/op
|
||||
BenchmarkXOR-10 7 157962637 ns/op 3590484 B/op 112912 allocs/op
|
||||
BenchmarkMUX-10 7 155910143 ns/op 3648014 B/op 114574 allocs/op
|
||||
PASS
|
||||
ok github.com/luxfi/fhe 18.051s
|
||||
-1003
File diff suppressed because it is too large
Load Diff
-1071
File diff suppressed because it is too large
Load Diff
-1004
File diff suppressed because it is too large
Load Diff
-1094
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,564 +0,0 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2024-2025, Lux Industries Inc
|
||||
//
|
||||
// Optimized Encrypted Comparison for Solidity/EVM
|
||||
//
|
||||
// Key innovation: Kogge-Stone parallel prefix comparison with GPU acceleration
|
||||
// - Traditional: Serial bit-by-bit comparison O(n) depth
|
||||
// - Optimized: Parallel prefix O(log n) depth with early termination hints
|
||||
//
|
||||
// Patent: PAT-FHE-C8 - Encrypted Comparison for Solidity
|
||||
// For enterprise licensing: [email protected]
|
||||
|
||||
#ifndef LUXFHE_ENCRYPTED_COMPARE_H
|
||||
#define LUXFHE_ENCRYPTED_COMPARE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
// =============================================================================
|
||||
// Forward Declarations
|
||||
// =============================================================================
|
||||
|
||||
typedef void* LuxFHEEngine;
|
||||
typedef void* LuxFHECiphertext;
|
||||
typedef void* LuxFHEInteger;
|
||||
typedef void* LuxFHECompareContext;
|
||||
|
||||
// =============================================================================
|
||||
// Comparison Result Types
|
||||
// =============================================================================
|
||||
|
||||
// Comparison operations for Solidity FHE precompile
|
||||
typedef enum {
|
||||
LUXFHE_CMP_LT = 0, // a < b
|
||||
LUXFHE_CMP_LE = 1, // a <= b
|
||||
LUXFHE_CMP_GT = 2, // a > b
|
||||
LUXFHE_CMP_GE = 3, // a >= b
|
||||
LUXFHE_CMP_EQ = 4, // a == b
|
||||
LUXFHE_CMP_NE = 5, // a != b
|
||||
LUXFHE_CMP_MIN = 6, // min(a, b)
|
||||
LUXFHE_CMP_MAX = 7 // max(a, b)
|
||||
} LuxFHECompareOp;
|
||||
|
||||
// Integer bit widths matching Solidity FHE types
|
||||
typedef enum {
|
||||
LUXFHE_UINT4 = 4,
|
||||
LUXFHE_UINT8 = 8,
|
||||
LUXFHE_UINT16 = 16,
|
||||
LUXFHE_UINT32 = 32,
|
||||
LUXFHE_UINT64 = 64,
|
||||
LUXFHE_UINT128 = 128,
|
||||
LUXFHE_UINT160 = 160, // Ethereum address
|
||||
LUXFHE_UINT256 = 256
|
||||
} LuxFHEUintWidth;
|
||||
|
||||
// =============================================================================
|
||||
// Kogge-Stone Parallel Comparison Tree
|
||||
// =============================================================================
|
||||
|
||||
// Configuration for parallel prefix network
|
||||
typedef struct {
|
||||
uint32_t num_bits; // Total bits to compare
|
||||
uint32_t block_size; // Bits per radix block (2 or 4)
|
||||
uint32_t num_stages; // log2(num_bits) stages
|
||||
bool use_gpu; // Enable GPU acceleration
|
||||
bool early_termination; // Enable early termination hints
|
||||
uint32_t batch_size; // Operations to batch for GPU
|
||||
} LuxFHEKoggeStoneConfig;
|
||||
|
||||
// Stage data for Kogge-Stone tree
|
||||
typedef struct {
|
||||
uint32_t stage; // Current stage index
|
||||
uint32_t stride; // Distance between compared elements
|
||||
uint32_t num_ops; // Operations in this stage
|
||||
} LuxFHEKoggeStoneStage;
|
||||
|
||||
// =============================================================================
|
||||
// Parallel Compare Context
|
||||
// =============================================================================
|
||||
|
||||
// Create comparison context with Kogge-Stone configuration
|
||||
LuxFHECompareContext luxfhe_compare_context_create(
|
||||
LuxFHEEngine engine,
|
||||
LuxFHEKoggeStoneConfig config
|
||||
);
|
||||
|
||||
// Free comparison context
|
||||
void luxfhe_compare_context_free(LuxFHECompareContext ctx);
|
||||
|
||||
// Get Kogge-Stone stage info
|
||||
LuxFHEKoggeStoneStage luxfhe_compare_get_stage_info(
|
||||
LuxFHECompareContext ctx,
|
||||
uint32_t stage
|
||||
);
|
||||
|
||||
// =============================================================================
|
||||
// Core Comparison Operations (Solidity FHE Interface)
|
||||
// =============================================================================
|
||||
|
||||
// FHE.lt(euintN a, euintN b) -> ebool
|
||||
// Parallel prefix less-than comparison
|
||||
// Algorithm:
|
||||
// 1. Compute bit differences: d[i] = a[i] XOR b[i]
|
||||
// 2. Kogge-Stone parallel prefix to find MSB difference
|
||||
// 3. Result = b[msb_diff_position]
|
||||
LuxFHECiphertext luxfhe_lt(
|
||||
LuxFHEEngine engine,
|
||||
LuxFHECompareContext ctx,
|
||||
LuxFHEInteger a,
|
||||
LuxFHEInteger b
|
||||
);
|
||||
|
||||
// FHE.le(euintN a, euintN b) -> ebool
|
||||
LuxFHECiphertext luxfhe_le(
|
||||
LuxFHEEngine engine,
|
||||
LuxFHECompareContext ctx,
|
||||
LuxFHEInteger a,
|
||||
LuxFHEInteger b
|
||||
);
|
||||
|
||||
// FHE.gt(euintN a, euintN b) -> ebool
|
||||
LuxFHECiphertext luxfhe_gt(
|
||||
LuxFHEEngine engine,
|
||||
LuxFHECompareContext ctx,
|
||||
LuxFHEInteger a,
|
||||
LuxFHEInteger b
|
||||
);
|
||||
|
||||
// FHE.ge(euintN a, euintN b) -> ebool
|
||||
LuxFHECiphertext luxfhe_ge(
|
||||
LuxFHEEngine engine,
|
||||
LuxFHECompareContext ctx,
|
||||
LuxFHEInteger a,
|
||||
LuxFHEInteger b
|
||||
);
|
||||
|
||||
// FHE.eq(euintN a, euintN b) -> ebool
|
||||
// Parallel XOR-reduction for equality
|
||||
LuxFHECiphertext luxfhe_eq(
|
||||
LuxFHEEngine engine,
|
||||
LuxFHECompareContext ctx,
|
||||
LuxFHEInteger a,
|
||||
LuxFHEInteger b
|
||||
);
|
||||
|
||||
// FHE.ne(euintN a, euintN b) -> ebool
|
||||
LuxFHECiphertext luxfhe_ne(
|
||||
LuxFHEEngine engine,
|
||||
LuxFHECompareContext ctx,
|
||||
LuxFHEInteger a,
|
||||
LuxFHEInteger b
|
||||
);
|
||||
|
||||
// FHE.min(euintN a, euintN b) -> euintN
|
||||
// Returns encrypted minimum using oblivious selection
|
||||
LuxFHEInteger luxfhe_min(
|
||||
LuxFHEEngine engine,
|
||||
LuxFHECompareContext ctx,
|
||||
LuxFHEInteger a,
|
||||
LuxFHEInteger b
|
||||
);
|
||||
|
||||
// FHE.max(euintN a, euintN b) -> euintN
|
||||
LuxFHEInteger luxfhe_max(
|
||||
LuxFHEEngine engine,
|
||||
LuxFHECompareContext ctx,
|
||||
LuxFHEInteger a,
|
||||
LuxFHEInteger b
|
||||
);
|
||||
|
||||
// =============================================================================
|
||||
// Batch Comparison (GPU-Optimized)
|
||||
// =============================================================================
|
||||
|
||||
// Batch comparison for multiple pairs
|
||||
// Enables GPU kernel saturation for high throughput
|
||||
typedef struct {
|
||||
LuxFHEInteger* a_values; // Array of first operands
|
||||
LuxFHEInteger* b_values; // Array of second operands
|
||||
uint32_t count; // Number of comparisons
|
||||
LuxFHECompareOp op; // Comparison operation
|
||||
} LuxFHECompareBatch;
|
||||
|
||||
// Execute batch comparison
|
||||
// Returns array of results (ebool for lt/le/gt/ge/eq/ne, euint for min/max)
|
||||
void* luxfhe_compare_batch(
|
||||
LuxFHEEngine engine,
|
||||
LuxFHECompareContext ctx,
|
||||
LuxFHECompareBatch* batch
|
||||
);
|
||||
|
||||
// Free batch results
|
||||
void luxfhe_compare_batch_free(void* results, uint32_t count, LuxFHECompareOp op);
|
||||
|
||||
// =============================================================================
|
||||
// Scalar Comparison (Plaintext Operand)
|
||||
// =============================================================================
|
||||
|
||||
// FHE.lt(euintN a, uintN b) -> ebool (plaintext right operand)
|
||||
// Optimization: precompute b's bit representation
|
||||
LuxFHECiphertext luxfhe_lt_scalar(
|
||||
LuxFHEEngine engine,
|
||||
LuxFHECompareContext ctx,
|
||||
LuxFHEInteger a,
|
||||
const uint8_t* b_bytes,
|
||||
uint32_t b_len
|
||||
);
|
||||
|
||||
// FHE.eq(euintN a, uintN b) -> ebool (plaintext right operand)
|
||||
LuxFHECiphertext luxfhe_eq_scalar(
|
||||
LuxFHEEngine engine,
|
||||
LuxFHECompareContext ctx,
|
||||
LuxFHEInteger a,
|
||||
const uint8_t* b_bytes,
|
||||
uint32_t b_len
|
||||
);
|
||||
|
||||
// =============================================================================
|
||||
// GPU Kernel Interface (Metal/CUDA)
|
||||
// =============================================================================
|
||||
|
||||
#ifdef LUXFHE_GPU_ENABLED
|
||||
|
||||
// Kogge-Stone parallel prefix kernel configuration
|
||||
typedef struct {
|
||||
uint32_t workgroup_size; // Threads per workgroup
|
||||
uint32_t num_workgroups; // Total workgroups
|
||||
uint32_t shared_mem_bytes; // Shared memory per workgroup
|
||||
} LuxFHEGPUKernelConfig;
|
||||
|
||||
// Get optimal kernel config for hardware
|
||||
LuxFHEGPUKernelConfig luxfhe_compare_get_kernel_config(
|
||||
LuxFHEEngine engine,
|
||||
uint32_t num_bits,
|
||||
uint32_t batch_size
|
||||
);
|
||||
|
||||
// Launch Kogge-Stone parallel prefix kernel
|
||||
// Computes (G, P) pairs: Generate and Propagate signals for comparison
|
||||
// G[i] = a[i] > b[i], P[i] = a[i] == b[i]
|
||||
int luxfhe_gpu_kogge_stone_prefix(
|
||||
LuxFHEEngine engine,
|
||||
LuxFHECompareContext ctx,
|
||||
LuxFHEGPUKernelConfig* config,
|
||||
LuxFHEInteger* a_batch,
|
||||
LuxFHEInteger* b_batch,
|
||||
uint32_t batch_size,
|
||||
LuxFHECiphertext* results
|
||||
);
|
||||
|
||||
// Early termination hint computation
|
||||
// Returns encrypted hint indicating MSB difference position
|
||||
LuxFHECiphertext luxfhe_gpu_early_term_hint(
|
||||
LuxFHEEngine engine,
|
||||
LuxFHECompareContext ctx,
|
||||
LuxFHEInteger a,
|
||||
LuxFHEInteger b
|
||||
);
|
||||
|
||||
#endif // LUXFHE_GPU_ENABLED
|
||||
|
||||
// =============================================================================
|
||||
// Statistics and Profiling
|
||||
// =============================================================================
|
||||
|
||||
typedef struct {
|
||||
uint64_t total_comparisons; // Total comparison operations
|
||||
uint64_t gpu_kernel_launches; // GPU kernel invocations
|
||||
uint64_t early_terminations; // Early termination opportunities
|
||||
double avg_depth_reduction; // Average depth reduction vs serial
|
||||
double avg_latency_us; // Average latency in microseconds
|
||||
double throughput_ops_sec; // Operations per second
|
||||
} LuxFHECompareStats;
|
||||
|
||||
// Get comparison statistics
|
||||
LuxFHECompareStats luxfhe_compare_get_stats(LuxFHECompareContext ctx);
|
||||
|
||||
// Reset statistics
|
||||
void luxfhe_compare_reset_stats(LuxFHECompareContext ctx);
|
||||
|
||||
// =============================================================================
|
||||
// Solidity Interface Specification
|
||||
// =============================================================================
|
||||
|
||||
/*
|
||||
* Solidity FHE Precompile Interface for Comparison Operations
|
||||
*
|
||||
* Address: 0x0100 (FHE Precompile Base)
|
||||
*
|
||||
* Function Selectors:
|
||||
* lt(bytes32 a, bytes32 b) -> 0x1234... // Returns encrypted bool
|
||||
* le(bytes32 a, bytes32 b) -> 0x2345...
|
||||
* gt(bytes32 a, bytes32 b) -> 0x3456...
|
||||
* ge(bytes32 a, bytes32 b) -> 0x4567...
|
||||
* eq(bytes32 a, bytes32 b) -> 0x5678...
|
||||
* ne(bytes32 a, bytes32 b) -> 0x6789...
|
||||
* min(bytes32 a, bytes32 b) -> 0x789a... // Returns encrypted uint
|
||||
* max(bytes32 a, bytes32 b) -> 0x89ab...
|
||||
*
|
||||
* Input Format:
|
||||
* - bytes32 handle: Ciphertext handle in global ciphertext store
|
||||
* - Type info encoded in handle's upper bits
|
||||
*
|
||||
* Gas Costs (approximate):
|
||||
* - lt/gt/le/ge: 50000 + 500 * log2(bit_width) gas
|
||||
* - eq/ne: 30000 + 300 * log2(bit_width) gas
|
||||
* - min/max: 80000 + 800 * log2(bit_width) gas
|
||||
*
|
||||
* Example Solidity Usage:
|
||||
*
|
||||
* import "fhe/FHE.sol";
|
||||
*
|
||||
* contract Auction {
|
||||
* euint256 highestBid;
|
||||
* eaddress highestBidder;
|
||||
*
|
||||
* function bid(einput encryptedBid, bytes calldata proof) external {
|
||||
* euint256 bidAmount = FHE.asEuint256(encryptedBid, proof);
|
||||
*
|
||||
* // Encrypted comparison: is new bid higher?
|
||||
* ebool isHigher = FHE.gt(bidAmount, highestBid);
|
||||
*
|
||||
* // Oblivious selection: update if higher
|
||||
* highestBid = FHE.select(isHigher, bidAmount, highestBid);
|
||||
* highestBidder = FHE.select(isHigher,
|
||||
* FHE.asEaddress(msg.sender),
|
||||
* highestBidder);
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
// =============================================================================
|
||||
// C++ API (when compiled as C++)
|
||||
// =============================================================================
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
|
||||
namespace luxfhe {
|
||||
namespace compare {
|
||||
|
||||
// Encrypted bit type (forward declaration)
|
||||
class EncryptedBit;
|
||||
class EncryptedInteger;
|
||||
|
||||
// =============================================================================
|
||||
// Kogge-Stone Parallel Prefix Tree
|
||||
// =============================================================================
|
||||
|
||||
// Generate-Propagate pair for comparison
|
||||
// G = a > b (generate: this position determines result)
|
||||
// P = a == b (propagate: defer to higher position)
|
||||
struct GPPair {
|
||||
std::shared_ptr<EncryptedBit> G; // Generate signal
|
||||
std::shared_ptr<EncryptedBit> P; // Propagate signal
|
||||
};
|
||||
|
||||
// Kogge-Stone operator: combines two GP pairs
|
||||
// (G1, P1) o (G0, P0) = (G1 OR (P1 AND G0), P1 AND P0)
|
||||
class KoggeStoneOp {
|
||||
public:
|
||||
virtual ~KoggeStoneOp() = default;
|
||||
|
||||
// Combine two GP pairs homomorphically
|
||||
virtual GPPair combine(const GPPair& high, const GPPair& low) = 0;
|
||||
};
|
||||
|
||||
// =============================================================================
|
||||
// ParallelCompare Class
|
||||
// =============================================================================
|
||||
|
||||
class ParallelCompare {
|
||||
public:
|
||||
// Configuration
|
||||
struct Config {
|
||||
uint32_t num_bits = 256;
|
||||
uint32_t block_size = 4;
|
||||
bool use_gpu = true;
|
||||
bool early_termination = true;
|
||||
uint32_t batch_size = 1024;
|
||||
};
|
||||
|
||||
// Constructor
|
||||
explicit ParallelCompare(Config config);
|
||||
~ParallelCompare();
|
||||
|
||||
// Disable copy, enable move
|
||||
ParallelCompare(const ParallelCompare&) = delete;
|
||||
ParallelCompare& operator=(const ParallelCompare&) = delete;
|
||||
ParallelCompare(ParallelCompare&&) noexcept;
|
||||
ParallelCompare& operator=(ParallelCompare&&) noexcept;
|
||||
|
||||
// =========================================================================
|
||||
// Core Comparison (Kogge-Stone Algorithm)
|
||||
// =========================================================================
|
||||
|
||||
// Less-than comparison using parallel prefix
|
||||
// Depth: O(log n) vs O(n) for serial
|
||||
std::shared_ptr<EncryptedBit> lessThan(
|
||||
const EncryptedInteger& a,
|
||||
const EncryptedInteger& b
|
||||
);
|
||||
|
||||
// Equality using parallel XOR-reduction
|
||||
std::shared_ptr<EncryptedBit> equal(
|
||||
const EncryptedInteger& a,
|
||||
const EncryptedInteger& b
|
||||
);
|
||||
|
||||
// =========================================================================
|
||||
// Derived Operations
|
||||
// =========================================================================
|
||||
|
||||
std::shared_ptr<EncryptedBit> lessEqual(
|
||||
const EncryptedInteger& a,
|
||||
const EncryptedInteger& b
|
||||
);
|
||||
|
||||
std::shared_ptr<EncryptedBit> greaterThan(
|
||||
const EncryptedInteger& a,
|
||||
const EncryptedInteger& b
|
||||
);
|
||||
|
||||
std::shared_ptr<EncryptedBit> greaterEqual(
|
||||
const EncryptedInteger& a,
|
||||
const EncryptedInteger& b
|
||||
);
|
||||
|
||||
std::shared_ptr<EncryptedBit> notEqual(
|
||||
const EncryptedInteger& a,
|
||||
const EncryptedInteger& b
|
||||
);
|
||||
|
||||
// =========================================================================
|
||||
// Selection Operations
|
||||
// =========================================================================
|
||||
|
||||
// Oblivious minimum: returns a if a < b, else b
|
||||
std::shared_ptr<EncryptedInteger> min(
|
||||
const EncryptedInteger& a,
|
||||
const EncryptedInteger& b
|
||||
);
|
||||
|
||||
// Oblivious maximum
|
||||
std::shared_ptr<EncryptedInteger> max(
|
||||
const EncryptedInteger& a,
|
||||
const EncryptedInteger& b
|
||||
);
|
||||
|
||||
// Oblivious selection: returns a if cond is true, else b
|
||||
std::shared_ptr<EncryptedInteger> select(
|
||||
const EncryptedBit& cond,
|
||||
const EncryptedInteger& a,
|
||||
const EncryptedInteger& b
|
||||
);
|
||||
|
||||
// =========================================================================
|
||||
// Batch Operations (GPU-Optimized)
|
||||
// =========================================================================
|
||||
|
||||
std::vector<std::shared_ptr<EncryptedBit>> batchLessThan(
|
||||
const std::vector<EncryptedInteger>& a_vec,
|
||||
const std::vector<EncryptedInteger>& b_vec
|
||||
);
|
||||
|
||||
std::vector<std::shared_ptr<EncryptedBit>> batchEqual(
|
||||
const std::vector<EncryptedInteger>& a_vec,
|
||||
const std::vector<EncryptedInteger>& b_vec
|
||||
);
|
||||
|
||||
// =========================================================================
|
||||
// Scalar Comparisons (Optimized)
|
||||
// =========================================================================
|
||||
|
||||
std::shared_ptr<EncryptedBit> lessThanScalar(
|
||||
const EncryptedInteger& a,
|
||||
const std::vector<uint8_t>& b_plaintext
|
||||
);
|
||||
|
||||
std::shared_ptr<EncryptedBit> equalScalar(
|
||||
const EncryptedInteger& a,
|
||||
const std::vector<uint8_t>& b_plaintext
|
||||
);
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> impl_;
|
||||
|
||||
// Kogge-Stone tree building
|
||||
std::vector<GPPair> buildGPPairs(
|
||||
const EncryptedInteger& a,
|
||||
const EncryptedInteger& b
|
||||
);
|
||||
|
||||
// Parallel prefix computation
|
||||
GPPair parallelPrefix(const std::vector<GPPair>& gp_pairs);
|
||||
|
||||
// GPU kernel dispatch
|
||||
void dispatchGPUKernel(
|
||||
const std::vector<GPPair>& gp_pairs,
|
||||
uint32_t stage,
|
||||
uint32_t stride
|
||||
);
|
||||
};
|
||||
|
||||
// =============================================================================
|
||||
// GPU Kernel Launcher
|
||||
// =============================================================================
|
||||
|
||||
class GPUCompareKernel {
|
||||
public:
|
||||
struct LaunchParams {
|
||||
uint32_t workgroup_size = 256;
|
||||
uint32_t num_workgroups = 0; // 0 = auto
|
||||
size_t shared_mem_bytes = 0;
|
||||
};
|
||||
|
||||
virtual ~GPUCompareKernel() = default;
|
||||
|
||||
// Launch Kogge-Stone stage kernel
|
||||
// Each stage computes GP pairs with distance 2^stage
|
||||
virtual void launchKoggeStoneStage(
|
||||
const LaunchParams& params,
|
||||
std::vector<GPPair>& gp_pairs,
|
||||
uint32_t stage
|
||||
) = 0;
|
||||
|
||||
// Launch XOR-reduction kernel for equality
|
||||
virtual void launchXorReduction(
|
||||
const LaunchParams& params,
|
||||
std::vector<std::shared_ptr<EncryptedBit>>& xor_bits
|
||||
) = 0;
|
||||
|
||||
// Launch oblivious selection kernel
|
||||
virtual void launchSelect(
|
||||
const LaunchParams& params,
|
||||
const EncryptedBit& cond,
|
||||
const EncryptedInteger& a,
|
||||
const EncryptedInteger& b,
|
||||
EncryptedInteger& result
|
||||
) = 0;
|
||||
};
|
||||
|
||||
// Factory for platform-specific kernel
|
||||
std::unique_ptr<GPUCompareKernel> createGPUCompareKernel();
|
||||
|
||||
} // namespace compare
|
||||
} // namespace luxfhe
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // LUXFHE_ENCRYPTED_COMPARE_H
|
||||
-1151
File diff suppressed because it is too large
Load Diff
@@ -1,242 +0,0 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// Copyright (c) 2025, Lux Industries Inc
|
||||
//
|
||||
// C bridge header for OpenFHE BinFHE (TFHE) operations
|
||||
// This header defines the C interface that Go calls via CGO
|
||||
|
||||
#ifndef TFHE_BRIDGE_H
|
||||
#define TFHE_BRIDGE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
// Opaque handle types
|
||||
typedef void* TfheContext;
|
||||
typedef void* TfheSecretKey;
|
||||
typedef void* TfhePublicKey;
|
||||
typedef void* TfheCiphertext;
|
||||
typedef void* TfheBootstrapKey;
|
||||
|
||||
// Security levels matching OpenFHE BINFHE_PARAMSET
|
||||
typedef enum {
|
||||
TFHE_TOY = 0, // ~16-bit security (testing only)
|
||||
TFHE_STD128 = 1, // 128-bit security (CGGI/GINX)
|
||||
TFHE_STD128_AP = 2, // 128-bit security (AP variant)
|
||||
TFHE_STD128_LMKCDEY = 3, // 128-bit security (LMKCDEY - fastest)
|
||||
TFHE_STD192 = 4, // 192-bit security
|
||||
TFHE_STD256 = 5 // 256-bit security
|
||||
} TfheSecurityLevel;
|
||||
|
||||
// Bootstrapping method
|
||||
typedef enum {
|
||||
TFHE_METHOD_GINX = 0, // GINX (default)
|
||||
TFHE_METHOD_AP = 1, // AP variant
|
||||
TFHE_METHOD_LMKCDEY = 2 // LMKCDEY (fastest)
|
||||
} TfheMethod;
|
||||
|
||||
// =============================================================================
|
||||
// Context Management
|
||||
// =============================================================================
|
||||
|
||||
// Create a new TFHE context with specified security level and method
|
||||
TfheContext tfhe_context_new(TfheSecurityLevel level, TfheMethod method);
|
||||
|
||||
// Free a TFHE context
|
||||
void tfhe_context_free(TfheContext ctx);
|
||||
|
||||
// Get version of the bridge library
|
||||
uint32_t tfhe_version(void);
|
||||
|
||||
// =============================================================================
|
||||
// Key Generation
|
||||
// =============================================================================
|
||||
|
||||
// Generate a secret key
|
||||
TfheSecretKey tfhe_keygen(TfheContext ctx);
|
||||
|
||||
// Free a secret key
|
||||
void tfhe_secretkey_free(TfheSecretKey sk);
|
||||
|
||||
// Generate bootstrap key (required for gate evaluation)
|
||||
int tfhe_bootstrap_keygen(TfheContext ctx, TfheSecretKey sk);
|
||||
|
||||
// Generate key switching key
|
||||
int tfhe_keyswitch_keygen(TfheContext ctx, TfheSecretKey sk);
|
||||
|
||||
// Check if bootstrap key is generated
|
||||
bool tfhe_has_bootstrap_key(TfheContext ctx);
|
||||
|
||||
// =============================================================================
|
||||
// Public Key Generation
|
||||
// =============================================================================
|
||||
|
||||
// Generate a public key from secret key
|
||||
TfhePublicKey tfhe_public_keygen(TfheContext ctx, TfheSecretKey sk);
|
||||
|
||||
// Free a public key
|
||||
void tfhe_public_key_free(TfhePublicKey pk);
|
||||
|
||||
// Serialize public key to bytes
|
||||
int tfhe_publickey_serialize(TfhePublicKey pk, uint8_t** out, size_t* out_len);
|
||||
|
||||
// Deserialize public key from bytes
|
||||
TfhePublicKey tfhe_publickey_deserialize(TfheContext ctx, const uint8_t* data, size_t len);
|
||||
|
||||
// =============================================================================
|
||||
// Encryption / Decryption (Boolean)
|
||||
// =============================================================================
|
||||
|
||||
// Encrypt a boolean value (0 or 1)
|
||||
TfheCiphertext tfhe_encrypt(TfheContext ctx, TfheSecretKey sk, int value);
|
||||
|
||||
// Encrypt a bit (alias for tfhe_encrypt)
|
||||
TfheCiphertext tfhe_encrypt_bit(TfheContext ctx, TfheSecretKey sk, int value);
|
||||
|
||||
// Encrypt a bit with public key
|
||||
TfheCiphertext tfhe_encrypt_bit_public(TfheContext ctx, TfhePublicKey pk, int value);
|
||||
|
||||
// Decrypt a ciphertext to boolean
|
||||
int tfhe_decrypt(TfheContext ctx, TfheSecretKey sk, TfheCiphertext ct);
|
||||
|
||||
// Decrypt a bit (alias for tfhe_decrypt)
|
||||
int tfhe_decrypt_bit(TfheContext ctx, TfheSecretKey sk, TfheCiphertext ct);
|
||||
|
||||
// Free a ciphertext
|
||||
void tfhe_ciphertext_free(TfheCiphertext ct);
|
||||
|
||||
// Free a secret key (alias for backward compatibility)
|
||||
void tfhe_secret_key_free(TfheSecretKey sk);
|
||||
|
||||
// Clone a ciphertext
|
||||
TfheCiphertext tfhe_ciphertext_clone(TfheCiphertext ct);
|
||||
|
||||
// =============================================================================
|
||||
// Boolean Gates (with bootstrapping)
|
||||
// =============================================================================
|
||||
|
||||
TfheCiphertext tfhe_and(TfheContext ctx, TfheCiphertext ct1, TfheCiphertext ct2);
|
||||
TfheCiphertext tfhe_or(TfheContext ctx, TfheCiphertext ct1, TfheCiphertext ct2);
|
||||
TfheCiphertext tfhe_xor(TfheContext ctx, TfheCiphertext ct1, TfheCiphertext ct2);
|
||||
TfheCiphertext tfhe_nand(TfheContext ctx, TfheCiphertext ct1, TfheCiphertext ct2);
|
||||
TfheCiphertext tfhe_nor(TfheContext ctx, TfheCiphertext ct1, TfheCiphertext ct2);
|
||||
TfheCiphertext tfhe_xnor(TfheContext ctx, TfheCiphertext ct1, TfheCiphertext ct2);
|
||||
TfheCiphertext tfhe_not(TfheContext ctx, TfheCiphertext ct);
|
||||
TfheCiphertext tfhe_mux(TfheContext ctx, TfheCiphertext sel, TfheCiphertext ct1, TfheCiphertext ct2);
|
||||
|
||||
// =============================================================================
|
||||
// Integer Operations (radix representation)
|
||||
// =============================================================================
|
||||
|
||||
// Integer ciphertext handle
|
||||
typedef void* TfheInteger;
|
||||
|
||||
// Integer types
|
||||
typedef enum {
|
||||
TFHE_UINT4 = 4,
|
||||
TFHE_UINT8 = 8,
|
||||
TFHE_UINT16 = 16,
|
||||
TFHE_UINT32 = 32,
|
||||
TFHE_UINT64 = 64,
|
||||
TFHE_UINT128 = 128,
|
||||
TFHE_UINT160 = 160,
|
||||
TFHE_UINT256 = 256
|
||||
} TfheIntType;
|
||||
|
||||
// Encrypt an integer
|
||||
TfheInteger tfhe_encrypt_integer(TfheContext ctx, TfheSecretKey sk, int64_t value, int bitLen);
|
||||
|
||||
// Encrypt an integer with public key
|
||||
TfheInteger tfhe_encrypt_integer_public(TfheContext ctx, TfhePublicKey pk, int64_t value, int bitLen);
|
||||
|
||||
// Decrypt an integer
|
||||
int64_t tfhe_decrypt_integer(TfheContext ctx, TfheSecretKey sk, TfheInteger ct);
|
||||
|
||||
// Free an integer ciphertext
|
||||
void tfhe_integer_free(TfheInteger ct);
|
||||
|
||||
// Clone an integer ciphertext
|
||||
TfheInteger tfhe_integer_clone(TfheInteger ct);
|
||||
|
||||
// Get the type of an integer ciphertext
|
||||
TfheIntType tfhe_integer_type(TfheInteger ct);
|
||||
|
||||
// =============================================================================
|
||||
// Integer Arithmetic
|
||||
// =============================================================================
|
||||
|
||||
TfheInteger tfhe_add(TfheContext ctx, TfheInteger a, TfheInteger b);
|
||||
TfheInteger tfhe_sub(TfheContext ctx, TfheInteger a, TfheInteger b);
|
||||
TfheInteger tfhe_neg(TfheContext ctx, TfheInteger a);
|
||||
TfheInteger tfhe_add_scalar(TfheContext ctx, TfheInteger a, int64_t scalar);
|
||||
TfheInteger tfhe_sub_scalar(TfheContext ctx, TfheInteger a, int64_t scalar);
|
||||
TfheInteger tfhe_mul_scalar(TfheContext ctx, TfheInteger a, int64_t scalar);
|
||||
|
||||
// =============================================================================
|
||||
// Integer Comparisons
|
||||
// =============================================================================
|
||||
|
||||
TfheCiphertext tfhe_eq(TfheContext ctx, TfheInteger a, TfheInteger b);
|
||||
TfheCiphertext tfhe_ne(TfheContext ctx, TfheInteger a, TfheInteger b);
|
||||
TfheCiphertext tfhe_lt(TfheContext ctx, TfheInteger a, TfheInteger b);
|
||||
TfheCiphertext tfhe_le(TfheContext ctx, TfheInteger a, TfheInteger b);
|
||||
TfheCiphertext tfhe_gt(TfheContext ctx, TfheInteger a, TfheInteger b);
|
||||
TfheCiphertext tfhe_ge(TfheContext ctx, TfheInteger a, TfheInteger b);
|
||||
TfheInteger tfhe_min(TfheContext ctx, TfheInteger a, TfheInteger b);
|
||||
TfheInteger tfhe_max(TfheContext ctx, TfheInteger a, TfheInteger b);
|
||||
|
||||
// =============================================================================
|
||||
// Integer Bitwise Operations
|
||||
// =============================================================================
|
||||
|
||||
TfheInteger tfhe_bitwise_and(TfheContext ctx, TfheInteger a, TfheInteger b);
|
||||
TfheInteger tfhe_bitwise_or(TfheContext ctx, TfheInteger a, TfheInteger b);
|
||||
TfheInteger tfhe_bitwise_xor(TfheContext ctx, TfheInteger a, TfheInteger b);
|
||||
TfheInteger tfhe_bitwise_not(TfheContext ctx, TfheInteger a);
|
||||
TfheInteger tfhe_shl(TfheContext ctx, TfheInteger a, int bits);
|
||||
TfheInteger tfhe_shr(TfheContext ctx, TfheInteger a, int bits);
|
||||
|
||||
// =============================================================================
|
||||
// Control Flow
|
||||
// =============================================================================
|
||||
|
||||
TfheInteger tfhe_select(TfheContext ctx, TfheCiphertext cond, TfheInteger if_true, TfheInteger if_false);
|
||||
TfheInteger tfhe_cast_to(TfheContext ctx, TfheInteger a, int target_bitlen);
|
||||
|
||||
// =============================================================================
|
||||
// Serialization
|
||||
// =============================================================================
|
||||
|
||||
// Serialize ciphertext to bytes (returns malloc'd buffer, caller must free)
|
||||
uint8_t* tfhe_serialize_ciphertext(TfheContext ctx, TfheCiphertext ct, size_t* out_len);
|
||||
|
||||
// Deserialize ciphertext from bytes
|
||||
TfheCiphertext tfhe_deserialize_ciphertext(TfheContext ctx, const uint8_t* data, size_t len);
|
||||
|
||||
// Serialize secret key to bytes (returns malloc'd buffer, caller must free)
|
||||
uint8_t* tfhe_serialize_secret_key(TfheContext ctx, TfheSecretKey sk, size_t* out_len);
|
||||
|
||||
// Deserialize secret key from bytes
|
||||
TfheSecretKey tfhe_deserialize_secret_key(TfheContext ctx, const uint8_t* data, size_t len);
|
||||
|
||||
// Serialize public key to bytes (returns malloc'd buffer, caller must free)
|
||||
uint8_t* tfhe_serialize_public_key(TfheContext ctx, TfhePublicKey pk, size_t* out_len);
|
||||
|
||||
// Deserialize public key from bytes
|
||||
TfhePublicKey tfhe_deserialize_public_key(TfheContext ctx, const uint8_t* data, size_t len);
|
||||
|
||||
// Serialize integer ciphertext to bytes (returns malloc'd buffer, caller must free)
|
||||
uint8_t* tfhe_serialize_integer(TfheContext ctx, TfheInteger ct, size_t* out_len);
|
||||
|
||||
// Deserialize integer ciphertext from bytes
|
||||
TfheInteger tfhe_deserialize_integer(TfheContext ctx, const uint8_t* data, size_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // TFHE_BRIDGE_H
|
||||
@@ -1,149 +0,0 @@
|
||||
// Command fhe-gateway runs the blockchain event listener and job gateway.
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/luxfi/fhe/internal/queue"
|
||||
"github.com/luxfi/fhe/internal/storage"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if err := run(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func run() error {
|
||||
var (
|
||||
redisAddr = flag.String("redis", "localhost:6379", "Redis address")
|
||||
redisDB = flag.Int("redis-db", 0, "Redis database number")
|
||||
queueName = flag.String("queue", "default", "queue name")
|
||||
storagePath = flag.String("storage", "/tmp/fhe-storage", "ciphertext storage path")
|
||||
httpAddr = flag.String("http", ":8080", "HTTP API address")
|
||||
rpcURL = flag.String("rpc", "", "Blockchain RPC URL")
|
||||
)
|
||||
flag.Parse()
|
||||
|
||||
log.Printf("FHE Gateway starting...")
|
||||
log.Printf(" Redis: %s", *redisAddr)
|
||||
log.Printf(" Storage: %s", *storagePath)
|
||||
log.Printf(" HTTP: %s", *httpAddr)
|
||||
if *rpcURL != "" {
|
||||
log.Printf(" RPC: %s", *rpcURL)
|
||||
}
|
||||
|
||||
// Queue.
|
||||
q, err := queue.NewRedisQueue(queue.RedisConfig{
|
||||
Addr: *redisAddr,
|
||||
DB: *redisDB,
|
||||
}, *queueName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("create queue: %w", err)
|
||||
}
|
||||
defer q.Close()
|
||||
|
||||
// Storage.
|
||||
store, err := storage.NewFileStorage(*storagePath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("create storage: %w", err)
|
||||
}
|
||||
|
||||
// Context with cancellation.
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
// HTTP API.
|
||||
mux := http.NewServeMux()
|
||||
|
||||
mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte("ok"))
|
||||
})
|
||||
|
||||
mux.HandleFunc("/status", func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, `{"status":"running"}`)
|
||||
})
|
||||
|
||||
mux.HandleFunc("/job/", func(w http.ResponseWriter, r *http.Request) {
|
||||
jobID := r.URL.Path[len("/job/"):]
|
||||
if jobID == "" {
|
||||
http.Error(w, "job ID required", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
job, err := q.Get(r.Context(), jobID)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprintf(w, `{"id":"%s","status":%d,"result":"%s","error":"%s"}`,
|
||||
job.ID, job.Status, job.ResultHandle, job.Error)
|
||||
})
|
||||
|
||||
// Store ciphertext endpoint
|
||||
mux.HandleFunc("/store", func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "POST" {
|
||||
http.Error(w, "POST required", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
data := make([]byte, r.ContentLength)
|
||||
if _, err := r.Body.Read(data); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
handle, err := store.Store(r.Context(), data)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprintf(w, `{"handle":"%s"}`, handle)
|
||||
})
|
||||
|
||||
server := &http.Server{
|
||||
Addr: *httpAddr,
|
||||
Handler: mux,
|
||||
ReadTimeout: 10 * time.Second,
|
||||
WriteTimeout: 10 * time.Second,
|
||||
}
|
||||
|
||||
go func() {
|
||||
log.Printf("HTTP server starting on %s", *httpAddr)
|
||||
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||
log.Printf("HTTP server error: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Wait for shutdown signal.
|
||||
sigCh := make(chan os.Signal, 1)
|
||||
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
|
||||
|
||||
sig := <-sigCh
|
||||
log.Printf("Received signal: %s", sig.String())
|
||||
|
||||
// Graceful shutdown.
|
||||
shutdownCtx, shutdownCancel := context.WithTimeout(ctx, 30*time.Second)
|
||||
defer shutdownCancel()
|
||||
|
||||
if err := server.Shutdown(shutdownCtx); err != nil {
|
||||
log.Printf("HTTP server shutdown error: %v", err)
|
||||
}
|
||||
|
||||
log.Println("Shutdown complete")
|
||||
return nil
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
//go:build cgo
|
||||
|
||||
// Lux FHE Server - Standalone FHE service node
|
||||
//
|
||||
// Provides:
|
||||
// - FHE operations (encrypt, decrypt, evaluate)
|
||||
// - GPU-accelerated batch operations via MLX
|
||||
// - Threshold FHE decryption network
|
||||
// - ZK verification service
|
||||
// - Key management
|
||||
//
|
||||
// Run as sidecar for Solidity stack:
|
||||
//
|
||||
// fhe-server -addr :8448 -gpu
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/luxfi/fhe/server"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var (
|
||||
addr = flag.String("addr", ":8448", "HTTP server address")
|
||||
threshold = flag.Bool("threshold", false, "Enable threshold FHE mode")
|
||||
parties = flag.Int("parties", 5, "Number of threshold parties")
|
||||
dataDir = flag.String("data", "./data", "Data directory for keys")
|
||||
gpuMode = flag.Bool("gpu", false, "Enable GPU acceleration (Metal/CUDA)")
|
||||
batchSize = flag.Int("batch", 32, "Batch size for GPU operations")
|
||||
)
|
||||
flag.Parse()
|
||||
|
||||
log.Printf("Lux FHE Server starting...")
|
||||
log.Printf(" Address: %s", *addr)
|
||||
log.Printf(" GPU mode: %v", *gpuMode)
|
||||
log.Printf(" Threshold mode: %v", *threshold)
|
||||
if *threshold {
|
||||
log.Printf(" Parties: %d", *parties)
|
||||
}
|
||||
if *gpuMode {
|
||||
log.Printf(" Batch size: %d", *batchSize)
|
||||
}
|
||||
|
||||
// Create server config
|
||||
cfg := server.Config{
|
||||
Address: *addr,
|
||||
ThresholdMode: *threshold,
|
||||
NumParties: *parties,
|
||||
DataDir: *dataDir,
|
||||
GPUMode: *gpuMode,
|
||||
BatchSize: *batchSize,
|
||||
}
|
||||
|
||||
// Initialize FHE server
|
||||
srv, err := server.New(cfg)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create server: %v", err)
|
||||
}
|
||||
|
||||
// Setup HTTP server
|
||||
httpServer := &http.Server{
|
||||
Addr: cfg.Address,
|
||||
Handler: srv.Handler(),
|
||||
ReadTimeout: 30 * time.Second,
|
||||
WriteTimeout: 30 * time.Second,
|
||||
}
|
||||
|
||||
// Start server in goroutine
|
||||
go func() {
|
||||
log.Printf("FHE Server listening on %s", cfg.Address)
|
||||
if err := httpServer.ListenAndServe(); err != http.ErrServerClosed {
|
||||
log.Fatalf("HTTP server error: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Wait for shutdown signal
|
||||
quit := make(chan os.Signal, 1)
|
||||
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
||||
<-quit
|
||||
|
||||
log.Println("Shutting down FHE Server...")
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
if err := httpServer.Shutdown(ctx); err != nil {
|
||||
log.Printf("Server shutdown error: %v", err)
|
||||
}
|
||||
|
||||
fmt.Println("FHE Server stopped")
|
||||
}
|
||||
@@ -1,325 +0,0 @@
|
||||
// Command fhe-worker runs FHE computation workers.
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/luxfi/fhe"
|
||||
"github.com/luxfi/fhe/internal/queue"
|
||||
"github.com/luxfi/fhe/internal/storage"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if err := run(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func run() error {
|
||||
var (
|
||||
numWorkers = flag.Int("workers", 4, "number of worker goroutines")
|
||||
redisAddr = flag.String("redis", "localhost:6379", "Redis address")
|
||||
redisDB = flag.Int("redis-db", 0, "Redis database number")
|
||||
queueName = flag.String("queue", "default", "queue name")
|
||||
storagePath = flag.String("storage", "/tmp/fhe-storage", "ciphertext storage path")
|
||||
metricsAddr = flag.String("metrics", ":9090", "metrics server address")
|
||||
)
|
||||
flag.Parse()
|
||||
|
||||
log.Printf("FHE Worker starting...")
|
||||
log.Printf(" Workers: %d", *numWorkers)
|
||||
log.Printf(" Redis: %s", *redisAddr)
|
||||
log.Printf(" Storage: %s", *storagePath)
|
||||
log.Printf(" Metrics: %s", *metricsAddr)
|
||||
|
||||
// Queue.
|
||||
q, err := queue.NewRedisQueue(queue.RedisConfig{
|
||||
Addr: *redisAddr,
|
||||
DB: *redisDB,
|
||||
}, *queueName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("create queue: %w", err)
|
||||
}
|
||||
defer q.Close()
|
||||
|
||||
// Storage.
|
||||
store, err := storage.NewFileStorage(*storagePath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("create storage: %w", err)
|
||||
}
|
||||
|
||||
// Initialize FHE parameters
|
||||
params, err := fhe.NewParametersFromLiteral(fhe.PN10QP27)
|
||||
if err != nil {
|
||||
return fmt.Errorf("create FHE parameters: %w", err)
|
||||
}
|
||||
|
||||
kgen := fhe.NewKeyGenerator(params)
|
||||
sk := kgen.GenSecretKey()
|
||||
bsk := kgen.GenBootstrapKey(sk)
|
||||
|
||||
// Worker pool.
|
||||
pool := &WorkerPool{
|
||||
numWorkers: *numWorkers,
|
||||
queue: q,
|
||||
storage: store,
|
||||
params: params,
|
||||
bsk: bsk,
|
||||
sk: sk,
|
||||
}
|
||||
|
||||
// Context with cancellation.
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
// Start workers.
|
||||
if err := pool.Start(ctx); err != nil {
|
||||
return fmt.Errorf("start workers: %w", err)
|
||||
}
|
||||
|
||||
// Metrics server.
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte("ok"))
|
||||
})
|
||||
mux.HandleFunc("/metrics", func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, "# HELP fhe_operations_total Total FHE operations\n")
|
||||
fmt.Fprintf(w, "# TYPE fhe_operations_total counter\n")
|
||||
fmt.Fprintf(w, "fhe_operations_total{status=\"success\"} %d\n", pool.successCount.Load())
|
||||
fmt.Fprintf(w, "fhe_operations_total{status=\"failure\"} %d\n", pool.failureCount.Load())
|
||||
})
|
||||
|
||||
server := &http.Server{
|
||||
Addr: *metricsAddr,
|
||||
Handler: mux,
|
||||
}
|
||||
|
||||
go func() {
|
||||
log.Printf("Metrics server starting on %s", *metricsAddr)
|
||||
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||
log.Printf("Metrics server error: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Wait for shutdown signal.
|
||||
sigCh := make(chan os.Signal, 1)
|
||||
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
|
||||
|
||||
sig := <-sigCh
|
||||
log.Printf("Received signal: %s", sig.String())
|
||||
|
||||
// Graceful shutdown.
|
||||
shutdownCtx, shutdownCancel := context.WithTimeout(ctx, 30*time.Second)
|
||||
defer shutdownCancel()
|
||||
|
||||
if err := server.Shutdown(shutdownCtx); err != nil {
|
||||
log.Printf("Metrics server shutdown error: %v", err)
|
||||
}
|
||||
|
||||
if err := pool.Stop(); err != nil {
|
||||
log.Printf("Worker pool shutdown error: %v", err)
|
||||
}
|
||||
|
||||
log.Println("Shutdown complete")
|
||||
return nil
|
||||
}
|
||||
|
||||
// WorkerPool manages a pool of FHE computation workers.
|
||||
type WorkerPool struct {
|
||||
numWorkers int
|
||||
queue queue.Queue
|
||||
storage storage.Storage
|
||||
params fhe.Parameters
|
||||
bsk *fhe.BootstrapKey
|
||||
sk *fhe.SecretKey
|
||||
wg sync.WaitGroup
|
||||
cancel context.CancelFunc
|
||||
running atomic.Bool
|
||||
successCount atomic.Int64
|
||||
failureCount atomic.Int64
|
||||
}
|
||||
|
||||
// Start starts the worker pool.
|
||||
func (p *WorkerPool) Start(ctx context.Context) error {
|
||||
if p.running.Load() {
|
||||
return errors.New("pool already running")
|
||||
}
|
||||
|
||||
ctx, p.cancel = context.WithCancel(ctx)
|
||||
p.running.Store(true)
|
||||
|
||||
log.Printf("Starting %d workers", p.numWorkers)
|
||||
|
||||
for i := 0; i < p.numWorkers; i++ {
|
||||
p.wg.Add(1)
|
||||
go p.worker(ctx, i)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Stop gracefully stops the worker pool.
|
||||
func (p *WorkerPool) Stop() error {
|
||||
if !p.running.Load() {
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Println("Stopping worker pool...")
|
||||
p.cancel()
|
||||
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
p.wg.Wait()
|
||||
close(done)
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-done:
|
||||
log.Println("Worker pool stopped")
|
||||
case <-time.After(30 * time.Second):
|
||||
log.Println("Shutdown timeout exceeded")
|
||||
return errors.New("shutdown timeout")
|
||||
}
|
||||
|
||||
p.running.Store(false)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *WorkerPool) worker(ctx context.Context, id int) {
|
||||
defer p.wg.Done()
|
||||
|
||||
log.Printf("Worker %d started", id)
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
log.Printf("Worker %d stopping", id)
|
||||
return
|
||||
default:
|
||||
}
|
||||
|
||||
job, err := p.queue.Pop(ctx)
|
||||
if err != nil {
|
||||
if errors.Is(err, context.Canceled) {
|
||||
return
|
||||
}
|
||||
log.Printf("Worker %d: failed to pop job: %v", id, err)
|
||||
time.Sleep(time.Second)
|
||||
continue
|
||||
}
|
||||
|
||||
p.processJob(ctx, id, job)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *WorkerPool) processJob(ctx context.Context, workerID int, job *queue.Job) {
|
||||
log.Printf("Worker %d: processing job %s (op=%d)", workerID, job.ID, job.Operation)
|
||||
|
||||
// Mark as processing.
|
||||
job.Status = queue.StatusProcessing
|
||||
if err := p.queue.Update(ctx, job); err != nil {
|
||||
log.Printf("Worker %d: failed to update job status: %v", workerID, err)
|
||||
}
|
||||
|
||||
// Load ciphertexts
|
||||
lhsData, err := p.storage.Load(ctx, storage.Handle(job.LHSHandle))
|
||||
if err != nil {
|
||||
job.Status = queue.StatusFailed
|
||||
job.Error = fmt.Sprintf("load lhs: %v", err)
|
||||
p.queue.Update(ctx, job)
|
||||
p.failureCount.Add(1)
|
||||
return
|
||||
}
|
||||
|
||||
// Create evaluator
|
||||
bitwiseEval := fhe.NewBitwiseEvaluator(p.params, p.bsk, p.sk)
|
||||
|
||||
// Deserialize LHS
|
||||
lhs := new(fhe.BitCiphertext)
|
||||
if err := lhs.UnmarshalBinary(lhsData); err != nil {
|
||||
job.Status = queue.StatusFailed
|
||||
job.Error = fmt.Sprintf("unmarshal lhs: %v", err)
|
||||
p.queue.Update(ctx, job)
|
||||
p.failureCount.Add(1)
|
||||
return
|
||||
}
|
||||
|
||||
var result *fhe.BitCiphertext
|
||||
|
||||
// Execute operation
|
||||
switch job.Operation {
|
||||
case 0: // Add
|
||||
rhsData, err := p.storage.Load(ctx, storage.Handle(job.RHSHandle))
|
||||
if err != nil {
|
||||
job.Status = queue.StatusFailed
|
||||
job.Error = fmt.Sprintf("load rhs: %v", err)
|
||||
p.queue.Update(ctx, job)
|
||||
p.failureCount.Add(1)
|
||||
return
|
||||
}
|
||||
rhs := new(fhe.BitCiphertext)
|
||||
if err := rhs.UnmarshalBinary(rhsData); err != nil {
|
||||
job.Status = queue.StatusFailed
|
||||
job.Error = fmt.Sprintf("unmarshal rhs: %v", err)
|
||||
p.queue.Update(ctx, job)
|
||||
p.failureCount.Add(1)
|
||||
return
|
||||
}
|
||||
result, err = bitwiseEval.Add(lhs, rhs)
|
||||
if err != nil {
|
||||
job.Status = queue.StatusFailed
|
||||
job.Error = fmt.Sprintf("add: %v", err)
|
||||
p.queue.Update(ctx, job)
|
||||
p.failureCount.Add(1)
|
||||
return
|
||||
}
|
||||
default:
|
||||
job.Status = queue.StatusFailed
|
||||
job.Error = fmt.Sprintf("unsupported operation: %d", job.Operation)
|
||||
p.queue.Update(ctx, job)
|
||||
p.failureCount.Add(1)
|
||||
return
|
||||
}
|
||||
|
||||
// Store result
|
||||
resultData, err := result.MarshalBinary()
|
||||
if err != nil {
|
||||
job.Status = queue.StatusFailed
|
||||
job.Error = fmt.Sprintf("marshal result: %v", err)
|
||||
p.queue.Update(ctx, job)
|
||||
p.failureCount.Add(1)
|
||||
return
|
||||
}
|
||||
|
||||
handle, err := p.storage.Store(ctx, resultData)
|
||||
if err != nil {
|
||||
job.Status = queue.StatusFailed
|
||||
job.Error = fmt.Sprintf("store result: %v", err)
|
||||
p.queue.Update(ctx, job)
|
||||
p.failureCount.Add(1)
|
||||
return
|
||||
}
|
||||
|
||||
// Update job status.
|
||||
job.Status = queue.StatusCompleted
|
||||
job.ResultHandle = string(handle)
|
||||
if err := p.queue.Update(ctx, job); err != nil {
|
||||
log.Printf("Worker %d: failed to update job result: %v", workerID, err)
|
||||
}
|
||||
|
||||
p.successCount.Add(1)
|
||||
log.Printf("Worker %d: job %s completed", workerID, job.ID)
|
||||
}
|
||||
@@ -1,289 +0,0 @@
|
||||
// Copyright (c) 2025, Lux Industries Inc
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build profile
|
||||
|
||||
// Command profile runs performance profiling on FHE operations.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// go build -tags profile -o profile ./cmd/profile
|
||||
// ./profile -cpu=cpu.prof -mem=mem.prof -iterations=1000
|
||||
//
|
||||
// Analyze profiles:
|
||||
//
|
||||
// go tool pprof -http=:8080 cpu.prof
|
||||
// go tool pprof -http=:8081 mem.prof
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/luxfi/fhe"
|
||||
)
|
||||
|
||||
var (
|
||||
cpuProfile = flag.String("cpu", "", "write cpu profile to file")
|
||||
memProfile = flag.String("mem", "", "write memory profile to file")
|
||||
iterations = flag.Int("iterations", 100, "number of iterations for each operation")
|
||||
operation = flag.String("op", "all", "operation to profile: all, keygen, encrypt, gates, circuit")
|
||||
verbose = flag.Bool("v", false, "verbose output")
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
// Configure profiling
|
||||
config := fhe.ProfileConfig{
|
||||
CPUProfile: *cpuProfile,
|
||||
MemProfile: *memProfile,
|
||||
}
|
||||
|
||||
profiler := fhe.NewProfiler(config)
|
||||
if err := profiler.Start(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to start profiler: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
defer profiler.Stop()
|
||||
|
||||
// Run profiling workload
|
||||
fmt.Printf("Running %d iterations of '%s'\n", *iterations, *operation)
|
||||
fmt.Printf("GOMAXPROCS: %d\n", runtime.GOMAXPROCS(0))
|
||||
|
||||
switch *operation {
|
||||
case "all":
|
||||
profileAll()
|
||||
case "keygen":
|
||||
profileKeyGen()
|
||||
case "encrypt":
|
||||
profileEncrypt()
|
||||
case "gates":
|
||||
profileGates()
|
||||
case "circuit":
|
||||
profileCircuit()
|
||||
default:
|
||||
fmt.Fprintf(os.Stderr, "Unknown operation: %s\n", *operation)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fhe.PrintMemStats()
|
||||
}
|
||||
|
||||
func profileAll() {
|
||||
profileKeyGen()
|
||||
profileEncrypt()
|
||||
profileGates()
|
||||
profileCircuit()
|
||||
}
|
||||
|
||||
func profileKeyGen() {
|
||||
fmt.Println("\n=== Key Generation ===")
|
||||
|
||||
params, err := fhe.NewParametersFromLiteral(fhe.PN10QP27)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
kg := fhe.NewKeyGenerator(params)
|
||||
|
||||
// Secret key generation
|
||||
timer := fhe.NewTimer("SecretKey generation")
|
||||
for i := 0; i < *iterations; i++ {
|
||||
kg.GenSecretKey()
|
||||
}
|
||||
d := timer.Stop()
|
||||
fmt.Printf(" Average: %v/op\n", d/time.Duration(*iterations))
|
||||
|
||||
// Public key generation
|
||||
sk := kg.GenSecretKey()
|
||||
timer = fhe.NewTimer("PublicKey generation")
|
||||
for i := 0; i < *iterations; i++ {
|
||||
kg.GenPublicKey(sk)
|
||||
}
|
||||
d = timer.Stop()
|
||||
fmt.Printf(" Average: %v/op\n", d/time.Duration(*iterations))
|
||||
|
||||
// Bootstrap key generation (fewer iterations - expensive)
|
||||
bkIter := *iterations / 10
|
||||
if bkIter < 1 {
|
||||
bkIter = 1
|
||||
}
|
||||
timer = fhe.NewTimer(fmt.Sprintf("BootstrapKey generation (%d iter)", bkIter))
|
||||
for i := 0; i < bkIter; i++ {
|
||||
kg.GenBootstrapKey(sk)
|
||||
}
|
||||
d = timer.Stop()
|
||||
fmt.Printf(" Average: %v/op\n", d/time.Duration(bkIter))
|
||||
}
|
||||
|
||||
func profileEncrypt() {
|
||||
fmt.Println("\n=== Encryption/Decryption ===")
|
||||
|
||||
params, err := fhe.NewParametersFromLiteral(fhe.PN10QP27)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
kg := fhe.NewKeyGenerator(params)
|
||||
sk := kg.GenSecretKey()
|
||||
enc := fhe.NewEncryptor(params, sk)
|
||||
dec := fhe.NewDecryptor(params, sk)
|
||||
|
||||
// Bit encryption
|
||||
timer := fhe.NewTimer("Bit encryption")
|
||||
for i := 0; i < *iterations; i++ {
|
||||
enc.Encrypt(true)
|
||||
}
|
||||
d := timer.Stop()
|
||||
fmt.Printf(" Average: %v/op\n", d/time.Duration(*iterations))
|
||||
|
||||
// Bit decryption
|
||||
ct := enc.Encrypt(true)
|
||||
timer = fhe.NewTimer("Bit decryption")
|
||||
for i := 0; i < *iterations; i++ {
|
||||
dec.Decrypt(ct)
|
||||
}
|
||||
d = timer.Stop()
|
||||
fmt.Printf(" Average: %v/op\n", d/time.Duration(*iterations))
|
||||
|
||||
// Byte encryption
|
||||
timer = fhe.NewTimer("Byte encryption")
|
||||
for i := 0; i < *iterations; i++ {
|
||||
enc.EncryptByte(0x42)
|
||||
}
|
||||
d = timer.Stop()
|
||||
fmt.Printf(" Average: %v/op\n", d/time.Duration(*iterations))
|
||||
|
||||
// Byte decryption
|
||||
ctByte := enc.EncryptByte(0x42)
|
||||
timer = fhe.NewTimer("Byte decryption")
|
||||
for i := 0; i < *iterations; i++ {
|
||||
dec.DecryptByte(ctByte)
|
||||
}
|
||||
d = timer.Stop()
|
||||
fmt.Printf(" Average: %v/op\n", d/time.Duration(*iterations))
|
||||
}
|
||||
|
||||
func profileGates() {
|
||||
fmt.Println("\n=== Boolean Gates ===")
|
||||
|
||||
params, err := fhe.NewParametersFromLiteral(fhe.PN10QP27)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
kg := fhe.NewKeyGenerator(params)
|
||||
sk := kg.GenSecretKey()
|
||||
bk := kg.GenBootstrapKey(sk)
|
||||
enc := fhe.NewEncryptor(params, sk)
|
||||
eval := fhe.NewEvaluator(params, bk, sk)
|
||||
|
||||
ct1 := enc.Encrypt(true)
|
||||
ct2 := enc.Encrypt(false)
|
||||
|
||||
gates := []struct {
|
||||
name string
|
||||
fn func() error
|
||||
}{
|
||||
{"AND", func() error { _, err := eval.AND(ct1, ct2); return err }},
|
||||
{"OR", func() error { _, err := eval.OR(ct1, ct2); return err }},
|
||||
{"XOR", func() error { _, err := eval.XOR(ct1, ct2); return err }},
|
||||
{"NAND", func() error { _, err := eval.NAND(ct1, ct2); return err }},
|
||||
{"NOR", func() error { _, err := eval.NOR(ct1, ct2); return err }},
|
||||
{"XNOR", func() error { _, err := eval.XNOR(ct1, ct2); return err }},
|
||||
{"NOT", func() error { eval.NOT(ct1); return nil }},
|
||||
}
|
||||
|
||||
for _, gate := range gates {
|
||||
timer := fhe.NewTimer(gate.name)
|
||||
for i := 0; i < *iterations; i++ {
|
||||
if err := gate.fn(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
d := timer.Stop()
|
||||
fmt.Printf(" Average: %v/op\n", d/time.Duration(*iterations))
|
||||
}
|
||||
|
||||
// MUX
|
||||
ct3 := enc.Encrypt(true)
|
||||
timer := fhe.NewTimer("MUX")
|
||||
for i := 0; i < *iterations; i++ {
|
||||
_, err := eval.MUX(ct1, ct2, ct3)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
d := timer.Stop()
|
||||
fmt.Printf(" Average: %v/op\n", d/time.Duration(*iterations))
|
||||
}
|
||||
|
||||
func profileCircuit() {
|
||||
fmt.Println("\n=== Circuit Evaluation ===")
|
||||
|
||||
params, err := fhe.NewParametersFromLiteral(fhe.PN10QP27)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
kg := fhe.NewKeyGenerator(params)
|
||||
sk := kg.GenSecretKey()
|
||||
bk := kg.GenBootstrapKey(sk)
|
||||
enc := fhe.NewEncryptor(params, sk)
|
||||
eval := fhe.NewEvaluator(params, bk, sk)
|
||||
|
||||
// 8-bit adder circuit
|
||||
a := enc.EncryptByte(0x42)
|
||||
b := enc.EncryptByte(0x37)
|
||||
|
||||
timer := fhe.NewTimer("8-bit Addition")
|
||||
for i := 0; i < *iterations; i++ {
|
||||
carry := enc.Encrypt(false)
|
||||
for bit := 0; bit < 8; bit++ {
|
||||
// Full adder for each bit
|
||||
axorb, err := eval.XOR(a[bit], b[bit])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
_, err = eval.XOR(axorb, carry)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
aandb, err := eval.AND(a[bit], b[bit])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
candaxorb, err := eval.AND(carry, axorb)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
carry, err = eval.OR(aandb, candaxorb)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
d := timer.Stop()
|
||||
fmt.Printf(" Average: %v/op\n", d/time.Duration(*iterations))
|
||||
|
||||
// Gate chain (simulating complex circuit)
|
||||
n := 16
|
||||
cts := make([]*fhe.Ciphertext, n)
|
||||
for i := 0; i < n; i++ {
|
||||
cts[i] = enc.Encrypt(i%2 == 0)
|
||||
}
|
||||
|
||||
timer = fhe.NewTimer(fmt.Sprintf("AND chain (%d gates)", n-1))
|
||||
for i := 0; i < *iterations; i++ {
|
||||
result := cts[0]
|
||||
for j := 1; j < n; j++ {
|
||||
result, err = eval.AND(result, cts[j])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
d = timer.Stop()
|
||||
fmt.Printf(" Average: %v/op\n", d/time.Duration(*iterations))
|
||||
fmt.Printf(" Per gate: %v\n", d/time.Duration(*iterations*(n-1)))
|
||||
}
|
||||
-132
@@ -1,132 +0,0 @@
|
||||
name: luxfhe
|
||||
|
||||
services:
|
||||
# =============================================================================
|
||||
# FHE Server - Standard Mode (port 8448)
|
||||
# =============================================================================
|
||||
server:
|
||||
build:
|
||||
context: .
|
||||
target: server
|
||||
image: ghcr.io/luxfi/fhe/server:latest
|
||||
container_name: luxfhe-server
|
||||
ports:
|
||||
- "8448:8448"
|
||||
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 (port 8449)
|
||||
# =============================================================================
|
||||
server-threshold:
|
||||
build:
|
||||
context: .
|
||||
target: server
|
||||
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 Gateway - Blockchain Event Listener (port 8080)
|
||||
# =============================================================================
|
||||
gateway:
|
||||
build:
|
||||
context: .
|
||||
target: gateway
|
||||
image: ghcr.io/luxfi/fhe/gateway:latest
|
||||
container_name: luxfhe-gateway
|
||||
ports:
|
||||
- "8080:8080"
|
||||
environment:
|
||||
- RPC_URL=${RPC_URL:-http://host.docker.internal:8545}
|
||||
command: ["-http", ":8080", "-redis", "redis:6379", "-storage", "/app/data"]
|
||||
volumes:
|
||||
- fhe-storage:/app/data
|
||||
depends_on:
|
||||
redis:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-q", "-O", "-", "http://localhost:8080/health"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
profiles:
|
||||
- coprocessor
|
||||
|
||||
# =============================================================================
|
||||
# FHE Worker - Computation Workers (port 9090 metrics)
|
||||
# =============================================================================
|
||||
worker:
|
||||
build:
|
||||
context: .
|
||||
target: worker
|
||||
image: ghcr.io/luxfi/fhe/worker:latest
|
||||
deploy:
|
||||
replicas: 2
|
||||
command: ["-redis", "redis:6379", "-storage", "/app/data", "-workers", "4", "-metrics", ":9090"]
|
||||
volumes:
|
||||
- fhe-storage:/app/data
|
||||
depends_on:
|
||||
redis:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-q", "-O", "-", "http://localhost:9090/health"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
profiles:
|
||||
- coprocessor
|
||||
|
||||
# =============================================================================
|
||||
# Redis - Job Queue
|
||||
# =============================================================================
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: luxfhe-redis
|
||||
ports:
|
||||
- "6379:6379"
|
||||
volumes:
|
||||
- redis-data:/data
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 3
|
||||
profiles:
|
||||
- coprocessor
|
||||
|
||||
# =============================================================================
|
||||
# Anvil - Local Blockchain for 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:
|
||||
fhe-storage:
|
||||
redis-data:
|
||||
@@ -1,99 +0,0 @@
|
||||
// Copyright (c) 2025, Lux Industries Inc
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package fhe
|
||||
|
||||
import (
|
||||
"github.com/luxfi/lattice/v7/core/rlwe"
|
||||
"github.com/luxfi/lattice/v7/ring"
|
||||
)
|
||||
|
||||
// Decryptor decrypts FHE ciphertexts to boolean values
|
||||
type Decryptor struct {
|
||||
params Parameters
|
||||
decryptor *rlwe.Decryptor
|
||||
ringQ *ring.Ring
|
||||
}
|
||||
|
||||
// NewDecryptor creates a new decryptor from secret key
|
||||
func NewDecryptor(params Parameters, sk *SecretKey) *Decryptor {
|
||||
return &Decryptor{
|
||||
params: params,
|
||||
decryptor: rlwe.NewDecryptor(params.paramsLWE, sk.SKLWE),
|
||||
ringQ: params.paramsLWE.RingQ(),
|
||||
}
|
||||
}
|
||||
|
||||
// Decrypt decrypts a ciphertext to a boolean
|
||||
func (dec *Decryptor) Decrypt(ct *Ciphertext) bool {
|
||||
pt := rlwe.NewPlaintext(dec.params.paramsLWE, ct.Level())
|
||||
dec.decryptor.Decrypt(ct.Ciphertext, pt)
|
||||
|
||||
if pt.IsNTT {
|
||||
dec.ringQ.INTT(pt.Value, pt.Value)
|
||||
}
|
||||
|
||||
// Get the constant term
|
||||
c := pt.Value.Coeffs[0][0]
|
||||
q := dec.params.QLWE()
|
||||
qHalf := q >> 1
|
||||
|
||||
// Decode:
|
||||
// - true was encoded as Q/8, so c ∈ [0, Q/2) means true
|
||||
// - false was encoded as 7Q/8, so c ∈ [Q/2, Q) means false
|
||||
return c < qHalf
|
||||
}
|
||||
|
||||
// DecryptBit returns the decrypted bit as int (0 or 1)
|
||||
func (dec *Decryptor) DecryptBit(ct *Ciphertext) int {
|
||||
if dec.Decrypt(ct) {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// DecryptByte decrypts 8 ciphertexts to a byte
|
||||
func (dec *Decryptor) DecryptByte(cts [8]*Ciphertext) byte {
|
||||
var b byte
|
||||
for i := 0; i < 8; i++ {
|
||||
if dec.Decrypt(cts[i]) {
|
||||
b |= 1 << i
|
||||
}
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// DecryptUint32 decrypts 32 ciphertexts to uint32
|
||||
func (dec *Decryptor) DecryptUint32(cts [32]*Ciphertext) uint32 {
|
||||
var v uint32
|
||||
for i := 0; i < 32; i++ {
|
||||
if dec.Decrypt(cts[i]) {
|
||||
v |= 1 << i
|
||||
}
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// DecryptUint64 decrypts 64 ciphertexts to uint64
|
||||
func (dec *Decryptor) DecryptUint64(cts [64]*Ciphertext) uint64 {
|
||||
var v uint64
|
||||
for i := 0; i < 64; i++ {
|
||||
if dec.Decrypt(cts[i]) {
|
||||
v |= 1 << i
|
||||
}
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// DecryptUint256 decrypts 256 ciphertexts to 4 uint64s
|
||||
func (dec *Decryptor) DecryptUint256(cts [256]*Ciphertext) [4]uint64 {
|
||||
var v [4]uint64
|
||||
for w := 0; w < 4; w++ {
|
||||
for i := 0; i < 64; i++ {
|
||||
if dec.Decrypt(cts[w*64+i]) {
|
||||
v[w] |= 1 << i
|
||||
}
|
||||
}
|
||||
}
|
||||
return v
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
import { source } from '@/lib/source'
|
||||
import type { Metadata } from 'next'
|
||||
import { DocsPage, DocsBody, DocsTitle, DocsDescription } from 'fumadocs-ui/page'
|
||||
import { notFound } from 'next/navigation'
|
||||
import ReactMarkdown from 'react-markdown'
|
||||
import remarkGfm from 'remark-gfm'
|
||||
import rehypeHighlight from 'rehype-highlight'
|
||||
import 'highlight.js/styles/github-dark.css'
|
||||
|
||||
export default async function Page(props: {
|
||||
params: Promise<{ slug?: string[] }>
|
||||
}) {
|
||||
const params = await props.params
|
||||
const page = source.getPage(params.slug)
|
||||
if (!page) notFound()
|
||||
|
||||
return (
|
||||
<DocsPage toc={page.data.toc} full={page.data.full}>
|
||||
<DocsTitle>{page.data.title}</DocsTitle>
|
||||
<DocsDescription>{page.data.description}</DocsDescription>
|
||||
<DocsBody>
|
||||
<div className="prose prose-neutral dark:prose-invert max-w-none">
|
||||
<ReactMarkdown remarkPlugins={[remarkGfm]} rehypePlugins={[rehypeHighlight]}>
|
||||
{page.data.content}
|
||||
</ReactMarkdown>
|
||||
</div>
|
||||
</DocsBody>
|
||||
</DocsPage>
|
||||
)
|
||||
}
|
||||
|
||||
export async function generateStaticParams() {
|
||||
return source.generateParams()
|
||||
}
|
||||
|
||||
export async function generateMetadata(props: {
|
||||
params: Promise<{ slug?: string[] }>
|
||||
}): Promise<Metadata> {
|
||||
const params = await props.params
|
||||
const page = source.getPage(params.slug)
|
||||
if (!page) notFound()
|
||||
|
||||
return {
|
||||
title: page.data.title,
|
||||
description: page.data.description,
|
||||
}
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
import { DocsLayout } from 'fumadocs-ui/layouts/docs'
|
||||
import type { ReactNode } from 'react'
|
||||
import { ExternalLink, Github } from 'lucide-react'
|
||||
import { Logo, LogoWithText } from '@/components/logo'
|
||||
import { source } from '@/lib/source'
|
||||
|
||||
function DiscordIcon({ className }: { className?: string }) {
|
||||
return (
|
||||
<svg className={className} viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028 14.09 14.09 0 0 0 1.226-1.994.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.955-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.946 2.418-2.157 2.418z"/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
function XIcon({ className }: { className?: string }) {
|
||||
return (
|
||||
<svg className={className} viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
const DOCS_CONFIG = {
|
||||
name: 'Lux TFHE',
|
||||
github: 'https://github.com/luxfi/fhe',
|
||||
socials: {
|
||||
website: 'https://lux.network',
|
||||
discord: 'https://discord.gg/luxfi',
|
||||
twitter: 'https://x.com/luxdefi',
|
||||
},
|
||||
footerLinks: [
|
||||
{
|
||||
text: 'View on GitHub',
|
||||
url: 'https://github.com/luxfi/fhe',
|
||||
icon: 'github',
|
||||
},
|
||||
{
|
||||
text: 'Lux Network Docs',
|
||||
url: 'https://docs.lux.network',
|
||||
icon: 'external',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
export default function Layout({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<DocsLayout
|
||||
tree={source.pageTree}
|
||||
nav={{
|
||||
title: <LogoWithText size={24} name={DOCS_CONFIG.name} />,
|
||||
}}
|
||||
sidebar={{
|
||||
defaultOpenLevel: 1,
|
||||
footer: (
|
||||
<div className="flex flex-col gap-3 text-xs">
|
||||
<div className="flex items-center gap-3">
|
||||
<a
|
||||
href={DOCS_CONFIG.socials.website}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-fd-muted-foreground hover:text-fd-foreground transition-colors"
|
||||
title="Lux Network"
|
||||
>
|
||||
<Logo size={20} />
|
||||
</a>
|
||||
<a
|
||||
href={DOCS_CONFIG.socials.discord}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-fd-muted-foreground hover:text-fd-foreground transition-colors"
|
||||
title="Discord"
|
||||
>
|
||||
<DiscordIcon className="size-5" />
|
||||
</a>
|
||||
<a
|
||||
href={DOCS_CONFIG.socials.twitter}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-fd-muted-foreground hover:text-fd-foreground transition-colors"
|
||||
title="X"
|
||||
>
|
||||
<XIcon className="size-5" />
|
||||
</a>
|
||||
</div>
|
||||
{DOCS_CONFIG.footerLinks.map((link, index) => (
|
||||
<a
|
||||
key={index}
|
||||
href={link.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="flex items-center gap-2 text-fd-muted-foreground hover:text-fd-foreground transition-colors"
|
||||
>
|
||||
{link.icon === 'github' ? (
|
||||
<Github className="size-4" />
|
||||
) : (
|
||||
<ExternalLink className="size-4" />
|
||||
)}
|
||||
{link.text}
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
),
|
||||
}}
|
||||
|
||||
>
|
||||
{children}
|
||||
</DocsLayout>
|
||||
)
|
||||
}
|
||||
@@ -1,222 +0,0 @@
|
||||
/**
|
||||
* Lux TFHE Documentation Theme
|
||||
* Matches Lux Network documentation styling
|
||||
*/
|
||||
|
||||
@import 'tailwindcss';
|
||||
|
||||
@custom-variant dark (&:is(.dark *));
|
||||
|
||||
/* Light mode - clean minimal */
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 0 0% 9%;
|
||||
--card: 0 0% 100%;
|
||||
--card-foreground: 0 0% 9%;
|
||||
--popover: 0 0% 100%;
|
||||
--popover-foreground: 0 0% 9%;
|
||||
--primary: 0 0% 9%;
|
||||
--primary-foreground: 0 0% 100%;
|
||||
--secondary: 0 0% 96%;
|
||||
--secondary-foreground: 0 0% 9%;
|
||||
--muted: 0 0% 96%;
|
||||
--muted-foreground: 0 0% 45%;
|
||||
--accent: 0 0% 96%;
|
||||
--accent-foreground: 0 0% 9%;
|
||||
--border: 0 0% 90%;
|
||||
--input: 0 0% 90%;
|
||||
--ring: 0 0% 64%;
|
||||
|
||||
/* Fumadocs color overrides */
|
||||
--color-fd-background: hsl(0, 0%, 100%);
|
||||
--color-fd-foreground: hsl(0, 0%, 9%);
|
||||
--color-fd-muted: hsl(0, 0%, 96%);
|
||||
--color-fd-muted-foreground: hsl(0, 0%, 45%);
|
||||
--color-fd-popover: hsl(0, 0%, 100%);
|
||||
--color-fd-popover-foreground: hsl(0, 0%, 9%);
|
||||
--color-fd-card: hsl(0, 0%, 100%);
|
||||
--color-fd-card-foreground: hsl(0, 0%, 9%);
|
||||
--color-fd-border: hsl(0, 0%, 90%);
|
||||
--color-fd-primary: hsl(0, 0%, 9%);
|
||||
--color-fd-primary-foreground: hsl(0, 0%, 100%);
|
||||
--color-fd-secondary: hsl(0, 0%, 96%);
|
||||
--color-fd-secondary-foreground: hsl(0, 0%, 9%);
|
||||
--color-fd-accent: hsl(0, 0%, 96%);
|
||||
--color-fd-accent-foreground: hsl(0, 0%, 9%);
|
||||
--color-fd-ring: hsl(0, 0%, 64%);
|
||||
}
|
||||
|
||||
/* Dark mode - true black */
|
||||
.dark {
|
||||
--background: 0 0% 0%;
|
||||
--foreground: 0 0% 98%;
|
||||
--card: 0 0% 4%;
|
||||
--card-foreground: 0 0% 98%;
|
||||
--popover: 0 0% 4%;
|
||||
--popover-foreground: 0 0% 98%;
|
||||
--primary: 0 0% 98%;
|
||||
--primary-foreground: 0 0% 4%;
|
||||
--secondary: 0 0% 10%;
|
||||
--secondary-foreground: 0 0% 98%;
|
||||
--muted: 0 0% 8%;
|
||||
--muted-foreground: 0 0% 55%;
|
||||
--accent: 0 0% 12%;
|
||||
--accent-foreground: 0 0% 98%;
|
||||
--border: 0 0% 15%;
|
||||
--input: 0 0% 15%;
|
||||
--ring: 0 0% 36%;
|
||||
|
||||
/* Fumadocs dark overrides */
|
||||
--color-fd-background: hsl(0, 0%, 0%);
|
||||
--color-fd-foreground: hsl(0, 0%, 98%);
|
||||
--color-fd-muted: hsl(0, 0%, 8%);
|
||||
--color-fd-muted-foreground: hsl(0, 0%, 55%);
|
||||
--color-fd-popover: hsl(0, 0%, 4%);
|
||||
--color-fd-popover-foreground: hsl(0, 0%, 98%);
|
||||
--color-fd-card: hsl(0, 0%, 4%);
|
||||
--color-fd-card-foreground: hsl(0, 0%, 98%);
|
||||
--color-fd-border: hsl(0, 0%, 15%);
|
||||
--color-fd-primary: hsl(0, 0%, 98%);
|
||||
--color-fd-primary-foreground: hsl(0, 0%, 4%);
|
||||
--color-fd-secondary: hsl(0, 0%, 10%);
|
||||
--color-fd-secondary-foreground: hsl(0, 0%, 98%);
|
||||
--color-fd-accent: hsl(0, 0%, 12%);
|
||||
--color-fd-accent-foreground: hsl(0, 0%, 98%);
|
||||
--color-fd-ring: hsl(0, 0%, 36%);
|
||||
}
|
||||
|
||||
/* Base styles */
|
||||
* {
|
||||
border-color: hsl(var(--border));
|
||||
}
|
||||
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
body {
|
||||
font-synthesis-weight: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
|
||||
/* Selection */
|
||||
::selection {
|
||||
background: rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.dark ::selection {
|
||||
background: rgba(255, 255, 255, 0.20);
|
||||
}
|
||||
|
||||
/* Code blocks - dark theme */
|
||||
pre {
|
||||
background: #0d0d0d !important;
|
||||
color: #e8e8e8;
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
border-radius: 0.625rem;
|
||||
padding: 1rem;
|
||||
overflow-x: auto;
|
||||
line-height: 1.5;
|
||||
font-variant-ligatures: none;
|
||||
}
|
||||
|
||||
pre code {
|
||||
background: transparent !important;
|
||||
border: none !important;
|
||||
padding: 0 !important;
|
||||
font-size: inherit;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
/* Inline code */
|
||||
:not(pre) > code {
|
||||
background: hsl(var(--muted));
|
||||
border-radius: 0.375rem;
|
||||
padding: 0.2em 0.45em;
|
||||
font-size: 0.875em;
|
||||
}
|
||||
|
||||
/* Remove typography plugin backticks */
|
||||
code::before,
|
||||
code::after {
|
||||
content: none !important;
|
||||
}
|
||||
|
||||
/* Tables */
|
||||
th {
|
||||
background: hsl(var(--muted) / 0.4);
|
||||
}
|
||||
|
||||
tr:hover td {
|
||||
background: hsl(var(--muted) / 0.2);
|
||||
}
|
||||
|
||||
/* Blockquotes */
|
||||
blockquote {
|
||||
border-left: 3px solid hsl(var(--primary) / 0.3);
|
||||
background: hsl(var(--muted) / 0.3);
|
||||
border-radius: 0 0.5rem 0.5rem 0;
|
||||
}
|
||||
|
||||
/* Typography improvements */
|
||||
h2 {
|
||||
padding-bottom: 0.75rem;
|
||||
border-bottom: 1px solid hsl(var(--border) / 0.4);
|
||||
}
|
||||
|
||||
/* Sidebar refinements */
|
||||
aside[role="complementary"] {
|
||||
border-right: 1px solid hsl(var(--border) / 0.5);
|
||||
}
|
||||
|
||||
/* Hide mobile subnav header on desktop */
|
||||
@media (min-width: 768px) {
|
||||
header#nd-subnav {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* TOC refinements */
|
||||
nav[aria-label="Table of Contents"] {
|
||||
border-left: 1px solid hsl(var(--border) / 0.3);
|
||||
}
|
||||
|
||||
/* Sidebar footer - social icons left, theme toggle right */
|
||||
aside .border-t.p-4.pt-2 {
|
||||
flex-direction: row !important;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
/* Theme toggle div pushed to right */
|
||||
aside .border-t.p-4.pt-2 > div:first-child {
|
||||
flex-shrink: 0;
|
||||
order: 1;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
/* Social icons come first (left side) */
|
||||
aside .border-t.p-4.pt-2 > div:last-child > div:first-child {
|
||||
order: 0;
|
||||
}
|
||||
|
||||
/* Our footer content - social icons inline, links below */
|
||||
aside .border-t.p-4.pt-2 > div:last-child {
|
||||
display: contents;
|
||||
}
|
||||
|
||||
/* Social icons row inline with theme toggle */
|
||||
aside .border-t.p-4.pt-2 > div:last-child > div:first-child {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
/* Text links on new row, full width, after theme toggle */
|
||||
aside .border-t.p-4.pt-2 > div:last-child > a {
|
||||
width: 100%;
|
||||
flex-basis: 100%;
|
||||
order: 2;
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
import type { ReactNode } from 'react'
|
||||
import { RootProvider } from 'fumadocs-ui/provider'
|
||||
import { Geist, Geist_Mono } from 'next/font/google'
|
||||
import 'fumadocs-ui/style.css'
|
||||
import './globals.css'
|
||||
|
||||
const geist = Geist({
|
||||
subsets: ['latin'],
|
||||
variable: '--font-geist',
|
||||
display: 'swap',
|
||||
})
|
||||
|
||||
const geistMono = Geist_Mono({
|
||||
subsets: ['latin'],
|
||||
variable: '--font-geist-mono',
|
||||
display: 'swap',
|
||||
})
|
||||
|
||||
// ============================================================================
|
||||
// CONFIGURE YOUR DOCS SITE HERE
|
||||
// ============================================================================
|
||||
const SITE_CONFIG = {
|
||||
name: 'Lux TFHE',
|
||||
description: 'Threshold Fully Homomorphic Encryption for the Lux Network. Compute on encrypted data without ever decrypting it. Multi-GPU acceleration with Metal, CUDA, and CPU backends.',
|
||||
url: 'https://tfhe.lux.network',
|
||||
keywords: ['TFHE', 'FHE', 'homomorphic encryption', 'threshold encryption', 'Lux Network', 'GPU', 'CUDA', 'Metal', 'MLX', 'privacy', 'confidential computing'],
|
||||
}
|
||||
|
||||
export const metadata = {
|
||||
title: {
|
||||
default: SITE_CONFIG.name,
|
||||
template: `%s | ${SITE_CONFIG.name}`,
|
||||
},
|
||||
description: SITE_CONFIG.description,
|
||||
keywords: SITE_CONFIG.keywords,
|
||||
authors: [{ name: 'Lux Network' }],
|
||||
metadataBase: new URL(SITE_CONFIG.url),
|
||||
icons: {
|
||||
icon: '/favicon.svg',
|
||||
apple: '/favicon.svg',
|
||||
},
|
||||
openGraph: {
|
||||
title: SITE_CONFIG.name,
|
||||
description: SITE_CONFIG.description,
|
||||
type: 'website',
|
||||
siteName: SITE_CONFIG.name,
|
||||
images: [
|
||||
{
|
||||
url: '/og.png',
|
||||
width: 1200,
|
||||
height: 630,
|
||||
alt: SITE_CONFIG.name,
|
||||
},
|
||||
],
|
||||
},
|
||||
twitter: {
|
||||
card: 'summary_large_image',
|
||||
title: SITE_CONFIG.name,
|
||||
description: SITE_CONFIG.description,
|
||||
images: ['/og.png'],
|
||||
},
|
||||
}
|
||||
|
||||
export default function RootLayout({
|
||||
children
|
||||
}: {
|
||||
children: ReactNode
|
||||
}) {
|
||||
return (
|
||||
<html lang="en" className={`${geist.variable} ${geistMono.variable}`} suppressHydrationWarning>
|
||||
<head>
|
||||
{/* Prevent flash - respect system preference */}
|
||||
<script
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `
|
||||
(function() {
|
||||
document.documentElement.classList.add('dark');
|
||||
})();
|
||||
`,
|
||||
}}
|
||||
/>
|
||||
</head>
|
||||
<body className="min-h-screen bg-background font-sans antialiased">
|
||||
<RootProvider
|
||||
theme={{
|
||||
enabled: true,
|
||||
defaultTheme: 'dark',
|
||||
}}
|
||||
>
|
||||
<div className="relative flex min-h-screen flex-col">
|
||||
{children}
|
||||
</div>
|
||||
</RootProvider>
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import { redirect } from 'next/navigation'
|
||||
|
||||
export default function HomePage() {
|
||||
redirect('/docs')
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
'use client'
|
||||
|
||||
import { getMenuBarSVG } from '@luxfi/logo'
|
||||
|
||||
interface LogoProps {
|
||||
size?: number
|
||||
className?: string
|
||||
}
|
||||
|
||||
export function Logo({ size = 24, className = '' }: LogoProps) {
|
||||
const svg = getMenuBarSVG()
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`logo-container inline-block ${className}`}
|
||||
style={{ width: size, height: size }}
|
||||
dangerouslySetInnerHTML={{ __html: svg }}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
interface LogoWithTextProps {
|
||||
size?: number
|
||||
name?: string
|
||||
}
|
||||
|
||||
export function LogoWithText({ size = 24, name = 'Docs' }: LogoWithTextProps) {
|
||||
return (
|
||||
<div className="flex items-center gap-2 group">
|
||||
<Logo
|
||||
size={size}
|
||||
className="transition-transform duration-200 group-hover:scale-110"
|
||||
/>
|
||||
<span className="font-bold text-lg">{name}</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,168 +0,0 @@
|
||||
---
|
||||
title: API Reference
|
||||
description: Complete API documentation for Lux FHE
|
||||
---
|
||||
|
||||
# API Reference
|
||||
|
||||
## Integer Types
|
||||
|
||||
| Type | Bits | Use Case |
|
||||
|------|------|----------|
|
||||
| `FheBool` | 1 | Boolean flags, comparison results |
|
||||
| `FheUint4` | 4 | Nibbles, small counters |
|
||||
| `FheUint8` | 8 | Bytes, small integers |
|
||||
| `FheUint16` | 16 | Short integers |
|
||||
| `FheUint32` | 32 | Standard integers |
|
||||
| `FheUint64` | 64 | Large integers |
|
||||
| `FheUint128` | 128 | UUIDs, very large values |
|
||||
| `FheUint160` | 160 | Ethereum addresses |
|
||||
| `FheUint256` | 256 | EVM word size |
|
||||
|
||||
## Key Types
|
||||
|
||||
### SecretKey
|
||||
|
||||
The private key used for decryption. **Never share this key.**
|
||||
|
||||
### PublicKey
|
||||
|
||||
The public key used for encryption. Can be freely shared with users.
|
||||
|
||||
### BootstrapKey
|
||||
|
||||
The key used for homomorphic operations. Share with computation servers.
|
||||
|
||||
## Encryptors
|
||||
|
||||
### BitwiseEncryptor (Secret Key)
|
||||
|
||||
```go
|
||||
enc := tfhe.NewBitwiseEncryptor(params, sk)
|
||||
ct := enc.EncryptUint64(value, tfhe.FheUint8)
|
||||
```
|
||||
|
||||
### BitwisePublicEncryptor (Public Key)
|
||||
|
||||
```go
|
||||
pubEnc := tfhe.NewBitwisePublicEncryptor(params, pk)
|
||||
ct := pubEnc.EncryptUint64(value, tfhe.FheUint8)
|
||||
```
|
||||
|
||||
## Decryptor
|
||||
|
||||
```go
|
||||
dec := tfhe.NewBitwiseDecryptor(params, sk)
|
||||
value := dec.DecryptUint64(ct)
|
||||
```
|
||||
|
||||
## Evaluator
|
||||
|
||||
### Arithmetic Operations
|
||||
|
||||
```go
|
||||
eval := tfhe.NewBitwiseEvaluator(params, bsk, sk)
|
||||
|
||||
// Addition
|
||||
sum, err := eval.Add(a, b)
|
||||
|
||||
// Subtraction
|
||||
diff, err := eval.Sub(a, b)
|
||||
|
||||
// Scalar addition (add plaintext constant)
|
||||
result, err := eval.ScalarAdd(a, 5)
|
||||
|
||||
// Negation
|
||||
neg, err := eval.Neg(a)
|
||||
```
|
||||
|
||||
### Comparison Operations
|
||||
|
||||
```go
|
||||
// All comparisons return a single encrypted bit (FheBool)
|
||||
eq, err := eval.Eq(a, b) // Equal
|
||||
lt, err := eval.Lt(a, b) // Less than
|
||||
le, err := eval.Le(a, b) // Less than or equal
|
||||
gt, err := eval.Gt(a, b) // Greater than
|
||||
ge, err := eval.Ge(a, b) // Greater than or equal
|
||||
|
||||
// Min/Max return the minimum/maximum of two values
|
||||
min, err := eval.Min(a, b)
|
||||
max, err := eval.Max(a, b)
|
||||
```
|
||||
|
||||
### Bitwise Operations
|
||||
|
||||
```go
|
||||
and, err := eval.And(a, b) // Bitwise AND
|
||||
or, err := eval.Or(a, b) // Bitwise OR
|
||||
xor, err := eval.Xor(a, b) // Bitwise XOR
|
||||
not, err := eval.Not(a) // Bitwise NOT
|
||||
```
|
||||
|
||||
### Shift Operations
|
||||
|
||||
```go
|
||||
left, err := eval.Shl(a, 2) // Shift left by 2
|
||||
right, err := eval.Shr(a, 2) // Shift right by 2
|
||||
```
|
||||
|
||||
### Selection
|
||||
|
||||
```go
|
||||
// Select based on encrypted condition (MUX)
|
||||
// Returns a if cond is true, b otherwise
|
||||
result, err := eval.Select(cond, a, b)
|
||||
```
|
||||
|
||||
### Type Conversion
|
||||
|
||||
```go
|
||||
// Convert from one type to another
|
||||
result, err := eval.CastTo(value, tfhe.FheUint16)
|
||||
```
|
||||
|
||||
## Boolean Gates
|
||||
|
||||
For low-level operations on individual encrypted bits:
|
||||
|
||||
```go
|
||||
boolEval := tfhe.NewEvaluator(params, bsk)
|
||||
|
||||
and := boolEval.And(a, b)
|
||||
or := boolEval.Or(a, b)
|
||||
xor := boolEval.Xor(a, b)
|
||||
not := boolEval.Not(a)
|
||||
nand := boolEval.Nand(a, b)
|
||||
nor := boolEval.Nor(a, b)
|
||||
xnor := boolEval.Xnor(a, b)
|
||||
mux := boolEval.Mux(cond, a, b)
|
||||
```
|
||||
|
||||
## Serialization
|
||||
|
||||
```go
|
||||
// Serialize ciphertext
|
||||
bytes, err := ct.MarshalBinary()
|
||||
|
||||
// Deserialize ciphertext
|
||||
ct := new(tfhe.BitCiphertext)
|
||||
err := ct.UnmarshalBinary(bytes)
|
||||
|
||||
// Keys can also be serialized
|
||||
skBytes, _ := sk.MarshalBinary()
|
||||
pkBytes, _ := pk.MarshalBinary()
|
||||
bskBytes, _ := bsk.MarshalBinary()
|
||||
```
|
||||
|
||||
## Random Number Generation
|
||||
|
||||
```go
|
||||
// Secret key RNG (for trusted environments)
|
||||
rng := tfhe.NewFheRNG(params, sk, seed)
|
||||
randomCt := rng.RandomUint(tfhe.FheUint8)
|
||||
|
||||
// Public key RNG (for untrusted environments)
|
||||
pubRng := tfhe.NewFheRNGPublic(params, pk, seed)
|
||||
randomCt := pubRng.RandomUint(tfhe.FheUint8)
|
||||
```
|
||||
@@ -1,112 +0,0 @@
|
||||
---
|
||||
title: Benchmarks
|
||||
description: Performance characteristics of Lux FHE
|
||||
---
|
||||
|
||||
# Benchmarks
|
||||
|
||||
All benchmarks run on Apple M1 Max (ARM64).
|
||||
|
||||
## Summary Comparison
|
||||
|
||||
| Operation | Pure Go | OpenFHE (CGO) | Winner |
|
||||
|-----------|---------|---------------|--------|
|
||||
| SecretKey Gen | 41.7 µs | 14.4 µs | CGO 2.9x |
|
||||
| BootstrapKey Gen | 131.9 ms | 2413 ms | **Go 18x** |
|
||||
| Encrypt Bit | 20.8 µs | 27.7 µs | Go 1.3x |
|
||||
| Decrypt Bit | 4.5 µs | 1.4 µs | CGO 3.2x |
|
||||
| NOT | 1.2 µs | 1.4 µs | ~Same |
|
||||
| AND | 51.3 ms | 56.2 ms | **Go 1.10x** |
|
||||
| OR | 52.3 ms | 56.4 ms | **Go 1.08x** |
|
||||
| XOR | 51.2 ms | 56.3 ms | **Go 1.10x** |
|
||||
| NAND | 52.0 ms | 56.4 ms | **Go 1.08x** |
|
||||
| NOR | 52.2 ms | 56.3 ms | **Go 1.08x** |
|
||||
| XNOR | 51.0 ms | 57.6 ms | **Go 1.13x** |
|
||||
|
||||
**Key Findings:**
|
||||
- Pure Go bootstrap key gen is **18x faster** than OpenFHE
|
||||
- Pure Go is faster for **ALL gates** (~51ms vs ~56ms)
|
||||
- XOR/XNOR optimized to use single bootstrap
|
||||
|
||||
## Boolean Gate Operations
|
||||
|
||||
| Operation | Time | Memory | Allocs |
|
||||
|-----------|------|--------|--------|
|
||||
| NOT | 1.2 µs | 8.9 KB | 11 |
|
||||
| AND | 51.3 ms | 1.2 MB | 38K |
|
||||
| OR | 52.3 ms | 1.2 MB | 38K |
|
||||
| XOR | 51.2 ms | 1.2 MB | 38K |
|
||||
| NAND | 52.0 ms | 1.2 MB | 38K |
|
||||
| NOR | 52.2 ms | 1.2 MB | 38K |
|
||||
| XNOR | 51.0 ms | 1.2 MB | 38K |
|
||||
| MUX | 158.4 ms | 3.6 MB | 114K |
|
||||
|
||||
## Multi-Input Gates
|
||||
|
||||
| Operation | Time | Memory | Notes |
|
||||
|-----------|------|--------|-------|
|
||||
| AND3 | 117.2 ms | 2.4 MB | 2 bootstraps |
|
||||
| OR3 | 118.7 ms | 2.4 MB | 2 bootstraps |
|
||||
| MAJORITY | 58.6 ms | 1.2 MB | **1 bootstrap** |
|
||||
|
||||
## Integer Encryption/Decryption
|
||||
|
||||
| Operation | Time | Memory | Allocs |
|
||||
|-----------|------|--------|--------|
|
||||
| Encrypt 8-bit | 166.8 µs | 128 KB | 234 |
|
||||
| Encrypt 16-bit | 326.6 µs | 256 KB | 466 |
|
||||
| Encrypt 32-bit | 663.5 µs | 512 KB | 930 |
|
||||
| Decrypt 8-bit | 36.5 µs | 37.9 KB | 64 |
|
||||
| Decrypt 16-bit | 74.0 µs | 75.8 KB | 128 |
|
||||
|
||||
## Integer Arithmetic (8-bit)
|
||||
|
||||
| Operation | Time | Memory | Allocs |
|
||||
|-----------|------|--------|--------|
|
||||
| Add | 3.50 s | 81.2 MB | 2.6M |
|
||||
| Sub | 5.20 s | 115.1 MB | 3.6M |
|
||||
| ScalarAdd | 1.61 s | 36.2 MB | 1.1M |
|
||||
|
||||
## Integer Comparisons (8-bit)
|
||||
|
||||
| Operation | Time | Memory | Allocs |
|
||||
|-----------|------|--------|--------|
|
||||
| Eq | 1.74 s | 37.3 MB | 1.2M |
|
||||
| Lt | 2.91 s | 64.0 MB | 2.0M |
|
||||
| Le | 4.52 s | 102.8 MB | 3.2M |
|
||||
| Gt | 2.78 s | 64.1 MB | 2.0M |
|
||||
| Min | 4.00 s | 93.1 MB | 2.9M |
|
||||
| Max | 4.01 s | 93.0 MB | 2.9M |
|
||||
|
||||
## Bitwise Operations (8-bit)
|
||||
|
||||
| Operation | Time | Memory | Allocs |
|
||||
|-----------|------|--------|--------|
|
||||
| AND | 420.5 ms | 9.7 MB | 306K |
|
||||
| OR | 429.2 ms | 9.6 MB | 304K |
|
||||
| XOR | 1.45 s | 29.0 MB | 916K |
|
||||
| NOT | 10.5 µs | 71.0 KB | 90 |
|
||||
| Shl | 9.9 µs | 35.4 KB | 42 |
|
||||
| Shr | 9.6 µs | 35.4 KB | 42 |
|
||||
|
||||
## Running Benchmarks
|
||||
|
||||
```bash
|
||||
# All benchmarks
|
||||
go test -bench=. -benchmem -run=^$ .
|
||||
|
||||
# Only lattice benchmarks
|
||||
go test -bench=BenchmarkLattice -benchmem -run=^$ .
|
||||
|
||||
# With memory profiling
|
||||
go test -bench=BenchmarkLatticeAdd8 -benchmem -memprofile=mem.prof -run=^$ .
|
||||
```
|
||||
|
||||
## Recommendations
|
||||
|
||||
| Use Case | Recommended Backend |
|
||||
|----------|---------------------|
|
||||
| Startup-sensitive (key gen) | Pure Go |
|
||||
| All boolean circuits | Pure Go (faster) |
|
||||
| No C++ dependencies needed | Pure Go |
|
||||
| Maximum integer performance | OpenFHE (GPU future) |
|
||||
@@ -1,243 +0,0 @@
|
||||
---
|
||||
title: GPU Acceleration
|
||||
description: Multi-GPU FHE acceleration with Metal (macOS) and CUDA (Linux/Windows)
|
||||
---
|
||||
|
||||
# GPU Acceleration
|
||||
|
||||
Lux FHE supports massively parallel bootstrapping on GPUs, providing 10-100x speedup for batch operations.
|
||||
|
||||
## Supported Backends
|
||||
|
||||
| Backend | Platform | Hardware | Status |
|
||||
|---------|----------|----------|--------|
|
||||
| Metal/MLX | macOS 13+ | Apple Silicon (M1/M2/M3) | ✅ Production |
|
||||
| CUDA | Linux/Windows | NVIDIA GPU (Compute 7.0+) | 🚧 In Development |
|
||||
| CPU | Any | Any | ✅ Fallback |
|
||||
|
||||
## macOS Setup (Metal/MLX)
|
||||
|
||||
Metal acceleration works out of the box on Apple Silicon Macs:
|
||||
|
||||
```go
|
||||
import "github.com/luxfi/fhe/gpu"
|
||||
|
||||
// Auto-detect Metal GPU
|
||||
cfg := gpu.Config{
|
||||
Backends: []string{"metal", "cpu"}, // Fallback to CPU if Metal unavailable
|
||||
}
|
||||
|
||||
engine, err := gpu.New(cfg)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer engine.Close()
|
||||
|
||||
// Check what backend was selected
|
||||
info := engine.Info()
|
||||
fmt.Printf("Using: %s (%s)\n", info.Backend, info.DeviceName)
|
||||
// Output: Using: metal (Apple M1 Max)
|
||||
```
|
||||
|
||||
## Linux/Windows Setup (CUDA)
|
||||
|
||||
CUDA acceleration requires the NVIDIA CUDA Toolkit:
|
||||
|
||||
```bash
|
||||
# Install CUDA Toolkit (Ubuntu/Debian)
|
||||
sudo apt install nvidia-cuda-toolkit
|
||||
|
||||
# Or download from NVIDIA
|
||||
# https://developer.nvidia.com/cuda-downloads
|
||||
```
|
||||
|
||||
```go
|
||||
cfg := gpu.Config{
|
||||
Backends: []string{"cuda", "cpu"},
|
||||
}
|
||||
|
||||
engine, _ := gpu.New(cfg)
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
```go
|
||||
type Config struct {
|
||||
// Backends in priority order
|
||||
// Options: "metal", "cuda", "cpu"
|
||||
Backends []string
|
||||
|
||||
// Maximum ciphertexts per batch
|
||||
// Larger = more parallelism, more memory
|
||||
MaxBatchSize int // Default: 1024
|
||||
|
||||
// GPU memory limit in bytes
|
||||
// 0 = use all available
|
||||
MemoryLimit int64 // Default: 0
|
||||
|
||||
// Number of GPU streams (CUDA only)
|
||||
NumStreams int // Default: 4
|
||||
|
||||
// Enable async execution
|
||||
Async bool // Default: true
|
||||
}
|
||||
```
|
||||
|
||||
## Batch Operations
|
||||
|
||||
The GPU engine excels at batch operations:
|
||||
|
||||
```go
|
||||
// Single operation (minimal speedup)
|
||||
result, _ := engine.Bootstrap(ct, bsk)
|
||||
|
||||
// Batch operation (10-100x speedup)
|
||||
results, _ := engine.BatchBootstrap(ciphertexts, bsk)
|
||||
|
||||
// Boolean gates on encrypted integers
|
||||
sumCts, _ := engine.BatchAdd(aInts, bInts, bsk)
|
||||
```
|
||||
|
||||
## Performance Characteristics
|
||||
|
||||
### Batch Size vs Throughput
|
||||
|
||||
| Batch Size | M1 Max (Metal) | RTX 4090 (CUDA) |
|
||||
|------------|----------------|-----------------|
|
||||
| 1 | ~50 ms | ~40 ms |
|
||||
| 10 | ~60 ms | ~45 ms |
|
||||
| 100 | ~150 ms | ~100 ms |
|
||||
| 1000 | ~500 ms | ~300 ms |
|
||||
| 10000 | ~4 s | ~2.5 s |
|
||||
|
||||
*Throughput increases dramatically with batch size.*
|
||||
|
||||
### Memory Requirements
|
||||
|
||||
| Batch Size | GPU Memory |
|
||||
|------------|------------|
|
||||
| 100 | ~500 MB |
|
||||
| 1000 | ~2 GB |
|
||||
| 10000 | ~8 GB |
|
||||
|
||||
## Multi-GPU Support
|
||||
|
||||
For systems with multiple GPUs:
|
||||
|
||||
```go
|
||||
cfg := gpu.Config{
|
||||
Backends: []string{"cuda"},
|
||||
DeviceIndex: 0, // GPU 0
|
||||
}
|
||||
engine0, _ := gpu.New(cfg)
|
||||
|
||||
cfg.DeviceIndex = 1 // GPU 1
|
||||
engine1, _ := gpu.New(cfg)
|
||||
|
||||
// Distribute work across GPUs
|
||||
go engine0.BatchBootstrap(batch1, bsk)
|
||||
go engine1.BatchBootstrap(batch2, bsk)
|
||||
```
|
||||
|
||||
## Async Execution
|
||||
|
||||
For maximum throughput with streaming data:
|
||||
|
||||
```go
|
||||
cfg := gpu.Config{
|
||||
Backends: []string{"metal"},
|
||||
Async: true,
|
||||
}
|
||||
engine, _ := gpu.New(cfg)
|
||||
|
||||
// Submit work without blocking
|
||||
future1 := engine.BatchBootstrapAsync(batch1, bsk)
|
||||
future2 := engine.BatchBootstrapAsync(batch2, bsk)
|
||||
|
||||
// Do other work...
|
||||
|
||||
// Collect results
|
||||
results1, _ := future1.Wait()
|
||||
results2, _ := future2.Wait()
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
```go
|
||||
engine, err := gpu.New(cfg)
|
||||
if err != nil {
|
||||
switch {
|
||||
case errors.Is(err, gpu.ErrNotSupported):
|
||||
// Platform doesn't support any GPU backend
|
||||
// Fall back to pure Go implementation
|
||||
case errors.Is(err, gpu.ErrOutOfMemory):
|
||||
// Not enough GPU memory
|
||||
// Reduce batch size or memory limit
|
||||
default:
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Benchmarking Your System
|
||||
|
||||
```bash
|
||||
# Run GPU benchmarks
|
||||
go test -bench=BenchmarkGPU -benchmem github.com/luxfi/fhe/gpu
|
||||
|
||||
# Compare with CPU
|
||||
go test -bench=BenchmarkLattice -benchmem github.com/luxfi/fhe
|
||||
```
|
||||
|
||||
## Platform-Specific Notes
|
||||
|
||||
### macOS (Metal/MLX)
|
||||
|
||||
- Requires macOS 13.0+ (Ventura or later)
|
||||
- Works on Apple Silicon (M1, M2, M3 series)
|
||||
- Intel Macs not supported (falls back to CPU)
|
||||
- Uses MLX framework for optimal Metal performance
|
||||
|
||||
### Linux (CUDA)
|
||||
|
||||
- Requires CUDA Toolkit 11.0+
|
||||
- NVIDIA GPU with Compute Capability 7.0+ (Volta or newer)
|
||||
- Tested on: RTX 3090, RTX 4090, A100, H100
|
||||
|
||||
### Windows (CUDA)
|
||||
|
||||
- Same requirements as Linux
|
||||
- CUDA Toolkit for Windows
|
||||
- WSL2 also works with Linux CUDA backend
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Metal not detected on macOS
|
||||
|
||||
```bash
|
||||
# Check Metal support
|
||||
system_profiler SPDisplaysDataType | grep Metal
|
||||
```
|
||||
|
||||
### CUDA not detected on Linux
|
||||
|
||||
```bash
|
||||
# Check CUDA installation
|
||||
nvcc --version
|
||||
nvidia-smi
|
||||
|
||||
# Check Go can find CUDA
|
||||
export CGO_CFLAGS="-I/usr/local/cuda/include"
|
||||
export CGO_LDFLAGS="-L/usr/local/cuda/lib64"
|
||||
```
|
||||
|
||||
### Out of memory errors
|
||||
|
||||
Reduce batch size or set a memory limit:
|
||||
|
||||
```go
|
||||
cfg := gpu.Config{
|
||||
MaxBatchSize: 256, // Smaller batches
|
||||
MemoryLimit: 2 << 30, // 2GB limit
|
||||
}
|
||||
```
|
||||
@@ -1,127 +0,0 @@
|
||||
---
|
||||
title: Lux TFHE
|
||||
description: Threshold Fully Homomorphic Encryption for Lux Network with Multi-GPU acceleration
|
||||
---
|
||||
|
||||
Compute on encrypted data without ever decrypting it. Built for the Lux Network with multi-GPU acceleration.
|
||||
|
||||
## Backends
|
||||
|
||||
| Backend | Platform | Performance | Use Case |
|
||||
|---------|----------|-------------|----------|
|
||||
| **Pure Go** | Any | Baseline | Portability, no dependencies |
|
||||
| **Metal/MLX** | macOS | 10-100x | Apple Silicon acceleration |
|
||||
| **CUDA** | Linux/Windows | 10-100x | NVIDIA GPU acceleration |
|
||||
| **CGO/OpenFHE** | Any | ~1x | Interoperability |
|
||||
|
||||
## Features
|
||||
|
||||
- **Multi-GPU Acceleration**: Massively parallel bootstrapping on Metal (macOS) and CUDA (Linux/Windows)
|
||||
- **Lux Network Native**: Designed for confidential smart contracts and threshold decryption
|
||||
- **Pure Go Fallback**: Zero dependencies option - compiles anywhere Go runs
|
||||
- **Patent-Safe**: Classic boolean circuit approach, no patented techniques
|
||||
- **Full Integer Support**: FheUint4 through FheUint256 (including Ethereum addresses)
|
||||
- **Blockchain Ready**: Public key encryption, deterministic RNG, serialization
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
go get github.com/luxfi/fhe
|
||||
```
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/luxfi/fhe"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Setup
|
||||
params, _ := tfhe.NewParametersFromLiteral(tfhe.PN10QP27)
|
||||
kg := tfhe.NewKeyGenerator(params)
|
||||
sk, pk := kg.GenKeyPair()
|
||||
bsk := kg.GenBootstrapKey(sk)
|
||||
|
||||
// Encrypt with public key
|
||||
pubEnc := tfhe.NewBitwisePublicEncryptor(params, pk)
|
||||
ctA := pubEnc.EncryptUint64(5, tfhe.FheUint8)
|
||||
ctB := pubEnc.EncryptUint64(3, tfhe.FheUint8)
|
||||
|
||||
// Compute on encrypted data
|
||||
eval := tfhe.NewBitwiseEvaluator(params, bsk, sk)
|
||||
ctSum, _ := eval.Add(ctA, ctB)
|
||||
|
||||
// Decrypt result
|
||||
dec := tfhe.NewBitwiseDecryptor(params, sk)
|
||||
result := dec.DecryptUint64(ctSum)
|
||||
fmt.Println("5 + 3 =", result) // 8
|
||||
}
|
||||
```
|
||||
|
||||
## GPU Acceleration (macOS)
|
||||
|
||||
```go
|
||||
import "github.com/luxfi/fhe/gpu"
|
||||
|
||||
// Configure GPU engine
|
||||
cfg := gpu.Config{
|
||||
Backends: []string{"metal", "cpu"},
|
||||
MaxBatchSize: 1024,
|
||||
MemoryLimit: 4 * 1024 * 1024 * 1024, // 4GB
|
||||
}
|
||||
|
||||
engine, _ := gpu.New(cfg)
|
||||
defer engine.Close()
|
||||
|
||||
// Batch operations execute in parallel on GPU
|
||||
results, _ := engine.BatchBootstrap(ciphertexts, bsk)
|
||||
```
|
||||
|
||||
## Performance (Apple M1 Max)
|
||||
|
||||
| Operation | Pure Go | GPU | Speedup |
|
||||
|-----------|---------|-----|---------|
|
||||
| Bootstrap Key Gen | 132 ms | 132 ms | 1x |
|
||||
| Boolean Gate (AND) | 51 ms | ~5 ms | **10x** |
|
||||
| 8-bit Integer Add | 3.5 s | ~350 ms | **10x** |
|
||||
| Batch 1000 ANDs | 51 s | ~500 ms | **100x** |
|
||||
|
||||
*GPU acceleration provides massive speedup for batch operations.*
|
||||
|
||||
## Documentation
|
||||
|
||||
- [Overview](/docs/overview) - What is TFHE and how does it work?
|
||||
- [GPU Acceleration](/docs/gpu) - Multi-GPU setup for Metal and CUDA
|
||||
- [API Reference](/docs/api) - Complete API documentation
|
||||
- [Benchmarks](/docs/benchmarks) - Detailed performance characteristics
|
||||
- [Security](/docs/security) - Security model and guarantees
|
||||
- [License](/docs/license) - Licensing information
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
tfhe/
|
||||
├── fhe.go # Core FHE types and parameters
|
||||
├── keygen.go # Key generation (secret, public, bootstrap)
|
||||
├── encryptor.go # Encryption with secret/public keys
|
||||
├── decryptor.go # Decryption
|
||||
├── evaluator.go # Homomorphic operations
|
||||
├── integer.go # Integer encryption/decryption
|
||||
├── bitwise.go # Boolean circuit operations
|
||||
├── gpu/ # Multi-GPU acceleration
|
||||
│ ├── engine.go # Metal/MLX backend (macOS)
|
||||
│ └── cuda/ # CUDA backend (Linux/Windows)
|
||||
└── server/ # Threshold decryption server
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
BSD-3-Clause + Patent Rights Reserved
|
||||
|
||||
- **Lux Network**: Free to use on Lux mainnet/testnets
|
||||
- **Research/Academic**: Free for non-commercial use
|
||||
- **Commercial**: License required for other networks
|
||||
|
||||
Contact: [email protected]
|
||||
@@ -1,68 +0,0 @@
|
||||
---
|
||||
title: License
|
||||
description: Licensing information for Lux FHE
|
||||
---
|
||||
|
||||
# License
|
||||
|
||||
## BSD 3-Clause License + Patent Rights Reserved
|
||||
|
||||
Copyright (c) 2025 Lux Partners Limited. All rights reserved.
|
||||
|
||||
## Software License
|
||||
|
||||
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
|
||||
2. Redistributions in binary form must reproduce the above copyright notice
|
||||
3. Neither the name of Lux Partners Limited nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission
|
||||
|
||||
## Patent Rights Reserved
|
||||
|
||||
All patent rights relating to this software and its implementation techniques are expressly reserved by Lux Partners Limited. This license does NOT grant any patent license, express or implied.
|
||||
|
||||
## Usage Terms
|
||||
|
||||
### Lux Network Exception (Free)
|
||||
|
||||
Use of this software on the Lux Network mainnet and its official testnets is permitted without additional licensing fees. This includes:
|
||||
|
||||
- Smart contracts and dApps deployed on Lux Network
|
||||
- Validators and nodes operating on Lux Network
|
||||
- Integration with Lux Network infrastructure
|
||||
- fhEVM operations on Lux Network chains
|
||||
|
||||
### Research & Academic Use (Free)
|
||||
|
||||
Non-commercial use for research, education, and academic purposes is permitted without additional licensing, subject to citation requirements.
|
||||
|
||||
### Commercial License Required
|
||||
|
||||
Any commercial use of this software outside of the Lux Network requires a separate commercial license from Lux Partners Limited. This includes:
|
||||
|
||||
- Use on other blockchain networks
|
||||
- Use in commercial products or services
|
||||
- SaaS offerings incorporating this technology
|
||||
- Enterprise deployments
|
||||
- Any for-profit use outside Lux Network
|
||||
|
||||
## Contact
|
||||
|
||||
For commercial licensing inquiries: [[email protected]](mailto:[email protected])
|
||||
|
||||
## Implementation Notice
|
||||
|
||||
This is an **ORIGINAL implementation** of FHE written from scratch in Go, based on published academic research:
|
||||
|
||||
- Built entirely on [github.com/luxfi/lattice](https://github.com/luxfi/lattice) (our own cryptographic primitives)
|
||||
- Implements algorithms from peer-reviewed publications
|
||||
- Contains novel optimizations developed independently
|
||||
|
||||
### Referenced Academic Works
|
||||
|
||||
- Chillotti et al. "FHE: Fast Fully Homomorphic Encryption Over the Torus" (Journal of Cryptology, 2020)
|
||||
- Ducas & Micciancio "FHEW: Bootstrapping Homomorphic Encryption in Less Than a Second" (EUROCRYPT 2015)
|
||||
|
||||
## Disclaimer
|
||||
|
||||
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 LUX PARTNERS LIMITED 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,15 +0,0 @@
|
||||
{
|
||||
"title": "Documentation",
|
||||
"pages": [
|
||||
"index",
|
||||
"overview",
|
||||
"---SDK---",
|
||||
"sdk",
|
||||
"---Reference---",
|
||||
"gpu",
|
||||
"api",
|
||||
"benchmarks",
|
||||
"security",
|
||||
"license"
|
||||
]
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
---
|
||||
title: Overview
|
||||
description: What is FHE and how does it work?
|
||||
---
|
||||
|
||||
# Overview
|
||||
|
||||
## What is FHE?
|
||||
|
||||
**Threshold Fully Homomorphic Encryption (FHE)** is a cryptographic technique that allows computation on encrypted data without decryption. The result of the computation is also encrypted, and only the holder of the secret key can decrypt it.
|
||||
|
||||
This enables privacy-preserving computation where:
|
||||
- Users encrypt their data with a public key
|
||||
- Servers perform computations on encrypted data
|
||||
- Only the user can decrypt the final result
|
||||
|
||||
## How It Works
|
||||
|
||||
### 1. Key Generation
|
||||
|
||||
```go
|
||||
params, _ := tfhe.NewParametersFromLiteral(tfhe.PN10QP27)
|
||||
kg := tfhe.NewKeyGenerator(params)
|
||||
sk, pk := kg.GenKeyPair() // Secret key (private), Public key (shareable)
|
||||
bsk := kg.GenBootstrapKey(sk) // Bootstrap key (for server operations)
|
||||
```
|
||||
|
||||
### 2. Encryption (User Side)
|
||||
|
||||
Users encrypt their data using the **public key** - they never need the secret key:
|
||||
|
||||
```go
|
||||
pubEnc := tfhe.NewBitwisePublicEncryptor(params, pk)
|
||||
encryptedValue := pubEnc.EncryptUint64(42, tfhe.FheUint8)
|
||||
```
|
||||
|
||||
### 3. Computation (Server Side)
|
||||
|
||||
The server performs operations on encrypted data using the **bootstrap key**:
|
||||
|
||||
```go
|
||||
eval := tfhe.NewBitwiseEvaluator(params, bsk, sk)
|
||||
result, _ := eval.Add(encA, encB) // Addition on encrypted data
|
||||
```
|
||||
|
||||
### 4. Decryption (User Side)
|
||||
|
||||
Only the holder of the secret key can decrypt:
|
||||
|
||||
```go
|
||||
dec := tfhe.NewBitwiseDecryptor(params, sk)
|
||||
plaintext := dec.DecryptUint64(result)
|
||||
```
|
||||
|
||||
## Boolean Circuit Approach
|
||||
|
||||
Lux FHE uses a **boolean circuit approach** for integer operations:
|
||||
|
||||
1. Each integer is represented as a vector of encrypted bits
|
||||
2. Operations are built from basic boolean gates (AND, OR, XOR, NOT)
|
||||
3. Each boolean gate requires a "bootstrapping" operation to reduce noise
|
||||
|
||||
This approach is:
|
||||
- **Patent-safe**: Uses pre-2020 techniques with no patented LUT methods
|
||||
- **Flexible**: Supports arbitrary bit widths (4-256 bits)
|
||||
- **Predictable**: Performance scales linearly with bit width
|
||||
|
||||
## Security
|
||||
|
||||
FHE security is based on the **Learning With Errors (LWE)** problem, which is believed to be resistant to both classical and quantum computers.
|
||||
|
||||
Key security features:
|
||||
- 128-bit security level
|
||||
- Semantic security (identical plaintexts have different ciphertexts)
|
||||
- IND-CPA secure encryption
|
||||
|
||||
## Use Cases
|
||||
|
||||
- **Confidential Smart Contracts**: Execute logic without revealing inputs
|
||||
- **Privacy-Preserving DeFi**: Trade without exposing positions
|
||||
- **Encrypted Voting**: Vote without revealing choices
|
||||
- **Secure Auctions**: Bid without revealing amounts
|
||||
- **Private Analytics**: Compute statistics on encrypted data
|
||||
@@ -1,238 +0,0 @@
|
||||
---
|
||||
title: C/C++ SDK
|
||||
description: Native C/C++ SDK for LuxFHE
|
||||
---
|
||||
|
||||
# C/C++ SDK
|
||||
|
||||
The C SDK provides native bindings with full C++ compatibility via `extern "C"`.
|
||||
|
||||
## Installation
|
||||
|
||||
### macOS / Linux
|
||||
|
||||
```bash
|
||||
# Build from source
|
||||
cd tfhe/c
|
||||
mkdir build && cd build
|
||||
cmake ..
|
||||
make
|
||||
sudo make install
|
||||
```
|
||||
|
||||
### Using pkg-config
|
||||
|
||||
```bash
|
||||
# After installation
|
||||
pkg-config --cflags --libs luxfhe
|
||||
```
|
||||
|
||||
### CMake Integration
|
||||
|
||||
```cmake
|
||||
find_package(luxfhe REQUIRED)
|
||||
target_link_libraries(myapp PRIVATE luxfhe::luxfhe)
|
||||
```
|
||||
|
||||
## Quick Start (C)
|
||||
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include <luxfhe.h>
|
||||
|
||||
int main() {
|
||||
// Create context
|
||||
LuxFHE_Context ctx = NULL;
|
||||
luxfhe_context_new(LUXFHE_PARAMS_PN10QP27, &ctx);
|
||||
|
||||
// Generate keys
|
||||
LuxFHE_SecretKey sk = NULL;
|
||||
LuxFHE_PublicKey pk = NULL;
|
||||
LuxFHE_BootstrapKey bsk = NULL;
|
||||
|
||||
luxfhe_keygen_secret(ctx, &sk);
|
||||
luxfhe_keygen_public(ctx, sk, &pk);
|
||||
luxfhe_keygen_bootstrap(ctx, sk, &bsk);
|
||||
|
||||
// Create encryptor/decryptor/evaluator
|
||||
LuxFHE_Encryptor enc = NULL;
|
||||
LuxFHE_Decryptor dec = NULL;
|
||||
LuxFHE_Evaluator eval = NULL;
|
||||
|
||||
luxfhe_encryptor_new_pk(ctx, pk, &enc);
|
||||
luxfhe_decryptor_new(ctx, sk, &dec);
|
||||
luxfhe_evaluator_new(ctx, bsk, sk, &eval);
|
||||
|
||||
// Encrypt
|
||||
LuxFHE_Ciphertext ct_true = NULL;
|
||||
LuxFHE_Ciphertext ct_false = NULL;
|
||||
luxfhe_encrypt_bool(enc, true, &ct_true);
|
||||
luxfhe_encrypt_bool(enc, false, &ct_false);
|
||||
|
||||
// Compute AND gate
|
||||
LuxFHE_Ciphertext ct_result = NULL;
|
||||
luxfhe_and(eval, ct_true, ct_false, &ct_result);
|
||||
|
||||
// Decrypt
|
||||
bool result;
|
||||
luxfhe_decrypt_bool(dec, ct_result, &result);
|
||||
printf("true AND false = %s\n", result ? "true" : "false");
|
||||
|
||||
// Cleanup
|
||||
luxfhe_ciphertext_free(ct_result);
|
||||
luxfhe_ciphertext_free(ct_true);
|
||||
luxfhe_ciphertext_free(ct_false);
|
||||
luxfhe_evaluator_free(eval);
|
||||
luxfhe_decryptor_free(dec);
|
||||
luxfhe_encryptor_free(enc);
|
||||
luxfhe_bootstrapkey_free(bsk);
|
||||
luxfhe_publickey_free(pk);
|
||||
luxfhe_secretkey_free(sk);
|
||||
luxfhe_context_free(ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
## Quick Start (C++)
|
||||
|
||||
```cpp
|
||||
#include <iostream>
|
||||
#include <luxfhe.h>
|
||||
|
||||
int main() {
|
||||
// Get version
|
||||
std::cout << "LuxFHE " << luxfhe_version() << std::endl;
|
||||
|
||||
// Create context
|
||||
LuxFHE_Context ctx = nullptr;
|
||||
if (luxfhe_context_new(LUXFHE_PARAMS_PN10QP27, &ctx) != LUXFHE_OK) {
|
||||
std::cerr << "Failed to create context" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Generate all keys at once
|
||||
LuxFHE_SecretKey sk = nullptr;
|
||||
LuxFHE_PublicKey pk = nullptr;
|
||||
LuxFHE_BootstrapKey bsk = nullptr;
|
||||
luxfhe_keygen_all(ctx, &sk, &pk, &bsk);
|
||||
|
||||
// ... use FHE operations
|
||||
|
||||
// Cleanup
|
||||
luxfhe_context_free(ctx);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### Error Codes
|
||||
|
||||
```c
|
||||
typedef enum {
|
||||
LUXFHE_OK = 0,
|
||||
LUXFHE_ERR_NULL_POINTER = -1,
|
||||
LUXFHE_ERR_INVALID_PARAM = -2,
|
||||
LUXFHE_ERR_KEYGEN_FAILED = -3,
|
||||
LUXFHE_ERR_ENCRYPT_FAILED = -4,
|
||||
LUXFHE_ERR_DECRYPT_FAILED = -5,
|
||||
LUXFHE_ERR_EVAL_FAILED = -6,
|
||||
LUXFHE_ERR_SERIALIZE_FAILED = -7,
|
||||
LUXFHE_ERR_DESERIALIZE_FAILED = -8,
|
||||
} LuxFHE_Error;
|
||||
```
|
||||
|
||||
### Parameter Sets
|
||||
|
||||
```c
|
||||
typedef enum {
|
||||
LUXFHE_PARAMS_PN10QP27 = 0, // ~128-bit, good performance
|
||||
LUXFHE_PARAMS_PN11QP54 = 1, // ~128-bit, higher precision
|
||||
} LuxFHE_ParamSet;
|
||||
```
|
||||
|
||||
### Context Management
|
||||
|
||||
```c
|
||||
LuxFHE_Error luxfhe_context_new(LuxFHE_ParamSet params, LuxFHE_Context* out);
|
||||
void luxfhe_context_free(LuxFHE_Context ctx);
|
||||
LuxFHE_Error luxfhe_context_params(LuxFHE_Context ctx, LuxFHE_ParamSet* out);
|
||||
```
|
||||
|
||||
### Key Generation
|
||||
|
||||
```c
|
||||
LuxFHE_Error luxfhe_keygen_secret(LuxFHE_Context ctx, LuxFHE_SecretKey* out);
|
||||
LuxFHE_Error luxfhe_keygen_public(LuxFHE_Context ctx, LuxFHE_SecretKey sk, LuxFHE_PublicKey* out);
|
||||
LuxFHE_Error luxfhe_keygen_bootstrap(LuxFHE_Context ctx, LuxFHE_SecretKey sk, LuxFHE_BootstrapKey* out);
|
||||
LuxFHE_Error luxfhe_keygen_all(LuxFHE_Context ctx, LuxFHE_SecretKey* sk, LuxFHE_PublicKey* pk, LuxFHE_BootstrapKey* bsk);
|
||||
```
|
||||
|
||||
### Encryption/Decryption
|
||||
|
||||
```c
|
||||
LuxFHE_Error luxfhe_encryptor_new_sk(LuxFHE_Context ctx, LuxFHE_SecretKey sk, LuxFHE_Encryptor* out);
|
||||
LuxFHE_Error luxfhe_encryptor_new_pk(LuxFHE_Context ctx, LuxFHE_PublicKey pk, LuxFHE_Encryptor* out);
|
||||
LuxFHE_Error luxfhe_decryptor_new(LuxFHE_Context ctx, LuxFHE_SecretKey sk, LuxFHE_Decryptor* out);
|
||||
|
||||
LuxFHE_Error luxfhe_encrypt_bool(LuxFHE_Encryptor enc, bool value, LuxFHE_Ciphertext* out);
|
||||
LuxFHE_Error luxfhe_decrypt_bool(LuxFHE_Decryptor dec, LuxFHE_Ciphertext ct, bool* out);
|
||||
|
||||
LuxFHE_Error luxfhe_encrypt_byte(LuxFHE_Encryptor enc, uint8_t value, LuxFHE_Ciphertext* out);
|
||||
LuxFHE_Error luxfhe_decrypt_byte(LuxFHE_Decryptor dec, LuxFHE_Ciphertext ct, uint8_t* out);
|
||||
```
|
||||
|
||||
### Gate Operations
|
||||
|
||||
```c
|
||||
LuxFHE_Error luxfhe_evaluator_new(LuxFHE_Context ctx, LuxFHE_BootstrapKey bsk, LuxFHE_SecretKey sk, LuxFHE_Evaluator* out);
|
||||
|
||||
// Basic gates
|
||||
LuxFHE_Error luxfhe_and(LuxFHE_Evaluator eval, LuxFHE_Ciphertext ct1, LuxFHE_Ciphertext ct2, LuxFHE_Ciphertext* out);
|
||||
LuxFHE_Error luxfhe_or(LuxFHE_Evaluator eval, LuxFHE_Ciphertext ct1, LuxFHE_Ciphertext ct2, LuxFHE_Ciphertext* out);
|
||||
LuxFHE_Error luxfhe_xor(LuxFHE_Evaluator eval, LuxFHE_Ciphertext ct1, LuxFHE_Ciphertext ct2, LuxFHE_Ciphertext* out);
|
||||
LuxFHE_Error luxfhe_not(LuxFHE_Evaluator eval, LuxFHE_Ciphertext ct, LuxFHE_Ciphertext* out);
|
||||
|
||||
// NAND/NOR/XNOR
|
||||
LuxFHE_Error luxfhe_nand(LuxFHE_Evaluator eval, LuxFHE_Ciphertext ct1, LuxFHE_Ciphertext ct2, LuxFHE_Ciphertext* out);
|
||||
LuxFHE_Error luxfhe_nor(LuxFHE_Evaluator eval, LuxFHE_Ciphertext ct1, LuxFHE_Ciphertext ct2, LuxFHE_Ciphertext* out);
|
||||
LuxFHE_Error luxfhe_xnor(LuxFHE_Evaluator eval, LuxFHE_Ciphertext ct1, LuxFHE_Ciphertext ct2, LuxFHE_Ciphertext* out);
|
||||
|
||||
// Multi-input gates
|
||||
LuxFHE_Error luxfhe_and3(LuxFHE_Evaluator eval, LuxFHE_Ciphertext ct1, LuxFHE_Ciphertext ct2, LuxFHE_Ciphertext ct3, LuxFHE_Ciphertext* out);
|
||||
LuxFHE_Error luxfhe_or3(LuxFHE_Evaluator eval, LuxFHE_Ciphertext ct1, LuxFHE_Ciphertext ct2, LuxFHE_Ciphertext ct3, LuxFHE_Ciphertext* out);
|
||||
LuxFHE_Error luxfhe_mux(LuxFHE_Evaluator eval, LuxFHE_Ciphertext sel, LuxFHE_Ciphertext ct1, LuxFHE_Ciphertext ct2, LuxFHE_Ciphertext* out);
|
||||
LuxFHE_Error luxfhe_majority(LuxFHE_Evaluator eval, LuxFHE_Ciphertext ct1, LuxFHE_Ciphertext ct2, LuxFHE_Ciphertext ct3, LuxFHE_Ciphertext* out);
|
||||
```
|
||||
|
||||
### Serialization
|
||||
|
||||
```c
|
||||
LuxFHE_Error luxfhe_secretkey_serialize(LuxFHE_SecretKey sk, uint8_t** data, size_t* len);
|
||||
LuxFHE_Error luxfhe_ciphertext_serialize(LuxFHE_Ciphertext ct, uint8_t** data, size_t* len);
|
||||
void luxfhe_bytes_free(uint8_t* data);
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
```c
|
||||
LuxFHE_Error err = luxfhe_context_new(LUXFHE_PARAMS_PN10QP27, &ctx);
|
||||
if (err != LUXFHE_OK) {
|
||||
const char* msg = luxfhe_error_string(err);
|
||||
fprintf(stderr, "Error: %s\n", msg);
|
||||
return 1;
|
||||
}
|
||||
```
|
||||
|
||||
## Building the Library
|
||||
|
||||
```bash
|
||||
cd tfhe
|
||||
CGO_ENABLED=1 go build -buildmode=c-shared -o c/lib/libluxfhe.dylib ./c/src/luxfhe.go
|
||||
```
|
||||
|
||||
Output files:
|
||||
- `libluxfhe.dylib` (macOS)
|
||||
- `libluxfhe.so` (Linux)
|
||||
- `luxfhe.dll` (Windows)
|
||||
@@ -1,155 +0,0 @@
|
||||
---
|
||||
title: Go SDK
|
||||
description: Native Go SDK for LuxFHE
|
||||
---
|
||||
|
||||
# Go SDK
|
||||
|
||||
The Go SDK is the native implementation of LuxFHE, offering the best performance and full feature access.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
go get github.com/luxfi/fhe
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/luxfi/fhe"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Initialize with security parameters
|
||||
params, _ := tfhe.NewParametersFromLiteral(tfhe.PN10QP27)
|
||||
kgen := tfhe.NewKeyGenerator(params)
|
||||
|
||||
// Generate keys
|
||||
sk := kgen.GenSecretKey()
|
||||
pk := kgen.GenPublicKey(sk)
|
||||
bsk := kgen.GenBootstrapKey(sk)
|
||||
|
||||
// Create encryptor/decryptor/evaluator
|
||||
enc := tfhe.NewBitwisePublicEncryptor(params, pk)
|
||||
dec := tfhe.NewBitwiseDecryptor(params, sk)
|
||||
eval := tfhe.NewBitwiseEvaluator(params, bsk, sk)
|
||||
|
||||
// Encrypt values
|
||||
ct1 := enc.EncryptUint64(100, tfhe.FheUint32)
|
||||
ct2 := enc.EncryptUint64(50, tfhe.FheUint32)
|
||||
|
||||
// Compute on encrypted data
|
||||
ctSum, _ := eval.Add(ct1, ct2)
|
||||
|
||||
// Decrypt result
|
||||
result := dec.DecryptUint64(ctSum)
|
||||
fmt.Printf("100 + 50 = %d\n", result)
|
||||
}
|
||||
```
|
||||
|
||||
## Parameter Sets
|
||||
|
||||
| Parameter | Security | Performance | Use Case |
|
||||
|-----------|----------|-------------|----------|
|
||||
| `PN10QP27` | ~128-bit | Fast | General purpose |
|
||||
| `PN11QP54` | ~128-bit | Higher precision | Financial, scientific |
|
||||
|
||||
## Boolean Operations
|
||||
|
||||
```go
|
||||
// Single bit operations
|
||||
ctTrue := enc.Encrypt(true)
|
||||
ctFalse := enc.Encrypt(false)
|
||||
|
||||
// Logic gates (with bootstrapping)
|
||||
ctAnd, _ := eval.And(ctTrue, ctFalse) // false
|
||||
ctOr, _ := eval.Or(ctTrue, ctFalse) // true
|
||||
ctXor, _ := eval.Xor(ctTrue, ctFalse) // true
|
||||
ctNot, _ := eval.Not(ctTrue) // false
|
||||
ctNand, _ := eval.Nand(ctTrue, ctTrue) // false
|
||||
```
|
||||
|
||||
## Integer Operations
|
||||
|
||||
```go
|
||||
// Supported types
|
||||
ct8 := enc.EncryptUint64(255, tfhe.FheUint8)
|
||||
ct16 := enc.EncryptUint64(65535, tfhe.FheUint16)
|
||||
ct32 := enc.EncryptUint64(4294967295, tfhe.FheUint32)
|
||||
ct64 := enc.EncryptUint64(1000000, tfhe.FheUint64)
|
||||
|
||||
// Arithmetic
|
||||
sum, _ := eval.Add(ct1, ct2)
|
||||
diff, _ := eval.Sub(ct1, ct2)
|
||||
|
||||
// Comparisons
|
||||
isEqual, _ := eval.Eq(ct1, ct2)
|
||||
isLess, _ := eval.Lt(ct1, ct2)
|
||||
isGreater, _ := eval.Gt(ct1, ct2)
|
||||
```
|
||||
|
||||
## GPU Acceleration
|
||||
|
||||
GPU acceleration is automatic on supported platforms:
|
||||
|
||||
```go
|
||||
import "github.com/luxfi/fhe/gpu"
|
||||
|
||||
// Check if GPU is available
|
||||
if gpu.Available() {
|
||||
engine := gpu.NewEngine(params)
|
||||
// Use engine.ParallelEvaluate for batched operations
|
||||
}
|
||||
```
|
||||
|
||||
### Supported GPUs
|
||||
|
||||
- **Apple Silicon**: M1/M2/M3/M4 via Metal
|
||||
- **NVIDIA**: CUDA-capable GPUs on Linux
|
||||
|
||||
## Serialization
|
||||
|
||||
```go
|
||||
// Serialize keys
|
||||
skBytes, _ := sk.MarshalBinary()
|
||||
pkBytes, _ := pk.MarshalBinary()
|
||||
bskBytes, _ := bsk.MarshalBinary()
|
||||
|
||||
// Deserialize
|
||||
var sk2 tfhe.SecretKey
|
||||
sk2.UnmarshalBinary(skBytes)
|
||||
|
||||
// Serialize ciphertexts
|
||||
ctBytes, _ := ct.MarshalBinary()
|
||||
```
|
||||
|
||||
## Benchmarks
|
||||
|
||||
On Apple M2 Pro:
|
||||
|
||||
| Operation | Time |
|
||||
|-----------|------|
|
||||
| Key Generation | ~100ms |
|
||||
| Bootstrap (single gate) | ~15ms |
|
||||
| 32-bit Addition | ~500ms |
|
||||
| 32-bit Comparison | ~300ms |
|
||||
|
||||
## Error Handling
|
||||
|
||||
```go
|
||||
result, err := eval.Add(ct1, ct2)
|
||||
if err != nil {
|
||||
log.Fatalf("FHE operation failed: %v", err)
|
||||
}
|
||||
```
|
||||
|
||||
## Thread Safety
|
||||
|
||||
- `KeyGenerator`: Thread-safe
|
||||
- `Encryptor`: Not thread-safe (create per goroutine)
|
||||
- `Decryptor`: Not thread-safe (create per goroutine)
|
||||
- `Evaluator`: Thread-safe for independent operations
|
||||
@@ -1,74 +0,0 @@
|
||||
---
|
||||
title: SDK Overview
|
||||
description: LuxFHE SDKs for multiple languages and platforms
|
||||
---
|
||||
|
||||
# LuxFHE SDKs
|
||||
|
||||
LuxFHE provides official SDKs for multiple programming languages and platforms, enabling fully homomorphic encryption across your entire stack.
|
||||
|
||||
## Available SDKs
|
||||
|
||||
| SDK | Platform | Status | Install |
|
||||
|-----|----------|--------|---------|
|
||||
| [Go](/docs/sdk/go) | Native | Stable | `go get github.com/luxfi/fhe` |
|
||||
| [TypeScript](/docs/sdk/typescript) | Node.js / Browser | Stable | `npm install @luxfi/tfhe` |
|
||||
| [Python](/docs/sdk/python) | Native (cffi) | Stable | `pip install luxfhe` |
|
||||
| [Rust](/docs/sdk/rust) | Native | Stable | `cargo add luxfhe` |
|
||||
| [C/C++](/docs/sdk/c) | Native | Stable | CMake / pkg-config |
|
||||
| [WASM](/docs/sdk/wasm) | Browser / Edge | Stable | Bundled with TypeScript |
|
||||
|
||||
## Quick Comparison
|
||||
|
||||
### Performance
|
||||
|
||||
Native SDKs (Go, Rust, C/C++) offer the best performance with direct access to hardware acceleration:
|
||||
|
||||
- **GPU Acceleration**: Available on Apple Silicon (Metal) and NVIDIA (CUDA)
|
||||
- **SIMD Optimization**: Automatic vectorization on all platforms
|
||||
- **Multi-threading**: Parallel gate evaluation
|
||||
|
||||
### Use Cases
|
||||
|
||||
| SDK | Best For |
|
||||
|-----|----------|
|
||||
| **Go** | Backend services, blockchain nodes, high-performance servers |
|
||||
| **TypeScript** | Web applications, Node.js APIs, browser-based encryption |
|
||||
| **Python** | ML pipelines, data science, prototyping |
|
||||
| **Rust** | Systems programming, embedded, performance-critical |
|
||||
| **C/C++** | Legacy integration, custom runtimes, embedded systems |
|
||||
| **WASM** | Edge computing, browser-only environments |
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────┐
|
||||
│ Your Application │
|
||||
├─────────┬─────────┬─────────┬─────────┬─────────┤
|
||||
│ Go │ TS/JS │ Python │ Rust │ C++ │
|
||||
├─────────┴─────────┴─────────┴─────────┴─────────┤
|
||||
│ LuxFHE Core (Pure Go) │
|
||||
├─────────────────────────────────────────────────┤
|
||||
│ GPU Acceleration (Metal/CUDA) [Optional] │
|
||||
└─────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Common Concepts
|
||||
|
||||
All SDKs share the same core concepts:
|
||||
|
||||
1. **Context**: Initialize FHE with security parameters
|
||||
2. **Key Generation**: Create secret, public, and bootstrap keys
|
||||
3. **Encryption**: Encrypt plaintext using public or secret key
|
||||
4. **Evaluation**: Perform operations on encrypted data
|
||||
5. **Decryption**: Decrypt results using secret key
|
||||
|
||||
## Getting Started
|
||||
|
||||
Choose your preferred SDK:
|
||||
|
||||
- **Go**: Best for server-side and blockchain applications
|
||||
- **TypeScript**: Best for web and Node.js applications
|
||||
- **Python**: Best for data science and ML workflows
|
||||
- **Rust**: Best for systems programming
|
||||
- **C/C++**: Best for native integrations
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"title": "SDKs",
|
||||
"pages": [
|
||||
"index",
|
||||
"go",
|
||||
"typescript",
|
||||
"python",
|
||||
"rust",
|
||||
"c",
|
||||
"wasm"
|
||||
]
|
||||
}
|
||||
@@ -1,215 +0,0 @@
|
||||
---
|
||||
title: Python SDK
|
||||
description: Python SDK for LuxFHE using CFFI
|
||||
---
|
||||
|
||||
# Python SDK
|
||||
|
||||
The Python SDK provides FHE capabilities for data science, ML pipelines, and prototyping.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
pip install luxfhe
|
||||
```
|
||||
|
||||
Or from source:
|
||||
|
||||
```bash
|
||||
cd tfhe/python
|
||||
pip install -e .
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```python
|
||||
from luxfhe import Context, ParamSet
|
||||
|
||||
# Create context with security parameters
|
||||
ctx = Context(ParamSet.PN10QP27)
|
||||
|
||||
# Generate keys
|
||||
sk = ctx.keygen_secret()
|
||||
pk = ctx.keygen_public(sk)
|
||||
bk = ctx.keygen_bootstrap(sk)
|
||||
|
||||
# Create encryptor/decryptor
|
||||
enc = ctx.encryptor(pk) # Public key encryption
|
||||
dec = ctx.decryptor(sk)
|
||||
|
||||
# Encrypt values
|
||||
ct_true = enc.encrypt(True)
|
||||
ct_false = enc.encrypt(False)
|
||||
|
||||
# Decrypt
|
||||
print(dec.decrypt(ct_true)) # True
|
||||
print(dec.decrypt(ct_false)) # False
|
||||
```
|
||||
|
||||
## Boolean Operations
|
||||
|
||||
```python
|
||||
# Create evaluator for gate operations
|
||||
eval = ctx.evaluator(bk, sk)
|
||||
|
||||
# Logic gates
|
||||
ct_and = eval.and_gate(ct_true, ct_false) # False
|
||||
ct_or = eval.or_gate(ct_true, ct_false) # True
|
||||
ct_xor = eval.xor_gate(ct_true, ct_false) # True
|
||||
ct_not = eval.not_gate(ct_true) # False
|
||||
ct_nand = eval.nand_gate(ct_true, ct_true) # False
|
||||
|
||||
# Decrypt results
|
||||
print(f"AND: {dec.decrypt(ct_and)}")
|
||||
print(f"OR: {dec.decrypt(ct_or)}")
|
||||
print(f"XOR: {dec.decrypt(ct_xor)}")
|
||||
```
|
||||
|
||||
## Secret Key vs Public Key Encryption
|
||||
|
||||
```python
|
||||
# Secret key encryption (faster, for owner)
|
||||
enc_sk = ctx.encryptor(sk)
|
||||
ct = enc_sk.encrypt(True)
|
||||
|
||||
# Public key encryption (anyone can encrypt)
|
||||
enc_pk = ctx.encryptor(pk)
|
||||
ct = enc_pk.encrypt(True)
|
||||
|
||||
# Both can be decrypted with secret key
|
||||
result = dec.decrypt(ct)
|
||||
```
|
||||
|
||||
## Byte Encryption
|
||||
|
||||
```python
|
||||
# Encrypt bytes (8 bits)
|
||||
ct_byte = enc.encrypt_byte(42)
|
||||
value = dec.decrypt_byte(ct_byte)
|
||||
print(value) # 42
|
||||
|
||||
# Encrypt multiple bytes
|
||||
data = [0, 127, 255]
|
||||
encrypted = [enc.encrypt_byte(b) for b in data]
|
||||
decrypted = [dec.decrypt_byte(ct) for ct in encrypted]
|
||||
```
|
||||
|
||||
## NumPy Integration
|
||||
|
||||
```python
|
||||
import numpy as np
|
||||
|
||||
# Encrypt array of booleans
|
||||
arr = np.array([True, False, True, True])
|
||||
encrypted_arr = [enc.encrypt(bool(x)) for x in arr]
|
||||
|
||||
# Perform homomorphic operations
|
||||
result_arr = []
|
||||
for i in range(len(encrypted_arr) - 1):
|
||||
ct_and = eval.and_gate(encrypted_arr[i], encrypted_arr[i+1])
|
||||
result_arr.append(ct_and)
|
||||
|
||||
# Decrypt results
|
||||
decrypted = [dec.decrypt(ct) for ct in result_arr]
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
|
||||
```python
|
||||
import os
|
||||
|
||||
# Set library path before import
|
||||
os.environ['LUXFHE_LIBRARY'] = '/path/to/libluxfhe.dylib'
|
||||
|
||||
from luxfhe import Context
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
```python
|
||||
from luxfhe import Context, LuxFHEError
|
||||
|
||||
try:
|
||||
ctx = Context()
|
||||
# ... operations
|
||||
except LuxFHEError as e:
|
||||
print(f"FHE error: {e}")
|
||||
except Exception as e:
|
||||
print(f"Unexpected error: {e}")
|
||||
```
|
||||
|
||||
## Parameter Sets
|
||||
|
||||
```python
|
||||
from luxfhe import ParamSet
|
||||
|
||||
# Standard security (~128-bit)
|
||||
ctx = Context(ParamSet.PN10QP27)
|
||||
|
||||
# Higher precision
|
||||
ctx = Context(ParamSet.PN11QP54)
|
||||
```
|
||||
|
||||
## Memory Management
|
||||
|
||||
Python bindings handle memory automatically via context managers:
|
||||
|
||||
```python
|
||||
# Keys are freed when out of scope
|
||||
def process():
|
||||
ctx = Context()
|
||||
sk = ctx.keygen_secret()
|
||||
# ... use keys
|
||||
# Keys freed here
|
||||
|
||||
# Or use explicit cleanup
|
||||
ctx = Context()
|
||||
sk = ctx.keygen_secret()
|
||||
del sk # Free immediately
|
||||
```
|
||||
|
||||
## Performance Tips
|
||||
|
||||
1. **Batch operations** when possible
|
||||
2. **Reuse encryptor/decryptor** instances
|
||||
3. **Use secret key encryption** when you own the data
|
||||
4. **Consider multiprocessing** for independent operations
|
||||
|
||||
```python
|
||||
from multiprocessing import Pool
|
||||
|
||||
def encrypt_batch(values, pk):
|
||||
ctx = Context()
|
||||
enc = ctx.encryptor(pk)
|
||||
return [enc.encrypt(v) for v in values]
|
||||
|
||||
# Parallel encryption
|
||||
with Pool(4) as p:
|
||||
results = p.starmap(encrypt_batch, [(batch, pk) for batch in batches])
|
||||
```
|
||||
|
||||
## Jupyter Notebook Example
|
||||
|
||||
```python
|
||||
# Cell 1: Setup
|
||||
from luxfhe import Context
|
||||
|
||||
ctx = Context()
|
||||
sk = ctx.keygen_secret()
|
||||
pk = ctx.keygen_public(sk)
|
||||
bk = ctx.keygen_bootstrap(sk)
|
||||
|
||||
print("Keys generated!")
|
||||
|
||||
# Cell 2: Encrypt
|
||||
enc = ctx.encryptor(pk)
|
||||
dec = ctx.decryptor(sk)
|
||||
eval = ctx.evaluator(bk, sk)
|
||||
|
||||
a = enc.encrypt(True)
|
||||
b = enc.encrypt(False)
|
||||
|
||||
# Cell 3: Compute
|
||||
result = eval.and_gate(a, b)
|
||||
print(f"True AND False = {dec.decrypt(result)}")
|
||||
```
|
||||
@@ -1,228 +0,0 @@
|
||||
---
|
||||
title: Rust SDK
|
||||
description: Rust SDK for LuxFHE with safe bindings
|
||||
---
|
||||
|
||||
# Rust SDK
|
||||
|
||||
The Rust SDK provides safe, idiomatic bindings to LuxFHE via FFI.
|
||||
|
||||
## Installation
|
||||
|
||||
Add to your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
luxfhe = "0.1"
|
||||
```
|
||||
|
||||
Or from git:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
luxfhe = { git = "https://github.com/luxfi/fhe", branch = "main" }
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```rust
|
||||
use luxfhe::{Context, ParamSet, Result};
|
||||
|
||||
fn main() -> Result<()> {
|
||||
// Create context
|
||||
let ctx = Context::new(ParamSet::PN10QP27)?;
|
||||
|
||||
// Generate keys
|
||||
let sk = ctx.keygen_secret()?;
|
||||
let pk = ctx.keygen_public(&sk)?;
|
||||
let bsk = ctx.keygen_bootstrap(&sk)?;
|
||||
|
||||
// Create encryptor/decryptor/evaluator
|
||||
let enc = ctx.encryptor_pk(&pk)?;
|
||||
let dec = ctx.decryptor(&sk)?;
|
||||
let eval = ctx.evaluator(&bsk, &sk)?;
|
||||
|
||||
// Encrypt
|
||||
let ct_true = enc.encrypt(true)?;
|
||||
let ct_false = enc.encrypt(false)?;
|
||||
|
||||
// Compute
|
||||
let ct_and = eval.and(&ct_true, &ct_false)?;
|
||||
|
||||
// Decrypt
|
||||
let result = dec.decrypt(&ct_and)?;
|
||||
println!("true AND false = {}", result);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### Context
|
||||
|
||||
```rust
|
||||
use luxfhe::{Context, ParamSet};
|
||||
|
||||
// Create with parameter set
|
||||
let ctx = Context::new(ParamSet::PN10QP27)?;
|
||||
|
||||
// Available parameter sets
|
||||
ParamSet::PN10QP27 // Standard, ~128-bit security
|
||||
ParamSet::PN11QP54 // Higher precision
|
||||
```
|
||||
|
||||
### Key Generation
|
||||
|
||||
```rust
|
||||
// Generate individually
|
||||
let sk = ctx.keygen_secret()?;
|
||||
let pk = ctx.keygen_public(&sk)?;
|
||||
let bsk = ctx.keygen_bootstrap(&sk)?;
|
||||
|
||||
// Generate all at once
|
||||
let (sk, pk, bsk) = ctx.keygen_all()?;
|
||||
```
|
||||
|
||||
### Encryption
|
||||
|
||||
```rust
|
||||
// Public key encryption (anyone can encrypt)
|
||||
let enc = ctx.encryptor_pk(&pk)?;
|
||||
let ct = enc.encrypt(true)?;
|
||||
|
||||
// Secret key encryption (faster)
|
||||
let enc = ctx.encryptor_sk(&sk)?;
|
||||
let ct = enc.encrypt(true)?;
|
||||
```
|
||||
|
||||
### Decryption
|
||||
|
||||
```rust
|
||||
let dec = ctx.decryptor(&sk)?;
|
||||
let plaintext: bool = dec.decrypt(&ct)?;
|
||||
```
|
||||
|
||||
### Gate Operations
|
||||
|
||||
```rust
|
||||
let eval = ctx.evaluator(&bsk, &sk)?;
|
||||
|
||||
// Basic gates
|
||||
let ct_and = eval.and(&ct1, &ct2)?;
|
||||
let ct_or = eval.or(&ct1, &ct2)?;
|
||||
let ct_xor = eval.xor(&ct1, &ct2)?;
|
||||
let ct_not = eval.not(&ct1)?;
|
||||
|
||||
// NAND/NOR/XNOR
|
||||
let ct_nand = eval.nand(&ct1, &ct2)?;
|
||||
let ct_nor = eval.nor(&ct1, &ct2)?;
|
||||
let ct_xnor = eval.xnor(&ct1, &ct2)?;
|
||||
|
||||
// Multi-input gates
|
||||
let ct_mux = eval.mux(&ct_sel, &ct_true, &ct_false)?;
|
||||
let ct_maj = eval.majority(&ct1, &ct2, &ct3)?;
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
```rust
|
||||
use luxfhe::{Error, Result};
|
||||
|
||||
fn process() -> Result<()> {
|
||||
let ctx = Context::new(ParamSet::PN10QP27)?;
|
||||
// ... operations
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Or handle specific errors
|
||||
match ctx.keygen_secret() {
|
||||
Ok(sk) => println!("Key generated"),
|
||||
Err(Error::NullPointer) => println!("Internal error"),
|
||||
Err(Error::InvalidParam) => println!("Invalid parameter"),
|
||||
Err(e) => println!("Other error: {:?}", e),
|
||||
}
|
||||
```
|
||||
|
||||
## Memory Safety
|
||||
|
||||
The Rust SDK ensures memory safety through:
|
||||
|
||||
- RAII for all FHE objects (automatic cleanup via `Drop`)
|
||||
- Borrow checker prevents use-after-free
|
||||
- No raw pointer exposure in public API
|
||||
|
||||
```rust
|
||||
{
|
||||
let ctx = Context::new(ParamSet::PN10QP27)?;
|
||||
let sk = ctx.keygen_secret()?;
|
||||
// sk is valid here
|
||||
} // sk and ctx automatically freed here
|
||||
```
|
||||
|
||||
## Thread Safety
|
||||
|
||||
```rust
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
|
||||
// Share context across threads
|
||||
let ctx = Arc::new(Context::new(ParamSet::PN10QP27)?);
|
||||
|
||||
let handles: Vec<_> = (0..4).map(|_| {
|
||||
let ctx = Arc::clone(&ctx);
|
||||
thread::spawn(move || {
|
||||
let sk = ctx.keygen_secret().unwrap();
|
||||
// Use sk...
|
||||
})
|
||||
}).collect();
|
||||
|
||||
for handle in handles {
|
||||
handle.join().unwrap();
|
||||
}
|
||||
```
|
||||
|
||||
## Ciphertext Cloning
|
||||
|
||||
```rust
|
||||
// Clone a ciphertext for reuse
|
||||
let ct_copy = ct.try_clone()?;
|
||||
```
|
||||
|
||||
## Feature Flags
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
luxfhe = { version = "0.1", features = ["system"] }
|
||||
```
|
||||
|
||||
- `system`: Use system-installed library instead of bundled
|
||||
|
||||
## Building from Source
|
||||
|
||||
```bash
|
||||
cd tfhe/rust
|
||||
cargo build --release
|
||||
```
|
||||
|
||||
Requirements:
|
||||
- Rust 1.70+
|
||||
- C compiler (for bindgen)
|
||||
- LuxFHE C library
|
||||
|
||||
## Benchmarks
|
||||
|
||||
Run benchmarks:
|
||||
|
||||
```bash
|
||||
cargo bench
|
||||
```
|
||||
|
||||
Example results (Apple M2):
|
||||
|
||||
| Operation | Time |
|
||||
|-----------|------|
|
||||
| Keygen | ~100ms |
|
||||
| Encrypt | ~1ms |
|
||||
| AND gate | ~15ms |
|
||||
| Full bootstrap | ~15ms |
|
||||
@@ -1,220 +0,0 @@
|
||||
---
|
||||
title: TypeScript SDK
|
||||
description: TypeScript SDK for Node.js and browsers
|
||||
---
|
||||
|
||||
# TypeScript SDK
|
||||
|
||||
The TypeScript SDK enables FHE in Node.js and browser environments via WebAssembly.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install @luxfi/tfhe
|
||||
# or
|
||||
pnpm add @luxfi/tfhe
|
||||
# or
|
||||
yarn add @luxfi/tfhe
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```typescript
|
||||
import { LuxFHE } from '@luxfi/tfhe';
|
||||
|
||||
async function main() {
|
||||
// Initialize (loads WASM)
|
||||
const fhe = await LuxFHE.init();
|
||||
|
||||
// Generate keys
|
||||
const keys = fhe.generateKeys();
|
||||
|
||||
// Encrypt values
|
||||
const ct1 = fhe.encrypt(100, 32, keys.publicKey);
|
||||
const ct2 = fhe.encrypt(50, 32, keys.publicKey);
|
||||
|
||||
// Compute on encrypted data
|
||||
const ctSum = fhe.add(ct1, ct2, keys.bootstrapKey, keys.secretKey);
|
||||
|
||||
// Decrypt result
|
||||
const result = fhe.decrypt(ctSum, keys.secretKey);
|
||||
console.log(`100 + 50 = ${result}`); // 150
|
||||
}
|
||||
|
||||
main();
|
||||
```
|
||||
|
||||
## Browser Usage
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script type="module">
|
||||
import { LuxFHE } from './node_modules/@luxfi/tfhe/dist/index.mjs';
|
||||
|
||||
async function run() {
|
||||
const fhe = await LuxFHE.init({
|
||||
wasmPath: './node_modules/@luxfi/tfhe/wasm/luxfhe.wasm',
|
||||
execPath: './node_modules/@luxfi/tfhe/wasm/wasm_exec.js',
|
||||
});
|
||||
|
||||
const keys = fhe.generateKeys();
|
||||
document.getElementById('status').textContent = 'FHE Ready!';
|
||||
}
|
||||
|
||||
run();
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="status">Loading...</div>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### Initialization
|
||||
|
||||
```typescript
|
||||
// Default initialization
|
||||
const fhe = await LuxFHE.init();
|
||||
|
||||
// Custom paths (for bundlers)
|
||||
const fhe = await LuxFHE.init({
|
||||
wasmPath: '/assets/luxfhe.wasm',
|
||||
execPath: '/assets/wasm_exec.js',
|
||||
});
|
||||
|
||||
// Singleton pattern
|
||||
const fhe = await LuxFHE.getInstance();
|
||||
```
|
||||
|
||||
### Key Generation
|
||||
|
||||
```typescript
|
||||
const keys = fhe.generateKeys();
|
||||
|
||||
// Keys are base64-encoded strings
|
||||
console.log(keys.secretKey); // Keep private!
|
||||
console.log(keys.publicKey); // Share with clients
|
||||
console.log(keys.bootstrapKey); // Needed for operations
|
||||
|
||||
// Store keys
|
||||
localStorage.setItem('fhe_keys', JSON.stringify(keys));
|
||||
```
|
||||
|
||||
### Encryption
|
||||
|
||||
```typescript
|
||||
// Encrypt with public key (anyone can encrypt)
|
||||
const ct = fhe.encrypt(value, bitWidth, keys.publicKey);
|
||||
|
||||
// Supported bit widths
|
||||
fhe.encrypt(15, 4, pk); // 4-bit (0-15)
|
||||
fhe.encrypt(255, 8, pk); // 8-bit (0-255)
|
||||
fhe.encrypt(65535, 16, pk); // 16-bit
|
||||
fhe.encrypt(value, 32, pk); // 32-bit (most common)
|
||||
fhe.encrypt(value, 64, pk); // 64-bit
|
||||
```
|
||||
|
||||
### Decryption
|
||||
|
||||
```typescript
|
||||
// Only secret key holder can decrypt
|
||||
const plaintext = fhe.decrypt(ciphertext, keys.secretKey);
|
||||
```
|
||||
|
||||
### Homomorphic Operations
|
||||
|
||||
```typescript
|
||||
// Arithmetic
|
||||
const ctSum = fhe.add(ct1, ct2, keys.bootstrapKey, keys.secretKey);
|
||||
const ctDiff = fhe.sub(ct1, ct2, keys.bootstrapKey, keys.secretKey);
|
||||
|
||||
// Comparisons (return encrypted 0 or 1)
|
||||
const ctEqual = fhe.eq(ct1, ct2, keys.bootstrapKey, keys.secretKey);
|
||||
const ctLess = fhe.lt(ct1, ct2, keys.bootstrapKey, keys.secretKey);
|
||||
const ctGreater = fhe.gt(ct1, ct2, keys.bootstrapKey, keys.secretKey);
|
||||
```
|
||||
|
||||
### Error Handling
|
||||
|
||||
```typescript
|
||||
import { LuxFHEError } from '@luxfi/tfhe';
|
||||
|
||||
try {
|
||||
const ct = fhe.encrypt(value, 32, publicKey);
|
||||
} catch (error) {
|
||||
if (error instanceof LuxFHEError) {
|
||||
console.error('FHE error:', error.message);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## TypeScript Types
|
||||
|
||||
```typescript
|
||||
import type {
|
||||
KeyPair,
|
||||
BitWidth,
|
||||
Ciphertext,
|
||||
InitOptions
|
||||
} from '@luxfi/tfhe';
|
||||
|
||||
// KeyPair
|
||||
interface KeyPair {
|
||||
secretKey: string; // base64
|
||||
publicKey: string; // base64
|
||||
bootstrapKey: string; // base64
|
||||
}
|
||||
|
||||
// BitWidth
|
||||
type BitWidth = 4 | 8 | 16 | 32 | 64 | 128 | 160 | 256;
|
||||
|
||||
// Ciphertext is just a base64 string
|
||||
type Ciphertext = string;
|
||||
```
|
||||
|
||||
## Web Worker Usage
|
||||
|
||||
For heavy computations, use Web Workers:
|
||||
|
||||
```typescript
|
||||
// worker.ts
|
||||
import { LuxFHE } from '@luxfi/tfhe';
|
||||
|
||||
let fhe: LuxFHE;
|
||||
|
||||
self.onmessage = async (e) => {
|
||||
if (e.data.type === 'init') {
|
||||
fhe = await LuxFHE.init();
|
||||
self.postMessage({ type: 'ready' });
|
||||
}
|
||||
|
||||
if (e.data.type === 'compute') {
|
||||
const { ct1, ct2, bsk, sk } = e.data;
|
||||
const result = fhe.add(ct1, ct2, bsk, sk);
|
||||
self.postMessage({ type: 'result', data: result });
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## Bundle Size
|
||||
|
||||
| File | Size |
|
||||
|------|------|
|
||||
| `luxfhe.wasm` | ~12 MB |
|
||||
| `wasm_exec.js` | ~17 KB |
|
||||
| `index.mjs` | ~9 KB |
|
||||
|
||||
Consider lazy loading the WASM module for better initial load times.
|
||||
|
||||
## Browser Compatibility
|
||||
|
||||
- Chrome 89+
|
||||
- Firefox 89+
|
||||
- Safari 15+
|
||||
- Edge 89+
|
||||
|
||||
Requires WebAssembly support.
|
||||
@@ -1,194 +0,0 @@
|
||||
---
|
||||
title: WebAssembly
|
||||
description: WASM module for browser and edge environments
|
||||
---
|
||||
|
||||
# WebAssembly SDK
|
||||
|
||||
The WASM module enables FHE in browsers and edge environments without native dependencies.
|
||||
|
||||
## Overview
|
||||
|
||||
The WASM module is compiled from Go and provides the same functionality as the native SDK:
|
||||
|
||||
- Key generation
|
||||
- Public/secret key encryption
|
||||
- Homomorphic operations (add, sub, eq, lt)
|
||||
- All operations run client-side
|
||||
|
||||
## Files
|
||||
|
||||
| File | Size | Purpose |
|
||||
|------|------|---------|
|
||||
| `luxfhe.wasm` | ~12 MB | Main WASM binary |
|
||||
| `wasm_exec.js` | ~17 KB | Go runtime for WASM |
|
||||
|
||||
## Direct Usage
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script src="wasm_exec.js"></script>
|
||||
<script>
|
||||
const go = new Go();
|
||||
WebAssembly.instantiateStreaming(fetch('luxfhe.wasm'), go.importObject)
|
||||
.then(result => {
|
||||
go.run(result.instance);
|
||||
|
||||
// luxfhe is now available globally
|
||||
console.log('Version:', luxfhe.version());
|
||||
|
||||
const keys = luxfhe.generateKeys();
|
||||
console.log('Keys generated!');
|
||||
|
||||
const ct = luxfhe.encrypt(42, 32, keys.publicKey);
|
||||
const result = luxfhe.decrypt(ct, keys.secretKey);
|
||||
console.log('Decrypted:', result);
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="output"></div>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
## Global API
|
||||
|
||||
Once loaded, `luxfhe` is available globally with these methods:
|
||||
|
||||
```javascript
|
||||
// Version
|
||||
luxfhe.version() // Returns "1.0.0"
|
||||
|
||||
// Key generation
|
||||
luxfhe.generateKeys()
|
||||
// Returns: { secretKey, publicKey, bootstrapKey }
|
||||
|
||||
// Encryption
|
||||
luxfhe.encrypt(value, bitWidth, publicKey)
|
||||
// Returns: base64 ciphertext
|
||||
|
||||
// Decryption
|
||||
luxfhe.decrypt(ciphertext, secretKey)
|
||||
// Returns: number
|
||||
|
||||
// Arithmetic
|
||||
luxfhe.add(ct1, ct2, bootstrapKey, secretKey)
|
||||
luxfhe.sub(ct1, ct2, bootstrapKey, secretKey)
|
||||
|
||||
// Comparisons
|
||||
luxfhe.eq(ct1, ct2, bootstrapKey, secretKey)
|
||||
luxfhe.lt(ct1, ct2, bootstrapKey, secretKey)
|
||||
```
|
||||
|
||||
## TypeScript Wrapper
|
||||
|
||||
For a better developer experience, use the TypeScript SDK which wraps the WASM module:
|
||||
|
||||
```typescript
|
||||
import { LuxFHE } from '@luxfi/tfhe';
|
||||
|
||||
const fhe = await LuxFHE.init();
|
||||
const keys = fhe.generateKeys();
|
||||
```
|
||||
|
||||
See [TypeScript SDK](/docs/sdk/typescript) for full documentation.
|
||||
|
||||
## Bit Widths
|
||||
|
||||
Supported encryption bit widths:
|
||||
|
||||
| Bits | Range | Use Case |
|
||||
|------|-------|----------|
|
||||
| 4 | 0-15 | Small enums |
|
||||
| 8 | 0-255 | Bytes, flags |
|
||||
| 16 | 0-65535 | Small integers |
|
||||
| 32 | 0-4B | General purpose |
|
||||
| 64 | 0-2^64 | Large values |
|
||||
| 128 | 0-2^128 | Cryptographic |
|
||||
| 160 | 0-2^160 | Ethereum addresses |
|
||||
| 256 | 0-2^256 | Hashes, big integers |
|
||||
|
||||
## Error Handling
|
||||
|
||||
WASM functions return error strings prefixed with "error:":
|
||||
|
||||
```javascript
|
||||
const result = luxfhe.encrypt(value, bitWidth, invalidKey);
|
||||
if (result.startsWith('error:')) {
|
||||
console.error('Encryption failed:', result);
|
||||
}
|
||||
```
|
||||
|
||||
## Performance
|
||||
|
||||
WASM performance is approximately 2-3x slower than native. For compute-intensive workloads, consider:
|
||||
|
||||
1. **Web Workers** for parallel operations
|
||||
2. **Native SDK** for server-side processing
|
||||
3. **Batching** multiple operations together
|
||||
|
||||
## Memory Considerations
|
||||
|
||||
- Initial load: ~50MB memory
|
||||
- Per ciphertext: ~1KB
|
||||
- Bootstrap key: ~50MB (loaded once)
|
||||
|
||||
Tips:
|
||||
- Load WASM lazily
|
||||
- Reuse key objects
|
||||
- Clear ciphertexts when done
|
||||
|
||||
## Browser Compatibility
|
||||
|
||||
Requires WebAssembly support:
|
||||
|
||||
| Browser | Version |
|
||||
|---------|---------|
|
||||
| Chrome | 57+ |
|
||||
| Firefox | 52+ |
|
||||
| Safari | 11+ |
|
||||
| Edge | 16+ |
|
||||
|
||||
## Building from Source
|
||||
|
||||
```bash
|
||||
cd tfhe/wasm
|
||||
GOOS=js GOARCH=wasm go build -o luxfhe.wasm main.go
|
||||
```
|
||||
|
||||
Copy Go WASM runtime:
|
||||
|
||||
```bash
|
||||
cp "$(go env GOROOT)/lib/wasm/wasm_exec.js" .
|
||||
```
|
||||
|
||||
## Deployment
|
||||
|
||||
### CDN
|
||||
|
||||
```html
|
||||
<script src="https://cdn.lux.network/tfhe/wasm_exec.js"></script>
|
||||
<script>
|
||||
const go = new Go();
|
||||
WebAssembly.instantiateStreaming(
|
||||
fetch('https://cdn.lux.network/tfhe/luxfhe.wasm'),
|
||||
go.importObject
|
||||
).then(result => go.run(result.instance));
|
||||
</script>
|
||||
```
|
||||
|
||||
### Self-Hosted
|
||||
|
||||
1. Copy `luxfhe.wasm` and `wasm_exec.js` to your static files
|
||||
2. Ensure proper MIME type for `.wasm` (`application/wasm`)
|
||||
3. Enable CORS if loading cross-origin
|
||||
|
||||
## Security Notes
|
||||
|
||||
- All operations run client-side
|
||||
- Secret keys never leave the browser
|
||||
- WASM provides memory isolation
|
||||
- Use HTTPS in production
|
||||
@@ -1,105 +0,0 @@
|
||||
---
|
||||
title: Security
|
||||
description: Security model and guarantees
|
||||
---
|
||||
|
||||
# Security
|
||||
|
||||
## Cryptographic Foundation
|
||||
|
||||
Lux FHE is built on the **Learning With Errors (LWE)** problem, a lattice-based cryptographic assumption that is:
|
||||
|
||||
- **Classically secure**: No known polynomial-time classical algorithms
|
||||
- **Quantum resistant**: No known polynomial-time quantum algorithms
|
||||
- **Well-studied**: Extensively analyzed by the cryptographic community
|
||||
|
||||
## Security Level
|
||||
|
||||
The default parameter set provides **128-bit security** against both classical and quantum adversaries.
|
||||
|
||||
## Security Properties
|
||||
|
||||
### Semantic Security (IND-CPA)
|
||||
|
||||
Encryptions of identical plaintexts produce different ciphertexts. An adversary cannot distinguish between encryptions of any two messages.
|
||||
|
||||
### Correctness
|
||||
|
||||
Decryption always produces the correct result, assuming operations are performed correctly and noise doesn't overflow.
|
||||
|
||||
### Noise Management
|
||||
|
||||
Each operation adds "noise" to ciphertexts. Bootstrapping resets the noise level, allowing unlimited computation depth.
|
||||
|
||||
## Threat Model
|
||||
|
||||
### What FHE Protects Against
|
||||
|
||||
- **Data exposure**: Servers never see plaintext values
|
||||
- **Traffic analysis**: Ciphertext sizes are uniform
|
||||
- **Side-channel attacks**: Operations are data-independent (constant-time)
|
||||
|
||||
### What FHE Does NOT Protect Against
|
||||
|
||||
- **Access patterns**: The sequence of operations may leak information
|
||||
- **Output size**: The number of output bits reveals information
|
||||
- **Timing attacks on application logic**: Your higher-level code must be careful
|
||||
|
||||
## Key Management
|
||||
|
||||
### Secret Key
|
||||
|
||||
- **Never share** the secret key
|
||||
- Store securely (HSM, secure enclave, encrypted at rest)
|
||||
- Use key derivation functions for multi-user scenarios
|
||||
|
||||
### Public Key
|
||||
|
||||
- Safe to share publicly
|
||||
- Users encrypt with this key
|
||||
- Does not reveal any information about the secret key
|
||||
|
||||
### Bootstrap Key
|
||||
|
||||
- Large key (~80 MB)
|
||||
- Required for homomorphic operations
|
||||
- Safe to share with computation servers
|
||||
- Does not reveal the secret key
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Validate all inputs** before encryption
|
||||
2. **Limit operation depth** to prevent noise overflow
|
||||
3. **Use public key encryption** for user-submitted data
|
||||
4. **Implement rate limiting** on FHE operations (they're expensive)
|
||||
5. **Audit your circuits** for information leakage
|
||||
|
||||
## Implementation Security
|
||||
|
||||
### No Patented Techniques
|
||||
|
||||
Lux FHE uses only pre-2020 techniques:
|
||||
|
||||
- Boolean circuit approach (Chillotti et al. 2016)
|
||||
- GINX bootstrapping method
|
||||
- Classic carry-propagate arithmetic
|
||||
|
||||
This avoids any potential patent issues with:
|
||||
- LUT-based integer techniques
|
||||
- Tree-based bootstrapping
|
||||
- Programmable bootstrapping optimizations
|
||||
|
||||
### Constant-Time Operations
|
||||
|
||||
All cryptographic operations are implemented to run in constant time, preventing timing-based side-channel attacks.
|
||||
|
||||
### Memory Safety
|
||||
|
||||
Written in Go with automatic memory management, eliminating common C/C++ vulnerabilities:
|
||||
- No buffer overflows
|
||||
- No use-after-free
|
||||
- No memory leaks
|
||||
|
||||
## Audits
|
||||
|
||||
[Contact us](mailto:[email protected]) for security audit reports.
|
||||
@@ -1,137 +0,0 @@
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import matter from 'gray-matter'
|
||||
|
||||
const DOCS_DIR = path.join(process.cwd(), 'content/docs')
|
||||
|
||||
export interface DocPage {
|
||||
slug: string[]
|
||||
data: {
|
||||
title: string
|
||||
description?: string
|
||||
content: string
|
||||
toc?: any
|
||||
full?: boolean
|
||||
body: any
|
||||
}
|
||||
}
|
||||
|
||||
interface DocMeta {
|
||||
title?: string
|
||||
description?: string
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
function getAllDocFiles(dir: string = DOCS_DIR, prefix: string[] = []): { file: string; slug: string[] }[] {
|
||||
try {
|
||||
const entries = fs.readdirSync(dir, { withFileTypes: true })
|
||||
const results: { file: string; slug: string[] }[] = []
|
||||
|
||||
for (const entry of entries) {
|
||||
if (entry.isDirectory()) {
|
||||
// Recurse into subdirectories
|
||||
const subResults = getAllDocFiles(
|
||||
path.join(dir, entry.name),
|
||||
[...prefix, entry.name]
|
||||
)
|
||||
results.push(...subResults)
|
||||
} else if (entry.name.endsWith('.md') || entry.name.endsWith('.mdx')) {
|
||||
const slug = entry.name.replace(/\.(md|mdx)$/, '')
|
||||
const fullSlug = slug === 'index' ? prefix : [...prefix, slug]
|
||||
results.push({
|
||||
file: path.join(dir, entry.name),
|
||||
slug: fullSlug,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return results
|
||||
} catch (error) {
|
||||
console.error('Error reading docs directory:', error)
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
function readDocFile(filePath: string, slug: string[]): DocPage | null {
|
||||
try {
|
||||
const fileContents = fs.readFileSync(filePath, 'utf8')
|
||||
const { data, content } = matter(fileContents)
|
||||
const meta = data as DocMeta
|
||||
|
||||
return {
|
||||
slug,
|
||||
data: {
|
||||
title: meta.title || slug[slug.length - 1] || 'Home',
|
||||
description: meta.description,
|
||||
content,
|
||||
toc: [],
|
||||
full: false,
|
||||
body: () => null,
|
||||
},
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error reading doc file ${filePath}:`, error)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export const source = {
|
||||
getPage(slugParam?: string[]): DocPage | null {
|
||||
if (!slugParam || slugParam.length === 0) {
|
||||
const indexPath = path.join(DOCS_DIR, 'index.mdx')
|
||||
if (fs.existsSync(indexPath)) {
|
||||
return readDocFile(indexPath, [])
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
// Build the file path from slug
|
||||
const slugPath = slugParam.join('/')
|
||||
|
||||
// Try different file extensions and index files
|
||||
const candidates = [
|
||||
path.join(DOCS_DIR, `${slugPath}.mdx`),
|
||||
path.join(DOCS_DIR, `${slugPath}.md`),
|
||||
path.join(DOCS_DIR, slugPath, 'index.mdx'),
|
||||
path.join(DOCS_DIR, slugPath, 'index.md'),
|
||||
]
|
||||
|
||||
for (const candidate of candidates) {
|
||||
if (fs.existsSync(candidate)) {
|
||||
return readDocFile(candidate, slugParam)
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
},
|
||||
|
||||
generateParams(): { slug: string[] }[] {
|
||||
const files = getAllDocFiles()
|
||||
return files.map(({ slug }) => ({ slug }))
|
||||
},
|
||||
|
||||
get pageTree() {
|
||||
const files = getAllDocFiles()
|
||||
const pages = files
|
||||
.map(({ file, slug }) => readDocFile(file, slug))
|
||||
.filter((p): p is DocPage => p !== null)
|
||||
.sort((a, b) => {
|
||||
if (a.slug.length === 0) return -1
|
||||
if (b.slug.length === 0) return 1
|
||||
// Sort by path depth first, then alphabetically
|
||||
if (a.slug.length !== b.slug.length) {
|
||||
return a.slug.length - b.slug.length
|
||||
}
|
||||
return a.slug.join('/').localeCompare(b.slug.join('/'))
|
||||
})
|
||||
|
||||
return {
|
||||
name: '',
|
||||
children: pages.map(p => ({
|
||||
type: 'page' as const,
|
||||
name: p.data.title,
|
||||
url: `/docs${p.slug.length > 0 ? '/' + p.slug.join('/') : ''}`,
|
||||
})),
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
const config = {
|
||||
output: 'export',
|
||||
basePath: '/tfhe',
|
||||
images: {
|
||||
unoptimized: true
|
||||
}
|
||||
}
|
||||
|
||||
export default config
|
||||
@@ -1,34 +0,0 @@
|
||||
{
|
||||
"name": "@luxfi/tfhe-docs",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"description": "Lux TFHE documentation",
|
||||
"scripts": {
|
||||
"dev": "next dev --port 3004",
|
||||
"build": "next build",
|
||||
"start": "next start"
|
||||
},
|
||||
"dependencies": {
|
||||
"@luxfi/logo": "^1.0.0",
|
||||
"fumadocs-core": "^15.3.4",
|
||||
"fumadocs-ui": "^15.3.4",
|
||||
"gray-matter": "^4.0.3",
|
||||
"highlight.js": "^11.11.1",
|
||||
"lucide-react": "^0.468.0",
|
||||
"next": "^15.3.3",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"react-markdown": "^10.1.0",
|
||||
"rehype-highlight": "^7.0.2",
|
||||
"remark-gfm": "^4.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/postcss": "^4.1.18",
|
||||
"@tailwindcss/typography": "^0.5.16",
|
||||
"@types/node": "^22.15.21",
|
||||
"@types/react": "^19.1.5",
|
||||
"autoprefixer": "^10.4.23",
|
||||
"tailwindcss": "^4.1.8",
|
||||
"typescript": "^5.8.3"
|
||||
}
|
||||
}
|
||||
Generated
-3378
File diff suppressed because it is too large
Load Diff
@@ -1,5 +0,0 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
'@tailwindcss/postcss': {},
|
||||
},
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
tfhe.lux.network
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
name: Check Markdown links
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
schedule:
|
||||
# Run everyday at 9:00 AM (See https://pubs.opengroup.org/onlinepubs/9699919799/utilities/crontab.html#tag_20_25_07)
|
||||
- cron: "0 9 * * *"
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
markdown-link-check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
persist-credentials: 'false'
|
||||
- uses: umbrelladocs/action-linkspector@874d01cae9fd488e3077b08952093235bd626977 # v1.3.7
|
||||
with:
|
||||
filter_mode: nofilter
|
||||
config_file: .linkspector.yml
|
||||
github_token: ${{ secrets.github_token }}
|
||||
reporter: github-pr-review
|
||||
fail_level: any
|
||||
@@ -0,0 +1,3 @@
|
||||
node_modules/
|
||||
package.json
|
||||
package-lock.json
|
||||
@@ -0,0 +1,8 @@
|
||||
dirs:
|
||||
- ./
|
||||
aliveStatusCodes:
|
||||
- 200
|
||||
ignorePatterns:
|
||||
- pattern: '^https://stackoverflow.com/.*$'
|
||||
- pattern: '^https://doi.org/.*$'
|
||||
useGitIgnore: true
|
||||
@@ -0,0 +1,405 @@
|
||||
<p align="center">
|
||||
<img src="https://github.com/luxfhe-ai/awesome-luxfhe/assets/157474013/3743d435-dbba-4d89-907a-81957e6a4b1a" width="200px">
|
||||
<br><br/>
|
||||
A curated list by the team at LuxFHE of blog posts, libraries, research papers, and tutorials on <b>Fully Homomorphic Encryption (FHE)</b>.
|
||||
</p>
|
||||
|
||||
|
||||
## Table of contents
|
||||
|
||||
- [Table of contents](#table-of-contents)
|
||||
- [Libraries and solutions](#libraries-and-solutions)
|
||||
- [White papers](#white-papers)
|
||||
- [Concrete ML Demos](#concrete-ml-demos)
|
||||
- [Tutorials](#tutorials)
|
||||
- [TFHE-rs](#tfhe-rs)
|
||||
- [Concrete](#concrete)
|
||||
- [Concrete ML](#concrete-ml)
|
||||
- [fhEVM](#fhevm)
|
||||
- [Hardware](#hardware)
|
||||
- [Product releases](#product-releases)
|
||||
- [LuxFHE product release round‑ups](#luxfhe-product-release-roundups)
|
||||
- [Concrete releases](#concrete-releases)
|
||||
- [TFHE‑rs releases](#tfhers-releases)
|
||||
- [Concrete ML releases](#concreteml-releases)
|
||||
- [FHEVM releases](#fhevm-releases)
|
||||
- [Bounty Program](#bounty-program)
|
||||
- [Announcements](#announcements)
|
||||
- [Engineering articles](#engineering-articles)
|
||||
- [Research papers and publications](#research-papers-and-publications)
|
||||
- [Talks, posters, and presentations](#talks-posters-and-presentations)
|
||||
- [Peer-reviewed](#peer-reviewed)
|
||||
- [Invited and self-hosted](#invited-and-self-hosted)
|
||||
|
||||
## Libraries and solutions
|
||||
LuxFHE's FHE libraries and solutions
|
||||
|
||||
- [FHEVM monorepo](https://github.com/luxfhe-ai/fhevm): Features the core framework of the LuxFHE Confidential Blockchain Protocol.
|
||||
- [TFHE-rs](https://github.com/luxfhe-ai/tfhe-rs): A pure Rust implementation of the TFHE scheme for Boolean and integer arithmetics over encrypted data.
|
||||
- [Concrete](https://github.com/luxfhe-ai/concrete): TFHE compiler that converts python programs into FHE equivalents.
|
||||
- [Concrete ML](https://github.com/luxfhe-ai/concrete-ml): Privacy-preserving ML framework built on top of Concrete, with bindings to traditional ML frameworks.
|
||||
- [LuxFHE Bounty Program](https://github.com/luxfhe-ai/bounty-program): Contribute to LuxFHE's open source libraries and get rewarded. More than €500,000 available in prizes.
|
||||
<br></br>
|
||||
|
||||
## White papers
|
||||
White papers by LuxFHE sorted by date
|
||||
- [FHEVM Litepaper](https://docs.luxfhe.ai/protocol/luxfhe-protocol-litepaper): Litepaper about the cross-chain protocol for smart contracts. - June 2025
|
||||
- [FHEVM whitepaper](https://github.com/luxfhe-ai/fhevm/blob/main/fhevm-whitepaper.pdf): Whitepaper about the cross-chain protocol for smart contracts. - June 2025
|
||||
- [TFHE-rs: A Practical Handbook First Edition](https://github.com/luxfhe-ai/tfhe-rs-handbook/blob/main/tfhe-rs-handbook.pdf) - February 2025
|
||||
- [FHEVM V2: Confidential EVM Smart Contracts using Fully Homomorphic Encryption](https://github.com/luxfhe-ai/fhevm-solidity/blob/main/fhevm-whitepaper-v2.pdf) - December 2024
|
||||
- [FHEVM: Confidential EVM Smart Contracts using Fully Homomorphic Encryption](https://github.com/luxfhe-ai/fhevm-solidity/blob/main/fhevm-whitepaper.pdf) - September 2023
|
||||
|
||||
## Concrete ML Demos
|
||||
Demos by LuxFHE's Concrete ML sorted by date
|
||||
|
||||
- [Encrypted DNA testing using Fully Homomorphic Encryption](https://huggingface.co/spaces/luxfhe-fhe/encrypted_dna)
|
||||
- [Encrypted anonymization using FHE](https://huggingface.co/spaces/luxfhe-fhe/encrypted-anonymization)
|
||||
- [Encrypted credit card approval prediction using FHE](https://huggingface.co/spaces/luxfhe-fhe/credit_card_approval_prediction)
|
||||
- [Encrypted sentiment analysis using FHE](https://huggingface.co/spaces/luxfhe-fhe/encrypted_sentiment_analysis)
|
||||
- [Encrypted health prediction using FHE](https://huggingface.co/spaces/luxfhe-fhe/encrypted_health_prediction)
|
||||
- [Encrypted image filtering using FHE](https://huggingface.co/spaces/luxfhe-fhe/encrypted_image_filtering)
|
||||
<br></br>
|
||||
|
||||
## Tutorials
|
||||
Tutorials by the LuxFHE team sorted by date
|
||||
|
||||
### TFHE-rs
|
||||
- [[Video tutorial] Introducing LuxFHE’s hardware accelerator for FHE - HPU on FPGA](https://www.luxfhe.ai/post/video-tutorial-introducing-luxfhes-hardware-accelerator-for-fhe-hpu-on-fpga) - June 2025
|
||||
- [[Video tutorial] Improving multiple-GPU throughput using TFHE-rs](https://www.luxfhe.ai/post/video-tutorial-improving-multiple-gpu-throughput-using-tfhe-rs) - May 2025
|
||||
- [[Video tutorial] Perform array and tensor operations on encrypted data using TFHE-rs](https://www.luxfhe.ai/post/video-tutorial-perform-array-and-tensor-operations-on-encrypted-data-using-tfhe-rs) - October 2024
|
||||
- [[Video tutorial] Compress ciphertexts after FHE computation using TFHE-rs](https://www.luxfhe.ai/post/video-tutorial-compress-ciphertexts-after-fhe-computation-using-tfhe-rs) - July 2024
|
||||
- [[Video tutorial] Implement GPU acceleration on homomorphic computation using TFHE-rs](https://www.luxfhe.ai/post/video-tutorial-implement-gpu-acceleration-on-homomorphic-computation-using-tfhe-rs) - May 2024
|
||||
- [[Video tutorial] Implement signed integers using TFHE-rs](https://www.youtube.com/watch?v=O0aGj_xUo40) - November 2023
|
||||
- [Boolean SHA256 using TFHE-rs](https://www.luxfhe.ai/post/boolean-sha256-tfhe-rs) - July 2023
|
||||
- [Dark market application using TFHE-rs](https://www.luxfhe.ai/post/dark-market-tfhe-rs) - July 2023
|
||||
- [Regular expression engine with TFHE-rs](https://www.luxfhe.ai/post/regex-engine-tfhe-rs) - June 2023
|
||||
|
||||
### Concrete
|
||||
- [[Video tutorial] Integrate Python FHE modules in Rust using Concrete](https://www.luxfhe.ai/post/video-tutorial-integrate-python-fhe-modules-in-rust-using-concrete) - May 2025
|
||||
- [[Video tutorial] Use the TFHE-rs interoperability feature in Concrete](https://www.luxfhe.ai/post/video-tutorial-use-the-tfhe-rs-interoperability-feature-in-concrete) - October 2024
|
||||
- [[Video tutorial] Implement GPU acceleration in FHE using Concrete](https://www.luxfhe.ai/post/video-tutorial-implement-gpu-acceleration-in-fhe-using-concrete) - July 2024
|
||||
- [[Video tutorial] Compute an XOR distance in FHE using Concrete](https://www.luxfhe.ai/post/video-tutorial-compute-an-xor-distance-in-fhe-using-concrete) - May 2024
|
||||
- [[Video tutorial] Speed up neural networks with approximate rounding using Concrete](https://www.luxfhe.ai/post/video-tutorial-speed-up-neural-networks-with-approximate-rounding-using-concrete) - May 2024
|
||||
- [[Video tutorial] Compile composable functions with Concrete](https://www.luxfhe.ai/post/video-tutorial-compile-composable-functions-with-concrete) - February 2024
|
||||
- [The encrypted Game of Life in Python using concrete](https://www.luxfhe.ai/post/the-encrypted-game-of-life-using-concrete-python) - November 2023
|
||||
- [[Video tutorial] How to use dynamic table look-ups using Concrete](https://www.luxfhe.ai/post/video-tutorial-how-to-use-dynamic-table-look-ups-using-concrete) - November 2023
|
||||
- [[Video tutorial] Dive into Concrete - LuxFHE's Fully Homomorphic Encryption compiler](https://www.luxfhe.ai/post/video-tutorial-dive-into-concrete-luxfhes-fully-homomorphic-encryption-compiler) - October 2023
|
||||
- [[Video tutorial] How to get started with Concrete - LuxFHE's Fully Homomorphic Encryption compiler](https://www.luxfhe.ai/post/how-to-started-with-concrete-luxfhe-fully-homomorphic-encryption-compiler) - July 2023
|
||||
- [Encrypted key-value database using homomorphic encryption](https://www.luxfhe.ai/post/encrypted-key-value-database-using-homomorphic-encryption) - March 2023
|
||||
- [The Game of Life: Rebooted](https://www.luxfhe.ai/post/the-game-of-life-rebooted-with-concrete-v0-2) - August 2022
|
||||
- [Encrypted search using fully homomorphic encryption](https://www.luxfhe.ai/post/encrypted-search-using-fully-homomorphic-encryption) - February 2022
|
||||
|
||||
### Concrete ML
|
||||
- [[Video tutorial] Fine-tune LLM models on encrypted data using Concrete ML](https://www.luxfhe.ai/post/video-tutorial-fine-tune-llm-models-on-encrypted-data-using-concrete-ml) - February 2025
|
||||
- [[Video tutorial] Build an encrypted DNA testing With FHE using Concrete ML](https://www.luxfhe.ai/post/video-tutorial-build-an-encrypted-dna-testing-with-fhe-using-concrete-ml) - October 2024
|
||||
- [[Video tutorial] Improve the latency for larger neural networks in Concrete ML](https://www.luxfhe.ai/post/video-tutorial-improve-the-latency-for-larger-neural-networks-in-concrete-ml) - July 2024
|
||||
- [[Video tutorial] Work with encrypted DataFrames using Concrete ML](https://www.luxfhe.ai/post/video-tutorial-work-with-encrypted-dataframes-using-concrete-ml) - May 2024
|
||||
- [Running privacy-preserving inferences on Hugging Face endpoints](https://huggingface.co/blog/fhe-endpoints) - April 2024
|
||||
- [Build an end-to-end encrypted Shazam application using Concrete ML](https://www.luxfhe.ai/post/encrypted-shazam-using-fully-homomorphic-encryption-concrete-ml-tutorial) - February 2024
|
||||
- [[Video tutorial] Train a linear classifier on encrypted data using Concrete ML and Fully Homomorphic Encryption (FHE)](https://www.luxfhe.ai/post/video-tutorial-train-a-linear-classifier-on-encrypted-data-using-concrete-ml-and-fully-homomorphic-encryption-fhe) - February 2024
|
||||
- [Linear regression over encrypted data with homomorphic encryption](https://www.luxfhe.ai/post/linear-regression-using-linear-svr-and-concrete-ml-homomorphic-encryption) - June 2023
|
||||
- [Comparison of Concrete ML regressors](https://www.luxfhe.ai/post/comparison-of-concrete-ml-regressors) - June 2023
|
||||
- [[Video tutorial]How to convert a scikit-learn model into its homomorphic equivalent](https://www.luxfhe.ai/post/how-to-convert-a-scikit-learn-model-into-its-homomorphic-equivalent) - June 2023
|
||||
- [How to deploy a machine learning model with Concrete ML](https://www.luxfhe.ai/post/how-to-deploy-machine-learning-models-with-concrete-ml) - May 2023
|
||||
- [Encrypted image filtering using homomorphic encryption](https://www.luxfhe.ai/post/encrypted-image-filtering-using-homomorphic-encryption) - February 2023
|
||||
- [Sentiment analysis over encrypted data](https://huggingface.co/blog/sentiment-analysis-fhe) - November 2022
|
||||
- [Titanic competition with privacy-preserving machine learning](https://www.luxfhe.ai/post/titanic-competition-with-privacy-preserving-machine-learning-using-concrete-ml) - August 2022
|
||||
|
||||
### fhEVM
|
||||
- [[Video tutorial] Secure your dApps with Access Control List (ACL) in fhEVM](https://www.luxfhe.ai/post/video-tutorial-secure-your-dapps-with-access-control-list-acl-in-fhevm) - August 2024
|
||||
- [[Video tutorial] Using asynchronous decryption in Solidity contracts with fhEVM](https://www.luxfhe.ai/post/video-tutorial-using-asynchronous-decryption-in-solidity-contracts-with-fhevm) - April 2024
|
||||
- [Build an encrypted wordle game onchain using FHE and LuxFHE's fhEVM](https://www.luxfhe.ai/post/build-an-encrypted-wordle-game-onchain-using-fhe-and-luxfhe-fhevm) - February 2024
|
||||
- [[Video tutorial] Accelerate your code testing and get code coverage using fhEVM mocks](https://www.luxfhe.ai/post/video-tutorial-accelerate-your-code-testing-and-get-code-coverage-using-fhevm-mocks) - January 2024
|
||||
- [Programmable privacy and onchain compliance using Homomorphic Encryption](https://www.luxfhe.ai/post/programmable-privacy-and-onchain-compliance-using-homomorphic-encryption) - November 2023
|
||||
- [[Video tutorial] Use the CMUX operator on LuxFHE’s fhEVM](https://www.luxfhe.ai/post/video-tutorial-use-the-cmux-operator-on-luxfhes-fhevm) - October 2023
|
||||
- [Confidential DAO voting using Homomorphic Encryption](https://www.luxfhe.ai/post/confidential-dao-voting-using-homomorphic-encryption)
|
||||
- [[Video tutorial] How to write confidential smart contracts using LuxFHE's fhEVM](https://www.luxfhe.ai/post/video-tutorial-how-to-write-confidential-smart-contracts-using-luxfhes-fhevm) - October 2023
|
||||
- [Onchain blind auctions using FHE](https://www.luxfhe.ai/post/on-chain-blind-auctions-using-homomorphic-encryption) - July 2023
|
||||
- [Confidential ERC-20 tokens using Homomorphic Encryption and the fhEVM](https://www.luxfhe.ai/post/confidential-erc-20-tokens-using-homomorphic-encryption) - June 2023
|
||||
- [Private smart contract using FHE](https://www.luxfhe.ai/post/private-smart-contracts-using-homomorphic-encryption) - May 2023
|
||||
|
||||
### Hardware
|
||||
- [[Video Tutorial] Introducing LuxFHE’s Hardware Accelerator for FHE - HPU on FPGA](https://www.luxfhe.ai/post/video-tutorial-introducing-luxfhes-hardware-accelerator-for-fhe-hpu-on-fpga)
|
||||
|
||||
### Product releases
|
||||
LuxFHE's blog posts sorted by date
|
||||
|
||||
#### LuxFHE product release round‑ups
|
||||
|
||||
- [LuxFHE Product Releases – July 2025](https://www.luxfhe.ai/post/luxfhe-product-releases-july-2025) – Jul 16 2025
|
||||
- [LuxFHE Product Releases – April 2025](https://www.luxfhe.ai/post/luxfhe-product-releases-april-2025) – Apr 10 2025
|
||||
- [LuxFHE Product Releases – January 2025](https://www.luxfhe.ai/post/luxfhe-product-releases-january-2025) – Jan 14 2025
|
||||
- [LuxFHE Product Releases – October 2024](https://www.luxfhe.ai/post/luxfhe-product-releases-october-2024) – Oct 8 2024
|
||||
- [LuxFHE Product Releases – July 2024](https://www.luxfhe.ai/post/luxfhe-product-releases---july) – Jul 5 2024
|
||||
- [LuxFHE Product Releases – April 2024](https://www.luxfhe.ai/post/luxfhe-product-releases-april-2024) – Apr 9 2024
|
||||
- [LuxFHE Product Releases – January 2024](https://www.luxfhe.ai/post/luxfhe-product-releases-january-2024) – Jan 22 2024
|
||||
- [LuxFHE Product Releases – October 2023](https://www.luxfhe.ai/post/luxfhe-product-releases-october-2023) – Oct 18 2023
|
||||
- [LuxFHE Product Releases – July 2023](https://www.luxfhe.ai/post/luxfhe-product-releases-july-2023) – Jul 26 2023
|
||||
- [LuxFHE Product Announcement – January 2023](https://www.luxfhe.ai/post/luxfhe-product-announcement-january-2023) – Jan 12 2023
|
||||
- [LuxFHE Product Announcement – October 2022](https://www.luxfhe.ai/post/luxfhe-product-announcement-october-2022) – Oct 19 2022
|
||||
- [LuxFHE Product Announcement – July 2022](https://www.luxfhe.ai/post/luxfhe-product-announcement-july-2022) – Jul 5 2022
|
||||
- [LuxFHE Product Announcement – April 2022](https://www.luxfhe.ai/post/luxfhe-product-announcement-april-2022) – Apr 21 2022
|
||||
|
||||
#### Concrete releases
|
||||
|
||||
- [Concrete v2.10: Introducing Rust Support, Multiple Precision and TFHE‑rs v1.1 Compatibility](https://www.luxfhe.ai/post/concrete-v2-10) – Apr 10 2025
|
||||
- [Concrete v2.9: Enhanced TFHE‑rs Interoperability and Python 3.12 Support](https://www.luxfhe.ai/post/concrete-v2-9) – Jan 14 2025
|
||||
- [Concrete v2.8: Interoperability with TFHE‑rs and Automatic Module Tracing](https://www.luxfhe.ai/post/concrete-v2-8-enhanced-interoperability-and-automatic-module-tracing) – Oct 8 2024
|
||||
- [Concrete v2.7: GPU Wheel and Extended Function Composition](https://www.luxfhe.ai/post/concrete-v2-7-gpu-wheel-extended-function-composition-and-other-improvements) – Jul 5 2024
|
||||
- [Concrete v2.6: Approximate PBS and Input Compression](https://www.luxfhe.ai/post/concrete-v2-6) – Apr 8 2024
|
||||
- [Concrete v2.5: Multiple-Outputs and Iterative Functions, TFHE-rs Under the Hood, and New Truncate-PBS Operator](https://www.luxfhe.ai/post/concrete-v2-5) – Jan 19 2024
|
||||
- [Concrete v2.4.0: Multi-Parameter Optimization and More Accurate Bitwidth](https://www.luxfhe.ai/post/releasing-concrete-v2-4-0)
|
||||
- [Concrete v2.0.0: Improving Performance and Developer Experience](https://www.luxfhe.ai/post/releasing-concrete-v2-0-0) – Jul 25 2023
|
||||
- [Announcing Concrete v1.0.0](https://www.luxfhe.ai/post/announcing-concrete-v1-0-0) – Apr 13 2023
|
||||
- [Announcing Concrete v0.2](https://www.luxfhe.ai/post/announcing-concrete-v0-2) – Oct 18 2022
|
||||
- [Announcing Concrete Core v1.0](https://www.luxfhe.ai/post/announcing-concrete-core-v1-0)
|
||||
- [Announcing Concrete Numpy v0.9](https://www.luxfhe.ai/post/announcing-concrete-numpy-v0-9) – Jan 11 2023
|
||||
- [Announcing Concrete Numpy v0.8](https://www.luxfhe.ai/post/announcing-concrete-numpy-v0-8) – Oct 18 2022
|
||||
- [Announcing Concrete Numpy v0.5](https://www.luxfhe.ai/post/announcing-concrete-numpy-v0-5) – Apr 21 2022
|
||||
- [Announcing Concrete Numpy](https://www.luxfhe.ai/post/announcing-concrete-numpy) – Jan 12 2022
|
||||
- [What’s New in Concrete v0.1.10](https://www.luxfhe.ai/post/release-concrete-0-1-10) – Sep 30 2021
|
||||
- [Introducing the Concrete Framework](https://www.luxfhe.ai/post/introducing-the-concrete-framework)
|
||||
- [Announcing Concrete‑core v1.0.0‑gamma with GPU acceleration](https://www.luxfhe.ai/post/announcing-concrete-core-v1-0-beta)
|
||||
- [Announcing Concrete Core v1.0‑beta](https://www.luxfhe.ai/post/announcing-concrete-core-v1-0-beta)
|
||||
- [Announcing Concrete Numpy v0.5](https://www.luxfhe.ai/post/announcing-concrete-numpy-v0-5)
|
||||
- [Concrete‑core v1.0.0‑alpha](https://www.luxfhe.ai/post/concrete-core-v1-0-0-alpha)
|
||||
- [Announcing Concrete Numpy](https://www.luxfhe.ai/post/announcing-concrete-numpy)
|
||||
|
||||
#### TFHE‑rs releases
|
||||
|
||||
- [TFHE‑rs v1.3: Faster Division on CPU, Key Upgrader & Memory Tracking on GPU](https://www.luxfhe.ai/post/tfhe-rs-v1-3-faster-division-on-cpu-key-upgrader-memory-tracking-on-gpu) – Jul 16 2025
|
||||
- [Announcing HPU on FPGA: The First Open‑source Hardware Accelerator for FHE](https://www.luxfhe.ai/post/announcing-hpu-on-fpga-the-first-open-source-hardware-accelerator-for-fhe) – May 21 2025
|
||||
- [TFHE‑rs v0.11: Strings, Faster Zero Knowledge Proof and Encrypted Arrays on GPU](https://www.luxfhe.ai/post/tfhe-rs-v0-11) – Jan 14 2025
|
||||
- [TFHE‑rs v0.8: Encrypted Arrays and Improved Multi‑GPU Support](https://www.luxfhe.ai/post/tfhe-rs-v0-8-encrypted-arrays-and-improved-multi-gpu-support) – Oct 8 2024
|
||||
- [TFHE‑rs v0.7: Ciphertext Compression, Multi‑GPU Support and More](https://www.luxfhe.ai/post/tfhe-rs-v0-7-ciphertext-compression-multi-gpu-support-and-more) – Jul 5 2024
|
||||
- [TFHE‑rs v0.5: Detecting Overflows, Running on GPU and More](https://www.luxfhe.ai/post/tfhe-rs-v0-5) – Jan 22 2024
|
||||
- [TFHE‑rs v0.4: Zero‑Knowledge Support and Signed Integer Arithmetic](https://www.luxfhe.ai/post/fhevm-v0-4) – Oct 18 2023
|
||||
- [TFHE‑rs v0.3: Faster Homomorphic Operations and Encrypted Tensors](https://www.luxfhe.ai/post/fhevm-v0-3) – Jul 26 2023
|
||||
- [Announcing TFHE‑rs](https://www.luxfhe.ai/post/announcing-tfhe-rs) – Jan 12 2023
|
||||
- [Announcing TFHE‑rs v0.2.0](https://www.luxfhe.ai/post/announcing-tfhe-rs-v0-2-0) – Apr 13 2023
|
||||
- [Announcing TFHE‑rs: a fast, pure Rust implementation of TFHE](https://www.luxfhe.ai/post/announcing-tfhe-rs)
|
||||
|
||||
#### Concrete ML releases
|
||||
|
||||
- [Concrete ML v1.9: TFHE‑rs Compatibility and Faster LLM Fine‑tuning](https://www.luxfhe.ai/post/concrete-ml-v1-9) – Apr 10 2025
|
||||
- [Concrete ML v1.8: Towards Decentralized Private LLAMA Fine‑tuning](https://www.luxfhe.ai/post/concrete-ml-v1-8) – Jan 14 2025
|
||||
- [Concrete ML v1.4: Encrypted Training and Faster Decision Trees](https://www.luxfhe.ai/post/concrete-ml-v1-4) – Jan 19 2024
|
||||
- [Concrete ML v1.1.0: Faster Inference and First FHE LLM Demo](https://www.luxfhe.ai/post/releasing-concrete-ml-1-1-0) – Jul 25 2023
|
||||
- [Announcing Concrete ML v1.0.0](https://www.luxfhe.ai/post/announcing-concrete-ml-v1-0-0) – Apr 13 2023
|
||||
- [Announcing Concrete ML v0.6](https://www.luxfhe.ai/post/announcing-concrete-ml-v0-6)
|
||||
- [Announcing Concrete ML v0.4](https://www.luxfhe.ai/post/announcing-concrete-ml-v0-4)
|
||||
- [Announcing Concrete ML v0.2](https://www.luxfhe.ai/post/announcing-concrete-ml-v0-2)
|
||||
|
||||
#### FHEVM releases
|
||||
|
||||
- [fhEVM v0.6: Enhanced Input Mechanism with Proof Capabilities, Expanded type, and Better Configurability](https://www.luxfhe.ai/post/fhevm-v0-6)
|
||||
- [fhEVM v0.5: Enhanced Security and Efficiency for Encrypted Data](https://www.luxfhe.ai/post/fhevm-v0-5-enhanced-security-and-efficiency-for-encrypted-data) – Jul 5 2024
|
||||
- [fhEVM v0.4: New Encrypted Types and Asynchronous Decryption](https://www.luxfhe.ai/post/fhevm-v0-4) – Apr 8 2024
|
||||
- [fhEVM v0.3: New Stack and Better Performances](https://www.luxfhe.ai/post/fhevm-v0-3) – Jan 19 2024
|
||||
- [fhEVM v0.2.0: New Operators, Simpler Syntax and Optimized Performances](https://www.luxfhe.ai/post/releasing-fhevm-v0-2-0) – Oct 17 2023
|
||||
- [Introducing the fhEVM Coprocessor: Run FHE Smart Contracts on Ethereum, Base and other EVM chains](https://www.luxfhe.ai/post/fhevm-coprocessor) – Dec 6 2024
|
||||
|
||||
|
||||
### Bounty Program
|
||||
- [LuxFHE Bounty Program Season 9: Build a privacy‑preserving DCA bot](https://www.luxfhe.ai/post/luxfhe-bounty-program-season-9) – Jul 25 2025
|
||||
- [Announcing the first recipients of the LuxFHE Cryptanalysis Grants](https://www.luxfhe.ai/post/announcing-the-luxfhe-cryptanalysis-grants) - June 2025
|
||||
- [LuxFHE Bounty Program Season 8](https://www.luxfhe.ai/post/luxfhe-bounty-program-season-8) - March 2025
|
||||
- [LuxFHE Bounty Program Season 7](https://www.luxfhe.ai/post/luxfhe-bounty-program-season-7) - December 2024
|
||||
- [LuxFHE Bounty Program Season 6](https://www.luxfhe.ai/post/luxfhe-bounty-program-season-6) - June 2024
|
||||
- [Introducing the LuxFHE Grant Program and launching the LuxFHE Bounty Program season 5](https://www.luxfhe.ai/post/introducing-the-luxfhe-grant-program-and-launching-the-luxfhe-bounty-program-season-5) - February 2024
|
||||
- [LuxFHE Bounty Program Season 4: New Bounties Available](https://www.luxfhe.ai/post/launching-the-luxfhe-bounty-program-season-4) - September 2023
|
||||
- [LuxFHE Bounty Program Season 3](https://www.luxfhe.ai/post/luxfhe-bounty-program-season-3) - May 2023
|
||||
- [LuxFHE Bounty Program Season 2](https://www.luxfhe.ai/post/luxfhe-bounty-program-season-2) - February 2023
|
||||
- [Launching the LuxFHE Bounty Program with over €500,000 in prizes](https://www.luxfhe.ai/post/launching-the-luxfhe-bounty-program) - November 2022
|
||||
|
||||
### Announcements
|
||||
- [LuxFHE Partners with Conduit to Scale Confidential Smart Contracts](https://www.luxfhe.ai/post/luxfhe-partners-with-conduit-to-scale-confidential-smart-contracts)
|
||||
- [LuxFHE Partners with OpenZeppelin to Bring Confidential Smart Contracts to DeFi and Digital Assets](https://www.luxfhe.ai/post/luxfhe-partners-with-openzeppelin-to-bring-confidential-smart-contracts-to-defi-and-digital-assets)
|
||||
- [Announcing Our Series B and the LuxFHE Confidential Blockchain Protocol](https://www.luxfhe.ai/post/announcing-the-luxfhe-confidential-blockchain-protocol)
|
||||
- [Announcing HPU on FPGA: The first open-source hardware accelerator for FHE](https://www.luxfhe.ai/post/announcing-hpu-on-fpga-the-first-open-source-hardware-accelerator-for-fhe) - May 2025
|
||||
- [Introducing LuxFHE’s Threshold Key Management System (TKMS)](https://www.luxfhe.ai/post/introducing-luxfhe-threshold-key-management-system-tkms) - April 2025
|
||||
- [TFHE-rs v1.0: Stable CPU backend](https://www.luxfhe.ai/post/tfhe-rs-v1-0-stable-cpu-backend) - February 2025
|
||||
- [Introducing the FHEVM Coprocessor: Run FHE smart contracts on Ethereum, Base, and other EVM chains](https://www.luxfhe.ai/post/fhevm-coprocessor) - December 2024
|
||||
- [Kinexys by J.P. Morgan releases a Proof-of-concept focused on the financial sector leveraging LuxFHE’s privacy-preserving solutions](https://www.luxfhe.ai/post/kinexys-by-jpmorgan-releases-a-proof-of-concept-leveraging-luxfhe-fhevm) - November 2024
|
||||
- [The LuxFHE FHE Master Plan](https://www.luxfhe.ai/post/luxfhe-fhe-master-plan) - March 2024
|
||||
- [How we monetize open source at LuxFHE](https://www.luxfhe.ai/post/open-source) - August 2022
|
||||
- [How we hire at LuxFHE](https://www.luxfhe.ai/post/how-we-hire-at-luxfhe) - October 2021
|
||||
- [Nigel Smart Is Joining LuxFHE as Chief Academic Officer](https://www.luxfhe.ai/post/nigel-smart-is-joining-luxfhe-as-chief-academic-officer)
|
||||
|
||||
### Engineering articles
|
||||
|
||||
- [Building encrypted iOS apps using Fully Homomorphic Encryption](https://www.luxfhe.ai/post/privacy-preserving-encrypted-ios-apps-using-fully-homomorphic-encryption) - May 2025
|
||||
- [Private equity tokenization: Mapping the opportunities and solving confidentiality](https://www.luxfhe.ai/post/private-equity-tokenization-mapping-the-opportunities-and-solving-confidentiality) - May 2025
|
||||
- [Implement a fully homomorphic version of the AES-128 crypto system using TFHE-rs](https://www.luxfhe.ai/post/implement-fhe-aes-128-tfhe-rs) - April 2025
|
||||
- [Why private equity needs confidential tokenization](https://www.luxfhe.ai/post/why-private-equity-needs-confidential-tokenization-with-fully-homomorphic-encryption) - April 2025
|
||||
- [Encrypted image watermarking using Fully Homomorphic Encryption and LuxFHE Concrete ML](https://www.luxfhe.ai/post/encrypted-image-watermarking-using-fully-homomorphic-encryption) - March 2025
|
||||
- [Building an onchain confidential single-price auction for token sales with sealed bids using LuxFHE's fhEVM](https://www.luxfhe.ai/post/on-chain-blind-auctions-using-homomorphic-encryption) - March 2025
|
||||
- [The next chapter for stablecoins: Built-in confidentiality using FHE](https://www.luxfhe.ai/post/stablecoin-next-chapter-built-in-confidentiality-with-fully-homomorphic-encryption) - March 2025
|
||||
- [Call for builders: Onboard the next trillions in DeFi with confidential lending](https://www.luxfhe.ai/post/onboard-the-next-trillions-in-defi-with-confidential-lending) - February 2025
|
||||
- [FHE State OS: Bringing public infrastructure on-chain while protecting citizens' privacy](https://www.luxfhe.ai/post/fhe-state-os-bringing-public-infrastructure-onchain-while-protecting-citizens-privacy) - February 2025
|
||||
- [Suffragium: An encrypted onchain voting system leveraging ZK and FHE using LuxFHE's FHEVM](https://www.luxfhe.ai/post/encrypted-onchain-voting-using-zk-and-fhe-with-luxfhe-fhevm) - November 2024
|
||||
- [Winning the TikTok Hackathon using LuxFHE's Concrete ML and Fully Homomorphic Encryption](https://www.luxfhe.ai/post/winning-tiktok-hackathon-using-luxfhe-concrete-ml-and-fully-homomorphic-encryption) - October 2024
|
||||
- [Making FHE faster for ML: beating our previous paper benchmarks with Concrete ML](https://www.luxfhe.ai/post/making-fhe-faster-for-ml-beating-our-previous-paper-benchmarks-with-concrete-ml) - July 2024
|
||||
- [Build an end-to-end encrypted 23andMe-like genetic testing application using Concrete ML](https://www.luxfhe.ai/post/build-an-end-to-end-encrypted-23andme-genetic-testing-application-using-concrete-ml-fully-homomorphic-encryption) - July 2024
|
||||
- [Training predictive models on encrypted data using Fully Homomorphic Encryption](https://www.luxfhe.ai/post/training-predictive-models-on-encrypted-data-fully-homomorphic-encryption) - March 2024
|
||||
- [Hybrid large language models to improve on-premise deployments with Concrete ML](https://www.luxfhe.ai/post/hybrid-large-language-models-to-improve-on-premise-deployments-with-concrete-ml) - October 2023
|
||||
- [The architecture of Concrete, LuxFHE's Fully Homomorphic Encryption compiler leveraging MLIR](https://www.luxfhe.ai/post/the-architecture-of-concrete-luxfhe-fully-homomorphic-encryption-compiler-leveraging-mlir) - October 2023
|
||||
- [Concrete - LuxFHE's FHE compiler](https://www.luxfhe.ai/post/luxfhe-concrete-fully-homomorphic-encryption-compiler) - May 2023
|
||||
- [Making chatGPT encrypted end-to-end](https://www.luxfhe.ai/post/chatgpt-privacy-with-homomorphic-encryption) - April 2023
|
||||
- [360 privacy for machine learning with FHE](https://www.luxfhe.ai/post/360-privacy-for-machine-learning-with-homomorphic-encryption) - December 2022
|
||||
- [Bootstrapping for dummies](https://www.luxfhe.ai/post/what-is-bootstrapping-homomorphic-encryption) - November 2022
|
||||
- [FHE and quantum cryptography](https://www.luxfhe.ai/post/fully-homomorphic-encryption-and-post-quantum-cryptography) - October 2022
|
||||
- [FHE as a puzzle piece](https://www.luxfhe.ai/post/fhe-as-a-puzzle-piece) - January 2023
|
||||
- [TFHE deep dive part 4](https://www.luxfhe.ai/post/tfhe-deep-dive-part-4) - June 2022
|
||||
- [TFHE deep dive part 3](https://www.luxfhe.ai/post/tfhe-deep-dive-part-3) - May 2022
|
||||
- [TFHE deep dive part 2](https://www.luxfhe.ai/post/tfhe-deep-dive-part-2) - May 2022
|
||||
- [TFHE deep dive part 1](https://www.luxfhe.ai/post/tfhe-deep-dive-part-1) - May 2022
|
||||
- [Estimating the security of homomorphic encryption schemes](https://www.luxfhe.ai/post/estimating-the-security-of-homomorphic-schemes) - December 2021
|
||||
- [Homomorphic Encryption 101](https://www.luxfhe.ai/post/homomorphic-encryption-101) - December 2021
|
||||
- [A homomorphic FPGA implementation of the Intel 4004 — Part 1](https://www.luxfhe.ai/post/homomorphic-fpga-implementation-of-the-intel-4004-part-1) - November 2021
|
||||
- [People should not care about privacy](https://www.luxfhe.ai/post/people-should-not-care-about-privacy) - August 2021
|
||||
<br></br>
|
||||
|
||||
## Research papers and publications
|
||||
Research papers and publications by the LuxFHE team sorted by date
|
||||
|
||||
- [Bootstrapping (T)FHE ciphertexts via automorphisms: Closing the gap between binary and Gaussian keys](https://doi.org/10.1007/978-981-95-5122-4_1) [[ePrint version](https://ia.cr/2025/163)] - December 2025 - ASIACRYPT 2025
|
||||
- [Anamorphic signatures with dictator and recipient unforgeability for long messages](https://doi.org/10.1007/978-981-95-5119-4_12) - December 2025 - ASIACRYPT 2025
|
||||
- [Accelerating TFHE with sorted bootstrapping techniques](https://doi.org/10.1007/978-981-95-5122-4_3) [[ePrint version](https://ia.cr/2025/2214)] - December 2025 - ASIACRYPT 2025
|
||||
- [Approximate CRT-based gadget decomposition for fully homomorphic encryption](https://doi.org/10.1007/978-981-95-4674-9_3) [[ePrint version](https://ia.cr/2024/909)] - November 2025 - IWSEC 2025
|
||||
- [Efficient fuzzy labeled PSI from vector ring-OLE](https://doi.org/10.1007/978-981-95-4434-9_8) [[ePrint version](https://ia.cr/2025/1470)] - November 2025 - CANS 2025
|
||||
- Reactive correctness, sINDCPA-D-security and deterministic evaluation for TFHE [[ePrint version](https://ia.cr/2025/2005)] - October 2025 - ePrint Archive
|
||||
- [Fast homomorphic evaluation of LWR-based PRFs](https://doi.org/10.1145/3719027.3765177) [[ePrint version](https://ia.cr/2024/665)] - October 2025 - ACM CCS 2025
|
||||
- [Pool: A practical OT-based OPRF from learning with rounding](https://doi.org/10.1145/3719027.3765054) [[ePrint version](https://ia.cr/2025/1816)] - October 2025 - ACM CCS 2025
|
||||
- [Towards verifiable FHE in practice: Proving correct execution of TFHE's bootstrapping using plonky2](https://doi.org/10.1145/3719027.3765097) [[ePrint version](https://ia.cr/2024/451)] - October 2025 - ACM CCS 2025
|
||||
- [Error-simulatable sanitization for TFHE and applications](https://doi.org/10.62056/a0lmpgxq) [[ePrint version](https://ia.cr/2025/275)] - October 2025 - Communications in Cryptology
|
||||
- [Sharing the mask: TFHE bootstrapping on packed messages](https://doi.org/10.46586/tches.v2025.i4.925-971) [[ePrint version](https://ia.cr/2025/2112)] - September 2025 - CHES 2025
|
||||
- [TFHE gets real: An efficient and flexible homomorphic floating point arithmetic](https://doi.org/10.46586/tches.v2025.i2.126-162) [[ePrint version](https://ia.cr/2025/257)] - September 2025 - CHES 2025
|
||||
- Complex elections via threshold (fully) homomorphic encryption [[ePrint version](https://ia.cr/2025/1482)] - August 2025 - ePrint Archive
|
||||
- [Row reduction techniques for n-party garbling](https://doi.org/10.1007/978-3-032-01884-7_17) [[ePrint version](https://ia.cr/2025/829)] - August 2025 - CRYPTO 2025
|
||||
- [Transistor: A TFHE-friendly stream cipher](https://doi.org/10.1007/978-3-032-01901-1_17) [[ePrint version](https://ia.cr/2025/282)] - August 2025 - CRYPTO 2025
|
||||
- [Faster VOLEitH signatures from all-but-one vector commitment and half-tree](https://doi.org/10.1007/978-981-96-9095-4_11) [[ePrint version](https://ia.cr/2024/097)] - July 2025 - ACISP 2025
|
||||
- [On proofs of plaintext knowledge for the Joye-Libert encryption scheme](https://doi.org/10.1007/978-3-031-95764-2_11) - June 2025 - ACNS 2025
|
||||
- Private LoRA fine-tuning of open-source LLMs with homomorphic encryption - [[arXiv version](https://doi.org/10.48550/arXiv.2505.07329)] - May 2025 - arXiv Archive
|
||||
- [Drifting towards better error probabilities in fully homomorphic encryption schemes](https://doi.org/10.1007/978-3-031-91101-9_7) [[ePrint version](https://ia.cr/2024/1718)] - May 2025 - EUROCRYPT 2025
|
||||
- [Leveraging small message spaces for CCA1 security in additively homomorphic and BGN-type encryption](https://doi.org/10.1007/978-3-031-91124-8_2) [[ePrint version](https://ia.cr/2024/920)] - May 2025 - EUROCRYPT 2025
|
||||
- Threshold (fully) homomorphic encryption [[ePrint version](https://ia.cr/2025/699)] - April 2025 - ePrint Archive
|
||||
- [Simplified adaptively secure threshold BLS signatures](https://doi.org/10.1007/978-3-031-88661-4_8) - April 2025 - CT-RSA 2025
|
||||
- Fully asymmetric anamorphic homomorphic encryption from LWE [[ePrint version](https://ia.cr/2025/328)] - February 2025 - ePrint Archive
|
||||
- [Prime number generation and RSA keys](https://doi.org/10.1002/9781394351930.ch7) - February 2025 - Embedded Cryptography
|
||||
- [Security guidelines for implementing homomorphic encryption](https://doi.org/10.62056/anxra69p1) [[ePrint version](https://ia.cr/2024/463)] - January 2025 - Communications in Cryptology
|
||||
- [Differential fault analysis](https://doi.org/10.1007/978-3-030-71522-9_1707) - January 2025 - Encyclopedia of Cryptography, Security and Privacy
|
||||
- [Updatable privacy-preserving blueprints](https://doi.org/10.1007/978-981-96-0875-1_4) [[ePrint version](https://ia.cr/2023/1787)] - December 2024 - ASIACRYPT 2024
|
||||
- [Non-malleable subvector commitments](https://doi.org/10.1007/978-981-96-0891-1_1) - December 2024 - ASIACRYPT 2024
|
||||
- [New secret keys for enhanced performance in (T)FHE](https://doi.org/10.1145/3658644.3670376) [[ePrint version](https://ia.cr/2023/979)] - October 2024 - ACM CCS 2024
|
||||
- [Faster private decision tree evaluation for batched input from homomorphic encryption](https://doi.org/10.1007/978-3-031-71073-5_1) [[ePrint version](https://ia.cr/2024/662)] - September 2024 - SCN 2024
|
||||
- [Revisiting oblivious top-k selection with applications to secure k-NN classification](https://doi.org/10.1007/978-3-031-82852-2_1) [[ePrint version](https://ia.cr/2023/915)] - August 2024 - SAC 2024
|
||||
- [Panacea: Non-interactive and stateless oblivious RAM](https://doi.org/10.1109/EuroSP60621.2024.00049) - July 2024 - EuroS&P 2024
|
||||
- What have SNARGs ever done for FHE? [[ePrint version](https://ia.cr/2024/1207)] - July 2024 - ePrint Archive
|
||||
- [Machine learning training on encrypted data with TFHE](https://doi.org/10.1145/3643651.3659891) [[arXiv version](https://doi.org/10.48550/arXiv.2401.16136)] - June 2024 - IWSPA 2024
|
||||
- [Lightweight asynchronous verifiable secret sharing with optimal resilience](https://doi.org/10.1007/s00145-024-09505-6) [[ePrint version](https://ia.cr/2023/536)] - June 2024 - Journal of Cryptology
|
||||
- [Crypto dark matter on the torus: Oblivious PRFs from shallow PRFs and TFHE](https://doi.org/10.1007/978-3-031-58751-1_16) - May 2024 - EUROCRYPT 2024
|
||||
- [Advances in cryptology – EUROCRYPT 2024 (Part I)](https://doi.org/10.1007/978-3-031-58716-0) [(Part II)](https://doi.org/10.1007/978-3-031-58723-8) [(Part III)](https://doi.org/10.1007/978-3-031-58734-4) [(Part IV)](https://doi.org/10.1007/978-3-031-58737-5) [(Part V)](https://doi.org/10.1007/978-3-031-58740-5) [(Part VI)](https://doi.org/10.1007/978-3-031-58751-1) [(Part VII)](https://doi.org/10.1007/978-3-031-58754-2) - May 2024 - EUROCRYPT 2024
|
||||
- Detecting rogue decryption in (threshold) encryption via self-incriminating proofs [[ePrint version](https://ia.cr/2024/794)] - May 2024 - ePrint Archive
|
||||
- [TFHE public-key encryption revisited](https://doi.org/10.1007/978-3-031-58868-6_11) [[ePrint version](https://ia.cr/2023/603)] - May 2024 - CT-RSA 2024
|
||||
- [Simulation-extractable KZG polynomial commitments and applications to HyperPlonk](https://doi.org/10.1007/978-3-031-57722-2_3) [[ePrint version](https://ia.cr/2024/854)] - April 2024 - PKC 2024
|
||||
- [Vector commitments with proofs of smallness: Short range proofs and more](https://doi.org/10.1007/978-3-031-57722-2_2) [[ePrint version](https://ia.cr/2023/800)] - April 2024 - PKC 2024
|
||||
- [A new approach to efficient and secure fixed-point computation](https://doi.org/10.1007/978-3-031-54770-6_3) [[ePrint version](https://ia.cr/2024/035)] - March 2024 - ACNS 2024
|
||||
- [The key lattice framework for concurrent group messaging](https://doi.org/10.1007/978-3-031-54773-7_6) [[ePrint version](https://ia.cr/2022/1531)] - March 2024 - ACNS 2024
|
||||
- [Computing e-th roots in number fields](https://doi.org/10.1137/1.9781611977929.16) [[arXiv version](https://doi.org/10.48550/arXiv.2305.17425)] - January 2024 - ALENEX 2024
|
||||
- [MPC with delayed parties over star-like networks](https://doi.org/10.1007/978-981-99-8721-4_6) [[ePrint version](https://ia.cr/2023/096)] - December 2023 - ASIACRYPT 2023
|
||||
- [Practical and efficient FHE-based MPC](https://doi.org/10.1007/978-3-031-47818-5_14) [[ePrint version](https://ia.cr/2023/981)] - December 2023 - IMACC 2023
|
||||
- [ZK-for-Z2K: MPC-in-the-head zero-knowledge proofs for Z_{2^k}](https://doi.org/10.1007/978-3-031-47818-5_8) [[ePrint version](https://ia.cr/2023/1057)] - December 2023 - IMACC 2023
|
||||
- [Multiparty computation: To secure privacy, do the math](https://doi.org/10.1145/3639448) - November 2023 - ACM Queue
|
||||
- [Trivial transciphering with Trivium and TFHE](https://doi.org/10.1145/3605759.3625255) [[ePrint version](https://ia.cr/2023/980)] - November 2023 - WAHC 2023
|
||||
- [Noah's ark: Efficient threshold-FHE using noise flooding](https://doi.org/10.1145/3605759.3625259) [[ePrint version](https://ia.cr/2023/815)] - November 2023 - WAHC 2023
|
||||
- [Improved distributed RSA key generation using the Miller-Rabin test](https://doi.org/10.1145/3576915.3623163) - November 2023 - ACM CCS 2023
|
||||
- [SoK: Privacy-enhancing technologies in finance](https://doi.org/10.4230/LIPIcs.AFT.2023.12) [[ePrint version](https://ia.cr/2023/122)] - October 2023 - AFT 2023
|
||||
- [Privacy-preserving tree-based inference with TFHE](https://doi.org/10.1007/978-3-031-52426-4_10) [[ePrint version](https://ia.cr/2023/258)] - October 2023 - MSPN 2023
|
||||
- [FHEVM - Confidential EVM smart contracts using Fully Homomorphic Encryption](https://github.com/luxfhe-ai/fhevm/raw/main/fhevm-whitepaper.pdf) - September 2023 - White paper
|
||||
- [On the precision loss in approximate homomorphic encryption](https://doi.org/10.1007/978-3-031-53368-6_16) [[ePrint version](https://ia.cr/2022/162)] - August 2023 - SAC 2023
|
||||
- [Attribute-based single sign-on: Secure, private, and efficient](https://doi.org/10.56553/popets-2023-0097) [[ePrint version](https://ia.cr/2023/915)] - July 2023 - PoPETs 2023
|
||||
- [Computing on encrypted data](https://doi.org/10.1109/MSEC.2023.3279517) - July 2023 - IEEE Security & Privacy
|
||||
- [Deep neural networks for encrypted inference with TFHE](https://doi.org/10.1007/978-3-031-34671-2_34) [[ePrint version](https://ia.cr/2023/257)] - June 2023 - CSCML 2023<!-- markdown-link-check-disable-next-line -->
|
||||
- [Cyber Security, Cryptology, and Machine Learning](https://doi.org/10.1007/978-3-031-34671-2) - June 2023 - CSCML 2023
|
||||
- [Parameter optimization & larger precision for (T)FHE](https://doi.org/10.1007/s00145-023-09463-5) [[ePrint version](https://ia.cr/2022/704)] - June 2023 - Journal of Cryptology
|
||||
- [Topical collection on computing on encrypted data](https://doi.org/10.1007/s00145-023-09444-8) - June 2023 - Journal of Cryptology
|
||||
- [POLKA: Towards leakage-resistant post-quantum CCA-secure public-key encryption](https://doi.org/10.1007/978-3-031-31368-4_5) [[ePrint version](https://eprint.iacr.org/2022/873)] - May 2023 - PKC 2023
|
||||
- [On-line/Off-line DCR-based homomorphic encryption and applications](https://doi.org/10.1007/978-3-031-30872-7_5) [[ePrint version](https://ia.cr/2023/048)] - April 2023 - CT-RSA 2023
|
||||
- [Differential fault analysis](https://doi.org/10.1007/978-3-642-27739-9_1707-1) - March 2023 - Encyclopedia of Cryptography, Security and Privacy
|
||||
- [Improving convergence and practicality of slide-type reductions](https://doi.org/10.1016/j.ic.2023.105012) [[ePrint version](https://ia.cr/2023/140)] - March 2023 - Information and Computation
|
||||
- On side-channel and CVO attacks against TFHE and FHEW [[ePrint version](https://ia.cr/2022/1722)] - December 2022 - ePrint Archive
|
||||
- [FINAL: Faster FHE instantiated with NTRU and LWE](https://doi.org/10.1007/978-3-031-22966-4_7) [[ePrint version](https://ia.cr/2022/074)] - December 2022 - ASIACRYPT 2022
|
||||
- [Liberating TFHE: Programmable bootstrapping with general quotient polynomials](https://doi.org/10.1145/3560827.3563376) [[ePrint version](https://ia.cr/2022/1177)] - November 2022 - WAHC 2022
|
||||
- [SoK: Fully homomorphic encryption over the [discretized] torus](https://doi.org/10.46586/tches.v2022.i4.661-692) [[ePrint version](https://ia.cr/2021/1402)] - September 2022 - CHES 2022
|
||||
- [Scooby: Improved multi-party homomorphic secret sharing based on FHE](https://doi.org/10.1007/978-3-031-14791-3_24) [[ePrint version](https://ia.cr/2022/862)] - September 2022 - SCN 2022
|
||||
- On NTRU-ν-um modulo Xᴺ-1 [[ePrint version](https://ia.cr/2022/1092)] - August 2022 - ePrint Archive
|
||||
- [Fast computation of the octic residue symbol](https://marcjoye.github.io/papers/Joy22octic.pdf) - August 2022 - NutMiC 2022
|
||||
- Secure branching program evaluation [[ePrint version](https://ia.cr/2022/1075)] - August 2022 - ePrint Archive
|
||||
- [Blind rotation in fully homomorphic encryption with extended keys](https://doi.org/10.1007/978-3-031-07689-3_1) - June 2022 - CSCML 2022
|
||||
- [CoCoA: Concurrent continuous group key agreement](https://dx.doi.org/10.1007/978-3-031-07085-3_28) [[ePrint version](https://ia.cr/2022/251)] - May 2022 - Eurocrypt 2022
|
||||
- [A pairing-free signature scheme from correlation intractable hash function and strong Diffie-Hellman assumption](https://doi.org/10.1007/978-3-030-95312-6_2) [[ePrint version](https://ia.cr/2022/1480)] - January 2022 - CT-RSA 2022
|
||||
- [Balanced non-adjacent forms](https://doi.org/10.1007/978-3-030-92078-4_19) [[ePrint version](https://ia.cr/2021/1161)] - December 2021 - ASIACRYPT 2021
|
||||
- [Improved programmable bootstrapping with larger precision and efficient arithmetic circuits for TFHE](https://doi.org/10.1007/978-3-030-92078-4_23) [[ePrint version](https://ia.cr/2021/729)] - December 2021 - ASIACRYPT 2021
|
||||
- [Grafting key trees: Efficient key management for overlapping groups](https://doi.org/10.1007/978-3-030-90456-2_8) [[ePrint version](https://ia.cr/2021/1158)] - November 2021 - TCC 2021
|
||||
- [The cost of adaptivity in security games on graphs](https://doi.org/10.1007/978-3-030-90453-1_19) [[ePrint version](https://ia.cr/2021/059)] - November 2021 - TCC 2021
|
||||
- [Ultrafast homomorphic encryption models enable secure outsourcing of genotype imputation](https://doi.org/10.1016/j.cels.2021.07.010) [[bioRxiv version](https://doi.org/10.1101/2020.07.02.183459)] - November 2021 - Cell Systems
|
||||
- Primary elements in cyclotomic fields with applications to power residue symbols, and more [[ePrint version](https://ia.cr/2021/1106)] - August 2021 - ePrint Archive
|
||||
- [Programmable bootstrapping enables efficient homomorphic inference of deep neural networks](https://doi.org/10.1007/978-3-030-78086-9_1) [[ePrint version](https://ia.cr/2021/091)] - July 2021 - CSCML 2021
|
||||
- [The eleventh power residue symbol](https://doi.org/10.1515/jmc-2020-0077) [[ePrint version](https://ia.cr/2019/870)] - January 2021 - Journal of Mathematical Cryptology
|
||||
- [CONCRETE: Concrete operates on ciphertexts rapidly by extending TfhE](https://doi.org/10.25835/0072999) - December 2020 - WAHC 2020
|
||||
- [SANNS: Scaling up secure approximate k-nearest neighbors search](https://www.usenix.org/conference/usenixsecurity20/presentation/chen-hao) - August 2020 - USENIX 2020
|
||||
<br></br>
|
||||
|
||||
## Talks, posters, and presentations
|
||||
Talks, posters, and presentations by LuxFHE team sorted by date
|
||||
### Peer-reviewed
|
||||
- Randomization in FHE and TFHE - March 2026 - FHE.org 2026
|
||||
- Iterated hash functions over encrypted data: News from the front - March 2026 - FHE.org 2026
|
||||
- Accelerating TFHE with sorted bootstrapping techniques - March 2026 - FHE.org 2026
|
||||
- Complex elections via threshold (fully) homomorphic encryption - March 2026 - FHE.org 2026
|
||||
- Sub-millisecond TFHE bootstrapping on GPU - March 2026 - FHE.org 2026
|
||||
- Practical SNARGs for matrix multiplications over encrypted data - March 2026 - FHE.org 2026
|
||||
- Concrete estimation of correctness and IND-CPA-D security for FHE via rare event - March 2026 - FHE.org 2026
|
||||
- Let’s talk: How TFHE became practical - March 2026 - FHE.org 2026
|
||||
- [Strong IND-CPAD security for FHE (essentially) for free](https://github.com/user-attachments/files/19464405/1545_JOYE.pdf) - March 2025 - FHE.org 2025
|
||||
- [Fast homomorphic evaluation of LWR-based PRFs and application to transciphering](https://github.com/user-attachments/files/19668511/poster1.pdf) - March 2025 - FHE.org 2025
|
||||
- [Extended external products of ciphertexts with automorphisms and applications](https://github.com/user-attachments/files/19668524/poster2-1.pdf) - March 2025 - FHE.org 2025
|
||||
- Practical robust MPC for Galois rings - March 2025 - TPMPC & RWMPC 2025
|
||||
- [Towards verifiable FHE in practice](https://eprint.iacr.org/2024/451) - October 2024 - zkSummit12
|
||||
- Advanced FHE and MPC protocols for the blockchain - June 2024 - TPMPC 2024
|
||||
- [IP protection & privacy in LLM: Leveraging Fully Homomorphic Encryption](data/RSA2024.pdf) [[video](https://www.youtube.com/watch?v=lmIgGD8csy0)] - May 2024 - RSA Conference 2024
|
||||
- [Advanced FHE protocols for the blockchain](https://iacr.org/submit/files/slides/2024/rwc/rwc2024/5/slides.pptx) - March 2024 - RWC 2024
|
||||
- [Revisiting oblivious top-k selection with applications to secure k-NN classification](https://github.com/FHE-org/fhe-org.github.io/files/14896282/1635-Geelen.pdf) - March 2024 - FHE.org 2024
|
||||
- [Security guidelines for implementing homomorphic encryption](https://github.com/FHE-org/fhe-org.github.io/files/14896275/1445-Gong.updated.pdf) - March 2024 - FHE.org 2024
|
||||
- [TFHE simplified: A practical guide to integer arithmetic and reliability](https://github.com/FHE-org/fhe-org.github.io/files/14896277/1545-Orfila.pdf) - March 2024 - FHE.org 2024
|
||||
- [Neural network training on encrypted data with TFHE](https://github.com/FHE-org/fhe-org.github.io/files/14896476/LuxFHE.30-Montero.pdf) - March 2024 - FHE.org 2024
|
||||
- [Towards verifiable bootstrapping in practice: Proving correct execution of TFHE’s blind rotation using plonky2](https://github.com/FHE-org/fhe-org.github.io/files/14896490/LuxFHE.13-Walter.pdf) - March 2024 - FHE.org 2024
|
||||
- [Game of life, revisited](https://github.com/FHE-org/fhe-org.github.io/files/14896286/LuxFHE.03-Mames.pdf) - March 2024 - FHE.org 2024
|
||||
- [Homomorphic integer division for TFHE](https://github.com/FHE-org/fhe-org.github.io/files/14896469/LuxFHE.37-Deo.pdf) - March 2024 - FHE.org 2024
|
||||
- [The inhibitor: ReLU and addition-based attention for efficient transformers under fully homomorphic encryption on the torus](https://github.com/FHE-org/fhe-org.github.io/files/14896485/LuxFHE.23-Brannvall.pdf) - March 2024 - FHE.org 2024
|
||||
- [Privacy-preserving tree-based inference with TFHE](https://github.com/luxfhe-ai/awesome-luxfhe/raw/main/data/PPML2023PresentationTrees.pdf) - August 2023 - PPML 2023
|
||||
- [Recent advances in homomorphic compilation](https://github.com/FHE-org/fhe-org.github.io/raw/main/conferences/conference-2023/media/homomorphic-compilation.pdf) - March 2023 - FHE.org 2023
|
||||
- [On NTRU-ν-um modulo Xᴺ-1](https://eprint.iacr.org/2022/1092) - March 2023 - FHE.org 2023
|
||||
- [Parameter optimization & larger precision for (T)FHE](https://github.com/FHE-org/fhe-org.github.io/raw/main/conferences/conference-2023/media/DL-ST-slides.pdf) - March 2023 - FHE.org 2023
|
||||
- [Private smart contracts using homomorphic encryption](https://github.com/FHE-org/fhe-org.github.io/raw/main/conferences/conference-2023/media/private-smart-contracts.pdf) - March 2023 - FHE.org 2023
|
||||
- [Fully homomorphic encryption for user privacy and model intellectual property protection](https://github.com/FHE-org/fhe-org.github.io/raw/main/conferences/conference-2023/media/user-privacy-model-protection.pdf) - March 2023 - FHE.org 2023
|
||||
- [Hybrid attacks on LWE and the lattice estimator](https://github.com/FHE-org/fhe-org.github.io/raw/main/conferences/conference-2022/media/hybrid-attacks.pdf) - May 2022 - FHE.org 2022
|
||||
- [Fast, easy, and accessible FHE with Concrete and specialized accelerators](https://github.com/FHE-org/fhe-org.github.io/raw/main/conferences/conference-2022/media/concrete-and-specialized-accelerators.pdf) - May 2022 - FHE.org 2022
|
||||
- [Concrete ML: A data-scientist-friendly toolkit for machine learning over encrypted data](https://github.com/FHE-org/fhe-org.github.io/raw/main/conferences/conference-2022/media/concrete-ml.pdf) - May 2022 - FHE.org 2022
|
||||
- [Performance of hierarchical transforms in homomorphic encryption: A case study on logistic regression inference](https://github.com/FHE-org/fhe-org.github.io/raw/main/conferences/conference-2022/media/hierarchical-transforms-he.pdf) - May 2022 - FHE.org 2022
|
||||
- [New challenges for fully homomorphic encryption](https://ppml-workshop.github.io/ppml20/pdfs/Chillotti_et_al.pdf) - December 2020 - PPML 2020
|
||||
|
||||
### Invited and self-hosted
|
||||
- Introducing the LuxFHE confidential blockchain protocol, a cross-chain protocol for confidential smart contracts using FHE - June 2025 - EthCC 8
|
||||
- [Unlocking regulated use cases for privacy: Preserving stablecoins](https://streameth.org/stable_summit/watch?session=668a76d16c180915b827aa38) - July 2024 - Stable Summit
|
||||
- [Threshold key generation and decryption for FHEVM Chains](https://www.youtube.com/watch?v=upKFexrGoUE) - July 2024 - EthCC 7
|
||||
- [Decentralized AI: Safeguarding privacy with FHE ](https://www.youtube.com/watch?v=a6dQQSaEtJM) - July 2024 - EthCC 7
|
||||
- [FHE on Ethereum](https://www.youtube.com/watch?v=WngC5cvV_fc) July 2024 - EthCC 7
|
||||
- [Privacy-preserving machine learning](data/AgoraCloudBruxelles2024.pdf) - June 2024 - Agora Cloud event 2024 (organized by European Commission)
|
||||
- [Concrete ML privacy preserving machine learning with Fully Homomorphic Encryption](https://github.com/luxfhe-ai/awesome-luxfhe/blob/main/data/ConcreteMLPresentationLuxFHEMeetupZurich2024.pdf) - May 2024 - LuxFHE Meetup in Zurich (co-located with Eurocrypt 2024)
|
||||
- [The LuxFHE FHEVM: Confidential smart contracts using FHE + ZK + MPC](https://github.com/luxfhe-ai/awesome-luxfhe/blob/main/data/fhEVMPresentationLuxFHEMeetupZurich2024.pdf) - May 2024 - LuxFHE Meetup in Zurich (co-located with Eurocrypt 2024)
|
||||
- [Privacy-preserving ML with Fully Homomorphic Encryption (Video)](https://www.youtube.com/watch?v=g1Zlu63TP0Y) - May 2024 - Google TechTalks
|
||||
- [Privacy-preserving ML with Fully Homomorphic Encryption](https://github.com/luxfhe-ai/awesome-luxfhe/blob/main/data/PPMLMIT2024.pdf) - May 2024 - MIT & Google
|
||||
|
||||
<br></br>
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
@@ -1,40 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"incremental": true,
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"./*"
|
||||
]
|
||||
},
|
||||
"target": "ES2017"
|
||||
},
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
".next/types/**/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
venv
|
||||
__pycache__
|
||||
|
||||
abi.json
|
||||
|
||||
**/.DS_Store
|
||||
|
||||
fhevmjs/node_modules
|
||||
@@ -0,0 +1,28 @@
|
||||
BSD 3-Clause Clear License
|
||||
|
||||
Copyright © 2023 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 Industries Inc 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 Industries Inc 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 Industries Inc 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.
|
||||
@@ -0,0 +1,5 @@
|
||||
|
||||
.PHONY: fmt
|
||||
fmt:
|
||||
isort pyfhevm/*.py
|
||||
black pyfhevm/*.py
|
||||
@@ -0,0 +1,83 @@
|
||||
# fhEVM Workshop
|
||||
|
||||
Welcome to this workshop on building an encrypted ERC20 token!
|
||||
|
||||
See more of our examples at https://dapps.luxfhe.ai.
|
||||
|
||||
## Getting started
|
||||
|
||||
Install LuxFHE Devnet in MetaMask:
|
||||
|
||||
- Network name: LuxFHE Devnet
|
||||
- RPC URL: https://devnet.luxfhe.ai
|
||||
- Chain ID: 8009
|
||||
- Currency symbol: ZAMA
|
||||
- Block explorer: https://main.explorer.luxfhe.ai/
|
||||
|
||||
## Encrypted ERC20
|
||||
|
||||
Set env variable `WORKSHOP_PRIVATE_KEY` to private key that was used to deploy the contract (as copied from MetaMask, i.e. without `0x` prefix):
|
||||
|
||||
```
|
||||
export WORKSHOP_PRIVATE_KEY=<private key>
|
||||
```
|
||||
|
||||
When a contract have been deployed to the devnet, the Python files can be used to interact with it by set env variable `CONTRACT` to the address (as copied from Remix) and saving the ABI to `abi.json`.
|
||||
|
||||
### Nodejs with fhevmjs
|
||||
|
||||
Go in `fhevmjs` directory and `npm install`. Be sure you set `WORKSHOP_PRIVATE_KEY` and `CONTRACT`
|
||||
|
||||
Mint new tokens:
|
||||
|
||||
```bash
|
||||
CONTRACT=<address> npm run mint 100
|
||||
```
|
||||
|
||||
Get your current balance:
|
||||
|
||||
```bash
|
||||
CONTRACT=<address> npm run balanceOf
|
||||
```
|
||||
|
||||
Make a transfer:
|
||||
|
||||
```bash
|
||||
CONTRACT=<address> npm run transfer 0x56c836D1d7c9f64b9654B433dCa16f1014429DC5 100
|
||||
```
|
||||
|
||||
### Python
|
||||
|
||||
Use Python3.10 or earlier:
|
||||
|
||||
```
|
||||
python3.10 -m venv venv
|
||||
. ./venv/bin/activate
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
For now we also need to installed the fhEVM cli:
|
||||
|
||||
```
|
||||
git clone https://github.com/luxfhe-ai/fhevm-tfhe-cli
|
||||
cd fhevm-tfhe-cli
|
||||
cargo install --path .
|
||||
```
|
||||
|
||||
Mint new tokens:
|
||||
|
||||
```
|
||||
python mint.py --amount 100 --contract <address>
|
||||
```
|
||||
|
||||
Get your current balance:
|
||||
|
||||
```
|
||||
python get_balance.py --contract <address>
|
||||
```
|
||||
|
||||
Make a transfer:
|
||||
|
||||
```
|
||||
python transfer.py --amount 5 --to <address> --contract <address>
|
||||
```
|
||||
@@ -0,0 +1,24 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
|
||||
import "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
|
||||
|
||||
abstract contract EIP712Reencrypt is EIP712 {
|
||||
constructor() EIP712("Authorization token", "1") {}
|
||||
|
||||
modifier signedBySender(bytes32 publicKey, bytes memory signature) {
|
||||
bytes32 digest = _hashTypedDataV4(
|
||||
keccak256(
|
||||
abi.encode(keccak256("Reencrypt(bytes32 publicKey)"), publicKey)
|
||||
)
|
||||
);
|
||||
address signer = ECDSA.recover(digest, signature);
|
||||
require(
|
||||
signer == msg.sender,
|
||||
"EIP712 signer and transaction signer do not match"
|
||||
);
|
||||
_;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import "fhevm/lib/TFHE.sol";
|
||||
|
||||
import "./eip712-reencrypt.sol";
|
||||
|
||||
contract EncryptedERC20 is EIP712Reencrypt {
|
||||
address public contractOwner;
|
||||
uint64 public totalSupply;
|
||||
|
||||
constructor() {
|
||||
contractOwner = msg.sender;
|
||||
}
|
||||
|
||||
mapping(address => euint64) internal balances;
|
||||
|
||||
function balanceOf(
|
||||
address wallet,
|
||||
bytes32 publicKey,
|
||||
bytes calldata signature
|
||||
)
|
||||
public
|
||||
view
|
||||
signedBySender(publicKey, signature)
|
||||
returns (bytes memory)
|
||||
{
|
||||
require(wallet == msg.sender);
|
||||
return TFHE.reencrypt(balances[msg.sender], publicKey, 0);
|
||||
}
|
||||
|
||||
function mint(uint64 amount) public {
|
||||
require(msg.sender == contractOwner);
|
||||
balances[contractOwner] = TFHE.add(balances[contractOwner], amount);
|
||||
totalSupply = totalSupply + amount;
|
||||
}
|
||||
|
||||
function transfer(address to, bytes calldata amountCiphertext) public returns (bool) {
|
||||
return transfer_reverting(to, amountCiphertext);
|
||||
// return transfer_leaking(to, amountCiphertext);
|
||||
// return transfer_nonleaking(to, amountCiphertext);
|
||||
}
|
||||
|
||||
function transfer_reverting(address to, bytes calldata amountCiphertext) internal returns (bool) {
|
||||
euint64 amount = TFHE.asEuint64(amountCiphertext);
|
||||
|
||||
ebool sufficient = TFHE.le(amount, balances[msg.sender]);
|
||||
|
||||
bool decrypted_sufficient = TFHE.decrypt(sufficient);
|
||||
require(decrypted_sufficient);
|
||||
|
||||
balances[to] = balances[to] + amount;
|
||||
balances[msg.sender] = balances[msg.sender] - amount;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function transfer_leaking(address to, bytes calldata amountCiphertext) internal returns (bool) {
|
||||
euint64 amount = TFHE.asEuint64(amountCiphertext);
|
||||
|
||||
ebool sufficient = TFHE.le(amount, balances[msg.sender]);
|
||||
|
||||
bool decrypted_sufficient = TFHE.decrypt(sufficient);
|
||||
if (decrypted_sufficient) {
|
||||
balances[to] = balances[to] + amount;
|
||||
balances[msg.sender] = balances[msg.sender] - amount;
|
||||
}
|
||||
|
||||
return decrypted_sufficient;
|
||||
}
|
||||
|
||||
function transfer_nonleaking(address to, bytes calldata amountCiphertext) internal returns (bool) {
|
||||
euint64 amount = TFHE.asEuint64(amountCiphertext);
|
||||
|
||||
ebool sufficient = TFHE.le(amount, balances[msg.sender]);
|
||||
|
||||
balances[to] = balances[to] + TFHE.select(sufficient, amount, TFHE.asEuint64(0));
|
||||
balances[msg.sender] = balances[msg.sender] - TFHE.select(sufficient, amount, TFHE.asEuint64(0));
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "fhevmjs-test",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"balanceOf": "node src/balanceOf.js",
|
||||
"mint": "node src/mint.js",
|
||||
"transfer": "node src/transfer.js"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"ethers": "^6.6.3",
|
||||
"fhevmjs": "^0.4.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
const { Wallet, Contract } = require('ethers');
|
||||
const { WALLET_PRIVATE_KEY, CONTRACT_ADDRESS } = require('./constants');
|
||||
const { getInstance, provider } = require('./instance.js');
|
||||
const abi = require('../../abi.json');
|
||||
|
||||
const signer = new Wallet(WALLET_PRIVATE_KEY, provider);
|
||||
const contract = new Contract(CONTRACT_ADDRESS, abi, signer);
|
||||
|
||||
const balanceOf = async () => {
|
||||
const fhevm = await getInstance();
|
||||
|
||||
console.log('Generating public key for reencryption');
|
||||
const clientPublicKey = fhevm.generatePublicKey({
|
||||
verifyingContract: CONTRACT_ADDRESS,
|
||||
});
|
||||
|
||||
console.log('Signing public key');
|
||||
const signature = await signer.signTypedData(
|
||||
clientPublicKey.eip712.domain,
|
||||
{ Reencrypt: clientPublicKey.eip712.types.Reencrypt },
|
||||
clientPublicKey.eip712.message
|
||||
);
|
||||
|
||||
console.log('Calling contract');
|
||||
const userAddress = await signer.getAddress();
|
||||
const encryptedBalance = await contract.balanceOf(
|
||||
userAddress,
|
||||
clientPublicKey.publicKey,
|
||||
signature
|
||||
);
|
||||
|
||||
console.log('Decrypting result using private key');
|
||||
const balance = fhevm.decrypt(CONTRACT_ADDRESS, encryptedBalance);
|
||||
return balance;
|
||||
};
|
||||
|
||||
balanceOf().then((balance) => {
|
||||
console.log(`Balance: ${balance}`);
|
||||
});
|
||||
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
DEVNET_URL: 'https://devnet.luxfhe.io/',
|
||||
WALLET_PRIVATE_KEY: process.env.WORKSHOP_PRIVATE_KEY,
|
||||
CONTRACT_ADDRESS: process.env.CONTRACT,
|
||||
};
|
||||
@@ -0,0 +1,25 @@
|
||||
const { createInstance, getPublicKeyCallParams } = require('fhevmjs');
|
||||
const { ethers, JsonRpcProvider } = require('ethers');
|
||||
const { DEVNET_URL } = require('./constants');
|
||||
|
||||
let _instance;
|
||||
const provider = new JsonRpcProvider(DEVNET_URL);
|
||||
|
||||
const getInstance = async () => {
|
||||
if (_instance) return _instance;
|
||||
// 1. Get chain id
|
||||
const network = await provider.getNetwork();
|
||||
const chainId = +network.chainId.toString();
|
||||
// Get blockchain public key
|
||||
const rawPublicKeyParams = await provider.call(getPublicKeyCallParams());
|
||||
const publicKeyParams = ethers.AbiCoder.defaultAbiCoder().decode(["bytes"], rawPublicKeyParams);
|
||||
const publicKey = publicKeyParams[0];
|
||||
// Create instance
|
||||
_instance = createInstance({ chainId, publicKey });
|
||||
return _instance;
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
getInstance,
|
||||
provider,
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
const { Wallet, Contract } = require('ethers');
|
||||
const { WALLET_PRIVATE_KEY, CONTRACT_ADDRESS } = require('./constants');
|
||||
const { getInstance, provider } = require('./instance.js');
|
||||
const abi = require('../../abi.json');
|
||||
|
||||
const signer = new Wallet(WALLET_PRIVATE_KEY, provider);
|
||||
const contract = new Contract(CONTRACT_ADDRESS, abi, signer);
|
||||
|
||||
const mint = async (amount) => {
|
||||
console.log('Sending transaction');
|
||||
const transaction = await contract.mint(amount);
|
||||
|
||||
console.log('Waiting for transaction validation...');
|
||||
await provider.waitForTransaction(transaction.hash);
|
||||
};
|
||||
|
||||
mint(+process.argv[2] || 1000)
|
||||
.then(() => {
|
||||
console.log('Transaction done!');
|
||||
})
|
||||
.catch((err) => console.log('Transaction failed :(', err));
|
||||
@@ -0,0 +1,29 @@
|
||||
const { Wallet, Contract } = require('ethers');
|
||||
const { WALLET_PRIVATE_KEY, WALLET_TO_TRANSFER, CONTRACT_ADDRESS } = require('./constants');
|
||||
const { getInstance, provider } = require('./instance.js');
|
||||
const abi = require('../../abi.json');
|
||||
|
||||
const signer = new Wallet(WALLET_PRIVATE_KEY, provider);
|
||||
const contract = new Contract(CONTRACT_ADDRESS, abi, signer);
|
||||
|
||||
const transfer = async (to_opt, amount) => {
|
||||
const fhevm = await getInstance();
|
||||
|
||||
// Default to own address if nothing specified
|
||||
const to = to_opt || await signer.getAddress();
|
||||
|
||||
console.log(`Encrypting ${amount}`);
|
||||
const encryptedAmount = fhevm.encrypt64(amount);
|
||||
|
||||
console.log('Sending transaction');
|
||||
const transaction = await contract['transfer(address,bytes)'](to, encryptedAmount);
|
||||
|
||||
console.log('Waiting for transaction validation...');
|
||||
await provider.waitForTransaction(transaction.hash);
|
||||
};
|
||||
|
||||
transfer(process.argv[2], +process.argv[3] || 100)
|
||||
.then(() => {
|
||||
console.log('Transaction done!');
|
||||
})
|
||||
.catch((err) => console.log('Transaction failed :(', err));
|
||||
@@ -0,0 +1,22 @@
|
||||
import argparse
|
||||
|
||||
from fhevm import FHEVM
|
||||
from utils import load_contract, setup_w3, setup_wallet
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("-c", "--contract")
|
||||
args = parser.parse_args()
|
||||
|
||||
w3 = setup_w3()
|
||||
my_account = setup_wallet(w3)
|
||||
fhevm = FHEVM(w3, my_account)
|
||||
erc20 = load_contract(w3, args.contract)
|
||||
|
||||
# call balanceOf
|
||||
public_key, signature = fhevm.generate_auth_token(erc20.address)
|
||||
encrypted_balance = erc20.functions.balanceOf(public_key, signature).call(
|
||||
{"from": my_account.address}
|
||||
)
|
||||
balance = fhevm.open(encrypted_balance)
|
||||
print(f"Balance: {balance}")
|
||||
@@ -0,0 +1,62 @@
|
||||
import os
|
||||
|
||||
import sha3
|
||||
from eip712_structs import Bytes, EIP712Struct, make_domain
|
||||
from nacl.public import PrivateKey, SealedBox
|
||||
|
||||
PUBLIC_KEY_CONTRACT = "0x0000000000000000000000000000000000000044"
|
||||
|
||||
|
||||
class Reencrypt(EIP712Struct):
|
||||
publicKey = Bytes(32)
|
||||
|
||||
|
||||
class FHEVM:
|
||||
def __init__(self, w3, account):
|
||||
self.network_encryption_key = None
|
||||
self.my_decryption_key = PrivateKey.generate()
|
||||
self.w3 = w3
|
||||
self.my_account = account
|
||||
|
||||
def encrypt32(self, plaintext):
|
||||
if self.network_encryption_key is None:
|
||||
print("Fetching global public key")
|
||||
self.network_encryption_key = self.w3.eth.call({"to": PUBLIC_KEY_CONTRACT})
|
||||
|
||||
with open("/tmp/zama_network_public_key", mode="wb") as f:
|
||||
f.write(self.network_encryption_key)
|
||||
res = os.system(
|
||||
f"fhevm-tfhe-cli public-encrypt-integer32 -v {plaintext} -c /tmp/zama_ciphertext -p /tmp/zama_network_public_key"
|
||||
)
|
||||
assert res == 0, "fail to execute fhe-tool"
|
||||
with open("/tmp/zama_ciphertext", mode="rb") as file:
|
||||
ciphertext = file.read()
|
||||
assert len(ciphertext) == 8404
|
||||
|
||||
return ciphertext
|
||||
|
||||
def generate_auth_token(self, contract_address):
|
||||
domain = make_domain(
|
||||
name="Authorization token",
|
||||
version="1",
|
||||
chainId=self.w3.eth.chain_id,
|
||||
verifyingContract=contract_address,
|
||||
)
|
||||
|
||||
msg = Reencrypt()
|
||||
msg["publicKey"] = self.my_decryption_key.public_key._public_key
|
||||
assert len(self.my_decryption_key.public_key._public_key) == 32
|
||||
|
||||
signable_bytes = msg.signable_bytes(domain)
|
||||
msg_hash = sha3.keccak_256(signable_bytes).digest()
|
||||
msg_sig = self.my_account.signHash(msg_hash)
|
||||
|
||||
sig = bytes.fromhex(msg_sig.signature.hex()[2:])
|
||||
public_key = self.my_decryption_key.public_key._public_key
|
||||
return public_key, sig
|
||||
|
||||
def open(self, ciphertext):
|
||||
unseal_box = SealedBox(self.my_decryption_key)
|
||||
plaintext_bytes = unseal_box.decrypt(ciphertext)
|
||||
plaintext = int.from_bytes(plaintext_bytes, "big")
|
||||
return plaintext
|
||||
@@ -0,0 +1,20 @@
|
||||
import argparse
|
||||
|
||||
from fhevm import FHEVM
|
||||
from utils import load_contract, send_transaction, setup_w3, setup_wallet
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("-c", "--contract")
|
||||
parser.add_argument("-a", "--amount", default=100)
|
||||
args = parser.parse_args()
|
||||
|
||||
w3 = setup_w3()
|
||||
my_account = setup_wallet(w3)
|
||||
fhevm = FHEVM(w3, my_account)
|
||||
erc20 = load_contract(w3, args.contract)
|
||||
|
||||
# call mint
|
||||
amount = fhevm.encrypt32(args.amount)
|
||||
mint = erc20.functions.mint(amount)
|
||||
send_transaction(w3, mint, my_account.address)
|
||||
@@ -0,0 +1,50 @@
|
||||
aiohttp==3.8.4
|
||||
aiosignal==1.3.1
|
||||
async-timeout==4.0.2
|
||||
attrs==23.1.0
|
||||
bitarray==2.7.6
|
||||
black==23.7.0
|
||||
certifi==2023.5.7
|
||||
cffi==1.15.1
|
||||
charset-normalizer==3.2.0
|
||||
click==8.1.4
|
||||
cytoolz==0.12.1
|
||||
eip712-structs==1.1.0
|
||||
eth-abi==4.1.0
|
||||
eth-account==0.9.0
|
||||
eth-hash==0.5.2
|
||||
eth-keyfile==0.6.1
|
||||
eth-keys==0.4.0
|
||||
eth-rlp==0.3.0
|
||||
eth-typing==3.4.0
|
||||
eth-utils==2.2.0
|
||||
frozenlist==1.3.3
|
||||
hexbytes==0.3.1
|
||||
idna==3.4
|
||||
isort==5.12.0
|
||||
jsonschema==4.18.1
|
||||
jsonschema-specifications==2023.6.1
|
||||
lru-dict==1.2.0
|
||||
multidict==6.0.4
|
||||
mypy-extensions==1.0.0
|
||||
packaging==23.1
|
||||
parsimonious==0.9.0
|
||||
pathspec==0.11.1
|
||||
platformdirs==3.8.1
|
||||
protobuf==4.23.4
|
||||
pycparser==2.21
|
||||
pycryptodome==3.18.0
|
||||
PyNaCl==1.5.0
|
||||
pysha3==1.0.2
|
||||
referencing==0.29.1
|
||||
regex==2023.6.3
|
||||
requests==2.31.0
|
||||
rlp==3.0.0
|
||||
rpds-py==0.8.10
|
||||
tomli==2.0.1
|
||||
toolz==0.12.0
|
||||
typing_extensions==4.7.1
|
||||
urllib3==2.0.3
|
||||
web3==6.5.0
|
||||
websockets==11.0.3
|
||||
yarl==1.9.2
|
||||
@@ -0,0 +1,22 @@
|
||||
import argparse
|
||||
|
||||
from fhevm import FHEVM
|
||||
from utils import load_contract, send_transaction, setup_w3, setup_wallet
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("-c", "--contract")
|
||||
parser.add_argument("-t", "--to", default=None)
|
||||
parser.add_argument("-a", "--amount", default=10)
|
||||
args = parser.parse_args()
|
||||
|
||||
w3 = setup_w3()
|
||||
my_account = setup_wallet(w3)
|
||||
fhevm = FHEVM(w3, my_account)
|
||||
erc20 = load_contract(w3, args.contract)
|
||||
|
||||
# call transfer
|
||||
amount = fhevm.encrypt32(args.amount)
|
||||
to = args.to or my_account.address
|
||||
transfer = erc20.functions.transfer(to, amount)
|
||||
send_transaction(w3, transfer, my_account.address)
|
||||
@@ -0,0 +1,53 @@
|
||||
import json
|
||||
import os
|
||||
|
||||
from eth_account import Account
|
||||
from web3 import Web3
|
||||
from web3.middleware import construct_sign_and_send_raw_middleware
|
||||
|
||||
SIGNATURE_KEY_VAR = "WORKSHOP_PRIVATE_KEY"
|
||||
DEVNET_VAR = "ETHCC23_DEVNET"
|
||||
DEFAULT_DEVNET = "https://devnet.zama.ai"
|
||||
|
||||
|
||||
def setup_w3():
|
||||
devnet = os.environ.get(DEVNET_VAR, DEFAULT_DEVNET)
|
||||
return Web3(Web3.HTTPProvider(devnet, request_kwargs={"timeout": 600}))
|
||||
|
||||
|
||||
def setup_wallet(w3):
|
||||
signature_key = os.environ.get(SIGNATURE_KEY_VAR)
|
||||
assert signature_key != None, f"Please specify env variable '{SIGNATURE_KEY_VAR}'"
|
||||
if not signature_key.startswith("0x"):
|
||||
signature_key = "0x" + signature_key
|
||||
account = Account.from_key(signature_key)
|
||||
w3.middleware_onion.add(construct_sign_and_send_raw_middleware(account))
|
||||
w3.eth.default_account = account.address
|
||||
print(f"Account address: {account.address}")
|
||||
return account
|
||||
|
||||
|
||||
def send_transaction(w3, tx, from_address):
|
||||
# # estimate gas
|
||||
# gas = tx.estimate_gas({"value": 0, "from": from_address})
|
||||
# print(f"Gas estimation: {gas}")
|
||||
|
||||
# send transaction
|
||||
tx_hash = tx.transact({"value": 0, "from": from_address}).hex()
|
||||
print(f"Transaction hash: {tx_hash}")
|
||||
|
||||
# wait for transaction to go through
|
||||
tx_receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
|
||||
assert tx_receipt["status"] == 1
|
||||
|
||||
|
||||
def load_contract(w3, address):
|
||||
print(f"Contract address: {address}")
|
||||
|
||||
with open("../abi.json", "rt") as f:
|
||||
abi = json.load(f)
|
||||
|
||||
return w3.eth.contract(
|
||||
address=address,
|
||||
abi=abi,
|
||||
)
|
||||
Generated
+1556
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
Executable
+17
@@ -0,0 +1,17 @@
|
||||
#!/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
|
||||
@@ -0,0 +1,191 @@
|
||||
/**
|
||||
* 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);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,9 @@
|
||||
import { defineConfig } from 'vitest/config';
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
include: ['test/**/*.test.ts'],
|
||||
testTimeout: 30000,
|
||||
hookTimeout: 30000,
|
||||
},
|
||||
});
|
||||
@@ -1,96 +0,0 @@
|
||||
// Copyright (c) 2025, Lux Industries Inc
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package fhe
|
||||
|
||||
import (
|
||||
"github.com/luxfi/lattice/v7/core/rlwe"
|
||||
)
|
||||
|
||||
// Encryptor encrypts boolean values into FHE ciphertexts
|
||||
type Encryptor struct {
|
||||
params Parameters
|
||||
encryptor *rlwe.Encryptor
|
||||
scale float64
|
||||
}
|
||||
|
||||
// NewEncryptor creates a new encryptor from secret key
|
||||
func NewEncryptor(params Parameters, sk *SecretKey) *Encryptor {
|
||||
return &Encryptor{
|
||||
params: params,
|
||||
encryptor: rlwe.NewEncryptor(params.paramsLWE, sk.SKLWE),
|
||||
scale: float64(params.QLWE()) / 4.0, // Encode bit as Q/4 or -Q/4
|
||||
}
|
||||
}
|
||||
|
||||
// Encrypt encrypts a boolean value
|
||||
// Note: Panics on error (should not happen with valid parameters)
|
||||
func (enc *Encryptor) Encrypt(value bool) *Ciphertext {
|
||||
pt := rlwe.NewPlaintext(enc.params.paramsLWE, enc.params.paramsLWE.MaxLevel())
|
||||
|
||||
q := enc.params.QLWE()
|
||||
// Encode with Q/8 scale so sums of two bits stay in distinguishable range:
|
||||
// - true -> +Q/8 (normalized +0.5 relative to Q/4 scale)
|
||||
// - false -> -Q/8 (normalized -0.5)
|
||||
// After sum:
|
||||
// - (0,0): -Q/4 normalized to -1
|
||||
// - (0,1): 0 normalized to 0
|
||||
// - (1,1): +Q/4 normalized to +1
|
||||
if value {
|
||||
pt.Value.Coeffs[0][0] = q / 8
|
||||
} else {
|
||||
pt.Value.Coeffs[0][0] = q - (q / 8) // = -Q/8 mod Q
|
||||
}
|
||||
|
||||
enc.params.paramsLWE.RingQ().NTT(pt.Value, pt.Value)
|
||||
|
||||
ct := rlwe.NewCiphertext(enc.params.paramsLWE, 1, enc.params.paramsLWE.MaxLevel())
|
||||
if err := enc.encryptor.Encrypt(pt, ct); err != nil {
|
||||
panic(err) // Should not happen with valid parameters
|
||||
}
|
||||
|
||||
return &Ciphertext{ct}
|
||||
}
|
||||
|
||||
// EncryptBit is an alias for Encrypt
|
||||
func (enc *Encryptor) EncryptBit(bit int) *Ciphertext {
|
||||
return enc.Encrypt(bit != 0)
|
||||
}
|
||||
|
||||
// EncryptByte encrypts a byte as 8 ciphertexts (LSB first)
|
||||
func (enc *Encryptor) EncryptByte(b byte) [8]*Ciphertext {
|
||||
var cts [8]*Ciphertext
|
||||
for i := 0; i < 8; i++ {
|
||||
cts[i] = enc.Encrypt((b>>i)&1 == 1)
|
||||
}
|
||||
return cts
|
||||
}
|
||||
|
||||
// EncryptUint32 encrypts a uint32 as 32 ciphertexts (LSB first)
|
||||
func (enc *Encryptor) EncryptUint32(v uint32) [32]*Ciphertext {
|
||||
var cts [32]*Ciphertext
|
||||
for i := 0; i < 32; i++ {
|
||||
cts[i] = enc.Encrypt((v>>i)&1 == 1)
|
||||
}
|
||||
return cts
|
||||
}
|
||||
|
||||
// EncryptUint64 encrypts a uint64 as 64 ciphertexts (LSB first)
|
||||
func (enc *Encryptor) EncryptUint64(v uint64) [64]*Ciphertext {
|
||||
var cts [64]*Ciphertext
|
||||
for i := 0; i < 64; i++ {
|
||||
cts[i] = enc.Encrypt((v>>i)&1 == 1)
|
||||
}
|
||||
return cts
|
||||
}
|
||||
|
||||
// EncryptUint256 encrypts a 256-bit value as 256 ciphertexts (LSB first)
|
||||
func (enc *Encryptor) EncryptUint256(v [4]uint64) [256]*Ciphertext {
|
||||
var cts [256]*Ciphertext
|
||||
for w := 0; w < 4; w++ {
|
||||
for i := 0; i < 64; i++ {
|
||||
cts[w*64+i] = enc.Encrypt((v[w]>>i)&1 == 1)
|
||||
}
|
||||
}
|
||||
return cts
|
||||
}
|
||||
-341
@@ -1,341 +0,0 @@
|
||||
// Copyright (c) 2025, Lux Industries Inc
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package fhe
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/luxfi/lattice/v7/core/rgsw/blindrot"
|
||||
"github.com/luxfi/lattice/v7/core/rlwe"
|
||||
"github.com/luxfi/lattice/v7/ring"
|
||||
)
|
||||
|
||||
// Evaluator evaluates boolean gates on encrypted data
|
||||
// SECURITY: This evaluator does NOT require the secret key.
|
||||
// It uses sample extraction and key switching for bootstrapping.
|
||||
type Evaluator struct {
|
||||
params Parameters
|
||||
eval *blindrot.Evaluator
|
||||
bsk *BootstrapKey
|
||||
ringQLWE *ring.Ring
|
||||
ringQBR *ring.Ring
|
||||
|
||||
// Key switching evaluator (BR -> LWE)
|
||||
ksEval *rlwe.Evaluator
|
||||
}
|
||||
|
||||
// NewEvaluator creates a new evaluator with bootstrap key.
|
||||
// SECURITY: No secret key is required - bootstrapping uses public key switching.
|
||||
func NewEvaluator(params Parameters, bsk *BootstrapKey) *Evaluator {
|
||||
// Create key switching evaluator using the key switch key in bootstrap key
|
||||
var ksEval *rlwe.Evaluator
|
||||
if bsk.KSK != nil {
|
||||
ksEval = rlwe.NewEvaluator(params.paramsBR, nil)
|
||||
}
|
||||
|
||||
return &Evaluator{
|
||||
params: params,
|
||||
eval: blindrot.NewEvaluator(params.paramsBR, params.paramsLWE),
|
||||
bsk: bsk,
|
||||
ringQLWE: params.paramsLWE.RingQ(),
|
||||
ringQBR: params.paramsBR.RingQ(),
|
||||
ksEval: ksEval,
|
||||
}
|
||||
}
|
||||
|
||||
// sampleExtractAndModSwitch extracts the result from an RLWE ciphertext
|
||||
// after blind rotation and converts it to an LWE ciphertext.
|
||||
//
|
||||
// When LWE and BR use the same dimension and modulus (recommended configuration),
|
||||
// this simply returns the ciphertext directly since no conversion is needed.
|
||||
//
|
||||
// SECURITY: This operation does NOT require the secret key. The ciphertext
|
||||
// remains encrypted throughout.
|
||||
func (eval *Evaluator) sampleExtractAndModSwitch(ctBR *rlwe.Ciphertext) (*Ciphertext, error) {
|
||||
// When same dimension and modulus, just return the ciphertext directly
|
||||
// The key is the same, so no conversion needed
|
||||
if eval.params.N() == eval.params.NBR() && eval.params.QLWE() == eval.params.QBR() {
|
||||
// Copy to a new ciphertext in LWE parameters (same as BR here)
|
||||
result := ctBR.CopyNew()
|
||||
return &Ciphertext{result}, nil
|
||||
}
|
||||
|
||||
// Different dimensions/moduli require modulus switching
|
||||
levelBR := ctBR.Level()
|
||||
ringQBR := eval.ringQBR.AtLevel(levelBR)
|
||||
qBR := eval.params.QBR()
|
||||
qLWE := eval.params.QLWE()
|
||||
|
||||
// Ensure we're working in coefficient domain
|
||||
c0 := ctBR.Value[0].CopyNew()
|
||||
c1 := ctBR.Value[1].CopyNew()
|
||||
|
||||
if ctBR.IsNTT {
|
||||
ringQBR.INTT(*c0, *c0)
|
||||
ringQBR.INTT(*c1, *c1)
|
||||
}
|
||||
|
||||
// Create output ciphertext in LWE parameters
|
||||
nLWE := eval.params.N()
|
||||
ctLWE := rlwe.NewCiphertext(eval.params.paramsLWE, 1, eval.params.paramsLWE.MaxLevel())
|
||||
|
||||
scaleFactor := float64(qLWE) / float64(qBR)
|
||||
|
||||
// Scale and copy first N_LWE coefficients
|
||||
for i := 0; i < nLWE; i++ {
|
||||
scaled0 := uint64(float64(c0.Coeffs[0][i])*scaleFactor + 0.5)
|
||||
scaled1 := uint64(float64(c1.Coeffs[0][i])*scaleFactor + 0.5)
|
||||
ctLWE.Value[0].Coeffs[0][i] = scaled0 % qLWE
|
||||
ctLWE.Value[1].Coeffs[0][i] = scaled1 % qLWE
|
||||
}
|
||||
|
||||
// Convert to NTT
|
||||
ringQLWE := eval.ringQLWE.AtLevel(eval.params.paramsLWE.MaxLevel())
|
||||
ringQLWE.NTT(ctLWE.Value[0], ctLWE.Value[0])
|
||||
ringQLWE.NTT(ctLWE.Value[1], ctLWE.Value[1])
|
||||
ctLWE.IsNTT = true
|
||||
|
||||
return &Ciphertext{ctLWE}, nil
|
||||
}
|
||||
|
||||
// bootstrap performs programmable bootstrapping with the given test polynomial
|
||||
// and returns a fresh LWE ciphertext with the result.
|
||||
//
|
||||
// SECURITY: This implementation does NOT decrypt - it uses sample extraction
|
||||
// and key switching, which are public operations on ciphertexts.
|
||||
func (eval *Evaluator) bootstrap(ct *Ciphertext, testPoly *ring.Poly) (*Ciphertext, error) {
|
||||
// Create map for single slot evaluation
|
||||
testPolyMap := map[int]*ring.Poly{0: testPoly}
|
||||
|
||||
// Step 1: Evaluate blind rotation
|
||||
// This produces an RLWE ciphertext under SKBR with the test polynomial
|
||||
// evaluated at the encrypted value
|
||||
results, err := eval.eval.Evaluate(ct.Ciphertext, testPolyMap, eval.bsk.BRK)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("bootstrap: %w", err)
|
||||
}
|
||||
|
||||
// Extract result for slot 0
|
||||
ctBR, ok := results[0]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("bootstrap: no result for slot 0")
|
||||
}
|
||||
|
||||
// Step 2: Sample extract and modulus switch
|
||||
// This extracts the result and scales to the LWE modulus
|
||||
return eval.sampleExtractAndModSwitch(ctBR)
|
||||
}
|
||||
|
||||
// addCiphertexts adds two ciphertexts element-wise
|
||||
func (eval *Evaluator) addCiphertexts(ct1, ct2 *Ciphertext) *Ciphertext {
|
||||
result := rlwe.NewCiphertext(eval.params.paramsLWE, 1, ct1.Level())
|
||||
|
||||
eval.ringQLWE.Add(ct1.Value[0], ct2.Value[0], result.Value[0])
|
||||
eval.ringQLWE.Add(ct1.Value[1], ct2.Value[1], result.Value[1])
|
||||
|
||||
result.IsNTT = ct1.IsNTT
|
||||
|
||||
return &Ciphertext{result}
|
||||
}
|
||||
|
||||
// doubleCiphertext multiplies a ciphertext by 2 (element-wise addition with itself)
|
||||
// This is key to OpenFHE's optimized XOR: 2*(ct1+ct2) causes wrap-around for (T,T) case
|
||||
func (eval *Evaluator) doubleCiphertext(ct *Ciphertext) *Ciphertext {
|
||||
result := rlwe.NewCiphertext(eval.params.paramsLWE, 1, ct.Level())
|
||||
|
||||
eval.ringQLWE.Add(ct.Value[0], ct.Value[0], result.Value[0])
|
||||
eval.ringQLWE.Add(ct.Value[1], ct.Value[1], result.Value[1])
|
||||
|
||||
result.IsNTT = ct.IsNTT
|
||||
|
||||
return &Ciphertext{result}
|
||||
}
|
||||
|
||||
// negateCiphertext negates a ciphertext
|
||||
func (eval *Evaluator) negateCiphertext(ct *Ciphertext) *Ciphertext {
|
||||
result := rlwe.NewCiphertext(eval.params.paramsLWE, 1, ct.Level())
|
||||
|
||||
eval.ringQLWE.Neg(ct.Value[0], result.Value[0])
|
||||
eval.ringQLWE.Neg(ct.Value[1], result.Value[1])
|
||||
|
||||
result.IsNTT = ct.IsNTT
|
||||
|
||||
return &Ciphertext{result}
|
||||
}
|
||||
|
||||
// addConstant adds a scalar constant to the ciphertext's constant term (b)
|
||||
// This is used for gate offsets like OpenFHE's gate constants
|
||||
func (eval *Evaluator) addConstant(ct *Ciphertext, constant uint64) *Ciphertext {
|
||||
result := ct.CopyNew()
|
||||
|
||||
// Add constant to the constant term (coefficient 0 of polynomial b)
|
||||
// Need to handle NTT form
|
||||
if result.IsNTT {
|
||||
eval.ringQLWE.INTT(result.Value[1], result.Value[1])
|
||||
}
|
||||
|
||||
q := eval.params.QLWE()
|
||||
result.Value[1].Coeffs[0][0] = (result.Value[1].Coeffs[0][0] + constant) % q
|
||||
|
||||
if ct.IsNTT {
|
||||
eval.ringQLWE.NTT(result.Value[1], result.Value[1])
|
||||
}
|
||||
|
||||
return &Ciphertext{result}
|
||||
}
|
||||
|
||||
// ========== Boolean Gates ==========
|
||||
|
||||
// NOT computes the logical NOT of the input
|
||||
// NOT(a) = 1 - a (free operation - just negate)
|
||||
func (eval *Evaluator) NOT(ct *Ciphertext) *Ciphertext {
|
||||
return eval.negateCiphertext(ct)
|
||||
}
|
||||
|
||||
// AND computes the logical AND of two inputs
|
||||
// AND(a, b) = 1 if a + b >= 1.5 (both are 1)
|
||||
func (eval *Evaluator) AND(ct1, ct2 *Ciphertext) (*Ciphertext, error) {
|
||||
sum := eval.addCiphertexts(ct1, ct2)
|
||||
return eval.bootstrap(sum, eval.bsk.TestPolyAND)
|
||||
}
|
||||
|
||||
// OR computes the logical OR of two inputs
|
||||
// OR(a, b) = 1 if a + b >= 0.5 (at least one is 1)
|
||||
func (eval *Evaluator) OR(ct1, ct2 *Ciphertext) (*Ciphertext, error) {
|
||||
sum := eval.addCiphertexts(ct1, ct2)
|
||||
return eval.bootstrap(sum, eval.bsk.TestPolyOR)
|
||||
}
|
||||
|
||||
// XOR computes the logical XOR of two inputs
|
||||
// Optimized algorithm matching OpenFHE: 2*(ct1 + ct2) with single bootstrap
|
||||
// The doubling causes (T,T) → 2*0.25 = 0.5 to wrap around to -0.5,
|
||||
// making the XOR test polynomial correctly return FALSE for both (T,T) and (F,F)
|
||||
func (eval *Evaluator) XOR(ct1, ct2 *Ciphertext) (*Ciphertext, error) {
|
||||
sum := eval.addCiphertexts(ct1, ct2)
|
||||
doubled := eval.doubleCiphertext(sum) // Key: 2*(ct1+ct2)
|
||||
return eval.bootstrap(doubled, eval.bsk.TestPolyXOR)
|
||||
}
|
||||
|
||||
// NAND computes the logical NAND of two inputs
|
||||
func (eval *Evaluator) NAND(ct1, ct2 *Ciphertext) (*Ciphertext, error) {
|
||||
sum := eval.addCiphertexts(ct1, ct2)
|
||||
return eval.bootstrap(sum, eval.bsk.TestPolyNAND)
|
||||
}
|
||||
|
||||
// NOR computes the logical NOR of two inputs
|
||||
func (eval *Evaluator) NOR(ct1, ct2 *Ciphertext) (*Ciphertext, error) {
|
||||
sum := eval.addCiphertexts(ct1, ct2)
|
||||
return eval.bootstrap(sum, eval.bsk.TestPolyNOR)
|
||||
}
|
||||
|
||||
// XNOR computes the logical XNOR of two inputs
|
||||
// Optimized algorithm matching OpenFHE: 2*(ct1 + ct2) with single bootstrap
|
||||
// Same as XOR but with inverted test polynomial
|
||||
func (eval *Evaluator) XNOR(ct1, ct2 *Ciphertext) (*Ciphertext, error) {
|
||||
sum := eval.addCiphertexts(ct1, ct2)
|
||||
doubled := eval.doubleCiphertext(sum) // Key: 2*(ct1+ct2)
|
||||
return eval.bootstrap(doubled, eval.bsk.TestPolyXNOR)
|
||||
}
|
||||
|
||||
// ANDNY computes AND with negated first input: AND(NOT(a), b)
|
||||
func (eval *Evaluator) ANDNY(ct1, ct2 *Ciphertext) (*Ciphertext, error) {
|
||||
return eval.AND(eval.NOT(ct1), ct2)
|
||||
}
|
||||
|
||||
// ANDYN computes AND with negated second input: AND(a, NOT(b))
|
||||
func (eval *Evaluator) ANDYN(ct1, ct2 *Ciphertext) (*Ciphertext, error) {
|
||||
return eval.AND(ct1, eval.NOT(ct2))
|
||||
}
|
||||
|
||||
// ORNY computes OR with negated first input: OR(NOT(a), b)
|
||||
func (eval *Evaluator) ORNY(ct1, ct2 *Ciphertext) (*Ciphertext, error) {
|
||||
return eval.OR(eval.NOT(ct1), ct2)
|
||||
}
|
||||
|
||||
// ORYN computes OR with negated second input: OR(a, NOT(b))
|
||||
func (eval *Evaluator) ORYN(ct1, ct2 *Ciphertext) (*Ciphertext, error) {
|
||||
return eval.OR(ct1, eval.NOT(ct2))
|
||||
}
|
||||
|
||||
// MUX computes the multiplexer: if sel then a else b
|
||||
// MUX(sel, a, b) = (sel AND a) OR (NOT(sel) AND b)
|
||||
func (eval *Evaluator) MUX(sel, ctTrue, ctFalse *Ciphertext) (*Ciphertext, error) {
|
||||
selAndTrue, err := eval.AND(sel, ctTrue)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
notSelAndFalse, err := eval.AND(eval.NOT(sel), ctFalse)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return eval.OR(selAndTrue, notSelAndFalse)
|
||||
}
|
||||
|
||||
// ========== Multi-Input Gates ==========
|
||||
//
|
||||
// Note: Single-bootstrap multi-input gates require careful offset tuning
|
||||
// matching OpenFHE's gate constants. For correctness, we use 2-bootstrap
|
||||
// composition here. Future optimization could add single-bootstrap versions.
|
||||
|
||||
// AND3 computes the logical AND of three inputs
|
||||
// AND3(a, b, c) = AND(AND(a, b), c)
|
||||
func (eval *Evaluator) AND3(ct1, ct2, ct3 *Ciphertext) (*Ciphertext, error) {
|
||||
ab, err := eval.AND(ct1, ct2)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return eval.AND(ab, ct3)
|
||||
}
|
||||
|
||||
// OR3 computes the logical OR of three inputs
|
||||
// OR3(a, b, c) = OR(OR(a, b), c)
|
||||
func (eval *Evaluator) OR3(ct1, ct2, ct3 *Ciphertext) (*Ciphertext, error) {
|
||||
ab, err := eval.OR(ct1, ct2)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return eval.OR(ab, ct3)
|
||||
}
|
||||
|
||||
// MAJORITY computes the majority vote of three inputs with single bootstrap
|
||||
// MAJORITY(a, b, c) = 1 if at least two inputs are 1
|
||||
// This uses a single bootstrap since the threshold at 0 correctly separates
|
||||
// 0-1 true inputs (sum < 0) from 2-3 true inputs (sum > 0)
|
||||
func (eval *Evaluator) MAJORITY(ct1, ct2, ct3 *Ciphertext) (*Ciphertext, error) {
|
||||
sum := eval.addCiphertexts(ct1, ct2)
|
||||
sum = eval.addCiphertexts(sum, ct3)
|
||||
return eval.bootstrap(sum, eval.bsk.TestPolyMAJORITY)
|
||||
}
|
||||
|
||||
// NAND3 computes the logical NAND of three inputs
|
||||
// NAND3(a, b, c) = NOT(AND3(a, b, c))
|
||||
func (eval *Evaluator) NAND3(ct1, ct2, ct3 *Ciphertext) (*Ciphertext, error) {
|
||||
result, err := eval.AND3(ct1, ct2, ct3)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return eval.NOT(result), nil
|
||||
}
|
||||
|
||||
// NOR3 computes the logical NOR of three inputs
|
||||
// NOR3(a, b, c) = NOT(OR3(a, b, c))
|
||||
func (eval *Evaluator) NOR3(ct1, ct2, ct3 *Ciphertext) (*Ciphertext, error) {
|
||||
result, err := eval.OR3(ct1, ct2, ct3)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return eval.NOT(result), nil
|
||||
}
|
||||
|
||||
// Copy creates a copy of a ciphertext
|
||||
func (eval *Evaluator) Copy(ct *Ciphertext) *Ciphertext {
|
||||
return &Ciphertext{ct.CopyNew()}
|
||||
}
|
||||
|
||||
// Refresh bootstraps a ciphertext to reduce noise
|
||||
func (eval *Evaluator) Refresh(ct *Ciphertext) (*Ciphertext, error) {
|
||||
return eval.bootstrap(ct, eval.bsk.TestPolyID)
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user