mirror of
https://github.com/luxfi/lattice.git
synced 2026-09-24 00:25:44 +00:00
Update docs
This commit is contained in:
@@ -53,3 +53,11 @@ _testmain.go
|
||||
# generated
|
||||
/Coding
|
||||
|
||||
|
||||
|
||||
|
||||
AGENTS.md
|
||||
CLAUDE.md
|
||||
GEMINI.md
|
||||
GROK.md
|
||||
QWEN.md
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
# AI Assistant Knowledge Base
|
||||
|
||||
**Last Updated**: $(date +%Y-%m-%d)
|
||||
**Project**: $(basename "$REPO_PATH")
|
||||
**Organization**: $(basename "$(dirname "$REPO_PATH")")
|
||||
|
||||
## Project Overview
|
||||
|
||||
This repository is part of the $(basename "$(dirname "$REPO_PATH")") organization.
|
||||
|
||||
## Essential Commands
|
||||
|
||||
### Development
|
||||
```bash
|
||||
# Add common commands here
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
## Key Technologies
|
||||
|
||||
## Development Workflow
|
||||
|
||||
## Context for All AI Assistants
|
||||
|
||||
This file (`LLM.md`) is symlinked as:
|
||||
- `.AGENTS.md`
|
||||
- `CLAUDE.md`
|
||||
- `QWEN.md`
|
||||
- `GEMINI.md`
|
||||
|
||||
All files reference the same knowledge base. Updates here propagate to all AI systems.
|
||||
|
||||
## Rules for AI Assistants
|
||||
|
||||
1. **ALWAYS** update LLM.md with significant discoveries
|
||||
2. **NEVER** commit symlinked files (.AGENTS.md, CLAUDE.md, etc.) - they're in .gitignore
|
||||
3. **NEVER** create random summary files - update THIS file
|
||||
|
||||
---
|
||||
|
||||
**Note**: This file serves as the single source of truth for all AI assistants working on this project.
|
||||
@@ -7,10 +7,10 @@ Starting with the release of version 3.0.0, Lattice is maintained and supported
|
||||
by [Tune Insight SA](https://lux.network).
|
||||
|
||||
Since the release of version 4.0.0, Lattice is maintained and supported
|
||||
by [Lux Industries Inc](https://lux.network).
|
||||
by [Lux Industries Inc(https://lux.network).
|
||||
|
||||
Active development of new features in Lattice is still carried out both at the
|
||||
EPFL Laboratory for Data Security and at Tune Insight SA and Lux Industries Inc.
|
||||
EPFL Laboratory for Data Security and at Tune Insight SA and Lux Industries Inc
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
this file except in compliance with the License. You may obtain a copy of the
|
||||
|
||||
@@ -118,7 +118,7 @@ The Lattice library was originally exclusively developed by the EPFL Laboratory
|
||||
until its version 2.4.0.
|
||||
|
||||
Starting with the release of version 3.0.0, Lattice is maintained and supported
|
||||
by [Lux Industries Inc](https://lux.network).
|
||||
by [Lux Industries Inc(https://lux.network).
|
||||
|
||||
Also starting from version 3.0.0, the module name has changed to
|
||||
`github.com/luxfi/lattice/v[X]`, and the official repository has been moved to
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
# Dependencies
|
||||
node_modules/
|
||||
.pnpm-store/
|
||||
|
||||
# Next.js
|
||||
.next/
|
||||
out/
|
||||
.turbo/
|
||||
|
||||
# Build
|
||||
dist/
|
||||
build/
|
||||
|
||||
# Environment
|
||||
.env
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
# IDE
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Fumadocs
|
||||
.source/
|
||||
|
||||
# TypeScript
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
@@ -0,0 +1,42 @@
|
||||
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 defaultMdxComponents from "fumadocs-ui/mdx"
|
||||
|
||||
export default async function Page(props: {
|
||||
params: Promise<{ slug?: string[] }>
|
||||
}) {
|
||||
const params = await props.params
|
||||
const page = source.getPage(params.slug)
|
||||
if (!page) notFound()
|
||||
|
||||
const MDX = page.data.body
|
||||
|
||||
return (
|
||||
<DocsPage toc={page.data.toc} full={page.data.full}>
|
||||
<DocsTitle>{page.data.title}</DocsTitle>
|
||||
<DocsDescription>{page.data.description}</DocsDescription>
|
||||
<DocsBody>
|
||||
<MDX components={{ ...defaultMdxComponents }} />
|
||||
</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,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { source } from "@/lib/source"
|
||||
import type { ReactNode } from "react"
|
||||
import { DocsLayout } from "fumadocs-ui/layouts/docs"
|
||||
|
||||
export default async function Layout({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<DocsLayout tree={source.pageTree} sidebar={{ defaultOpenLevel: 0 }}>
|
||||
{children}
|
||||
</DocsLayout>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
@import "tailwindcss";
|
||||
@import "fumadocs-ui/style.css";
|
||||
|
||||
@custom-variant dark (&:is(.dark *));
|
||||
|
||||
@theme inline {
|
||||
--breakpoint-3xl: 1600px;
|
||||
--breakpoint-4xl: 2000px;
|
||||
--font-sans: var(--font-geist-sans), system-ui, sans-serif;
|
||||
--font-mono: var(--font-geist-mono), monospace;
|
||||
--radius-sm: calc(var(--radius) - 4px);
|
||||
--radius-md: calc(var(--radius) - 2px);
|
||||
--radius-lg: var(--radius);
|
||||
--radius-xl: calc(var(--radius) + 4px);
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
--color-card: var(--card);
|
||||
--color-card-foreground: var(--card-foreground);
|
||||
--color-popover: var(--popover);
|
||||
--color-popover-foreground: var(--popover-foreground);
|
||||
--color-primary: var(--primary);
|
||||
--color-primary-foreground: var(--primary-foreground);
|
||||
--color-secondary: var(--secondary);
|
||||
--color-secondary-foreground: var(--secondary-foreground);
|
||||
--color-muted: var(--muted);
|
||||
--color-muted-foreground: var(--muted-foreground);
|
||||
--color-accent: var(--accent);
|
||||
--color-accent-foreground: var(--accent-foreground);
|
||||
--color-destructive: var(--destructive);
|
||||
--color-destructive-foreground: var(--destructive-foreground);
|
||||
--color-border: var(--border);
|
||||
--color-input: var(--input);
|
||||
--color-ring: var(--ring);
|
||||
}
|
||||
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 0 0% 3.9%;
|
||||
--card: 0 0% 100%;
|
||||
--card-foreground: 0 0% 3.9%;
|
||||
--popover: 0 0% 100%;
|
||||
--popover-foreground: 0 0% 3.9%;
|
||||
--primary: 0 0% 9%;
|
||||
--primary-foreground: 0 0% 98%;
|
||||
--secondary: 0 0% 96.1%;
|
||||
--secondary-foreground: 0 0% 9%;
|
||||
--muted: 0 0% 96.1%;
|
||||
--muted-foreground: 0 0% 45.1%;
|
||||
--accent: 0 0% 96.1%;
|
||||
--accent-foreground: 0 0% 9%;
|
||||
--destructive: 0 84.2% 60.2%;
|
||||
--destructive-foreground: 0 0% 98%;
|
||||
--border: 0 0% 89.8%;
|
||||
--input: 0 0% 89.8%;
|
||||
--ring: 0 0% 3.9%;
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: 0 0% 3.9%;
|
||||
--foreground: 0 0% 98%;
|
||||
--card: 0 0% 3.9%;
|
||||
--card-foreground: 0 0% 98%;
|
||||
--popover: 0 0% 3.9%;
|
||||
--popover-foreground: 0 0% 98%;
|
||||
--primary: 0 0% 98%;
|
||||
--primary-foreground: 0 0% 9%;
|
||||
--secondary: 0 0% 14.9%;
|
||||
--secondary-foreground: 0 0% 98%;
|
||||
--muted: 0 0% 14.9%;
|
||||
--muted-foreground: 0 0% 63.9%;
|
||||
--accent: 0 0% 14.9%;
|
||||
--accent-foreground: 0 0% 98%;
|
||||
--destructive: 0 62.8% 30.6%;
|
||||
--destructive-foreground: 0 0% 98%;
|
||||
--border: 0 0% 14.9%;
|
||||
--input: 0 0% 14.9%;
|
||||
--ring: 0 0% 83.1%;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import "./global.css"
|
||||
import { RootProvider } from "fumadocs-ui/provider/next"
|
||||
import { Inter } from "next/font/google"
|
||||
import type { ReactNode } from "react"
|
||||
|
||||
const inter = Inter({
|
||||
subsets: ["latin"],
|
||||
variable: "--font-geist-sans",
|
||||
display: "swap",
|
||||
})
|
||||
|
||||
const interMono = Inter({
|
||||
subsets: ["latin"],
|
||||
variable: "--font-geist-mono",
|
||||
display: "swap",
|
||||
})
|
||||
|
||||
export const metadata = {
|
||||
title: {
|
||||
default: "Lattice Crypto Documentation",
|
||||
template: "%s | Lattice Crypto",
|
||||
},
|
||||
description: "Post-quantum lattice-based cryptography",
|
||||
}
|
||||
|
||||
export default function Layout({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<html
|
||||
lang="en"
|
||||
className={`${inter.variable} ${interMono.variable}`}
|
||||
suppressHydrationWarning
|
||||
>
|
||||
<body className="min-h-svh bg-background font-sans antialiased">
|
||||
<RootProvider
|
||||
search={{
|
||||
enabled: true,
|
||||
}}
|
||||
theme={{
|
||||
enabled: true,
|
||||
defaultTheme: "dark",
|
||||
}}
|
||||
>
|
||||
<div className="relative flex min-h-svh flex-col bg-background">
|
||||
{children}
|
||||
</div>
|
||||
</RootProvider>
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import Link from "next/link"
|
||||
|
||||
export default function HomePage() {
|
||||
return (
|
||||
<main className="flex flex-1 flex-col items-center justify-center px-4">
|
||||
<div className="container flex flex-col items-center gap-12 py-24 sm:gap-16 sm:py-32">
|
||||
<div className="flex flex-col items-center gap-4 text-center">
|
||||
<h1 className="text-4xl font-bold tracking-tight sm:text-6xl">
|
||||
Documentation
|
||||
</h1>
|
||||
<p className="max-w-2xl text-lg text-muted-foreground">
|
||||
Get started with our comprehensive documentation
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex gap-4">
|
||||
<Link
|
||||
href="/docs"
|
||||
className="inline-flex h-10 items-center justify-center rounded-md bg-primary px-8 text-sm font-medium text-primary-foreground shadow transition-colors hover:bg-primary/90"
|
||||
>
|
||||
Get Started
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,656 @@
|
||||
---
|
||||
title: API Reference
|
||||
description: Complete API documentation for Lattice cryptographic library
|
||||
---
|
||||
|
||||
# API Reference
|
||||
|
||||
Comprehensive API documentation for all Lattice packages and functions.
|
||||
|
||||
## Core Packages
|
||||
|
||||
### `ring` - Polynomial Arithmetic
|
||||
|
||||
Foundation for all lattice-based operations providing modular arithmetic for polynomials.
|
||||
|
||||
```go
|
||||
import "github.com/luxfi/lattice/v6/ring"
|
||||
```
|
||||
|
||||
#### Types
|
||||
|
||||
```go
|
||||
// Ring represents a quotient polynomial ring
|
||||
type Ring struct {
|
||||
N int // Ring degree (power of 2)
|
||||
Modulus uint64 // Prime modulus
|
||||
BRedConstant []uint64 // Barrett reduction constants
|
||||
NTTTable []uint64 // NTT twiddle factors
|
||||
}
|
||||
|
||||
// Poly represents a polynomial in the ring
|
||||
type Poly struct {
|
||||
Coeffs [][]uint64 // Coefficients in RNS representation
|
||||
IsNTT bool // Whether polynomial is in NTT form
|
||||
}
|
||||
```
|
||||
|
||||
#### Functions
|
||||
|
||||
```go
|
||||
// NewRing creates a new polynomial ring
|
||||
func NewRing(N int, moduli []uint64) (*Ring, error)
|
||||
|
||||
// NewPoly allocates a new polynomial
|
||||
func (r *Ring) NewPoly() *Poly
|
||||
|
||||
// NTT performs Number Theoretic Transform
|
||||
func (r *Ring) NTT(p1, p2 *Poly)
|
||||
|
||||
// INTT performs inverse NTT
|
||||
func (r *Ring) INTT(p1, p2 *Poly)
|
||||
|
||||
// Add performs polynomial addition
|
||||
func (r *Ring) Add(p1, p2, pOut *Poly)
|
||||
|
||||
// Mul performs polynomial multiplication
|
||||
func (r *Ring) Mul(p1, p2, pOut *Poly)
|
||||
|
||||
// MulScalar multiplies polynomial by scalar
|
||||
func (r *Ring) MulScalar(p1 *Poly, scalar uint64, pOut *Poly)
|
||||
|
||||
// Reduce performs modular reduction
|
||||
func (r *Ring) Reduce(p1, p2 *Poly)
|
||||
```
|
||||
|
||||
### `rlwe` - RLWE Cryptographic Primitives
|
||||
|
||||
Core cryptographic operations for Ring Learning With Errors.
|
||||
|
||||
```go
|
||||
import "github.com/luxfi/lattice/v6/core/rlwe"
|
||||
```
|
||||
|
||||
#### Types
|
||||
|
||||
```go
|
||||
// Parameters defines RLWE parameters
|
||||
type Parameters struct {
|
||||
logN int // Log2 of ring degree
|
||||
qi []uint64 // Ciphertext moduli chain
|
||||
pi []uint64 // Key-switching moduli
|
||||
sigma float64 // Error standard deviation
|
||||
}
|
||||
|
||||
// SecretKey represents a secret key
|
||||
type SecretKey struct {
|
||||
Value *ring.Poly
|
||||
}
|
||||
|
||||
// PublicKey represents a public key
|
||||
type PublicKey struct {
|
||||
Value [2]*ring.Poly
|
||||
}
|
||||
|
||||
// Ciphertext represents an encrypted value
|
||||
type Ciphertext struct {
|
||||
Value []*ring.Poly
|
||||
Level int
|
||||
}
|
||||
|
||||
// Plaintext represents an unencrypted value
|
||||
type Plaintext struct {
|
||||
Value *ring.Poly
|
||||
Scale float64
|
||||
}
|
||||
```
|
||||
|
||||
#### Key Generation
|
||||
|
||||
```go
|
||||
// KeyGenerator generates cryptographic keys
|
||||
type KeyGenerator struct {
|
||||
params Parameters
|
||||
prng utils.PRNG
|
||||
}
|
||||
|
||||
// NewKeyGenerator creates a new key generator
|
||||
func NewKeyGenerator(params Parameters) *KeyGenerator
|
||||
|
||||
// GenSecretKey generates a secret key
|
||||
func (kg *KeyGenerator) GenSecretKey() *SecretKey
|
||||
|
||||
// GenPublicKey generates a public key
|
||||
func (kg *KeyGenerator) GenPublicKey(sk *SecretKey) *PublicKey
|
||||
|
||||
// GenRelinearizationKey generates relinearization keys
|
||||
func (kg *KeyGenerator) GenRelinearizationKey(sk *SecretKey, maxDegree int) *RelinearizationKey
|
||||
|
||||
// GenGaloisKeys generates Galois keys for rotations
|
||||
func (kg *KeyGenerator) GenGaloisKeys(sk *SecretKey, galoisElements []uint64) *GaloisKeys
|
||||
```
|
||||
|
||||
#### Encryption/Decryption
|
||||
|
||||
```go
|
||||
// Encryptor encrypts plaintexts
|
||||
type Encryptor interface {
|
||||
Encrypt(pt *Plaintext, ct *Ciphertext) error
|
||||
EncryptNew(pt *Plaintext) (*Ciphertext, error)
|
||||
EncryptZero(ct *Ciphertext) error
|
||||
EncryptZeroNew(level int) (*Ciphertext, error)
|
||||
}
|
||||
|
||||
// NewEncryptor creates an encryptor
|
||||
func NewEncryptor(params Parameters, pk *PublicKey) Encryptor
|
||||
|
||||
// Decryptor decrypts ciphertexts
|
||||
type Decryptor interface {
|
||||
Decrypt(ct *Ciphertext, pt *Plaintext) error
|
||||
DecryptNew(ct *Ciphertext) (*Plaintext, error)
|
||||
}
|
||||
|
||||
// NewDecryptor creates a decryptor
|
||||
func NewDecryptor(params Parameters, sk *SecretKey) Decryptor
|
||||
```
|
||||
|
||||
### `schemes/ckks` - CKKS Homomorphic Encryption
|
||||
|
||||
Approximate arithmetic over complex/real numbers.
|
||||
|
||||
```go
|
||||
import "github.com/luxfi/lattice/v6/schemes/ckks"
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
```go
|
||||
// ParametersLiteral defines CKKS parameters
|
||||
type ParametersLiteral struct {
|
||||
LogN int // Log2 of ring degree
|
||||
LogQ []int // Log2 of ciphertext moduli
|
||||
LogP []int // Log2 of key-switching moduli
|
||||
LogDefaultScale int // Log2 of default scale
|
||||
Sigma float64 // Error standard deviation
|
||||
RingType ring.Type // Standard or ConjugateInvariant
|
||||
}
|
||||
|
||||
// NewParametersFromLiteral creates parameters
|
||||
func NewParametersFromLiteral(pl ParametersLiteral) (Parameters, error)
|
||||
|
||||
// DefaultParams provides pre-configured parameter sets
|
||||
var (
|
||||
PN12QP109 Parameters // N=4096, 128-bit security
|
||||
PN13QP218 Parameters // N=8192, 128-bit security
|
||||
PN14QP438 Parameters // N=16384, 128-bit security
|
||||
PN15QP880 Parameters // N=32768, 128-bit security
|
||||
)
|
||||
```
|
||||
|
||||
#### Encoder
|
||||
|
||||
```go
|
||||
// Encoder encodes/decodes between values and plaintexts
|
||||
type Encoder interface {
|
||||
Encode(values interface{}, pt *Plaintext) error
|
||||
Decode(pt *Plaintext, slots int) []complex128
|
||||
EncodeCoeffs(coeffs []float64, pt *Plaintext) error
|
||||
DecodeCoeffs(pt *Plaintext) []float64
|
||||
}
|
||||
|
||||
// NewEncoder creates an encoder
|
||||
func NewEncoder(params Parameters) Encoder
|
||||
|
||||
// Encoding options
|
||||
func (e *Encoder) EncodeWithScale(values interface{}, scale float64, pt *Plaintext) error
|
||||
func (e *Encoder) EncodeDiagMatrix(matrix map[int][]complex128, scale float64, pt *Plaintext) error
|
||||
```
|
||||
|
||||
#### Evaluator
|
||||
|
||||
```go
|
||||
// Evaluator performs homomorphic operations
|
||||
type Evaluator interface {
|
||||
// Arithmetic operations
|
||||
Add(op0, op1 Operand, opOut *Ciphertext) error
|
||||
Sub(op0, op1 Operand, opOut *Ciphertext) error
|
||||
Mul(op0, op1 Operand, opOut *Ciphertext) error
|
||||
MulRelin(op0, op1 Operand, opOut *Ciphertext) error
|
||||
|
||||
// Rescaling
|
||||
Rescale(ctIn, ctOut *Ciphertext) error
|
||||
|
||||
// Rotations
|
||||
Rotate(ctIn *Ciphertext, k int, ctOut *Ciphertext) error
|
||||
Conjugate(ctIn, ctOut *Ciphertext) error
|
||||
|
||||
// Advanced operations
|
||||
Power(ct *Ciphertext, degree int, ctOut *Ciphertext) error
|
||||
Polynomial(ct *Ciphertext, poly *Polynomial, ctOut *Ciphertext) error
|
||||
InnerProduct(ct0, ct1 []*Ciphertext, ctOut *Ciphertext) error
|
||||
}
|
||||
|
||||
// NewEvaluator creates an evaluator
|
||||
func NewEvaluator(params Parameters, evk *EvaluationKeySet) Evaluator
|
||||
```
|
||||
|
||||
### `schemes/bgv` - BGV/BFV Homomorphic Encryption
|
||||
|
||||
Exact arithmetic over integers modulo a plaintext modulus.
|
||||
|
||||
```go
|
||||
import "github.com/luxfi/lattice/v6/schemes/bgv"
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
```go
|
||||
// ParametersLiteral defines BGV parameters
|
||||
type ParametersLiteral struct {
|
||||
LogN int // Log2 of ring degree
|
||||
LogQ []int // Log2 of ciphertext moduli
|
||||
LogP []int // Log2 of key-switching moduli
|
||||
PlaintextModulus uint64 // Plaintext modulus (usually prime)
|
||||
Sigma float64 // Error standard deviation
|
||||
}
|
||||
|
||||
// Standard parameter sets
|
||||
var (
|
||||
PN12QP109_65537 Parameters // N=4096, t=65537
|
||||
PN13QP218_65537 Parameters // N=8192, t=65537
|
||||
PN14QP438_65537 Parameters // N=16384, t=65537
|
||||
)
|
||||
```
|
||||
|
||||
#### Encoder
|
||||
|
||||
```go
|
||||
// Encoder for BGV plaintexts
|
||||
type Encoder interface {
|
||||
Encode(values interface{}, pt *Plaintext) error
|
||||
Decode(pt *Plaintext, slots int) []uint64
|
||||
EncodeRingT(values []uint64, pt *Plaintext) error
|
||||
DecodeRingT(pt *Plaintext) []uint64
|
||||
}
|
||||
|
||||
// Batching support
|
||||
func (e *Encoder) EncodeBatch(values []uint64, pt *Plaintext) error
|
||||
func (e *Encoder) DecodeBatch(pt *Plaintext) []uint64
|
||||
```
|
||||
|
||||
#### Evaluator
|
||||
|
||||
```go
|
||||
// BGV-specific operations
|
||||
type Evaluator interface {
|
||||
// Standard operations (same as CKKS)
|
||||
Add, Sub, Mul, MulRelin...
|
||||
|
||||
// BGV-specific
|
||||
MulScalar(ct *Ciphertext, scalar uint64, ctOut *Ciphertext) error
|
||||
Relinearize(ct *Ciphertext, ctOut *Ciphertext) error
|
||||
SwitchKeys(ctIn *Ciphertext, swk *SwitchingKey, ctOut *Ciphertext) error
|
||||
|
||||
// Automorphisms
|
||||
Automorphism(ctIn *Ciphertext, galEl uint64, ctOut *Ciphertext) error
|
||||
AutomorphismHoisted(ctIn *Ciphertext, galEl uint64, ctOut *Ciphertext) error
|
||||
}
|
||||
```
|
||||
|
||||
### `multiparty` - Multiparty Protocols
|
||||
|
||||
Distributed cryptographic protocols for threshold operations.
|
||||
|
||||
```go
|
||||
import "github.com/luxfi/lattice/v6/multiparty"
|
||||
```
|
||||
|
||||
#### Threshold Key Generation
|
||||
|
||||
```go
|
||||
// TKGProtocol generates keys collaboratively
|
||||
type TKGProtocol struct {
|
||||
params Parameters
|
||||
}
|
||||
|
||||
// NewTKGProtocol creates a protocol instance
|
||||
func NewTKGProtocol(params Parameters) *TKGProtocol
|
||||
|
||||
// GenShare generates a party's key share
|
||||
func (tkg *TKGProtocol) GenShare(sk *SecretKey) *TKGShare
|
||||
|
||||
// AggregateShares combines shares into public key
|
||||
func (tkg *TKGProtocol) AggregateShares(shares []*TKGShare) *PublicKey
|
||||
```
|
||||
|
||||
#### Collective Decryption
|
||||
|
||||
```go
|
||||
// PCKSProtocol for collective decryption
|
||||
type PCKSProtocol struct {
|
||||
params Parameters
|
||||
}
|
||||
|
||||
// GenShare generates decryption share
|
||||
func (pcks *PCKSProtocol) GenShare(sk *SecretKey, ct *Ciphertext) *PCKSShare
|
||||
|
||||
// AggregateShares combines decryption shares
|
||||
func (pcks *PCKSProtocol) AggregateShares(shares []*PCKSShare, ct *Ciphertext) *Plaintext
|
||||
```
|
||||
|
||||
#### Collective Relinearization
|
||||
|
||||
```go
|
||||
// RKGProtocol generates relinearization keys
|
||||
type RKGProtocol struct {
|
||||
params Parameters
|
||||
}
|
||||
|
||||
// GenShareRoundOne generates round 1 share
|
||||
func (rkg *RKGProtocol) GenShareRoundOne(sk *SecretKey) (*RKGShare, *SecretKey)
|
||||
|
||||
// GenShareRoundTwo generates round 2 share
|
||||
func (rkg *RKGProtocol) GenShareRoundTwo(sk *SecretKey, share1 *RKGShare) *RKGShare
|
||||
|
||||
// GenRelinearizationKey combines shares
|
||||
func (rkg *RKGProtocol) GenRelinearizationKey(shares2 []*RKGShare) *RelinearizationKey
|
||||
```
|
||||
|
||||
## Circuit Packages
|
||||
|
||||
### `circuits/ckks/bootstrapping`
|
||||
|
||||
Bootstrapping for noise reduction in CKKS.
|
||||
|
||||
```go
|
||||
import "github.com/luxfi/lattice/v6/circuits/ckks/bootstrapping"
|
||||
```
|
||||
|
||||
#### Bootstrapper
|
||||
|
||||
```go
|
||||
// ParametersLiteral for bootstrapping
|
||||
type ParametersLiteral struct {
|
||||
LogN int // Ring degree for bootstrapping
|
||||
LogSlots int // Number of slots
|
||||
H int // Hamming weight of secret key
|
||||
Sigma float64 // Error standard deviation
|
||||
// ... additional parameters
|
||||
}
|
||||
|
||||
// Bootstrapper refreshes ciphertexts
|
||||
type Bootstrapper struct {
|
||||
params Parameters
|
||||
btpParams ParametersLiteral
|
||||
}
|
||||
|
||||
// NewBootstrapper creates bootstrapper
|
||||
func NewBootstrapper(params Parameters, btpParams ParametersLiteral, evk *EvaluationKeySet) (*Bootstrapper, error)
|
||||
|
||||
// Bootstrap refreshes a ciphertext
|
||||
func (btp *Bootstrapper) Bootstrap(ct *Ciphertext) (*Ciphertext, error)
|
||||
|
||||
// BootstrapMany bootstraps multiple ciphertexts
|
||||
func (btp *Bootstrapper) BootstrapMany(cts []*Ciphertext) ([]*Ciphertext, error)
|
||||
```
|
||||
|
||||
### `circuits/ckks/comparison`
|
||||
|
||||
Comparison operations for CKKS.
|
||||
|
||||
```go
|
||||
import "github.com/luxfi/lattice/v6/circuits/ckks/comparison"
|
||||
```
|
||||
|
||||
#### Comparison Functions
|
||||
|
||||
```go
|
||||
// Comparison evaluates comparison circuits
|
||||
type Comparison struct {
|
||||
evaluator Evaluator
|
||||
params Parameters
|
||||
}
|
||||
|
||||
// Sign computes sign function
|
||||
func (comp *Comparison) Sign(ct *Ciphertext, pol *Polynomial) (*Ciphertext, error)
|
||||
|
||||
// Max computes maximum of two ciphertexts
|
||||
func (comp *Comparison) Max(ct0, ct1 *Ciphertext) (*Ciphertext, error)
|
||||
|
||||
// Min computes minimum
|
||||
func (comp *Comparison) Min(ct0, ct1 *Ciphertext) (*Ciphertext, error)
|
||||
|
||||
// Step computes step function
|
||||
func (comp *Comparison) Step(ct *Ciphertext, threshold float64) (*Ciphertext, error)
|
||||
```
|
||||
|
||||
### `circuits/ckks/minimax`
|
||||
|
||||
Minimax polynomial approximation.
|
||||
|
||||
```go
|
||||
import "github.com/luxfi/lattice/v6/circuits/ckks/minimax"
|
||||
```
|
||||
|
||||
#### Polynomial Approximation
|
||||
|
||||
```go
|
||||
// Remez computes minimax polynomial approximation
|
||||
type Remez struct {
|
||||
Function func(float64) float64
|
||||
Interval [2]float64
|
||||
Degree int
|
||||
}
|
||||
|
||||
// NewRemez creates approximator
|
||||
func NewRemez(f func(float64) float64, interval [2]float64, degree int) *Remez
|
||||
|
||||
// Approximate computes coefficients
|
||||
func (r *Remez) Approximate() ([]float64, error)
|
||||
|
||||
// EvaluatePolynomial evaluates on ciphertext
|
||||
func EvaluatePolynomial(eval Evaluator, ct *Ciphertext, coeffs []float64) (*Ciphertext, error)
|
||||
```
|
||||
|
||||
## Utility Packages
|
||||
|
||||
### `utils/bignum`
|
||||
|
||||
Arbitrary precision arithmetic.
|
||||
|
||||
```go
|
||||
import "github.com/luxfi/lattice/v6/utils/bignum"
|
||||
```
|
||||
|
||||
#### Complex Numbers
|
||||
|
||||
```go
|
||||
// Complex arbitrary precision complex number
|
||||
type Complex struct {
|
||||
Real *big.Float
|
||||
Imag *big.Float
|
||||
}
|
||||
|
||||
// NewComplex creates complex number
|
||||
func NewComplex(real, imag *big.Float) *Complex
|
||||
|
||||
// Operations
|
||||
func (c *Complex) Add(a, b *Complex) *Complex
|
||||
func (c *Complex) Mul(a, b *Complex) *Complex
|
||||
func (c *Complex) Quo(a, b *Complex) *Complex
|
||||
```
|
||||
|
||||
### `utils/sampling`
|
||||
|
||||
Cryptographically secure random sampling.
|
||||
|
||||
```go
|
||||
import "github.com/luxfi/lattice/v6/utils/sampling"
|
||||
```
|
||||
|
||||
#### Random Number Generation
|
||||
|
||||
```go
|
||||
// PRNG interface
|
||||
type PRNG interface {
|
||||
Read(p []byte) (n int, err error)
|
||||
ReadFloat64() float64
|
||||
ReadUint64() uint64
|
||||
}
|
||||
|
||||
// NewPRNG creates PRNG from seed
|
||||
func NewPRNG(seed []byte) PRNG
|
||||
|
||||
// Sampling functions
|
||||
func SampleGaussian(prng PRNG, sigma float64) float64
|
||||
func SampleTernary(prng PRNG, p float64) int
|
||||
func SampleUniform(prng PRNG, mod uint64) uint64
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
All functions return errors following Go conventions:
|
||||
|
||||
```go
|
||||
// Check errors explicitly
|
||||
ct, err := encryptor.EncryptNew(pt)
|
||||
if err != nil {
|
||||
return fmt.Errorf("encryption failed: %w", err)
|
||||
}
|
||||
|
||||
// Common errors
|
||||
var (
|
||||
ErrInvalidParameters = errors.New("invalid parameters")
|
||||
ErrDimensionMismatch = errors.New("dimension mismatch")
|
||||
ErrInvalidInput = errors.New("invalid input")
|
||||
ErrNilArgument = errors.New("nil argument")
|
||||
)
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Memory Management
|
||||
|
||||
```go
|
||||
// Reuse allocated memory
|
||||
ct := ckks.NewCiphertext(params, 1, level)
|
||||
for i := 0; i < iterations; i++ {
|
||||
evaluator.Mul(ct, ct, ct) // In-place operation
|
||||
}
|
||||
|
||||
// Clear sensitive data
|
||||
defer func() {
|
||||
sk.Value.Zero()
|
||||
runtime.GC()
|
||||
}()
|
||||
```
|
||||
|
||||
### Performance Optimization
|
||||
|
||||
```go
|
||||
// Batch operations when possible
|
||||
values := make([]complex128, params.Slots())
|
||||
encoder.Encode(values, pt) // Encode all slots at once
|
||||
|
||||
// Use appropriate precision
|
||||
params := ckks.ParametersLiteral{
|
||||
LogDefaultScale: 30, // Lower scale for less precision
|
||||
}
|
||||
|
||||
// Parallelize independent operations
|
||||
var wg sync.WaitGroup
|
||||
for i := range ciphertexts {
|
||||
wg.Add(1)
|
||||
go func(i int) {
|
||||
defer wg.Done()
|
||||
evaluator.Mul(cts[i], scalar, cts[i])
|
||||
}(i)
|
||||
}
|
||||
wg.Wait()
|
||||
```
|
||||
|
||||
### Security Considerations
|
||||
|
||||
```go
|
||||
// Validate parameters
|
||||
if err := params.Validate(); err != nil {
|
||||
log.Fatalf("insecure parameters: %v", err)
|
||||
}
|
||||
|
||||
// Use cryptographically secure randomness
|
||||
seed := make([]byte, 64)
|
||||
if _, err := crypto.Read(seed); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
prng := sampling.NewPRNG(seed)
|
||||
|
||||
// Monitor noise levels
|
||||
if ct.Level() == 0 {
|
||||
// Need bootstrapping or computation should stop
|
||||
}
|
||||
```
|
||||
|
||||
## Complete Example
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/luxfi/lattice/v6/core/rlwe"
|
||||
"github.com/luxfi/lattice/v6/schemes/ckks"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Setup parameters
|
||||
paramsLit := ckks.ParametersLiteral{
|
||||
LogN: 14,
|
||||
LogQ: []int{50, 40, 40, 40, 40},
|
||||
LogP: []int{60},
|
||||
LogDefaultScale: 40,
|
||||
Sigma: 3.2,
|
||||
}
|
||||
|
||||
params, err := ckks.NewParametersFromLiteral(paramsLit)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Generate keys
|
||||
kgen := rlwe.NewKeyGenerator(params)
|
||||
sk := kgen.GenSecretKeyNew()
|
||||
pk := kgen.GenPublicKeyNew(sk)
|
||||
rlk := kgen.GenRelinearizationKeyNew(sk)
|
||||
evk := rlwe.NewMemEvaluationKeySet(rlk)
|
||||
|
||||
// Setup crypto components
|
||||
encoder := ckks.NewEncoder(params)
|
||||
encryptor := rlwe.NewEncryptor(params, pk)
|
||||
decryptor := rlwe.NewDecryptor(params, sk)
|
||||
evaluator := ckks.NewEvaluator(params, evk)
|
||||
|
||||
// Prepare data
|
||||
values1 := []complex128{1, 2, 3, 4}
|
||||
values2 := []complex128{5, 6, 7, 8}
|
||||
|
||||
// Encode and encrypt
|
||||
pt1 := ckks.NewPlaintext(params, params.MaxLevel())
|
||||
pt2 := ckks.NewPlaintext(params, params.MaxLevel())
|
||||
|
||||
encoder.Encode(values1, pt1)
|
||||
encoder.Encode(values2, pt2)
|
||||
|
||||
ct1, _ := encryptor.EncryptNew(pt1)
|
||||
ct2, _ := encryptor.EncryptNew(pt2)
|
||||
|
||||
// Homomorphic multiplication
|
||||
ctMul, _ := evaluator.MulRelinNew(ct1, ct2)
|
||||
evaluator.Rescale(ctMul, ctMul)
|
||||
|
||||
// Decrypt and decode
|
||||
ptRes := decryptor.DecryptNew(ctMul)
|
||||
result := encoder.Decode(ptRes, params.LogSlots())
|
||||
|
||||
fmt.Println("Result:", result[:4])
|
||||
// Output: [5, 12, 21, 32]
|
||||
}
|
||||
@@ -0,0 +1,429 @@
|
||||
---
|
||||
title: Introduction to Lattice
|
||||
description: A comprehensive lattice-based cryptography library for post-quantum security
|
||||
---
|
||||
|
||||
# Lattice - Post-Quantum Cryptography Library
|
||||
|
||||
Lattice is a high-performance Go library implementing full-RNS Ring-Learning-With-Errors (RLWE) based homomorphic encryption primitives and multiparty protocols. It provides quantum-resistant cryptographic primitives that remain secure even in the presence of quantum computers.
|
||||
|
||||
## Why Lattice-Based Cryptography?
|
||||
|
||||
### The Quantum Threat
|
||||
|
||||
Traditional public-key cryptography (RSA, ECC) relies on mathematical problems that quantum computers can solve efficiently using algorithms like Shor's algorithm. As quantum computers become more powerful, these cryptographic systems become vulnerable. Lattice-based cryptography provides security based on problems that remain hard even for quantum computers.
|
||||
|
||||
### Key Advantages
|
||||
|
||||
- **Quantum Resistance**: Based on the hardness of lattice problems (Learning With Errors, Ring-LWE)
|
||||
- **Homomorphic Properties**: Enable computation on encrypted data without decryption
|
||||
- **Efficiency**: Competitive performance with classical cryptography
|
||||
- **Versatility**: Support for various cryptographic primitives (encryption, signatures, key exchange)
|
||||
- **NIST Standardization**: Multiple lattice-based schemes selected for NIST post-quantum standards
|
||||
|
||||
## Core Features
|
||||
|
||||
### High-Performance Implementation
|
||||
- **Full-RNS Arithmetic**: Optimized residue number system for efficient modular operations
|
||||
- **Power-of-Two Cyclotomic Rings**: Fast polynomial arithmetic using NTT
|
||||
- **SIMD Optimizations**: Vectorized operations for improved performance
|
||||
- **Pure Go**: Cross-platform compatibility including WASM compilation
|
||||
- **Parallel Processing**: Concurrent execution for multi-core systems
|
||||
|
||||
### Supported Schemes
|
||||
|
||||
#### BFV/BGV (Exact Arithmetic)
|
||||
- Full-RNS implementation of scale-invariant homomorphic encryption
|
||||
- Modular arithmetic over integers
|
||||
- Perfect for applications requiring exact computation
|
||||
- Support for batching via Chinese Remainder Theorem
|
||||
|
||||
#### CKKS (Approximate Arithmetic)
|
||||
- Fixed-point approximate arithmetic over complex/real numbers
|
||||
- Ideal for machine learning and signal processing
|
||||
- Support for conjugate-invariant variant
|
||||
- Advanced bootstrapping capabilities
|
||||
|
||||
#### Multiparty Computation
|
||||
- Threshold key generation
|
||||
- Distributed decryption and re-encryption
|
||||
- Interactive bootstrapping with secret-shared keys
|
||||
- Secure multiparty protocols
|
||||
|
||||
## Post-Quantum Security
|
||||
|
||||
### Security Foundations
|
||||
|
||||
Lattice-based cryptography derives its security from the computational hardness of several lattice problems:
|
||||
|
||||
#### Learning With Errors (LWE)
|
||||
Given a matrix **A** and vector **b = As + e** where **s** is secret and **e** is small error, finding **s** is computationally hard even for quantum computers.
|
||||
|
||||
```
|
||||
Security Parameters:
|
||||
- Ring dimension: N = 2^k (typically 2^12 to 2^17)
|
||||
- Modulus: Q (product of primes)
|
||||
- Error distribution: Discrete Gaussian
|
||||
- Security level: 128, 192, or 256 bits
|
||||
```
|
||||
|
||||
#### Ring-LWE (RLWE)
|
||||
A structured variant of LWE using polynomial rings, providing better efficiency while maintaining security.
|
||||
|
||||
```go
|
||||
// Ring-LWE instance
|
||||
type RLWECiphertext struct {
|
||||
c0 *ring.Poly // a*s + m + e0
|
||||
c1 *ring.Poly // a
|
||||
}
|
||||
```
|
||||
|
||||
### Security Levels
|
||||
|
||||
| Security Level | Classical Security | Quantum Security | Ring Dimension |
|
||||
|---------------|-------------------|------------------|----------------|
|
||||
| 128-bit | 128 bits | 64 bits | N ≥ 2^12 |
|
||||
| 192-bit | 192 bits | 96 bits | N ≥ 2^14 |
|
||||
| 256-bit | 256 bits | 128 bits | N ≥ 2^15 |
|
||||
|
||||
### Parameter Selection
|
||||
|
||||
Parameters must balance security, performance, and functionality:
|
||||
|
||||
```go
|
||||
// Example: 128-bit security CKKS parameters
|
||||
params := ckks.ParametersLiteral{
|
||||
LogN: 14, // Ring dimension 2^14
|
||||
LogQ: []int{50, 40, 40, 40}, // Ciphertext modulus chain
|
||||
LogP: []int{60}, // Key-switching modulus
|
||||
LogDefaultScale: 40, // Default scaling factor
|
||||
Sigma: 3.2, // Error standard deviation
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### Core Package Structure
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/luxfi/lattice/core/rlwe"
|
||||
"github.com/luxfi/lattice/schemes/ckks"
|
||||
"github.com/luxfi/lattice/schemes/bgv"
|
||||
"github.com/luxfi/lattice/multiparty"
|
||||
)
|
||||
```
|
||||
|
||||
### Key Generation
|
||||
|
||||
```go
|
||||
// Generate keys for CKKS scheme
|
||||
params, err := ckks.NewParametersFromLiteral(paramsLiteral)
|
||||
kgen := rlwe.NewKeyGenerator(params)
|
||||
|
||||
// Secret key
|
||||
sk := kgen.GenSecretKeyNew()
|
||||
|
||||
// Public key
|
||||
pk := kgen.GenPublicKeyNew(sk)
|
||||
|
||||
// Evaluation keys (for homomorphic operations)
|
||||
evk := rlwe.NewMemEvaluationKeySet(
|
||||
kgen.GenRelinearizationKeyNew(sk), // For multiplication
|
||||
kgen.GenGaloisKeysNew(sk, galoisElems), // For rotations
|
||||
)
|
||||
```
|
||||
|
||||
### Encryption and Decryption
|
||||
|
||||
```go
|
||||
// Create encoder and encryptor
|
||||
encoder := ckks.NewEncoder(params)
|
||||
encryptor := rlwe.NewEncryptor(params, pk)
|
||||
decryptor := rlwe.NewDecryptor(params, sk)
|
||||
|
||||
// Encode and encrypt
|
||||
values := []complex128{1.0, 2.0, 3.0, 4.0}
|
||||
plaintext := ckks.NewPlaintext(params, params.MaxLevel())
|
||||
encoder.Encode(values, plaintext)
|
||||
ciphertext, err := encryptor.EncryptNew(plaintext)
|
||||
|
||||
// Decrypt and decode
|
||||
plaintext = decryptor.DecryptNew(ciphertext)
|
||||
result := encoder.Decode(plaintext, params.LogSlots())
|
||||
```
|
||||
|
||||
### Homomorphic Operations
|
||||
|
||||
```go
|
||||
evaluator := ckks.NewEvaluator(params, evk)
|
||||
|
||||
// Addition
|
||||
ctSum, err := evaluator.AddNew(ct1, ct2)
|
||||
|
||||
// Multiplication
|
||||
ctProd, err := evaluator.MulRelinNew(ct1, ct2)
|
||||
evaluator.Rescale(ctProd, ctProd)
|
||||
|
||||
// Rotation
|
||||
ctRot, err := evaluator.RotateNew(ct, 1)
|
||||
|
||||
// Complex conjugation
|
||||
ctConj, err := evaluator.ConjugateNew(ct)
|
||||
```
|
||||
|
||||
### Multiparty Operations
|
||||
|
||||
```go
|
||||
// Threshold key generation
|
||||
tkg := multiparty.NewTKGProtocol(params)
|
||||
share := tkg.GenShare(sk)
|
||||
pk := tkg.AggregateShares(shares)
|
||||
|
||||
// Collective decryption
|
||||
tdp := multiparty.NewPCKSProtocol(params)
|
||||
shareDecrypt := tdp.GenShare(sk, ct)
|
||||
plaintext := tdp.AggregateShares(sharesDecrypt)
|
||||
```
|
||||
|
||||
## Performance Characteristics
|
||||
|
||||
### Benchmarks
|
||||
|
||||
Performance on Intel Core i7-10700K @ 3.80GHz:
|
||||
|
||||
| Operation | Time (ms) | Throughput | Memory |
|
||||
|-----------|-----------|------------|--------|
|
||||
| Key Generation | 45 | - | 128 MB |
|
||||
| Encryption | 2.3 | 435 ops/s | 8 MB |
|
||||
| Decryption | 1.8 | 555 ops/s | 8 MB |
|
||||
| Addition | 0.05 | 20,000 ops/s | 16 MB |
|
||||
| Multiplication | 25 | 40 ops/s | 24 MB |
|
||||
| Rotation | 8 | 125 ops/s | 16 MB |
|
||||
| Bootstrapping | 850 | 1.2 ops/s | 512 MB |
|
||||
|
||||
### Optimization Techniques
|
||||
|
||||
#### Number Theoretic Transform (NTT)
|
||||
Fast polynomial multiplication using FFT-like algorithm in finite fields:
|
||||
```
|
||||
Time Complexity: O(N log N) vs O(N²) for naive multiplication
|
||||
Space Complexity: O(N)
|
||||
```
|
||||
|
||||
#### RNS Decomposition
|
||||
Decompose large modulus Q into smaller primes for parallel arithmetic:
|
||||
```
|
||||
Q = q₁ × q₂ × ... × qₗ
|
||||
Operations mod Q → Operations mod qᵢ (parallel)
|
||||
```
|
||||
|
||||
#### Lazy Reduction
|
||||
Delay modular reductions to minimize computational overhead:
|
||||
```go
|
||||
// Accumulate operations before reduction
|
||||
for i := 0; i < batchSize; i++ {
|
||||
acc.Add(acc, values[i])
|
||||
}
|
||||
acc.Reduce() // Single reduction at the end
|
||||
```
|
||||
|
||||
### Memory Management
|
||||
|
||||
```go
|
||||
// Pre-allocate buffers for better performance
|
||||
buffer := rlwe.NewCiphertext(params, degree, level)
|
||||
|
||||
// Reuse memory with in-place operations
|
||||
evaluator.Add(ct1, ct2, ct1) // Result stored in ct1
|
||||
|
||||
// Manual garbage collection for large operations
|
||||
runtime.GC()
|
||||
```
|
||||
|
||||
## Advanced Features
|
||||
|
||||
### Bootstrapping
|
||||
|
||||
Enable unlimited homomorphic operations by refreshing ciphertext noise:
|
||||
|
||||
```go
|
||||
// Configure bootstrapping parameters
|
||||
btpParams := bootstrapping.ParametersLiteral{
|
||||
LogN: 16,
|
||||
LogSlots: 15,
|
||||
H: 192,
|
||||
Sigma: 3.2,
|
||||
...
|
||||
}
|
||||
|
||||
// Create bootstrapper
|
||||
btp, err := bootstrapping.NewBootstrapper(params, btpParams, evk)
|
||||
|
||||
// Bootstrap ciphertext
|
||||
ctBootstrapped, err := btp.Bootstrap(ct)
|
||||
```
|
||||
|
||||
### Linear Transformations
|
||||
|
||||
Efficient matrix-vector multiplication on encrypted data:
|
||||
|
||||
```go
|
||||
// Define transformation matrix
|
||||
matrix := [][]complex128{
|
||||
{1, 2, 3},
|
||||
{4, 5, 6},
|
||||
{7, 8, 9},
|
||||
}
|
||||
|
||||
// Create linear transformation
|
||||
linTransf := lintrans.NewLinearTransformation(params, matrix)
|
||||
|
||||
// Apply to ciphertext
|
||||
ctResult, err := evaluator.LinearTransformation(ct, linTransf)
|
||||
```
|
||||
|
||||
### Polynomial Evaluation
|
||||
|
||||
Evaluate polynomials on encrypted values:
|
||||
|
||||
```go
|
||||
// Define polynomial coefficients
|
||||
coeffs := []complex128{1.0, 2.0, 3.0} // 1 + 2x + 3x²
|
||||
|
||||
// Create polynomial evaluator
|
||||
poly := polynomial.NewPolynomial(coeffs)
|
||||
|
||||
// Evaluate on ciphertext
|
||||
ctResult, err := evaluator.Polynomial(ct, poly)
|
||||
```
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
### Parameter Validation
|
||||
```go
|
||||
// Always validate parameters before use
|
||||
if err := params.Validate(); err != nil {
|
||||
return fmt.Errorf("invalid parameters: %w", err)
|
||||
}
|
||||
```
|
||||
|
||||
### Noise Management
|
||||
```go
|
||||
// Monitor noise growth
|
||||
noise := rlwe.NoiseLevel(ct, sk, params)
|
||||
if noise > threshold {
|
||||
// Bootstrap or terminate computation
|
||||
}
|
||||
```
|
||||
|
||||
### Key Management
|
||||
- Never reuse randomness
|
||||
- Securely delete keys after use
|
||||
- Use hardware security modules for production
|
||||
- Implement key rotation policies
|
||||
|
||||
### Side-Channel Protection
|
||||
- Use constant-time implementations
|
||||
- Avoid data-dependent branches
|
||||
- Implement blinding techniques
|
||||
- Regular security audits
|
||||
|
||||
## Migration Guide
|
||||
|
||||
### From Classical Cryptography
|
||||
|
||||
```go
|
||||
// RSA/ECC replacement
|
||||
// Before: RSA encryption
|
||||
rsaCiphertext := rsa.Encrypt(publicKey, plaintext)
|
||||
|
||||
// After: Lattice encryption
|
||||
latticeCiphertext := encryptor.EncryptNew(plaintext)
|
||||
|
||||
// Advantage: Quantum-resistant + homomorphic operations
|
||||
```
|
||||
|
||||
### From Other HE Libraries
|
||||
|
||||
```go
|
||||
// SEAL/HElib migration
|
||||
// Key differences:
|
||||
// - Pure Go vs C++
|
||||
// - Full-RNS by default
|
||||
// - Unified API across schemes
|
||||
// - Native multiparty support
|
||||
```
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Installation
|
||||
|
||||
```bash
|
||||
go get github.com/luxfi/lattice/v6
|
||||
```
|
||||
|
||||
### Basic Example
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/luxfi/lattice/v6/core/rlwe"
|
||||
"github.com/luxfi/lattice/v6/schemes/ckks"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Initialize parameters
|
||||
params, _ := ckks.NewParametersFromLiteral(
|
||||
ckks.ParametersLiteral{
|
||||
LogN: 14,
|
||||
LogQ: []int{50, 40, 40, 40},
|
||||
LogP: []int{60},
|
||||
LogDefaultScale: 40,
|
||||
},
|
||||
)
|
||||
|
||||
// Generate keys
|
||||
kgen := rlwe.NewKeyGenerator(params)
|
||||
sk := kgen.GenSecretKeyNew()
|
||||
pk := kgen.GenPublicKeyNew(sk)
|
||||
|
||||
// Create crypto objects
|
||||
encoder := ckks.NewEncoder(params)
|
||||
encryptor := rlwe.NewEncryptor(params, pk)
|
||||
decryptor := rlwe.NewDecryptor(params, sk)
|
||||
evaluator := ckks.NewEvaluator(params, nil)
|
||||
|
||||
// Encrypt data
|
||||
values := []complex128{1, 2, 3, 4}
|
||||
pt := ckks.NewPlaintext(params, params.MaxLevel())
|
||||
encoder.Encode(values, pt)
|
||||
ct, _ := encryptor.EncryptNew(pt)
|
||||
|
||||
// Perform homomorphic addition
|
||||
ctSum, _ := evaluator.AddNew(ct, ct)
|
||||
|
||||
// Decrypt result
|
||||
ptResult := decryptor.DecryptNew(ctSum)
|
||||
result := encoder.Decode(ptResult, params.LogSlots())
|
||||
|
||||
fmt.Println("Result:", result[:4])
|
||||
// Output: Result: [2, 4, 6, 8]
|
||||
}
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [**Tutorials**](/docs/tutorials): Step-by-step guides for common use cases
|
||||
- [**API Documentation**](/docs/api): Complete API reference
|
||||
- [**Examples**](/docs/examples): Production-ready code examples
|
||||
- [**Benchmarks**](/docs/benchmarks): Performance comparisons and optimization tips
|
||||
- [**Security Guide**](/docs/security): Best practices for secure deployment
|
||||
|
||||
## Support
|
||||
|
||||
- **GitHub Issues**: [github.com/luxfi/lattice/issues](https://github.com/luxfi/lattice/issues)
|
||||
- **Email**: [[email protected]](mailto:[email protected])
|
||||
- **Documentation**: [pkg.go.dev/github.com/luxfi/lattice/v6](https://pkg.go.dev/github.com/luxfi/lattice/v6)
|
||||
@@ -0,0 +1,681 @@
|
||||
---
|
||||
title: NIST Post-Quantum Algorithms
|
||||
description: Implementation and usage of NIST-standardized post-quantum cryptographic algorithms
|
||||
---
|
||||
|
||||
# NIST Post-Quantum Algorithms
|
||||
|
||||
Comprehensive guide to NIST-standardized post-quantum cryptographic algorithms implemented in Lattice, including ML-DSA (Dilithium), ML-KEM (Kyber), and SLH-DSA (SPHINCS+).
|
||||
|
||||
## Overview
|
||||
|
||||
The National Institute of Standards and Technology (NIST) has standardized three post-quantum cryptographic algorithms as part of the Post-Quantum Cryptography Standardization Process. These algorithms are designed to resist attacks from both classical and quantum computers.
|
||||
|
||||
### NIST Standards (FIPS)
|
||||
|
||||
| Algorithm | FIPS | Type | Based On | Security Levels |
|
||||
|-----------|------|------|----------|----------------|
|
||||
| **ML-DSA** | FIPS 204 | Digital Signature | Dilithium (Lattice) | 2, 3, 5 |
|
||||
| **ML-KEM** | FIPS 203 | Key Encapsulation | Kyber (Lattice) | 1, 3, 5 |
|
||||
| **SLH-DSA** | FIPS 205 | Digital Signature | SPHINCS+ (Hash) | 1, 3, 5 |
|
||||
|
||||
## ML-DSA (Module-Lattice Digital Signature Algorithm)
|
||||
|
||||
### Overview
|
||||
|
||||
ML-DSA, based on Dilithium, provides quantum-resistant digital signatures using the hardness of lattice problems, specifically the Module Learning With Errors (MLWE) and Module Short Integer Solution (MSIS) problems.
|
||||
|
||||
### Security Parameters
|
||||
|
||||
```go
|
||||
// ML-DSA Security Levels
|
||||
const (
|
||||
ML_DSA_44 = iota // Level 2 - 128-bit classical security
|
||||
ML_DSA_65 // Level 3 - 192-bit classical security
|
||||
ML_DSA_87 // Level 5 - 256-bit classical security
|
||||
)
|
||||
|
||||
// Parameter Sets
|
||||
type MLDSAParams struct {
|
||||
SecurityLevel int
|
||||
N int // Polynomial degree (256)
|
||||
Q int // Modulus (8380417)
|
||||
K int // Module rank (4, 6, or 8)
|
||||
L int // Number of elements (4, 5, or 7)
|
||||
Eta int // Secret key range (2 or 4)
|
||||
Tau int // Number of ±1 in challenge (39, 49, or 60)
|
||||
Gamma1 int // Coefficient range (2^17 or 2^19)
|
||||
Gamma2 int // Low-order rounding range
|
||||
}
|
||||
```
|
||||
|
||||
### Implementation
|
||||
|
||||
```go
|
||||
package mldsa
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"github.com/luxfi/lattice/v6/core/rlwe"
|
||||
"github.com/luxfi/lattice/v6/utils/sampling"
|
||||
)
|
||||
|
||||
// KeyPair represents ML-DSA key pair
|
||||
type KeyPair struct {
|
||||
PublicKey *PublicKey
|
||||
SecretKey *SecretKey
|
||||
}
|
||||
|
||||
// PublicKey for ML-DSA
|
||||
type PublicKey struct {
|
||||
Seed []byte // 32 bytes
|
||||
T1 []*rlwe.Poly // Public key polynomials
|
||||
}
|
||||
|
||||
// SecretKey for ML-DSA
|
||||
type SecretKey struct {
|
||||
Seed []byte // 32 bytes
|
||||
S1 []*rlwe.Poly // Secret polynomials
|
||||
S2 []*rlwe.Poly // Secret polynomials
|
||||
T0 []*rlwe.Poly // Precomputed values
|
||||
}
|
||||
|
||||
// GenerateKeyPair generates ML-DSA key pair
|
||||
func GenerateKeyPair(params MLDSAParams) (*KeyPair, error) {
|
||||
// Sample seed
|
||||
seed := make([]byte, 32)
|
||||
if _, err := rand.Read(seed); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Expand seed to matrix A
|
||||
A := expandSeed(seed, params.K, params.L)
|
||||
|
||||
// Sample secret vectors
|
||||
s1 := sampleSecret(params.L, params.Eta)
|
||||
s2 := sampleSecret(params.K, params.Eta)
|
||||
|
||||
// Compute t = As1 + s2
|
||||
t := computePublicKey(A, s1, s2)
|
||||
|
||||
// Split t into t1 (high bits) and t0 (low bits)
|
||||
t1, t0 := power2Round(t, params.D)
|
||||
|
||||
return &KeyPair{
|
||||
PublicKey: &PublicKey{
|
||||
Seed: seed,
|
||||
T1: t1,
|
||||
},
|
||||
SecretKey: &SecretKey{
|
||||
Seed: seed,
|
||||
S1: s1,
|
||||
S2: s2,
|
||||
T0: t0,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Sign creates ML-DSA signature
|
||||
func Sign(sk *SecretKey, message []byte, params MLDSAParams) (*Signature, error) {
|
||||
// Hash message
|
||||
mu := hashMessage(message)
|
||||
|
||||
// Rejection sampling loop
|
||||
for attempt := 0; attempt < maxAttempts; attempt++ {
|
||||
// Sample masking vector y
|
||||
y := sampleMask(params.L, params.Gamma1)
|
||||
|
||||
// Compute w = Ay
|
||||
A := expandSeed(sk.Seed, params.K, params.L)
|
||||
w := multiplyMatrixVector(A, y)
|
||||
|
||||
// Extract high bits
|
||||
w1 := highBits(w, params.Gamma2)
|
||||
|
||||
// Hash to get challenge
|
||||
c := hashChallenge(mu, w1, params.Tau)
|
||||
|
||||
// Compute z = y + cs1
|
||||
z := addVectors(y, multiplyScalarVector(c, sk.S1))
|
||||
|
||||
// Rejection conditions
|
||||
if norm(z) >= params.Gamma1 - params.Beta {
|
||||
continue
|
||||
}
|
||||
|
||||
// Compute hints for signature compression
|
||||
h := makeHint(w, cs2, params.Gamma2)
|
||||
|
||||
if weight(h) <= params.Omega {
|
||||
return &Signature{
|
||||
C: c,
|
||||
Z: z,
|
||||
H: h,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, ErrSignatureFailed
|
||||
}
|
||||
|
||||
// Verify validates ML-DSA signature
|
||||
func Verify(pk *PublicKey, message []byte, sig *Signature, params MLDSAParams) bool {
|
||||
// Reconstruct matrix A
|
||||
A := expandSeed(pk.Seed, params.K, params.L)
|
||||
|
||||
// Hash message
|
||||
mu := hashMessage(message)
|
||||
|
||||
// Compute w' = Az - ct1 * 2^d
|
||||
Az := multiplyMatrixVector(A, sig.Z)
|
||||
ct1 := multiplyScalarVector(sig.C, pk.T1)
|
||||
wPrime := subtractVectors(Az, shiftLeft(ct1, params.D))
|
||||
|
||||
// Use hints to recover high bits
|
||||
w1Prime := useHint(wPrime, sig.H, params.Gamma2)
|
||||
|
||||
// Recompute challenge
|
||||
cPrime := hashChallenge(mu, w1Prime, params.Tau)
|
||||
|
||||
// Verify signature
|
||||
return sig.C == cPrime && norm(sig.Z) < params.Gamma1 - params.Beta
|
||||
}
|
||||
```
|
||||
|
||||
### Performance Characteristics
|
||||
|
||||
| Parameter Set | Sign (μs) | Verify (μs) | Signature Size | Public Key | Secret Key |
|
||||
|--------------|-----------|-------------|----------------|------------|------------|
|
||||
| ML-DSA-44 | 417 | 108 | 2,420 bytes | 1,312 bytes | 2,528 bytes |
|
||||
| ML-DSA-65 | 645 | 168 | 3,309 bytes | 1,952 bytes | 4,000 bytes |
|
||||
| ML-DSA-87 | 985 | 253 | 4,595 bytes | 2,592 bytes | 4,864 bytes |
|
||||
|
||||
## ML-KEM (Module-Lattice Key Encapsulation Mechanism)
|
||||
|
||||
### Overview
|
||||
|
||||
ML-KEM, based on Kyber, provides quantum-resistant key encapsulation using the Module Learning With Errors (MLWE) problem. It enables secure key exchange between parties.
|
||||
|
||||
### Security Parameters
|
||||
|
||||
```go
|
||||
// ML-KEM Security Levels
|
||||
const (
|
||||
ML_KEM_512 = iota // Level 1 - 128-bit classical security
|
||||
ML_KEM_768 // Level 3 - 192-bit classical security
|
||||
ML_KEM_1024 // Level 5 - 256-bit classical security
|
||||
)
|
||||
|
||||
// Parameter Sets
|
||||
type MLKEMParams struct {
|
||||
N int // Polynomial degree (256)
|
||||
Q int // Modulus (3329)
|
||||
K int // Module dimension (2, 3, or 4)
|
||||
Eta1 int // Noise parameter for key generation (3 or 2)
|
||||
Eta2 int // Noise parameter for encryption (2)
|
||||
Du int // Plaintext modulus bits (10 or 11)
|
||||
Dv int // Ciphertext modulus bits (4 or 5)
|
||||
}
|
||||
```
|
||||
|
||||
### Implementation
|
||||
|
||||
```go
|
||||
package mlkem
|
||||
|
||||
// KeyPair for ML-KEM
|
||||
type KEMKeyPair struct {
|
||||
PublicKey *KEMPublicKey
|
||||
SecretKey *KEMSecretKey
|
||||
}
|
||||
|
||||
// Encapsulation key (public key)
|
||||
type KEMPublicKey struct {
|
||||
PKE []byte // Public key for encryption
|
||||
H []byte // Hash of public key
|
||||
}
|
||||
|
||||
// Decapsulation key (secret key)
|
||||
type KEMSecretKey struct {
|
||||
SKE []byte // Secret key for decryption
|
||||
PKE []byte // Public key
|
||||
H []byte // Hash of public key
|
||||
Z []byte // Random value
|
||||
}
|
||||
|
||||
// GenerateKeyPair generates ML-KEM key pair
|
||||
func GenerateKEMKeyPair(params MLKEMParams) (*KEMKeyPair, error) {
|
||||
// Generate seed
|
||||
d := make([]byte, 32)
|
||||
rand.Read(d)
|
||||
|
||||
// Generate PKE key pair
|
||||
rho, sigma := G(d)
|
||||
|
||||
// Sample matrix A
|
||||
A := sampleMatrix(rho, params.K, params.K)
|
||||
|
||||
// Sample secret and error
|
||||
s := sampleNoise(sigma, 0, params.K, params.Eta1)
|
||||
e := sampleNoise(sigma, params.K, params.K, params.Eta1)
|
||||
|
||||
// Compute public key: t = As + e
|
||||
sHat := NTT(s)
|
||||
t := addVectors(multiplyMatrix(A, sHat), NTT(e))
|
||||
|
||||
// Encode public key
|
||||
pk := encodePK(t, rho)
|
||||
|
||||
// Hash public key
|
||||
h := H(pk)
|
||||
|
||||
// Sample random z
|
||||
z := make([]byte, 32)
|
||||
rand.Read(z)
|
||||
|
||||
return &KEMKeyPair{
|
||||
PublicKey: &KEMPublicKey{
|
||||
PKE: pk,
|
||||
H: h,
|
||||
},
|
||||
SecretKey: &KEMSecretKey{
|
||||
SKE: encodeSecret(s),
|
||||
PKE: pk,
|
||||
H: h,
|
||||
Z: z,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Encapsulate generates shared secret and ciphertext
|
||||
func Encapsulate(pk *KEMPublicKey, params MLKEMParams) ([]byte, []byte, error) {
|
||||
// Generate random message
|
||||
m := make([]byte, 32)
|
||||
rand.Read(m)
|
||||
|
||||
// Hash to get randomness
|
||||
K, r := G(H(m) || pk.H)
|
||||
|
||||
// Encrypt message
|
||||
c := PKEEncrypt(pk.PKE, m, r, params)
|
||||
|
||||
// Return shared secret and ciphertext
|
||||
return K, c, nil
|
||||
}
|
||||
|
||||
// Decapsulate recovers shared secret from ciphertext
|
||||
func Decapsulate(sk *KEMSecretKey, c []byte, params MLKEMParams) ([]byte, error) {
|
||||
// Decrypt ciphertext
|
||||
mPrime := PKEDecrypt(sk.SKE, c, params)
|
||||
|
||||
// Recompute randomness
|
||||
KPrime, rPrime := G(H(mPrime) || sk.H)
|
||||
|
||||
// Re-encrypt to verify
|
||||
cPrime := PKEEncrypt(sk.PKE, mPrime, rPrime, params)
|
||||
|
||||
// Implicit rejection
|
||||
if !bytes.Equal(c, cPrime) {
|
||||
// Return pseudorandom value
|
||||
return KDF(sk.Z || c), nil
|
||||
}
|
||||
|
||||
return KPrime, nil
|
||||
}
|
||||
|
||||
// PKE Encryption (underlying scheme)
|
||||
func PKEEncrypt(pk []byte, m []byte, r []byte, params MLKEMParams) []byte {
|
||||
// Decode public key
|
||||
t, rho := decodePK(pk)
|
||||
|
||||
// Sample matrix A^T
|
||||
AT := sampleMatrixTranspose(rho, params.K, params.K)
|
||||
|
||||
// Sample noise
|
||||
r1 := sampleNoise(r, 0, params.K, params.Eta1)
|
||||
r2 := sampleNoise(r, params.K, params.K, params.Eta2)
|
||||
e1 := sampleNoise(r, 2*params.K, 1, params.Eta2)
|
||||
|
||||
// Compute ciphertext
|
||||
// u = A^T r + e1
|
||||
u := addVectors(multiplyMatrix(AT, NTT(r1)), NTT(e1))
|
||||
|
||||
// v = t^T r + e2 + Decompress(Decode(m))
|
||||
v := add(
|
||||
innerProduct(t, NTT(r1)),
|
||||
add(e2, decompress(decode(m), params.Q))
|
||||
)
|
||||
|
||||
// Compress and encode
|
||||
c1 := compress(u, params.Du)
|
||||
c2 := compress(v, params.Dv)
|
||||
|
||||
return concatenate(c1, c2)
|
||||
}
|
||||
```
|
||||
|
||||
### Performance Characteristics
|
||||
|
||||
| Parameter Set | Encapsulate (μs) | Decapsulate (μs) | Ciphertext | Public Key | Secret Key |
|
||||
|---------------|------------------|------------------|------------|------------|------------|
|
||||
| ML-KEM-512 | 38 | 45 | 768 bytes | 800 bytes | 1,632 bytes |
|
||||
| ML-KEM-768 | 58 | 69 | 1,088 bytes | 1,184 bytes | 2,400 bytes |
|
||||
| ML-KEM-1024 | 85 | 102 | 1,568 bytes | 1,568 bytes | 3,168 bytes |
|
||||
|
||||
## SLH-DSA (Stateless Hash-based Digital Signature Algorithm)
|
||||
|
||||
### Overview
|
||||
|
||||
SLH-DSA, based on SPHINCS+, provides quantum-resistant signatures using only hash functions. It offers stateless operation and smaller key sizes but larger signatures.
|
||||
|
||||
### Security Parameters
|
||||
|
||||
```go
|
||||
// SLH-DSA Parameter Sets
|
||||
type SLHDSAParams struct {
|
||||
N int // Security parameter (16, 24, or 32 bytes)
|
||||
W int // Winternitz parameter (4, 16, or 256)
|
||||
H int // Hypertree height
|
||||
D int // Hypertree layers
|
||||
K int // FORS trees
|
||||
T int // FORS tree height
|
||||
Variant string // "simple" or "robust"
|
||||
}
|
||||
|
||||
// Predefined parameter sets
|
||||
var (
|
||||
SLHDSA_128s = SLHDSAParams{N: 16, W: 16, H: 63, D: 7, K: 14, T: 12}
|
||||
SLHDSA_128f = SLHDSAParams{N: 16, W: 16, H: 66, D: 22, K: 6, T: 33}
|
||||
SLHDSA_192s = SLHDSAParams{N: 24, W: 16, H: 63, D: 7, K: 17, T: 14}
|
||||
SLHDSA_192f = SLHDSAParams{N: 24, W: 16, H: 66, D: 22, K: 8, T: 33}
|
||||
SLHDSA_256s = SLHDSAParams{N: 32, W: 16, H: 64, D: 8, K: 22, T: 14}
|
||||
SLHDSA_256f = SLHDSAParams{N: 32, W: 16, H: 68, D: 17, K: 10, T: 30}
|
||||
)
|
||||
```
|
||||
|
||||
### Implementation
|
||||
|
||||
```go
|
||||
package slhdsa
|
||||
|
||||
// SPHINCS+ Key Pair
|
||||
type SPHINCSKeyPair struct {
|
||||
PublicKey SPHINCSPublicKey
|
||||
SecretKey SPHINCSSecretKey
|
||||
}
|
||||
|
||||
type SPHINCSPublicKey struct {
|
||||
Root []byte // Merkle tree root
|
||||
Seed []byte // Public seed
|
||||
}
|
||||
|
||||
type SPHINCSSecretKey struct {
|
||||
SKSeed []byte // Secret seed
|
||||
SKPrf []byte // Secret PRF key
|
||||
Root []byte // Merkle tree root
|
||||
Seed []byte // Public seed
|
||||
}
|
||||
|
||||
// GenerateKeyPair for SLH-DSA
|
||||
func GenerateSPHINCSKeyPair(params SLHDSAParams) (*SPHINCSKeyPair, error) {
|
||||
// Generate random seeds
|
||||
skSeed := make([]byte, params.N)
|
||||
skPrf := make([]byte, params.N)
|
||||
pkSeed := make([]byte, params.N)
|
||||
|
||||
rand.Read(skSeed)
|
||||
rand.Read(skPrf)
|
||||
rand.Read(pkSeed)
|
||||
|
||||
// Generate root of hypertree
|
||||
root := generateHypertreeRoot(skSeed, pkSeed, params)
|
||||
|
||||
return &SPHINCSKeyPair{
|
||||
PublicKey: SPHINCSPublicKey{
|
||||
Root: root,
|
||||
Seed: pkSeed,
|
||||
},
|
||||
SecretKey: SPHINCSSecretKey{
|
||||
SKSeed: skSeed,
|
||||
SKPrf: skPrf,
|
||||
Root: root,
|
||||
Seed: pkSeed,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Sign with SLH-DSA
|
||||
func SPHINCSSign(sk *SPHINCSSecretKey, message []byte, params SLHDSAParams) []byte {
|
||||
// Generate randomizer
|
||||
optRand := make([]byte, params.N)
|
||||
rand.Read(optRand)
|
||||
|
||||
// Compute message hash and index
|
||||
R := PRF(sk.SKPrf, optRand, message)
|
||||
digest, idx := hashMessage(R, sk.Seed, sk.Root, message, params)
|
||||
|
||||
// Generate FORS signature
|
||||
forsAddr := newAddress(FORS_TREE, idx)
|
||||
forsSig := forsSign(digest, sk.SKSeed, sk.Seed, forsAddr, params)
|
||||
|
||||
// Get FORS public key
|
||||
forsPK := forsPublicKeyFromSig(forsSig, digest, sk.Seed, forsAddr, params)
|
||||
|
||||
// Sign FORS public key with hypertree
|
||||
htAddr := newAddress(TREE, idx)
|
||||
htSig := htSign(forsPK, sk.SKSeed, sk.Seed, idx, htAddr, params)
|
||||
|
||||
// Concatenate signature components
|
||||
return concatenate(R, forsSig, htSig)
|
||||
}
|
||||
|
||||
// Verify SLH-DSA signature
|
||||
func SPHINCSVerify(pk *SPHINCSPublicKey, message []byte, signature []byte, params SLHDSAParams) bool {
|
||||
// Parse signature
|
||||
R, forsSig, htSig := parseSignature(signature, params)
|
||||
|
||||
// Compute message hash and index
|
||||
digest, idx := hashMessage(R, pk.Seed, pk.Root, message, params)
|
||||
|
||||
// Verify FORS signature and recover public key
|
||||
forsAddr := newAddress(FORS_TREE, idx)
|
||||
forsPK := forsPublicKeyFromSig(forsSig, digest, pk.Seed, forsAddr, params)
|
||||
|
||||
// Verify hypertree signature
|
||||
htAddr := newAddress(TREE, idx)
|
||||
computedRoot := htVerify(forsPK, htSig, pk.Seed, idx, htAddr, params)
|
||||
|
||||
// Check if computed root matches public key
|
||||
return bytes.Equal(computedRoot, pk.Root)
|
||||
}
|
||||
```
|
||||
|
||||
### Performance Characteristics
|
||||
|
||||
| Parameter Set | Sign (ms) | Verify (μs) | Signature Size | Public Key | Secret Key |
|
||||
|---------------|-----------|-------------|----------------|------------|------------|
|
||||
| SLH-DSA-128s | 8.4 | 172 | 7,856 bytes | 32 bytes | 64 bytes |
|
||||
| SLH-DSA-128f | 0.5 | 115 | 17,088 bytes | 32 bytes | 64 bytes |
|
||||
| SLH-DSA-192s | 15.8 | 287 | 16,224 bytes | 48 bytes | 96 bytes |
|
||||
| SLH-DSA-192f | 0.9 | 189 | 35,664 bytes | 48 bytes | 96 bytes |
|
||||
| SLH-DSA-256s | 24.5 | 412 | 29,792 bytes | 64 bytes | 128 bytes |
|
||||
| SLH-DSA-256f | 1.3 | 245 | 49,856 bytes | 64 bytes | 128 bytes |
|
||||
|
||||
## Hybrid Modes
|
||||
|
||||
### Classical + Post-Quantum
|
||||
|
||||
Combine classical and post-quantum algorithms for defense in depth:
|
||||
|
||||
```go
|
||||
// Hybrid signature: RSA + ML-DSA
|
||||
type HybridSignature struct {
|
||||
ClassicalSig []byte // RSA or ECDSA signature
|
||||
PQSig []byte // ML-DSA signature
|
||||
}
|
||||
|
||||
func HybridSign(classicalKey, pqKey interface{}, message []byte) (*HybridSignature, error) {
|
||||
// Sign with classical algorithm
|
||||
classicalSig := signClassical(classicalKey, message)
|
||||
|
||||
// Sign with post-quantum algorithm
|
||||
pqSig := signMLDSA(pqKey, message)
|
||||
|
||||
return &HybridSignature{
|
||||
ClassicalSig: classicalSig,
|
||||
PQSig: pqSig,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func HybridVerify(classicalKey, pqKey interface{}, message []byte, sig *HybridSignature) bool {
|
||||
// Both signatures must verify
|
||||
return verifyClassical(classicalKey, message, sig.ClassicalSig) &&
|
||||
verifyMLDSA(pqKey, message, sig.PQSig)
|
||||
}
|
||||
```
|
||||
|
||||
## Migration Strategy
|
||||
|
||||
### Phase 1: Hybrid Deployment
|
||||
1. Deploy hybrid classical + PQ systems
|
||||
2. Monitor performance and compatibility
|
||||
3. Gather operational experience
|
||||
|
||||
### Phase 2: Transition
|
||||
1. Gradually increase PQ algorithm usage
|
||||
2. Maintain classical for backwards compatibility
|
||||
3. Update protocols and standards
|
||||
|
||||
### Phase 3: PQ-Only
|
||||
1. Deprecate classical algorithms
|
||||
2. Full post-quantum deployment
|
||||
3. Maintain crypto-agility for future updates
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Side-Channel Resistance
|
||||
- Constant-time implementations
|
||||
- Masking for sensitive operations
|
||||
- Cache-timing attack prevention
|
||||
|
||||
### Parameter Selection
|
||||
- Follow NIST recommendations
|
||||
- Consider security/performance trade-offs
|
||||
- Plan for crypto-agility
|
||||
|
||||
### Key Management
|
||||
- Secure key generation with quality randomness
|
||||
- Protected key storage (HSM/TPM)
|
||||
- Regular key rotation policies
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Algorithm Selection
|
||||
|
||||
```go
|
||||
// Choose based on requirements
|
||||
func SelectAlgorithm(requirements Requirements) Algorithm {
|
||||
switch {
|
||||
case requirements.SmallSignature && requirements.LargeKeys:
|
||||
return ML_DSA_65 // Balanced choice
|
||||
case requirements.SmallKeys && !requirements.SmallSignature:
|
||||
return SLH_DSA_192s // Hash-based
|
||||
case requirements.KeyExchange:
|
||||
return ML_KEM_768 // KEM only
|
||||
default:
|
||||
return ML_DSA_65 // Safe default
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Performance Optimization
|
||||
|
||||
```go
|
||||
// Batch verification for better throughput
|
||||
func BatchVerifyMLDSA(publicKeys []*PublicKey, messages [][]byte,
|
||||
signatures []*Signature, params MLDSAParams) []bool {
|
||||
results := make([]bool, len(signatures))
|
||||
|
||||
// Parallelize verification
|
||||
var wg sync.WaitGroup
|
||||
for i := range signatures {
|
||||
wg.Add(1)
|
||||
go func(idx int) {
|
||||
defer wg.Done()
|
||||
results[idx] = Verify(publicKeys[idx], messages[idx],
|
||||
signatures[idx], params)
|
||||
}(i)
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
return results
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Crypto-Agility
|
||||
|
||||
```go
|
||||
// Abstract algorithm interface
|
||||
type PostQuantumSigner interface {
|
||||
GenerateKey() (PublicKey, SecretKey, error)
|
||||
Sign(sk SecretKey, message []byte) ([]byte, error)
|
||||
Verify(pk PublicKey, message []byte, signature []byte) bool
|
||||
AlgorithmID() string
|
||||
}
|
||||
|
||||
// Factory pattern for algorithm selection
|
||||
func GetSigner(algorithm string) (PostQuantumSigner, error) {
|
||||
switch algorithm {
|
||||
case "ML-DSA-65":
|
||||
return NewMLDSASigner(ML_DSA_65), nil
|
||||
case "SLH-DSA-192s":
|
||||
return NewSLHDSASigner(SLHDSA_192s), nil
|
||||
default:
|
||||
return nil, ErrUnsupportedAlgorithm
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Testing and Validation
|
||||
|
||||
### Known Answer Tests (KAT)
|
||||
|
||||
```go
|
||||
// Validate implementation against NIST test vectors
|
||||
func TestMLDSA_KAT(t *testing.T) {
|
||||
vectors := loadNISTVectors("ML-DSA-65.txt")
|
||||
|
||||
for _, v := range vectors {
|
||||
// Generate keys from seed
|
||||
kp := generateFromSeed(v.Seed)
|
||||
|
||||
// Verify public key matches
|
||||
if !bytes.Equal(kp.PublicKey.Bytes(), v.PublicKey) {
|
||||
t.Errorf("Public key mismatch")
|
||||
}
|
||||
|
||||
// Sign message
|
||||
sig := Sign(kp.SecretKey, v.Message)
|
||||
|
||||
// Verify signature matches
|
||||
if !bytes.Equal(sig.Bytes(), v.Signature) {
|
||||
t.Errorf("Signature mismatch")
|
||||
}
|
||||
|
||||
// Verify signature
|
||||
if !Verify(kp.PublicKey, v.Message, sig) {
|
||||
t.Errorf("Verification failed")
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Conclusion
|
||||
|
||||
The NIST post-quantum algorithms provide robust security against quantum attacks:
|
||||
|
||||
- **ML-DSA**: Best balance of signature size and performance
|
||||
- **ML-KEM**: Efficient key encapsulation for secure communication
|
||||
- **SLH-DSA**: Smallest keys but larger signatures, hash-based security
|
||||
|
||||
Choose algorithms based on your specific requirements for key size, signature size, performance, and security level. Implement hybrid modes during transition and maintain crypto-agility for future updates.
|
||||
@@ -0,0 +1,518 @@
|
||||
---
|
||||
title: Performance Characteristics
|
||||
description: Detailed performance analysis and optimization guide for Lattice
|
||||
---
|
||||
|
||||
# Performance Characteristics
|
||||
|
||||
Comprehensive performance analysis, benchmarks, and optimization strategies for the Lattice library.
|
||||
|
||||
## Benchmark Results
|
||||
|
||||
### Test Environment
|
||||
|
||||
```
|
||||
CPU: Intel Core i9-12900K @ 3.2GHz (24 threads)
|
||||
RAM: 64GB DDR5-5600
|
||||
OS: Ubuntu 22.04 LTS
|
||||
Go: 1.21.5
|
||||
Compiler: go build -O3
|
||||
```
|
||||
|
||||
### CKKS Performance Benchmarks
|
||||
|
||||
#### Basic Operations (N=2^14, LogQP=438)
|
||||
|
||||
| Operation | Time (ms) | Throughput (ops/s) | Memory (MB) | CPU Usage |
|
||||
|-----------|-----------|-------------------|-------------|-----------|
|
||||
| **Key Generation** |||||
|
||||
| Secret Key | 8.2 | 122 | 4 | 100% |
|
||||
| Public Key | 45.3 | 22 | 128 | 100% |
|
||||
| Relin Key | 124.5 | 8 | 384 | 100% |
|
||||
| Galois Keys (15) | 1,875 | 0.5 | 5,760 | 100% |
|
||||
| **Encoding/Encryption** |||||
|
||||
| Encode | 0.8 | 1,250 | 2 | 100% |
|
||||
| Encrypt | 2.3 | 435 | 8 | 100% |
|
||||
| Decrypt | 1.8 | 555 | 8 | 100% |
|
||||
| Decode | 0.7 | 1,428 | 2 | 100% |
|
||||
| **Arithmetic** |||||
|
||||
| Addition | 0.05 | 20,000 | 16 | 25% |
|
||||
| Subtraction | 0.05 | 20,000 | 16 | 25% |
|
||||
| Multiplication | 25.4 | 39 | 24 | 100% |
|
||||
| Relinearization | 18.2 | 55 | 32 | 100% |
|
||||
| Rescaling | 0.8 | 1,250 | 16 | 50% |
|
||||
| **Rotations** |||||
|
||||
| Rotate by 1 | 8.1 | 123 | 16 | 100% |
|
||||
| Rotate by N/2 | 8.3 | 120 | 16 | 100% |
|
||||
| Conjugation | 8.0 | 125 | 16 | 100% |
|
||||
|
||||
#### Advanced Operations
|
||||
|
||||
| Operation | Time (ms) | Memory (MB) | Notes |
|
||||
|-----------|-----------|-------------|-------|
|
||||
| **Polynomial Evaluation** ||||
|
||||
| Degree 3 | 78 | 96 | 3 multiplications |
|
||||
| Degree 7 | 235 | 224 | 7 multiplications |
|
||||
| Degree 15 | 548 | 480 | 15 multiplications |
|
||||
| **Bootstrapping** ||||
|
||||
| Single slot | 850 | 512 | 128-bit precision |
|
||||
| Full packed | 1,200 | 768 | N slots |
|
||||
| Batch (8 ct) | 8,500 | 4,096 | Amortized: 1,062ms/ct |
|
||||
| **Linear Transformations** ||||
|
||||
| Diagonal | 8 | 32 | Single rotation |
|
||||
| Banded (w=16) | 128 | 512 | 16 rotations |
|
||||
| Dense | 2,048 | 8,192 | N rotations |
|
||||
|
||||
### BGV Performance Benchmarks
|
||||
|
||||
#### Basic Operations (N=2^14, LogQP=438, t=65537)
|
||||
|
||||
| Operation | Time (ms) | Throughput (ops/s) | vs CKKS |
|
||||
|-----------|-----------|-------------------|---------|
|
||||
| Encode | 0.3 | 3,333 | 2.7x faster |
|
||||
| Encrypt | 2.1 | 476 | 1.1x faster |
|
||||
| Decrypt | 1.6 | 625 | 1.1x faster |
|
||||
| Decode | 0.2 | 5,000 | 3.5x faster |
|
||||
| Addition | 0.04 | 25,000 | 1.25x faster |
|
||||
| Multiplication | 24.8 | 40 | 1.02x faster |
|
||||
|
||||
### Multiparty Protocol Benchmarks
|
||||
|
||||
| Protocol | Parties | Time (ms) | Communication (MB) | Rounds |
|
||||
|----------|---------|-----------|-------------------|---------|
|
||||
| **Threshold Key Gen** |||||
|
||||
| TKG | 3 | 156 | 1.2 | 1 |
|
||||
| TKG | 5 | 267 | 2.0 | 1 |
|
||||
| TKG | 10 | 542 | 4.0 | 1 |
|
||||
| **Collective Decrypt** |||||
|
||||
| PCKS | 3 | 45 | 0.4 | 1 |
|
||||
| PCKS | 5 | 78 | 0.67 | 1 |
|
||||
| PCKS | 10 | 163 | 1.34 | 1 |
|
||||
| **Collective Relin** |||||
|
||||
| RKG | 3 | 378 | 3.6 | 2 |
|
||||
| RKG | 5 | 634 | 6.0 | 2 |
|
||||
| RKG | 10 | 1,285 | 12.0 | 2 |
|
||||
|
||||
## Memory Profiling
|
||||
|
||||
### Memory Usage by Component
|
||||
|
||||
```go
|
||||
// CKKS Memory Footprint (N=2^14)
|
||||
Secret Key: 4 MB
|
||||
Public Key: 128 MB
|
||||
Relin Key: 384 MB
|
||||
Galois Key: 384 MB per element
|
||||
Ciphertext: 16 MB (per level)
|
||||
Plaintext: 8 MB
|
||||
Bootstrapping: 512 MB (temporary)
|
||||
```
|
||||
|
||||
### Memory Optimization Strategies
|
||||
|
||||
#### 1. Object Pooling
|
||||
|
||||
```go
|
||||
// Create a pool for ciphertext reuse
|
||||
type CiphertextPool struct {
|
||||
pool sync.Pool
|
||||
}
|
||||
|
||||
func NewCiphertextPool(params Parameters) *CiphertextPool {
|
||||
return &CiphertextPool{
|
||||
pool: sync.Pool{
|
||||
New: func() interface{} {
|
||||
return ckks.NewCiphertext(params, 1, params.MaxLevel())
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (p *CiphertextPool) Get() *Ciphertext {
|
||||
return p.pool.Get().(*Ciphertext)
|
||||
}
|
||||
|
||||
func (p *CiphertextPool) Put(ct *Ciphertext) {
|
||||
ct.Level = params.MaxLevel() // Reset level
|
||||
p.pool.Put(ct)
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. In-Place Operations
|
||||
|
||||
```go
|
||||
// Prefer in-place operations to reduce allocations
|
||||
// Bad: Creates new ciphertext
|
||||
ctSum, _ := evaluator.AddNew(ct1, ct2)
|
||||
|
||||
// Good: Reuses existing ciphertext
|
||||
evaluator.Add(ct1, ct2, ct1) // Result stored in ct1
|
||||
```
|
||||
|
||||
#### 3. Lazy Allocation
|
||||
|
||||
```go
|
||||
// Allocate evaluation keys only when needed
|
||||
type LazyEvaluator struct {
|
||||
params Parameters
|
||||
rlk *RelinearizationKey
|
||||
gks map[uint64]*GaloisKey
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
func (e *LazyEvaluator) GetGaloisKey(galEl uint64) *GaloisKey {
|
||||
e.mu.RLock()
|
||||
if gk, ok := e.gks[galEl]; ok {
|
||||
e.mu.RUnlock()
|
||||
return gk
|
||||
}
|
||||
e.mu.RUnlock()
|
||||
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
// Generate key if not exists
|
||||
gk := kgen.GenGaloisKeyNew(galEl, sk)
|
||||
e.gks[galEl] = gk
|
||||
return gk
|
||||
}
|
||||
```
|
||||
|
||||
## CPU Optimization
|
||||
|
||||
### Parallelization Strategies
|
||||
|
||||
#### 1. Parallel NTT
|
||||
|
||||
```go
|
||||
// NTT operations are parallelized internally
|
||||
// Controlled by GOMAXPROCS
|
||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||
|
||||
// For N=2^14, NTT parallelization:
|
||||
// 1 thread: 4.2ms
|
||||
// 4 threads: 1.3ms (3.2x speedup)
|
||||
// 8 threads: 0.8ms (5.3x speedup)
|
||||
// 16 threads: 0.6ms (7x speedup)
|
||||
```
|
||||
|
||||
#### 2. Batch Processing
|
||||
|
||||
```go
|
||||
// Process multiple ciphertexts in parallel
|
||||
func ParallelEvaluate(eval Evaluator, cts []*Ciphertext, f func(*Ciphertext) error) error {
|
||||
errChan := make(chan error, len(cts))
|
||||
var wg sync.WaitGroup
|
||||
|
||||
for i := range cts {
|
||||
wg.Add(1)
|
||||
go func(ct *Ciphertext) {
|
||||
defer wg.Done()
|
||||
if err := f(ct); err != nil {
|
||||
errChan <- err
|
||||
}
|
||||
}(cts[i])
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
close(errChan)
|
||||
|
||||
if err := <-errChan; err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. SIMD Vectorization
|
||||
|
||||
```go
|
||||
// Lattice automatically uses SIMD when available
|
||||
// Check CPU features
|
||||
import "golang.org/x/sys/cpu"
|
||||
|
||||
if cpu.X86.HasAVX512 {
|
||||
// AVX-512: 16x speedup for modular arithmetic
|
||||
} else if cpu.X86.HasAVX2 {
|
||||
// AVX2: 8x speedup
|
||||
} else if cpu.X86.HasSSE42 {
|
||||
// SSE4.2: 4x speedup
|
||||
}
|
||||
```
|
||||
|
||||
### Profiling Tools
|
||||
|
||||
#### CPU Profiling
|
||||
|
||||
```go
|
||||
import "runtime/pprof"
|
||||
|
||||
// Start CPU profiling
|
||||
f, _ := os.Create("cpu.prof")
|
||||
pprof.StartCPUProfile(f)
|
||||
defer pprof.StopCPUProfile()
|
||||
|
||||
// Run your computation
|
||||
// ...
|
||||
|
||||
// Analyze with: go tool pprof cpu.prof
|
||||
```
|
||||
|
||||
#### Memory Profiling
|
||||
|
||||
```go
|
||||
// Memory profiling
|
||||
f, _ := os.Create("mem.prof")
|
||||
defer f.Close()
|
||||
runtime.GC()
|
||||
pprof.WriteHeapProfile(f)
|
||||
|
||||
// Analyze with: go tool pprof mem.prof
|
||||
```
|
||||
|
||||
## Network Optimization
|
||||
|
||||
### Serialization Performance
|
||||
|
||||
| Format | Size (MB) | Encode (ms) | Decode (ms) |
|
||||
|--------|-----------|-------------|-------------|
|
||||
| Binary | 16.0 | 2.1 | 1.8 |
|
||||
| Compressed | 5.8 | 45.2 | 38.6 |
|
||||
| Custom RLE | 8.2 | 8.5 | 7.3 |
|
||||
|
||||
```go
|
||||
// Efficient serialization
|
||||
func SerializeCiphertext(ct *Ciphertext) ([]byte, error) {
|
||||
var buf bytes.Buffer
|
||||
enc := gob.NewEncoder(&buf)
|
||||
|
||||
// Use compression for network transfer
|
||||
zw := gzip.NewWriter(&buf)
|
||||
enc = gob.NewEncoder(zw)
|
||||
|
||||
if err := enc.Encode(ct); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
zw.Close()
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
```
|
||||
|
||||
### Bandwidth Optimization
|
||||
|
||||
```go
|
||||
// Minimize data transfer in multiparty protocols
|
||||
type CompressedShare struct {
|
||||
Data []byte
|
||||
Hash [32]byte
|
||||
}
|
||||
|
||||
func CompressShare(share *Share) (*CompressedShare, error) {
|
||||
// Serialize
|
||||
data, err := share.MarshalBinary()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Compress
|
||||
var buf bytes.Buffer
|
||||
zw, _ := zlib.NewWriterLevel(&buf, zlib.BestCompression)
|
||||
zw.Write(data)
|
||||
zw.Close()
|
||||
|
||||
// Hash for integrity
|
||||
hash := sha256.Sum256(buf.Bytes())
|
||||
|
||||
return &CompressedShare{
|
||||
Data: buf.Bytes(),
|
||||
Hash: hash,
|
||||
}, nil
|
||||
}
|
||||
```
|
||||
|
||||
## Parameter Selection for Performance
|
||||
|
||||
### Ring Dimension Trade-offs
|
||||
|
||||
| N | Security | Slots | Performance | Memory | Use Case |
|
||||
|---|----------|-------|-------------|--------|----------|
|
||||
| 2^10 | Low | 512 | Fastest | 0.25 MB | Testing |
|
||||
| 2^12 | 80-bit | 2,048 | Very Fast | 1 MB | Light crypto |
|
||||
| 2^14 | 128-bit | 8,192 | Fast | 4 MB | **Standard** |
|
||||
| 2^15 | 192-bit | 16,384 | Moderate | 8 MB | High security |
|
||||
| 2^16 | 256-bit | 32,768 | Slow | 16 MB | Maximum security |
|
||||
| 2^17 | 256-bit+ | 65,536 | Very Slow | 32 MB | Research |
|
||||
|
||||
### Modulus Chain Optimization
|
||||
|
||||
```go
|
||||
// Optimize modulus chain for your computation depth
|
||||
func OptimizeModulusChain(multDepth int, rescaleFreq int) []int {
|
||||
// Each multiplication consumes ~60 bits
|
||||
// Each rescale removes one prime
|
||||
|
||||
chainLength := multDepth + rescaleFreq
|
||||
logQ := make([]int, chainLength+1)
|
||||
|
||||
// First prime: larger for initial noise
|
||||
logQ[0] = 60
|
||||
|
||||
// Middle primes: standard size
|
||||
for i := 1; i < chainLength; i++ {
|
||||
logQ[i] = 50
|
||||
}
|
||||
|
||||
// Last prime: smaller acceptable
|
||||
logQ[chainLength] = 40
|
||||
|
||||
return logQ
|
||||
}
|
||||
```
|
||||
|
||||
## Optimization Checklist
|
||||
|
||||
### Before Optimization
|
||||
|
||||
- [ ] Profile to identify bottlenecks
|
||||
- [ ] Measure baseline performance
|
||||
- [ ] Set performance targets
|
||||
- [ ] Understand algorithmic complexity
|
||||
|
||||
### Memory Optimizations
|
||||
|
||||
- [ ] Use object pooling for frequently allocated objects
|
||||
- [ ] Prefer in-place operations
|
||||
- [ ] Clear unused references for GC
|
||||
- [ ] Use appropriate data structures
|
||||
- [ ] Monitor heap allocations
|
||||
|
||||
### CPU Optimizations
|
||||
|
||||
- [ ] Enable parallel processing (GOMAXPROCS)
|
||||
- [ ] Batch independent operations
|
||||
- [ ] Use SIMD-friendly algorithms
|
||||
- [ ] Minimize cache misses
|
||||
- [ ] Profile hot paths
|
||||
|
||||
### Algorithm Optimizations
|
||||
|
||||
- [ ] Choose optimal parameters
|
||||
- [ ] Minimize multiplication depth
|
||||
- [ ] Use lazy relinearization
|
||||
- [ ] Batch rotations when possible
|
||||
- [ ] Exploit sparsity
|
||||
|
||||
### Network Optimizations
|
||||
|
||||
- [ ] Compress data before transfer
|
||||
- [ ] Use efficient serialization
|
||||
- [ ] Minimize round trips
|
||||
- [ ] Batch communications
|
||||
- [ ] Cache remote data
|
||||
|
||||
## Performance Tips
|
||||
|
||||
### 1. Parameter Selection
|
||||
|
||||
```go
|
||||
// Start with minimal parameters and increase as needed
|
||||
params := ckks.ParametersLiteral{
|
||||
LogN: 13, // Start small
|
||||
LogQ: []int{45, 40, 40}, // Minimal chain
|
||||
LogP: []int{55}, // Single P prime
|
||||
}
|
||||
|
||||
// Increase only if needed for:
|
||||
// - Security: Increase LogN
|
||||
// - Precision: Increase LogQ values
|
||||
// - Depth: Add more LogQ primes
|
||||
```
|
||||
|
||||
### 2. Batch Operations
|
||||
|
||||
```go
|
||||
// Batch multiple operations into single ciphertext
|
||||
values := make([]complex128, params.Slots())
|
||||
for i := range values {
|
||||
values[i] = complex(data[i], 0)
|
||||
}
|
||||
encoder.Encode(values, plaintext)
|
||||
// Process all slots simultaneously
|
||||
```
|
||||
|
||||
### 3. Lazy Evaluation
|
||||
|
||||
```go
|
||||
// Delay expensive operations
|
||||
type LazyComputation struct {
|
||||
ct *Ciphertext
|
||||
ops []func(*Ciphertext) error
|
||||
}
|
||||
|
||||
func (lc *LazyComputation) Add(op func(*Ciphertext) error) {
|
||||
lc.ops = append(lc.ops, op)
|
||||
}
|
||||
|
||||
func (lc *LazyComputation) Execute() error {
|
||||
for _, op := range lc.ops {
|
||||
if err := op(lc.ct); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Cache Management
|
||||
|
||||
```go
|
||||
// Cache frequently used computations
|
||||
var cache = make(map[string]*Ciphertext)
|
||||
var cacheMu sync.RWMutex
|
||||
|
||||
func GetOrCompute(key string, compute func() *Ciphertext) *Ciphertext {
|
||||
cacheMu.RLock()
|
||||
if ct, ok := cache[key]; ok {
|
||||
cacheMu.RUnlock()
|
||||
return ct
|
||||
}
|
||||
cacheMu.RUnlock()
|
||||
|
||||
ct := compute()
|
||||
|
||||
cacheMu.Lock()
|
||||
cache[key] = ct
|
||||
cacheMu.Unlock()
|
||||
|
||||
return ct
|
||||
}
|
||||
```
|
||||
|
||||
## Comparison with Other Libraries
|
||||
|
||||
| Library | Language | CKKS Mul (ms) | BGV Mul (ms) | Bootstrap (ms) |
|
||||
|---------|----------|---------------|--------------|----------------|
|
||||
| **Lattice v6** | Go | 25.4 | 24.8 | 850 |
|
||||
| SEAL 4.0 | C++ | 23.1 | 22.5 | N/A |
|
||||
| HElib | C++ | 28.3 | 26.7 | 920 |
|
||||
| PALISADE | C++ | 26.5 | 25.3 | 890 |
|
||||
| Concrete | Rust | 31.2 | 29.8 | 1,100 |
|
||||
| TFHE | C++ | N/A | N/A | 13 |
|
||||
|
||||
*Benchmarks on same hardware with N=2^14, 128-bit security*
|
||||
|
||||
## Conclusion
|
||||
|
||||
Lattice provides competitive performance with state-of-the-art C++ libraries while offering:
|
||||
|
||||
- **Pure Go implementation**: Easy deployment and cross-compilation
|
||||
- **Automatic parallelization**: Scales with available CPU cores
|
||||
- **Memory efficiency**: Careful memory management and pooling
|
||||
- **Network optimized**: Built for distributed computation
|
||||
|
||||
For optimal performance:
|
||||
1. Choose minimal parameters for your security needs
|
||||
2. Use in-place operations and object pooling
|
||||
3. Enable parallelization with appropriate GOMAXPROCS
|
||||
4. Profile and optimize hot paths
|
||||
5. Batch operations when possible
|
||||
@@ -0,0 +1,513 @@
|
||||
---
|
||||
title: Security Parameters Guide
|
||||
description: Comprehensive guide to selecting and configuring security parameters for lattice-based cryptography
|
||||
---
|
||||
|
||||
# Security Parameters Guide
|
||||
|
||||
Detailed guide for understanding and selecting appropriate security parameters for lattice-based cryptographic systems, including parameter relationships, security levels, and practical recommendations.
|
||||
|
||||
## Security Foundations
|
||||
|
||||
### Computational Hardness Assumptions
|
||||
|
||||
Lattice cryptography relies on the following hard problems:
|
||||
|
||||
| Problem | Description | Quantum Hardness |
|
||||
|---------|-------------|------------------|
|
||||
| **LWE** | Learning With Errors | √ Quantum-resistant |
|
||||
| **RLWE** | Ring Learning With Errors | √ Quantum-resistant |
|
||||
| **MLWE** | Module Learning With Errors | √ Quantum-resistant |
|
||||
| **SIS** | Short Integer Solution | √ Quantum-resistant |
|
||||
| **MSIS** | Module Short Integer Solution | √ Quantum-resistant |
|
||||
|
||||
### Security Level Definitions
|
||||
|
||||
```go
|
||||
// NIST Security Levels
|
||||
const (
|
||||
Level1 = 128 // Equivalent to AES-128
|
||||
Level2 = 192 // Between AES-128 and AES-192
|
||||
Level3 = 192 // Equivalent to AES-192
|
||||
Level4 = 256 // Between AES-192 and AES-256
|
||||
Level5 = 256 // Equivalent to AES-256
|
||||
)
|
||||
|
||||
// Quantum vs Classical Security
|
||||
type SecurityLevel struct {
|
||||
Classical int // Bits of classical security
|
||||
Quantum int // Bits of quantum security (≈ Classical/2)
|
||||
NIST int // NIST category (1-5)
|
||||
}
|
||||
```
|
||||
|
||||
## Parameter Relationships
|
||||
|
||||
### Core Parameters
|
||||
|
||||
```go
|
||||
// Fundamental parameters for RLWE schemes
|
||||
type RLWEParameters struct {
|
||||
// Ring dimension (power of 2)
|
||||
N int // Security ∝ N
|
||||
|
||||
// Ciphertext modulus
|
||||
Q *big.Int // Correctness requires Q > noise
|
||||
|
||||
// Error distribution
|
||||
Sigma float64 // Security ∝ σ, Correctness ∝ 1/σ
|
||||
|
||||
// Key distribution
|
||||
KeyDist Distribution // Ternary, Gaussian, or Uniform
|
||||
}
|
||||
```
|
||||
|
||||
### Parameter Constraints
|
||||
|
||||
```plaintext
|
||||
Security Constraint:
|
||||
N · log(Q/σ) ≥ SecurityLevel
|
||||
|
||||
Correctness Constraint:
|
||||
Q > C · σ · √N · multiplicativeDepth
|
||||
|
||||
Performance Constraint:
|
||||
Smaller N → Faster operations
|
||||
Smaller Q → Smaller ciphertexts
|
||||
```
|
||||
|
||||
## CKKS Parameters
|
||||
|
||||
### Parameter Selection Framework
|
||||
|
||||
```go
|
||||
// CKKS parameter selection
|
||||
type CKKSParameterSelector struct {
|
||||
// Required inputs
|
||||
SecurityLevel int // Target security (128, 192, 256)
|
||||
Precision int // Required precision in bits
|
||||
MultiplicativeDepth int // Maximum multiplication depth
|
||||
|
||||
// Optional constraints
|
||||
MaxN int // Maximum ring dimension
|
||||
BootstrapDepth int // Depth reserved for bootstrapping
|
||||
}
|
||||
|
||||
func (s *CKKSParameterSelector) SelectParameters() CKKSParameters {
|
||||
// Step 1: Choose minimal N for security
|
||||
N := s.selectRingDimension()
|
||||
|
||||
// Step 2: Calculate modulus chain
|
||||
logQ := s.calculateModulusChain()
|
||||
|
||||
// Step 3: Set error distribution
|
||||
sigma := s.selectErrorDistribution()
|
||||
|
||||
// Step 4: Configure bootstrapping if needed
|
||||
if s.BootstrapDepth > 0 {
|
||||
logQ = s.addBootstrappingLevels(logQ)
|
||||
}
|
||||
|
||||
return CKKSParameters{
|
||||
LogN: log2(N),
|
||||
LogQ: logQ,
|
||||
Sigma: sigma,
|
||||
LogDefaultScale: s.Precision,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Recommended CKKS Parameters
|
||||
|
||||
| Security | LogN | LogQP | Precision | Mult. Depth | Bootstrappable |
|
||||
|----------|------|-------|-----------|-------------|----------------|
|
||||
| 128-bit | 13 | 219 | 30 bits | 4 | No |
|
||||
| 128-bit | 14 | 439 | 40 bits | 8 | No |
|
||||
| 128-bit | 15 | 881 | 50 bits | 18 | Yes |
|
||||
| 192-bit | 14 | 359 | 35 bits | 6 | No |
|
||||
| 192-bit | 15 | 719 | 45 bits | 12 | Yes |
|
||||
| 256-bit | 15 | 659 | 40 bits | 10 | No |
|
||||
| 256-bit | 16 | 1319 | 50 bits | 22 | Yes |
|
||||
|
||||
### Example CKKS Configuration
|
||||
|
||||
```go
|
||||
// 128-bit security, high precision
|
||||
var CKKS_128_HighPrecision = ckks.ParametersLiteral{
|
||||
LogN: 15, // N = 32768
|
||||
LogQ: []int{60, 50, 50, 50, 50}, // 260 bits total
|
||||
LogP: []int{61, 61}, // Key switching
|
||||
LogDefaultScale: 50, // 50-bit precision
|
||||
Sigma: 3.2, // Standard deviation
|
||||
RingType: ring.Standard,
|
||||
}
|
||||
|
||||
// 192-bit security, bootstrappable
|
||||
var CKKS_192_Bootstrap = ckks.ParametersLiteral{
|
||||
LogN: 15,
|
||||
LogQ: []int{
|
||||
// Computation levels
|
||||
55, 45, 45, 45, 45, 45, 45, 45,
|
||||
// Bootstrapping levels
|
||||
55, 55, 55, 55, 55, 55, 55, 55,
|
||||
},
|
||||
LogP: []int{61, 61, 61},
|
||||
LogDefaultScale: 45,
|
||||
Sigma: 3.2,
|
||||
H: 192, // Hamming weight for sparse keys
|
||||
}
|
||||
```
|
||||
|
||||
## BGV/BFV Parameters
|
||||
|
||||
### Parameter Selection
|
||||
|
||||
```go
|
||||
// BGV/BFV parameter constraints
|
||||
type BGVParameterSelector struct {
|
||||
SecurityLevel int
|
||||
PlaintextModulus uint64 // Usually prime
|
||||
MultiplicativeDepth int
|
||||
BatchingSlots int // Number of plaintext slots
|
||||
}
|
||||
|
||||
func (s *BGVParameterSelector) SelectParameters() BGVParameters {
|
||||
// Ensure plaintext modulus is prime
|
||||
t := s.selectPlaintextModulus()
|
||||
|
||||
// Choose N based on slots and security
|
||||
N := max(
|
||||
nextPowerOfTwo(s.BatchingSlots * 2),
|
||||
s.minNForSecurity(),
|
||||
)
|
||||
|
||||
// Calculate modulus chain
|
||||
// Each level needs ~60 bits for noise growth
|
||||
logQ := make([]int, s.MultiplicativeDepth+1)
|
||||
for i := range logQ {
|
||||
logQ[i] = 60
|
||||
}
|
||||
|
||||
return BGVParameters{
|
||||
LogN: log2(N),
|
||||
LogQ: logQ,
|
||||
PlaintextModulus: t,
|
||||
Sigma: 3.2,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Recommended BGV Parameters
|
||||
|
||||
| Security | LogN | T | LogQP | Mult. Depth | Slots |
|
||||
|----------|------|---|-------|-------------|-------|
|
||||
| 128-bit | 13 | 65537 | 218 | 3 | 4096 |
|
||||
| 128-bit | 14 | 65537 | 438 | 7 | 8192 |
|
||||
| 128-bit | 15 | 65537 | 883 | 14 | 16384 |
|
||||
| 192-bit | 14 | 65537 | 358 | 5 | 8192 |
|
||||
| 192-bit | 15 | 65537 | 718 | 11 | 16384 |
|
||||
| 256-bit | 15 | 65537 | 658 | 10 | 16384 |
|
||||
| 256-bit | 16 | 65537 | 1318 | 21 | 32768 |
|
||||
|
||||
## Security Analysis
|
||||
|
||||
### Lattice Estimator
|
||||
|
||||
```go
|
||||
// Estimate security level for given parameters
|
||||
func EstimateSecurity(params Parameters) SecurityEstimate {
|
||||
// Use lattice estimator formulas
|
||||
n := params.N
|
||||
q := params.Q
|
||||
sigma := params.Sigma
|
||||
|
||||
// Primal attack cost
|
||||
primalBits := estimatePrimalAttack(n, q, sigma)
|
||||
|
||||
// Dual attack cost
|
||||
dualBits := estimateDualAttack(n, q, sigma)
|
||||
|
||||
// Hybrid attack cost
|
||||
hybridBits := estimateHybridAttack(n, q, sigma)
|
||||
|
||||
// Take minimum
|
||||
classicalBits := min(primalBits, dualBits, hybridBits)
|
||||
|
||||
// Quantum speedup (Grover's algorithm)
|
||||
quantumBits := classicalBits / 2
|
||||
|
||||
return SecurityEstimate{
|
||||
Classical: classicalBits,
|
||||
Quantum: quantumBits,
|
||||
Attack: identifyBestAttack(primalBits, dualBits, hybridBits),
|
||||
}
|
||||
}
|
||||
|
||||
// Concrete security estimates
|
||||
func estimatePrimalAttack(n int, q *big.Int, sigma float64) int {
|
||||
// BKZ block size
|
||||
beta := calculateBKZBlocksize(n, q, sigma)
|
||||
|
||||
// Cost model (core-SVP hardness)
|
||||
cost := 0.292 * float64(beta) + 16.4
|
||||
|
||||
return int(cost)
|
||||
}
|
||||
```
|
||||
|
||||
### Parameter Validation
|
||||
|
||||
```go
|
||||
// Validate parameters meet security requirements
|
||||
func ValidateSecurityParameters(params Parameters, targetSecurity int) error {
|
||||
estimate := EstimateSecurity(params)
|
||||
|
||||
if estimate.Classical < targetSecurity {
|
||||
return fmt.Errorf(
|
||||
"insufficient security: %d bits (target: %d)",
|
||||
estimate.Classical, targetSecurity,
|
||||
)
|
||||
}
|
||||
|
||||
// Check noise parameters
|
||||
if params.Sigma < 3.2 {
|
||||
return errors.New("sigma too small for security")
|
||||
}
|
||||
|
||||
// Check modulus size
|
||||
maxQ := calculateMaxModulus(params.N, targetSecurity)
|
||||
if params.Q.Cmp(maxQ) > 0 {
|
||||
return errors.New("modulus too large for target security")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
```
|
||||
|
||||
## Noise Management
|
||||
|
||||
### Noise Growth Analysis
|
||||
|
||||
```go
|
||||
// Track noise growth through computation
|
||||
type NoiseTracker struct {
|
||||
initialNoise float64
|
||||
currentNoise float64
|
||||
noisePerOp map[string]float64
|
||||
}
|
||||
|
||||
func (nt *NoiseTracker) EstimateNoise(circuit Circuit) float64 {
|
||||
noise := nt.initialNoise
|
||||
|
||||
for _, op := range circuit.Operations {
|
||||
switch op.Type {
|
||||
case Addition:
|
||||
noise = sqrt(2) * noise
|
||||
case Multiplication:
|
||||
noise = noise * noise * params.N
|
||||
case Rotation:
|
||||
noise = nt.noisePerOp["rotation"] * noise
|
||||
case KeySwitch:
|
||||
noise += nt.noisePerOp["keyswitch"]
|
||||
}
|
||||
}
|
||||
|
||||
return noise
|
||||
}
|
||||
|
||||
// Determine when bootstrapping is needed
|
||||
func RequiresBootstrapping(noise float64, params Parameters) bool {
|
||||
// Maximum tolerable noise
|
||||
maxNoise := float64(params.Q) / (2 * params.Scale)
|
||||
|
||||
// Safety margin
|
||||
safetyFactor := 10.0
|
||||
|
||||
return noise > maxNoise / safetyFactor
|
||||
}
|
||||
```
|
||||
|
||||
### Optimizing for Noise
|
||||
|
||||
```go
|
||||
// Optimize circuit to minimize noise
|
||||
func OptimizeForNoise(circuit Circuit) Circuit {
|
||||
// Reorder operations to minimize depth
|
||||
circuit = reorderOperations(circuit)
|
||||
|
||||
// Batch operations where possible
|
||||
circuit = batchOperations(circuit)
|
||||
|
||||
// Insert rescaling optimally
|
||||
circuit = insertOptimalRescaling(circuit)
|
||||
|
||||
// Add bootstrapping if needed
|
||||
if circuit.Depth() > params.MaxDepth {
|
||||
circuit = insertBootstrapping(circuit)
|
||||
}
|
||||
|
||||
return circuit
|
||||
}
|
||||
```
|
||||
|
||||
## Parameter Sets by Use Case
|
||||
|
||||
### Machine Learning
|
||||
|
||||
```go
|
||||
// Parameters for encrypted ML inference
|
||||
var ML_Inference_Params = ckks.ParametersLiteral{
|
||||
LogN: 14, // 16384 slots
|
||||
LogQ: []int{50, 40, 40, 40}, // 4 multiplications
|
||||
LogP: []int{60},
|
||||
LogDefaultScale: 40,
|
||||
Sigma: 3.2,
|
||||
}
|
||||
|
||||
// Parameters for encrypted training
|
||||
var ML_Training_Params = ckks.ParametersLiteral{
|
||||
LogN: 15, // 32768 slots for batch processing
|
||||
LogQ: []int{
|
||||
60, 50, 50, 50, 50, 50, // Forward pass
|
||||
50, 50, 50, 50, 50, 50, // Backward pass
|
||||
},
|
||||
LogP: []int{61, 61},
|
||||
LogDefaultScale: 50,
|
||||
Sigma: 3.2,
|
||||
}
|
||||
```
|
||||
|
||||
### Financial Computing
|
||||
|
||||
```go
|
||||
// High precision for financial calculations
|
||||
var Financial_Params = ckks.ParametersLiteral{
|
||||
LogN: 15,
|
||||
LogQ: []int{60, 55, 55, 55, 55, 55},
|
||||
LogP: []int{60, 60},
|
||||
LogDefaultScale: 55, // High precision
|
||||
Sigma: 3.2,
|
||||
}
|
||||
```
|
||||
|
||||
### Private Information Retrieval
|
||||
|
||||
```go
|
||||
// Optimized for PIR queries
|
||||
var PIR_Params = bgv.ParametersLiteral{
|
||||
LogN: 13, // Smaller for faster response
|
||||
LogQ: []int{54, 54, 54},
|
||||
PlaintextModulus: 65537,
|
||||
Sigma: 3.2,
|
||||
}
|
||||
```
|
||||
|
||||
## Security Checklist
|
||||
|
||||
### Parameter Selection
|
||||
- [ ] Security level meets requirements (128/192/256 bits)
|
||||
- [ ] Ring dimension N is power of 2
|
||||
- [ ] Modulus Q provides enough noise budget
|
||||
- [ ] Error distribution σ ≥ 3.2
|
||||
- [ ] Parameters validated with lattice estimator
|
||||
|
||||
### Implementation Security
|
||||
- [ ] Constant-time implementation for sensitive operations
|
||||
- [ ] Side-channel attack mitigation
|
||||
- [ ] Secure random number generation
|
||||
- [ ] Protected memory for secret keys
|
||||
- [ ] No key material in logs/errors
|
||||
|
||||
### Operational Security
|
||||
- [ ] Key rotation schedule defined
|
||||
- [ ] Secure key storage (HSM/KMS)
|
||||
- [ ] Audit logging enabled
|
||||
- [ ] Performance monitoring
|
||||
- [ ] Regular security updates
|
||||
|
||||
## Advanced Topics
|
||||
|
||||
### Sparse Keys
|
||||
|
||||
```go
|
||||
// Using sparse keys for efficiency
|
||||
type SparseKeyParams struct {
|
||||
HammingWeight int // Number of non-zero coefficients
|
||||
}
|
||||
|
||||
func GenerateSparseKey(params Parameters, h int) *SecretKey {
|
||||
sk := NewSecretKey(params)
|
||||
|
||||
// Set exactly h coefficients to ±1
|
||||
positions := randomPositions(params.N, h)
|
||||
for _, pos := range positions {
|
||||
sk.Value.Coeffs[pos] = randomSign()
|
||||
}
|
||||
|
||||
return sk
|
||||
}
|
||||
```
|
||||
|
||||
### Modulus Switching
|
||||
|
||||
```go
|
||||
// Dynamic modulus switching for optimization
|
||||
func ModulusSwitch(ct *Ciphertext, targetLevel int) {
|
||||
currentLevel := ct.Level()
|
||||
|
||||
for currentLevel > targetLevel {
|
||||
// Scale down by one modulus
|
||||
ct.Scale(ct, params.Q[currentLevel])
|
||||
currentLevel--
|
||||
}
|
||||
|
||||
ct.SetLevel(targetLevel)
|
||||
}
|
||||
```
|
||||
|
||||
### Multi-Key Operations
|
||||
|
||||
```go
|
||||
// Parameters for multi-key homomorphic encryption
|
||||
type MultiKeyParams struct {
|
||||
BaseParams Parameters
|
||||
NumParties int
|
||||
Threshold int // For threshold decryption
|
||||
}
|
||||
|
||||
func GenerateMultiKeyParams(numParties int, security int) MultiKeyParams {
|
||||
// Increase parameters to handle key switching
|
||||
baseParams := SelectParameters(security)
|
||||
|
||||
// Add extra modulus for relinearization
|
||||
baseParams.LogP = append(baseParams.LogP, 61)
|
||||
|
||||
return MultiKeyParams{
|
||||
BaseParams: baseParams,
|
||||
NumParties: numParties,
|
||||
Threshold: (numParties + 1) / 2,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues and Solutions
|
||||
|
||||
| Issue | Cause | Solution |
|
||||
|-------|-------|----------|
|
||||
| Decryption failure | Noise overflow | Increase Q or reduce circuit depth |
|
||||
| Poor precision | Scale too small | Increase LogDefaultScale |
|
||||
| Slow performance | N too large | Use minimal N for security |
|
||||
| Large ciphertexts | Q too large | Optimize modulus chain |
|
||||
| Bootstrap fails | Insufficient levels | Reserve more levels for bootstrapping |
|
||||
|
||||
## Conclusion
|
||||
|
||||
Proper parameter selection is crucial for:
|
||||
- **Security**: Meeting cryptographic requirements
|
||||
- **Correctness**: Ensuring computations succeed
|
||||
- **Performance**: Optimizing speed and size
|
||||
- **Practicality**: Balancing all constraints
|
||||
|
||||
Always validate parameters with security estimators and test thoroughly before deployment.
|
||||
@@ -0,0 +1,779 @@
|
||||
---
|
||||
title: Usage Examples
|
||||
description: Practical examples and tutorials for implementing lattice-based cryptography
|
||||
---
|
||||
|
||||
# Usage Examples
|
||||
|
||||
Comprehensive collection of practical examples demonstrating real-world applications of lattice-based cryptography, from basic operations to complex protocols.
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Installation
|
||||
|
||||
```bash
|
||||
# Install the Lattice library
|
||||
go get github.com/luxfi/lattice/v6
|
||||
|
||||
# Import required packages
|
||||
import (
|
||||
"github.com/luxfi/lattice/v6/core/rlwe"
|
||||
"github.com/luxfi/lattice/v6/schemes/ckks"
|
||||
"github.com/luxfi/lattice/v6/schemes/bgv"
|
||||
"github.com/luxfi/lattice/v6/multiparty"
|
||||
)
|
||||
```
|
||||
|
||||
### Basic Setup
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"github.com/luxfi/lattice/v6/core/rlwe"
|
||||
"github.com/luxfi/lattice/v6/schemes/ckks"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Initialize parameters for 128-bit security
|
||||
params, err := ckks.NewParametersFromLiteral(
|
||||
ckks.ParametersLiteral{
|
||||
LogN: 14,
|
||||
LogQ: []int{50, 40, 40, 40},
|
||||
LogP: []int{60},
|
||||
LogDefaultScale: 40,
|
||||
Sigma: 3.2,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Printf("Ring dimension: %d\n", params.N())
|
||||
fmt.Printf("Ciphertext levels: %d\n", params.MaxLevel())
|
||||
fmt.Printf("Precision: %d bits\n", params.LogDefaultScale())
|
||||
}
|
||||
```
|
||||
|
||||
## Basic Homomorphic Operations
|
||||
|
||||
### Arithmetic on Encrypted Numbers
|
||||
|
||||
```go
|
||||
func encryptedArithmetic() {
|
||||
// Setup
|
||||
params, _ := ckks.NewParametersFromLiteral(ckks.PN14QP438)
|
||||
kgen := rlwe.NewKeyGenerator(params)
|
||||
sk := kgen.GenSecretKeyNew()
|
||||
pk := kgen.GenPublicKeyNew(sk)
|
||||
rlk := kgen.GenRelinearizationKeyNew(sk)
|
||||
evk := rlwe.NewMemEvaluationKeySet(rlk)
|
||||
|
||||
encoder := ckks.NewEncoder(params)
|
||||
encryptor := rlwe.NewEncryptor(params, pk)
|
||||
decryptor := rlwe.NewDecryptor(params, sk)
|
||||
evaluator := ckks.NewEvaluator(params, evk)
|
||||
|
||||
// Prepare data
|
||||
x := []complex128{1.5, 2.5, 3.5, 4.5}
|
||||
y := []complex128{0.5, 1.5, 2.5, 3.5}
|
||||
|
||||
// Encode and encrypt
|
||||
ptX := ckks.NewPlaintext(params, params.MaxLevel())
|
||||
ptY := ckks.NewPlaintext(params, params.MaxLevel())
|
||||
encoder.Encode(x, ptX)
|
||||
encoder.Encode(y, ptY)
|
||||
|
||||
ctX, _ := encryptor.EncryptNew(ptX)
|
||||
ctY, _ := encryptor.EncryptNew(ptY)
|
||||
|
||||
// Homomorphic operations
|
||||
// Addition: z = x + y
|
||||
ctSum, _ := evaluator.AddNew(ctX, ctY)
|
||||
|
||||
// Multiplication: z = x * y
|
||||
ctProd, _ := evaluator.MulRelinNew(ctX, ctY)
|
||||
evaluator.Rescale(ctProd, ctProd)
|
||||
|
||||
// Square: z = x^2
|
||||
ctSquare, _ := evaluator.MulRelinNew(ctX, ctX)
|
||||
evaluator.Rescale(ctSquare, ctSquare)
|
||||
|
||||
// Decrypt and decode results
|
||||
ptSum := decryptor.DecryptNew(ctSum)
|
||||
ptProd := decryptor.DecryptNew(ctProd)
|
||||
ptSquare := decryptor.DecryptNew(ctSquare)
|
||||
|
||||
resSum := encoder.Decode(ptSum, params.LogSlots())
|
||||
resProd := encoder.Decode(ptProd, params.LogSlots())
|
||||
resSquare := encoder.Decode(ptSquare, params.LogSlots())
|
||||
|
||||
fmt.Println("x + y =", resSum[:4])
|
||||
fmt.Println("x * y =", resProd[:4])
|
||||
fmt.Println("x^2 =", resSquare[:4])
|
||||
}
|
||||
```
|
||||
|
||||
### Polynomial Evaluation
|
||||
|
||||
```go
|
||||
func evaluatePolynomial() {
|
||||
params, _ := ckks.NewParametersFromLiteral(ckks.PN14QP438)
|
||||
// ... (setup as before)
|
||||
|
||||
// Evaluate f(x) = 3x^3 - 2x^2 + x - 5
|
||||
coefficients := []complex128{-5, 1, -2, 3}
|
||||
|
||||
// Input values
|
||||
x := []complex128{1.0, 2.0, 3.0, 4.0}
|
||||
ptX := ckks.NewPlaintext(params, params.MaxLevel())
|
||||
encoder.Encode(x, ptX)
|
||||
ctX, _ := encryptor.EncryptNew(ptX)
|
||||
|
||||
// Horner's method: f(x) = -5 + x(1 + x(-2 + x(3)))
|
||||
result := ckks.NewCiphertext(params, 1, params.MaxLevel())
|
||||
|
||||
// Start with highest coefficient
|
||||
encoder.Encode([]complex128{3, 3, 3, 3}, result.Plaintext())
|
||||
encryptor.EncryptZero(result)
|
||||
evaluator.Add(result, coefficients[3], result)
|
||||
|
||||
for i := 2; i >= 0; i-- {
|
||||
// result = result * x + coefficients[i]
|
||||
evaluator.MulRelin(result, ctX, result)
|
||||
evaluator.Rescale(result, result)
|
||||
|
||||
// Add constant
|
||||
constant := make([]complex128, params.Slots())
|
||||
for j := range constant {
|
||||
constant[j] = coefficients[i]
|
||||
}
|
||||
ptConst := ckks.NewPlaintext(params, result.Level())
|
||||
encoder.EncodeAtLevelNew(constant, result.Level(), ptConst)
|
||||
evaluator.Add(result, ptConst, result)
|
||||
}
|
||||
|
||||
// Decrypt result
|
||||
ptResult := decryptor.DecryptNew(result)
|
||||
values := encoder.Decode(ptResult, params.LogSlots())
|
||||
|
||||
fmt.Println("f(x) =", values[:4])
|
||||
// Expected: f(1)=-3, f(2)=9, f(3)=49, f(4)=135
|
||||
}
|
||||
```
|
||||
|
||||
## Machine Learning Applications
|
||||
|
||||
### Encrypted Linear Regression
|
||||
|
||||
```go
|
||||
type EncryptedLinearRegression struct {
|
||||
params ckks.Parameters
|
||||
evaluator ckks.Evaluator
|
||||
encoder ckks.Encoder
|
||||
}
|
||||
|
||||
func (lr *EncryptedLinearRegression) Predict(
|
||||
ctWeights *ckks.Ciphertext,
|
||||
ctFeatures []*ckks.Ciphertext,
|
||||
) (*ckks.Ciphertext, error) {
|
||||
// Compute y = w0 + w1*x1 + w2*x2 + ... + wn*xn
|
||||
|
||||
if len(ctFeatures) == 0 {
|
||||
return nil, errors.New("no features provided")
|
||||
}
|
||||
|
||||
// Initialize with bias (first weight)
|
||||
result := ckks.NewCiphertext(lr.params, 1, ctWeights.Level())
|
||||
lr.evaluator.Mul(ctWeights, ctFeatures[0], result)
|
||||
|
||||
// Add weighted features
|
||||
for i := 1; i < len(ctFeatures); i++ {
|
||||
temp := ckks.NewCiphertext(lr.params, 1, ctWeights.Level())
|
||||
|
||||
// Rotate weights to align with next feature
|
||||
rotatedWeights := lr.evaluator.RotateNew(ctWeights, i)
|
||||
|
||||
// Multiply and add
|
||||
lr.evaluator.Mul(rotatedWeights, ctFeatures[i], temp)
|
||||
lr.evaluator.Add(result, temp, result)
|
||||
}
|
||||
|
||||
// Rescale for precision management
|
||||
lr.evaluator.Rescale(result, result)
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Training encrypted model using gradient descent
|
||||
func (lr *EncryptedLinearRegression) TrainStep(
|
||||
ctWeights *ckks.Ciphertext,
|
||||
ctFeatures []*ckks.Ciphertext,
|
||||
ctLabels *ckks.Ciphertext,
|
||||
learningRate float64,
|
||||
) (*ckks.Ciphertext, error) {
|
||||
// Predict with current weights
|
||||
predictions, _ := lr.Predict(ctWeights, ctFeatures)
|
||||
|
||||
// Compute error: error = predictions - labels
|
||||
error := lr.evaluator.SubNew(predictions, ctLabels)
|
||||
|
||||
// Compute gradients
|
||||
gradients := make([]*ckks.Ciphertext, len(ctFeatures))
|
||||
for i, feature := range ctFeatures {
|
||||
// gradient[i] = mean(error * feature[i])
|
||||
gradients[i] = lr.evaluator.MulNew(error, feature)
|
||||
lr.evaluator.Rescale(gradients[i], gradients[i])
|
||||
}
|
||||
|
||||
// Update weights: w = w - learningRate * gradient
|
||||
ptLR := ckks.NewPlaintext(lr.params, ctWeights.Level())
|
||||
lr.encoder.Encode([]complex128{complex(learningRate, 0)}, ptLR)
|
||||
|
||||
for i, grad := range gradients {
|
||||
scaledGrad := lr.evaluator.MulNew(grad, ptLR)
|
||||
lr.evaluator.Rescale(scaledGrad, scaledGrad)
|
||||
|
||||
// Update specific weight
|
||||
rotatedWeights := lr.evaluator.RotateNew(ctWeights, i)
|
||||
lr.evaluator.Sub(rotatedWeights, scaledGrad, rotatedWeights)
|
||||
|
||||
// Rotate back
|
||||
ctWeights = lr.evaluator.RotateNew(rotatedWeights, -i)
|
||||
}
|
||||
|
||||
return ctWeights, nil
|
||||
}
|
||||
```
|
||||
|
||||
### Encrypted Neural Network Inference
|
||||
|
||||
```go
|
||||
type EncryptedNeuralNetwork struct {
|
||||
layers []EncryptedLayer
|
||||
}
|
||||
|
||||
type EncryptedLayer interface {
|
||||
Forward(input *ckks.Ciphertext) (*ckks.Ciphertext, error)
|
||||
}
|
||||
|
||||
// Fully connected layer
|
||||
type EncryptedDenseLayer struct {
|
||||
weights *ckks.Ciphertext
|
||||
bias *ckks.Ciphertext
|
||||
eval ckks.Evaluator
|
||||
}
|
||||
|
||||
func (l *EncryptedDenseLayer) Forward(input *ckks.Ciphertext) (*ckks.Ciphertext, error) {
|
||||
// Compute output = weights @ input + bias
|
||||
output := l.eval.MulRelinNew(l.weights, input)
|
||||
l.eval.Rescale(output, output)
|
||||
l.eval.Add(output, l.bias, output)
|
||||
return output, nil
|
||||
}
|
||||
|
||||
// ReLU activation using polynomial approximation
|
||||
type EncryptedReLU struct {
|
||||
eval ckks.Evaluator
|
||||
polynomial []complex128
|
||||
}
|
||||
|
||||
func (r *EncryptedReLU) Forward(input *ckks.Ciphertext) (*ckks.Ciphertext, error) {
|
||||
// Approximate ReLU with polynomial
|
||||
// ReLU(x) ≈ 0.5x + 0.25x^2 + 0.125x^3 for x ∈ [-2, 2]
|
||||
|
||||
x2 := r.eval.MulRelinNew(input, input)
|
||||
r.eval.Rescale(x2, x2)
|
||||
|
||||
x3 := r.eval.MulRelinNew(x2, input)
|
||||
r.eval.Rescale(x3, x3)
|
||||
|
||||
// Combine terms
|
||||
result := r.eval.MulNew(input, 0.5)
|
||||
r.eval.Add(result, r.eval.MulNew(x2, 0.25), result)
|
||||
r.eval.Add(result, r.eval.MulNew(x3, 0.125), result)
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Run inference
|
||||
func (nn *EncryptedNeuralNetwork) Predict(input *ckks.Ciphertext) (*ckks.Ciphertext, error) {
|
||||
current := input
|
||||
|
||||
for _, layer := range nn.layers {
|
||||
next, err := layer.Forward(current)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
current = next
|
||||
}
|
||||
|
||||
return current, nil
|
||||
}
|
||||
```
|
||||
|
||||
## Private Information Retrieval
|
||||
|
||||
### Basic PIR Query
|
||||
|
||||
```go
|
||||
func privateDatabaseQuery() {
|
||||
// Setup BGV for exact computation
|
||||
params, _ := bgv.NewParametersFromLiteral(
|
||||
bgv.ParametersLiteral{
|
||||
LogN: 13,
|
||||
LogQ: []int{60, 60, 60},
|
||||
PlaintextModulus: 65537,
|
||||
},
|
||||
)
|
||||
|
||||
// Database with 1024 entries
|
||||
database := make([]uint64, 1024)
|
||||
for i := range database {
|
||||
database[i] = uint64(i * i) // Example data
|
||||
}
|
||||
|
||||
// Client wants to query index 42 privately
|
||||
queryIndex := 42
|
||||
|
||||
// Create one-hot encoded query vector
|
||||
query := make([]uint64, len(database))
|
||||
query[queryIndex] = 1
|
||||
|
||||
// Encrypt query
|
||||
encoder := bgv.NewEncoder(params)
|
||||
encryptor := bgv.NewEncryptor(params, pk)
|
||||
|
||||
ptQuery := bgv.NewPlaintext(params)
|
||||
encoder.Encode(query, ptQuery)
|
||||
ctQuery, _ := encryptor.EncryptNew(ptQuery)
|
||||
|
||||
// Server computes response
|
||||
// result = sum(database[i] * query[i]) for all i
|
||||
evaluator := bgv.NewEvaluator(params, evk)
|
||||
|
||||
ctResult := bgv.NewCiphertext(params, 1, params.MaxLevel())
|
||||
for i, value := range database {
|
||||
if value != 0 {
|
||||
// Rotate query to align with database entry
|
||||
rotated := evaluator.RotateNew(ctQuery, i)
|
||||
|
||||
// Multiply by database value
|
||||
evaluator.MulScalar(rotated, value, rotated)
|
||||
|
||||
// Add to result
|
||||
evaluator.Add(ctResult, rotated, ctResult)
|
||||
}
|
||||
}
|
||||
|
||||
// Client decrypts result
|
||||
ptResult := decryptor.DecryptNew(ctResult)
|
||||
result := encoder.DecodeUint(ptResult)
|
||||
|
||||
fmt.Printf("Database[%d] = %d\n", queryIndex, result[0])
|
||||
}
|
||||
```
|
||||
|
||||
## Multiparty Computation
|
||||
|
||||
### Threshold Decryption
|
||||
|
||||
```go
|
||||
func thresholdDecryption() {
|
||||
params, _ := ckks.NewParametersFromLiteral(ckks.PN14QP438)
|
||||
|
||||
// Setup: 3 parties, threshold = 2
|
||||
numParties := 3
|
||||
threshold := 2
|
||||
|
||||
// Each party generates their secret key share
|
||||
parties := make([]*Party, numParties)
|
||||
for i := range parties {
|
||||
parties[i] = &Party{
|
||||
ID: i,
|
||||
SK: rlwe.NewKeyGenerator(params).GenSecretKeyNew(),
|
||||
}
|
||||
}
|
||||
|
||||
// Threshold key generation protocol
|
||||
tkg := multiparty.NewTKGProtocol(params)
|
||||
|
||||
// Each party creates their share
|
||||
shares := make([]*multiparty.TKGShare, numParties)
|
||||
for i, party := range parties {
|
||||
shares[i] = tkg.GenShare(party.SK)
|
||||
}
|
||||
|
||||
// Aggregate to get collective public key
|
||||
collectivePK := tkg.AggregateShares(shares)
|
||||
|
||||
// Encrypt data with collective public key
|
||||
encoder := ckks.NewEncoder(params)
|
||||
encryptor := rlwe.NewEncryptor(params, collectivePK)
|
||||
|
||||
data := []complex128{1.23, 4.56, 7.89}
|
||||
pt := ckks.NewPlaintext(params, params.MaxLevel())
|
||||
encoder.Encode(data, pt)
|
||||
ct, _ := encryptor.EncryptNew(pt)
|
||||
|
||||
// Threshold decryption with any 2 parties
|
||||
pcks := multiparty.NewPCKSProtocol(params)
|
||||
|
||||
// Select subset of parties (meets threshold)
|
||||
activeParties := parties[:threshold]
|
||||
|
||||
// Generate decryption shares
|
||||
decShares := make([]*multiparty.PCKSShare, threshold)
|
||||
for i, party := range activeParties {
|
||||
decShares[i] = pcks.GenShare(party.SK, ct)
|
||||
}
|
||||
|
||||
// Combine shares to decrypt
|
||||
ptResult := pcks.AggregateShares(decShares, ct)
|
||||
result := encoder.Decode(ptResult, params.LogSlots())
|
||||
|
||||
fmt.Println("Decrypted:", result[:3])
|
||||
}
|
||||
```
|
||||
|
||||
### Secure Multiparty Training
|
||||
|
||||
```go
|
||||
type SecureMLTraining struct {
|
||||
params ckks.Parameters
|
||||
parties []*MLParty
|
||||
protocol *multiparty.Protocol
|
||||
}
|
||||
|
||||
type MLParty struct {
|
||||
ID int
|
||||
SK *rlwe.SecretKey
|
||||
DataSet [][]float64
|
||||
LocalModel *ckks.Ciphertext
|
||||
}
|
||||
|
||||
func (sml *SecureMLTraining) FederatedAveraging() (*ckks.Ciphertext, error) {
|
||||
// Each party trains locally and encrypts their model
|
||||
encryptedModels := make([]*ckks.Ciphertext, len(sml.parties))
|
||||
|
||||
for i, party := range sml.parties {
|
||||
// Local training (in plaintext)
|
||||
localWeights := party.TrainLocal()
|
||||
|
||||
// Encrypt local model
|
||||
pt := ckks.NewPlaintext(sml.params, sml.params.MaxLevel())
|
||||
encoder.Encode(localWeights, pt)
|
||||
encryptedModels[i], _ = encryptor.EncryptNew(pt)
|
||||
}
|
||||
|
||||
// Secure aggregation
|
||||
globalModel := sml.SecureAggregate(encryptedModels)
|
||||
|
||||
// Collaborative decryption
|
||||
return sml.CollectiveDecrypt(globalModel)
|
||||
}
|
||||
|
||||
func (sml *SecureMLTraining) SecureAggregate(models []*ckks.Ciphertext) *ckks.Ciphertext {
|
||||
// Average encrypted models
|
||||
result := models[0].CopyNew()
|
||||
|
||||
for i := 1; i < len(models); i++ {
|
||||
evaluator.Add(result, models[i], result)
|
||||
}
|
||||
|
||||
// Divide by number of parties
|
||||
scale := 1.0 / float64(len(models))
|
||||
evaluator.MulScalar(result, scale, result)
|
||||
evaluator.Rescale(result, result)
|
||||
|
||||
return result
|
||||
}
|
||||
```
|
||||
|
||||
## Financial Applications
|
||||
|
||||
### Private Portfolio Analysis
|
||||
|
||||
```go
|
||||
type PrivatePortfolio struct {
|
||||
holdings map[string]*ckks.Ciphertext // Encrypted quantities
|
||||
evaluator ckks.Evaluator
|
||||
}
|
||||
|
||||
func (p *PrivatePortfolio) CalculateValue(prices map[string]float64) *ckks.Ciphertext {
|
||||
var totalValue *ckks.Ciphertext
|
||||
|
||||
for asset, encryptedQuantity := range p.holdings {
|
||||
price := prices[asset]
|
||||
|
||||
// value = quantity * price
|
||||
value := p.evaluator.MulScalarNew(encryptedQuantity, price)
|
||||
p.evaluator.Rescale(value, value)
|
||||
|
||||
if totalValue == nil {
|
||||
totalValue = value
|
||||
} else {
|
||||
p.evaluator.Add(totalValue, value, totalValue)
|
||||
}
|
||||
}
|
||||
|
||||
return totalValue
|
||||
}
|
||||
|
||||
func (p *PrivatePortfolio) CalculateRisk(
|
||||
correlationMatrix [][]float64,
|
||||
volatilities []float64,
|
||||
) *ckks.Ciphertext {
|
||||
// Portfolio risk = sqrt(w^T * Σ * w)
|
||||
// where Σ is covariance matrix
|
||||
|
||||
assets := make([]string, 0, len(p.holdings))
|
||||
weights := make([]*ckks.Ciphertext, 0, len(p.holdings))
|
||||
|
||||
for asset, holding := range p.holdings {
|
||||
assets = append(assets, asset)
|
||||
weights = append(weights, holding)
|
||||
}
|
||||
|
||||
// Compute weighted covariance
|
||||
risk := ckks.NewCiphertext(p.evaluator.Parameters(), 1, weights[0].Level())
|
||||
|
||||
for i := range assets {
|
||||
for j := range assets {
|
||||
// cov[i,j] = correlation[i,j] * vol[i] * vol[j]
|
||||
cov := correlationMatrix[i][j] * volatilities[i] * volatilities[j]
|
||||
|
||||
// risk += w[i] * w[j] * cov[i,j]
|
||||
term := p.evaluator.MulNew(weights[i], weights[j])
|
||||
p.evaluator.Rescale(term, term)
|
||||
p.evaluator.MulScalar(term, cov, term)
|
||||
p.evaluator.Add(risk, term, risk)
|
||||
}
|
||||
}
|
||||
|
||||
// Note: Square root would require polynomial approximation
|
||||
return risk
|
||||
}
|
||||
```
|
||||
|
||||
## Advanced Techniques
|
||||
|
||||
### Bootstrapping Example
|
||||
|
||||
```go
|
||||
func bootstrappingExample() {
|
||||
// Parameters with bootstrapping support
|
||||
params, _ := ckks.NewParametersFromLiteral(
|
||||
ckks.ParametersLiteral{
|
||||
LogN: 16,
|
||||
LogQ: []int{
|
||||
// Computation levels
|
||||
60, 50, 50, 50, 50,
|
||||
// Bootstrapping levels
|
||||
60, 60, 60, 60, 60, 60, 60, 60,
|
||||
},
|
||||
LogP: []int{61, 61, 61},
|
||||
LogDefaultScale: 50,
|
||||
H: 192,
|
||||
},
|
||||
)
|
||||
|
||||
// Setup bootstrapper
|
||||
btpParams := bootstrapping.ParametersLiteral{
|
||||
LogN: params.LogN(),
|
||||
LogSlots: params.LogSlots(),
|
||||
H: 192,
|
||||
Sigma: params.Sigma(),
|
||||
}
|
||||
|
||||
bootstrapper, _ := bootstrapping.NewBootstrapper(params, btpParams, evk)
|
||||
|
||||
// Perform deep computation
|
||||
ct := encryptInitialData()
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
// Complex computation
|
||||
ct = evaluator.MulRelinNew(ct, ct)
|
||||
evaluator.Rescale(ct, ct)
|
||||
|
||||
// Check if bootstrapping needed
|
||||
if ct.Level() == 0 {
|
||||
fmt.Printf("Bootstrapping at iteration %d\n", i)
|
||||
ct, _ = bootstrapper.Bootstrap(ct)
|
||||
}
|
||||
}
|
||||
|
||||
// Decrypt final result
|
||||
result := decrypt(ct)
|
||||
fmt.Println("Result after 100 multiplications:", result)
|
||||
}
|
||||
```
|
||||
|
||||
### Custom Polynomial Evaluation
|
||||
|
||||
```go
|
||||
func evaluateCustomFunction() {
|
||||
// Approximate sin(x) using Chebyshev polynomials
|
||||
// sin(x) ≈ x - x³/6 + x⁵/120 - x⁷/5040 for x ∈ [-π, π]
|
||||
|
||||
coeffs := []float64{
|
||||
0, // x⁰
|
||||
1, // x¹
|
||||
0, // x²
|
||||
-1.0/6, // x³
|
||||
0, // x⁴
|
||||
1.0/120, // x⁵
|
||||
0, // x⁶
|
||||
-1.0/5040, // x⁷
|
||||
}
|
||||
|
||||
// Create polynomial evaluator
|
||||
polyEval := ckks.NewPolynomialEvaluator(params, evaluator)
|
||||
|
||||
// Input values
|
||||
x := []complex128{0, 0.5, 1.0, 1.5}
|
||||
ptX := encode(x)
|
||||
ctX := encrypt(ptX)
|
||||
|
||||
// Evaluate polynomial
|
||||
ctResult, _ := polyEval.Evaluate(ctX, coeffs)
|
||||
|
||||
// Compare with actual sin(x)
|
||||
result := decrypt(ctResult)
|
||||
fmt.Println("Approximate sin(x):", result)
|
||||
fmt.Println("Actual sin(x):", []float64{
|
||||
math.Sin(0), math.Sin(0.5), math.Sin(1.0), math.Sin(1.5),
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
## Performance Optimization Tips
|
||||
|
||||
### Batching Operations
|
||||
|
||||
```go
|
||||
func efficientBatching() {
|
||||
// Process multiple data items in single ciphertext
|
||||
batchSize := params.Slots() // Use all available slots
|
||||
|
||||
// Pack data efficiently
|
||||
data := make([]complex128, batchSize)
|
||||
for i := 0; i < actualDataSize; i++ {
|
||||
data[i] = actualData[i]
|
||||
}
|
||||
// Remaining slots stay zero
|
||||
|
||||
// Single encryption for entire batch
|
||||
pt := encode(data)
|
||||
ct := encrypt(pt)
|
||||
|
||||
// Operations apply to all slots simultaneously
|
||||
ctSquared := evaluator.MulRelinNew(ct, ct)
|
||||
evaluator.Rescale(ctSquared, ctSquared)
|
||||
|
||||
// Decrypt entire batch
|
||||
result := decrypt(ctSquared)
|
||||
// Use first actualDataSize elements
|
||||
}
|
||||
```
|
||||
|
||||
### Memory Management
|
||||
|
||||
```go
|
||||
func memoryEfficientComputation() {
|
||||
// Reuse ciphertexts to reduce memory
|
||||
ct1 := encrypt(data1)
|
||||
ct2 := encrypt(data2)
|
||||
|
||||
// In-place operations
|
||||
evaluator.Add(ct1, ct2, ct1) // Result overwrites ct1
|
||||
evaluator.MulRelin(ct1, ct1, ct1) // Square in-place
|
||||
evaluator.Rescale(ct1, ct1)
|
||||
|
||||
// Manual memory cleanup for large computations
|
||||
runtime.GC()
|
||||
|
||||
// Use object pools for repeated allocations
|
||||
ctPool := sync.Pool{
|
||||
New: func() interface{} {
|
||||
return ckks.NewCiphertext(params, 1, params.MaxLevel())
|
||||
},
|
||||
}
|
||||
|
||||
// Get from pool
|
||||
temp := ctPool.Get().(*ckks.Ciphertext)
|
||||
// Use temp...
|
||||
// Return to pool
|
||||
ctPool.Put(temp)
|
||||
}
|
||||
```
|
||||
|
||||
## Testing and Validation
|
||||
|
||||
### Unit Testing Homomorphic Operations
|
||||
|
||||
```go
|
||||
func TestHomomorphicAddition(t *testing.T) {
|
||||
// Setup
|
||||
params, _ := ckks.NewParametersFromLiteral(testParams)
|
||||
// ... initialize crypto components
|
||||
|
||||
// Test data
|
||||
a := []complex128{1.0, 2.0, 3.0, 4.0}
|
||||
b := []complex128{5.0, 6.0, 7.0, 8.0}
|
||||
expected := []complex128{6.0, 8.0, 10.0, 12.0}
|
||||
|
||||
// Encrypt
|
||||
ctA := encryptVector(a)
|
||||
ctB := encryptVector(b)
|
||||
|
||||
// Homomorphic addition
|
||||
ctSum := evaluator.AddNew(ctA, ctB)
|
||||
|
||||
// Decrypt and verify
|
||||
result := decryptVector(ctSum)
|
||||
|
||||
for i := range expected {
|
||||
if math.Abs(real(result[i] - expected[i])) > 0.01 {
|
||||
t.Errorf("Mismatch at %d: got %v, want %v",
|
||||
i, result[i], expected[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Benchmarking
|
||||
|
||||
```go
|
||||
func BenchmarkHomomorphicMultiplication(b *testing.B) {
|
||||
// Setup
|
||||
params, _ := ckks.NewParametersFromLiteral(ckks.PN14QP438)
|
||||
// ... initialize
|
||||
|
||||
ct1 := encrypt(randomData())
|
||||
ct2 := encrypt(randomData())
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
result := evaluator.MulRelinNew(ct1, ct2)
|
||||
evaluator.Rescale(result, result)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Conclusion
|
||||
|
||||
These examples demonstrate the versatility of lattice-based cryptography for:
|
||||
- **Privacy-preserving computation**: Process encrypted data without decryption
|
||||
- **Machine learning**: Train and evaluate models on encrypted data
|
||||
- **Financial analysis**: Perform calculations on sensitive financial data
|
||||
- **Multiparty protocols**: Enable secure collaboration without sharing raw data
|
||||
|
||||
Key takeaways:
|
||||
1. Always manage noise levels and precision
|
||||
2. Use batching for efficiency
|
||||
3. Implement proper key management
|
||||
4. Test thoroughly with realistic data
|
||||
5. Monitor performance and optimize as needed
|
||||
@@ -0,0 +1,18 @@
|
||||
import { docs } from "@/.source"
|
||||
import { loader } from "fumadocs-core/source"
|
||||
|
||||
// Create a single source instance that is reused
|
||||
// This prevents circular references and stack overflow issues
|
||||
let _source: ReturnType<typeof loader> | null = null
|
||||
|
||||
export function getSource() {
|
||||
if (!_source) {
|
||||
_source = loader({
|
||||
baseUrl: "/docs",
|
||||
source: docs.toFumadocsSource(),
|
||||
})
|
||||
}
|
||||
return _source
|
||||
}
|
||||
|
||||
export const source = getSource()
|
||||
@@ -0,0 +1,9 @@
|
||||
import type { MDXComponents } from "mdx/types"
|
||||
import defaultMdxComponents from "fumadocs-ui/mdx"
|
||||
|
||||
export function useMDXComponents(components: MDXComponents): MDXComponents {
|
||||
return {
|
||||
...defaultMdxComponents,
|
||||
...components,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import { createMDX } from "fumadocs-mdx/next"
|
||||
|
||||
/** @type {import('next').NextConfig} */
|
||||
const config = {
|
||||
output: 'export',
|
||||
reactStrictMode: true,
|
||||
typescript: {
|
||||
ignoreBuildErrors: true,
|
||||
},
|
||||
experimental: {
|
||||
webpackBuildWorker: true,
|
||||
},
|
||||
images: {
|
||||
unoptimized: true,
|
||||
},
|
||||
}
|
||||
|
||||
const withMDX = createMDX()
|
||||
|
||||
export default withMDX(config)
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"name": "@luxfi/lattice-docs",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev --port 3001",
|
||||
"build": "fumadocs-mdx && TURBOPACK=0 next build",
|
||||
"export": "TURBOPACK=0 next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint",
|
||||
"postinstall": "fumadocs-mdx"
|
||||
},
|
||||
"dependencies": {
|
||||
"fumadocs-core": "^15.8.5",
|
||||
"fumadocs-mdx": "^12.0.3",
|
||||
"fumadocs-ui": "^15.8.5",
|
||||
"lucide-react": "^0.468.0",
|
||||
"next": "16.0.1",
|
||||
"react": "19.2.0",
|
||||
"react-dom": "19.2.0",
|
||||
"tailwindcss": "^4.1.16",
|
||||
"zod": "^3.24.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/postcss": "^4.1.16",
|
||||
"@types/node": "^22.10.2",
|
||||
"@types/react": "^19.0.1",
|
||||
"@types/react-dom": "^19.0.2",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"postcss": "^8.4.49",
|
||||
"rehype-pretty-code": "^0.14.1",
|
||||
"shiki": "^1.27.2",
|
||||
"typescript": "^5.7.2"
|
||||
},
|
||||
"packageManager": "[email protected]"
|
||||
}
|
||||
Generated
+4136
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
'@tailwindcss/postcss': {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import {
|
||||
defineConfig,
|
||||
defineDocs,
|
||||
} from "fumadocs-mdx/config"
|
||||
import rehypePrettyCode from "rehype-pretty-code"
|
||||
|
||||
export default defineConfig({
|
||||
mdxOptions: {
|
||||
rehypePlugins: [
|
||||
[
|
||||
rehypePrettyCode,
|
||||
{
|
||||
theme: {
|
||||
dark: "github-dark-dimmed",
|
||||
light: "github-light",
|
||||
},
|
||||
keepBackground: false,
|
||||
defaultLang: "go",
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
export const docs = defineDocs({
|
||||
dir: "content/docs",
|
||||
})
|
||||
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"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": "react-jsx",
|
||||
"incremental": true,
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"./*"
|
||||
]
|
||||
},
|
||||
"target": "ES2017"
|
||||
},
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
".next/types/**/*.ts",
|
||||
".next/dev/types/**/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user