Skip to main content

Encryption Schemes

This guide explains the three HE schemes supported by HETorch: CKKS, BFV, and BGV.

Overview

SchemeArithmeticPrecisionUse CaseComplexity
CKKSApproximate (float-like)~40-60 bitsNeural networks, MLMedium
BFVExact (integer)ExactDecision trees, countersLow
BGVExact (integer)ExactSimilar to BFVMedium

CKKS (Cheon-Kim-Kim-Song)

Overview

CKKS is an approximate HE scheme designed for real/complex number arithmetic. It's the most suitable scheme for neural networks and machine learning.

Key Features

  • Approximate Arithmetic: Operations introduce small rounding errors (similar to floating-point)
  • Rescaling: Manages scale growth after multiplications
  • Leveled: Limited multiplication depth determined by modulus chain
  • Bootstrapping: Can refresh ciphertexts to enable deeper computations

When to Use

Good for:

  • Neural networks
  • Signal processing
  • Approximate computations
  • Real-valued data

Not good for:

  • Exact integer arithmetic
  • Comparisons (>, <, ==)
  • Branching logic

Parameters

from hetorch import CKKSParameters

params = CKKSParameters(
poly_modulus_degree=8192, # Polynomial degree (power of 2)
coeff_modulus=[60, 40, 40, 60], # Modulus chain
scale=2**40, # Scaling factor
noise_budget=100.0 # Initial noise budget
)

poly_modulus_degree

Controls security, slot count, and performance:

ValueSecuritySlotsPerformanceUse Case
4096~100 bits2048FastDevelopment, testing
8192~128 bits4096BalancedRecommended
16384~192 bits8192SlowHigh security
32768~256 bits16384Very slowMaximum security

Recommendation: Use 8192 for most applications.

coeff_modulus

Determines multiplication depth and precision:

# Example: [60, 40, 40, 60]
# - First 60: Special prime for encoding
# - Middle 40s: Computation primes (one per multiplication level)
# - Last 60: Special prime for decoding
# Length = max_depth + 1

# 2 multiplications
coeff_modulus=[60, 40, 40, 60] # Length 4 = 2 mults + 2 special

# 4 multiplications
coeff_modulus=[60, 40, 40, 40, 40, 60] # Length 6 = 4 mults + 2 special

# 8 multiplications
coeff_modulus=[60, 40, 40, 40, 40, 40, 40, 40, 40, 60] # Length 10

Guidelines:

  • Each multiplication consumes one level
  • More levels = deeper computations but larger ciphertexts
  • Typical: 2-4 levels for simple models, 6-10 for deep models

scale

Controls precision vs range tradeoff:

ValuePrecisionRangeUse Case
2^30~9 decimal digitsLargerWide range values
2^40~12 decimal digitsBalancedRecommended
2^50~15 decimal digitsSmallerHigh precision

Recommendation: Use 2^40 for most applications.

noise_budget

Initial noise capacity (used with noise simulation):

params = CKKSParameters(
poly_modulus_degree=8192,
coeff_modulus=[60, 40, 40, 60],
scale=2**40,
noise_budget=100.0 # 100 bits of noise budget
)

CKKS Operations

Supported Operations

# Ciphertext-ciphertext
cadd(ct1, ct2) # Addition
cmult(ct1, ct2) # Multiplication (consumes 1 level)
rotate(ct, steps) # Rotation

# Plaintext-ciphertext
padd(ct, pt) # Addition
pmult(ct, pt) # Multiplication (consumes 1 level)

# Scheme-specific
rescale(ct) # Rescale after multiplication
relinearize(ct) # Reduce ciphertext size
bootstrap(ct) # Refresh noise budget

Rescaling

After multiplication, scale increases. Rescaling brings it back:

# Without rescaling
x = encrypt(1.0, scale=2^40)
y = encrypt(2.0, scale=2^40)
z = cmult(x, y) # scale = 2^80 (too large!)

# With rescaling
x = encrypt(1.0, scale=2^40)
y = encrypt(2.0, scale=2^40)
z = cmult(x, y) # scale = 2^80
z = rescale(z) # scale = 2^40 (back to normal)

HETorch's RescalingInsertionPass handles this automatically.

Example

from hetorch import HEScheme, CKKSParameters, CompilationContext, FakeBackend

context = CompilationContext(
scheme=HEScheme.CKKS,
params=CKKSParameters(
poly_modulus_degree=8192,
coeff_modulus=[60, 40, 40, 60],
scale=2**40,
noise_budget=100.0
),
backend=FakeBackend()
)

BFV (Brakerski-Fan-Vercauteren)

Overview

BFV is an exact HE scheme for integer arithmetic. It provides exact results with no approximation error.

Key Features

  • Exact Arithmetic: No rounding errors
  • Integer Operations: Works with integers modulo plain_modulus
  • Leveled: Limited multiplication depth
  • No Rescaling: Simpler than CKKS (no scale management)

When to Use

Good for:

  • Exact integer computations
  • Counters, voting
  • Decision trees
  • Boolean circuits

Not good for:

  • Floating-point arithmetic
  • Neural networks (requires quantization)

Parameters

from hetorch import BFVParameters

params = BFVParameters(
poly_modulus_degree=8192,
coeff_modulus=[60, 60, 60],
plain_modulus=1024
)

plain_modulus

Determines the integer range:

# plain_modulus = 1024
# Values: 0 to 1023

# plain_modulus = 65537 (prime)
# Values: 0 to 65536

Guidelines:

  • Must be prime or power of 2
  • Larger = more range but slower
  • Typical: 1024 - 65537

BFV Operations

# Ciphertext-ciphertext
cadd(ct1, ct2) # Addition (exact)
cmult(ct1, ct2) # Multiplication (exact, consumes 1 level)
rotate(ct, steps) # Rotation

# Plaintext-ciphertext
padd(ct, pt) # Addition (exact)
pmult(ct, pt) # Multiplication (exact)

# Scheme-specific
relinearize(ct) # Reduce ciphertext size

Example

from hetorch import HEScheme, BFVParameters, CompilationContext, FakeBackend

context = CompilationContext(
scheme=HEScheme.BFV,
params=BFVParameters(
poly_modulus_degree=8192,
coeff_modulus=[60, 60, 60],
plain_modulus=1024
),
backend=FakeBackend()
)

BGV (Brakerski-Gentry-Vaikuntanathan)

Overview

BGV is similar to BFV but with different noise management. It's also an exact integer scheme.

Key Features

  • Exact Arithmetic: No rounding errors
  • Integer Operations: Works with integers modulo plain_modulus
  • Leveled: Limited multiplication depth
  • Modulus Switching: Different noise management than BFV

When to Use

Similar to BFV. Choice between BFV and BGV depends on specific use case and backend support.

Parameters

from hetorch import BGVParameters

params = BGVParameters(
poly_modulus_degree=8192,
coeff_modulus=[60, 60, 60],
plain_modulus=1024
)

Same parameters as BFV.

Example

from hetorch import HEScheme, BGVParameters, CompilationContext, FakeBackend

context = CompilationContext(
scheme=HEScheme.BGV,
params=BGVParameters(
poly_modulus_degree=8192,
coeff_modulus=[60, 60, 60],
plain_modulus=1024
),
backend=FakeBackend()
)

Scheme Comparison

Arithmetic Type

SchemeTypeExample
CKKSApproximate1.5 + 2.3 ≈ 3.8 (±0.0001)
BFVExact5 + 7 = 12 (exact)
BGVExact5 + 7 = 12 (exact)

Multiplication Depth

All schemes have limited multiplication depth:

# CKKS with coeff_modulus=[60, 40, 40, 60]
x = encrypt(2.0) # level: 2
y = x * x # level: 1 (consumed 1)
z = y * y # level: 0 (consumed 1)
w = z * z # ERROR: no levels left!

# Solution: Use bootstrapping
z_boot = bootstrap(z) # level: 2 (refreshed)
w = z_boot * z_boot # level: 1 (OK)

Performance

SchemeSpeedCiphertext SizeComplexity
CKKSMediumMediumMedium (rescaling)
BFVFastSmallLow (simple)
BGVMediumMediumMedium (modulus switching)

Use Case Matrix

ApplicationRecommended SchemeWhy
Neural networksCKKSApproximate arithmetic, rescaling
Logistic regressionCKKSReal-valued weights
Decision treesBFV/BGVExact comparisons
Voting/countingBFV/BGVExact integers
Signal processingCKKSReal-valued signals
Boolean circuitsBFV/BGVExact logic

Choosing a Scheme

Decision Tree

Do you need exact results?
├─ Yes → Do you need integers?
│ ├─ Yes → BFV or BGV
│ └─ No → Not supported (use CKKS with high precision)
└─ No → CKKS

For Neural Networks

Always use CKKS:

  • Supports real-valued weights and activations
  • Polynomial approximations work well
  • Rescaling manages scale growth
  • Bootstrapping enables deep networks

For Other Applications

  • Exact integer arithmetic: BFV or BGV
  • Approximate arithmetic: CKKS
  • Boolean logic: BFV or BGV
  • Real-valued data: CKKS

Parameter Selection Guidelines

Security Level

poly_modulus_degreeSecurity (bits)Use Case
4096~100Development only
8192~128Production
16384~192High security
32768~256Maximum security

Multiplication Depth

Estimate depth needed:

# Example: 3-layer neural network
# Layer 1: Linear + ReLU (degree 8 polynomial)
# - Linear: 1 multiplication
# - ReLU polynomial: 8 multiplications
# - Total: 9 multiplications
# Layer 2: Same as layer 1
# - Total: 9 multiplications
# Layer 3: Linear only
# - Total: 1 multiplication
# Grand total: 19 multiplications

# Need coeff_modulus length: 19 + 1 = 20
coeff_modulus = [60] + [40] * 18 + [60] # 20 primes

Optimization: Use lazy rescaling and BSGS to reduce depth.

Slot Count

# Slot count = poly_modulus_degree / 2 (for CKKS/BFV)

poly_modulus_degree = 8192
slot_count = 4096 # Can pack 4096 values per ciphertext

Scheme-Specific Passes

CKKS Only

  • RescalingInsertionPass: Manages scale after multiplications

All Schemes

  • RelinearizationInsertionPass: Reduces ciphertext size
  • BootstrappingInsertionPass: Refreshes noise budget

Example Pipelines

CKKS Pipeline:

from hetorch.passes import PassPipeline
from hetorch.passes.builtin import (
InputPackingPass,
NonlinearToPolynomialPass,
RescalingInsertionPass,
RelinearizationInsertionPass,
BootstrappingInsertionPass,
)

pipeline = PassPipeline([
InputPackingPass(),
NonlinearToPolynomialPass(),
RescalingInsertionPass(strategy="lazy"), # CKKS only
RelinearizationInsertionPass(strategy="lazy"),
BootstrappingInsertionPass(level_threshold=15.0),
])

BFV/BGV Pipeline:

pipeline = PassPipeline([
InputPackingPass(),
# No NonlinearToPolynomialPass (exact arithmetic)
# No RescalingInsertionPass (not needed)
RelinearizationInsertionPass(strategy="lazy"),
BootstrappingInsertionPass(level_threshold=20.0),
])

Next Steps