Lux Docs

Security Parameters Guide

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:

ProblemDescriptionQuantum Hardness
LWELearning With Errors√ Quantum-resistant
RLWERing Learning With Errors√ Quantum-resistant
MLWEModule Learning With Errors√ Quantum-resistant
SISShort Integer Solution√ Quantum-resistant
MSISModule Short Integer Solution√ Quantum-resistant

Security Level Definitions

// 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

// 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

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

// 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,
    }
}
SecurityLogNLogQPPrecisionMult. DepthBootstrappable
128-bit1321930 bits4No
128-bit1443940 bits8No
128-bit1588150 bits18Yes
192-bit1435935 bits6No
192-bit1571945 bits12Yes
256-bit1565940 bits10No
256-bit16131950 bits22Yes

Example CKKS Configuration

// 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

// 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,
    }
}
SecurityLogNTLogQPMult. DepthSlots
128-bit136553721834096
128-bit146553743878192
128-bit15655378831416384
192-bit146553735858192
192-bit15655377181116384
256-bit15655376581016384
256-bit166553713182132768

Security Analysis

Lattice Estimator

// 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

// 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

// 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

// 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

// 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

// 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

// 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

// 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

// 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

// 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

IssueCauseSolution
Decryption failureNoise overflowIncrease Q or reduce circuit depth
Poor precisionScale too smallIncrease LogDefaultScale
Slow performanceN too largeUse minimal N for security
Large ciphertextsQ too largeOptimize modulus chain
Bootstrap failsInsufficient levelsReserve 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.

On this page