Skip to content

Adds composintscaling* support for SPARSE_ENCAPSULATED (all CKKS bootstrapping flavors), StC-First BT, and CKKS FBT - #1286

Merged
pascoec merged 8 commits into
devfrom
issue-1267
Sep 1, 2026
Merged

Adds composintscaling* support for SPARSE_ENCAPSULATED (all CKKS bootstrapping flavors), StC-First BT, and CKKS FBT#1286
pascoec merged 8 commits into
devfrom
issue-1267

Conversation

@yspolyakov

@yspolyakov yspolyakov commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR completes the composite scaling (COMPOSITESCALINGAUTO/COMPOSITESCALINGMANUAL) support for CKKS bootstrapping. It adds composite scaling to the two bootstrapping flavors that did not support it yet — the SlotsToCoeffs-first slot-encoding mode and functional bootstrapping (EvalFBT) — and enables the SPARSE_ENCAPSULATED secret key distribution with composite scaling for all three flavors (ModRaise-first, SlotsToCoeffs-first, and functional bootstrapping). In all cases the precision/noise of composite scaling is on par with FLEXIBLEAUTO for the same parameters, and composite scaling now also enables functional bootstrapping with scaling factors above 64 bits (up to the 120-bit maximum of composite scaling).

Fixes #1267.

Changes

1. COMPOSITESCALING* for the SlotsToCoeffs-first bootstrapping mode (BTSlotsEncoding = true)

The setup side and the post-ModRaise code were already composite-aware; the mode was disabled because of three issues in EvalBootstrapStCFirst:

  • The expected input level counted levels in degree-1 units, while the SlotsToCoeffs matrix is encoded for compositeDegree * (levelBudget + 2) remaining towers (modulus mismatch for composite scaling).
  • The level adjustment applied when the input arrives with extra levels mixed up the current and target levels (relative to AdjustLevelsAndDepthInPlace). This is invisible for FLEXIBLEAUTO (its per-level scaling factors agree to ~2^-30) but capped composite scaling at ~15 bits.
  • When deg = log2(q0 / 2^p) exceeds the correction factor (allowed for composite scaling), the correction wrapped around (unsigned subtraction); it is now clamped to 0 in both bootstrapping variants (e.g., composite degree 3, or a small correction factor).

The StC-first variant is now enabled for all composite scaling bootstrapping unit tests (FULL/EDGE/SPARSE, ITERATIVE, NUM_TOWERS, SERIALIZE), and four StCFirst* precision regression tests (CS vs FA) were added to UnitTestCKKSrnsCompositeScalingVsFlexible.cpp.

2. COMPOSITESCALING* for CKKS functional bootstrapping

Composite scaling is handled like the FLEXIBLE* modes (the raised ciphertext is declared to carry the level-specific scaling factor and the ratios to the nominal 2^p are folded into the encoding/decoding matrices), with all tower counts scaled by the composite degree: the moduli of the bottom level and of the output, the levels of the homomorphic encoding/decoding matrices, the modulus raise (via ExtendCiphertext), the rescaling steps, and the level reduction in EvalHomDecoding. SchemeletRLWEMP interprets levels in multiplicative levels for composite scaling.

Two precision issues that were invisible for single-prime moduli were fixed along the way:

  • The ratio between the bottom modulus and the closest power of two (pre) was folded into the matrices although the correction applied after the modulus raise already removes it exactly. For composite moduli (~2^-10 off a power of two) this scaled the mod-raise overflows and cost ~14 bits. It is now applied only in the FIXED* modes.
  • For UNIFORM_TERNARY, the division by K_UNIFORM was applied as a tiny scalar (~1/(K·N)) after the modulus raise, whose encoding at the scaling factor loses precision unless the scaling factor is close to a power of two. The division by K is now folded into the CoeffsToSlots matrix for all distributions, which also avoids amplifying the CoeffsToSlots key-switching noise by K.

Note that the parameter generation for composite scaling requires firstModSize > scalingModSize, so in these modes the first modulus has to be at least one bit larger than the scaling factor (whose bit length matches the RLWE ciphertext modulus).

3. SPARSE_ENCAPSULATED with composite scaling (all bootstrapping flavors)

  • The sparse key switching is defined over the bottom basis Ql = {q_0, ..., q_{d-1}} (d = composite degree): the ciphertext and the keys are extended from Ql to the auxiliary basis P' and scaled back down with exact (HPS-style) CRT basis switches over all d limbs (the single-limb centered lift is kept for d = 1). The Ql-only tables are shared with the composite scaling modulus raise; only the P'-dependent tables are new.
  • Auxiliary modulus P': ~66 bits for bottom moduli of at most 60 bits (two 33-bit primes, or three ~22-bit primes when the register word size is at most 33 bits), and ~127 bits (split into primes fitting the register word size) for larger bottom moduli of up to 121 bits, where the Hamming weight of the sparse secret is also increased from 32 to 64. The primes of the composite cases are searched upwards so that enough primes exist up to ring dimension 2^17 (verified).
  • With composite scaling, the sparse-encapsulated case uses the K = 25 approximation of the modular reduction: the existing coefficient tables in functional bootstrapping and a new degree-44 table (g_coefficientsSparseAlt) in regular bootstrapping, generated from the closed form of the Chebyshev coefficients (Bessel functions). GetFBTDepth/AdjustDepthFBT take an optional composite degree to select the same tables.
  • The modulus raise of the three bootstrapping flavors is factored into ModRaiseInPlace.

Precision

Composite scaling vs FLEXIBLEAUTO for the same parameters (UNIFORM_TERNARY, 59/60-bit moduli, noise/precision in bits):

  • SlotsToCoeffs-first bootstrapping: within ~1–2 bits at ring 2^12 and ahead of FLEXIBLEAUTO in most configurations at rings 2^13/2^14 (e.g., 2^14: 8 slots +2.4, 1024 slots +1.5, full packing +1.2).
  • Functional bootstrapping (output noise): identical within 0.6 bits with full packing at rings 2^12–2^14 for binary, 4-bit and 8-bit LUTs, sparse and uniform ternary; the 8-slot configurations are multimodal for both techniques and agree in distribution.

Tests

  • UnitTestCKKSrnsCompositeScalingBootstrap.cpp: StC-first variants for all test types; SPARSE_ENCAPSULATED rows for composite degrees 2 and 3 (66- and 127-bit auxiliary moduli); a KeySwitchSparse round-trip test over the composite bottom basis; the largest scaling factors (119 bits with a 120-bit first modulus at register word size 64, and 120 bits with a 121-bit first modulus at register word size 32).
  • UnitTestCKKSrnsCompositeScalingVsFlexible.cpp: four StC-first CS-vs-FA regression tests.
  • UnitTestFBT.cpp: COMPOSITESCALINGAUTO rows (LUTs, sign digit, consecutive levels, MVB, multi-limb initial scaling, 90-bit scaling factors), COMPOSITESCALINGMANUAL rows, SPARSE_ENCAPSULATED + composite rows, the largest scaling factors, and a new FBT_NOISE_VS_FLEXIBLE test type asserting that the composite scaling noise is within 3 bits of FLEXIBLEAUTO (maximum over three runs, for robustness against the key-dependent approximation error).

The full PKE unit test suite passes (2029 tests).

Documentation

COMPOSITE_SCALING.md and CKKS_FUNCTIONAL_BOOTSTRAPING.md describe the supported modes, the first-modulus requirement, the auxiliary modulus rules of sparse encapsulation, and the support of scaling factors above 64 bits; the functional bootstrapping example comments were updated accordingly.

🤖 Generated with Claude Code

Yuriy Polyakov and others added 3 commits August 26, 2026 11:27
…trapping mode

The SlotsToCoeffs-first slot-encoding mode (BTSlotsEncoding = true) now
works with COMPOSITESCALINGAUTO/MANUAL. Three issues were fixed in
EvalBootstrapStCFirst / EvalBootstrap:

- The expected input level counted levels in degree-1 units, while the
  SlotsToCoeffs matrix is encoded for compositeDegree * (levelBudget + 2)
  remaining towers, which caused a modulus mismatch for composite scaling.
- The level adjustment applied when the input has extra levels mixed up
  the current and target levels (relative to AdjustLevelsAndDepthInPlace).
  This is invisible for FLEXIBLEAUTO but capped the composite scaling
  precision at ~15 bits.
- When deg = log2(q0 / 2^p) exceeds the correction factor (allowed for
  composite scaling), the correction is now clamped to 0 instead of
  wrapping around (affected both bootstrapping modes, e.g., for
  composite degree 3 or a small correction factor).

Precision of composite scaling is comparable to FLEXIBLEAUTO in this mode
(within ~1-3 bits, and typically better at ring dimension 2^14), matching
the behavior of the ModRaise-first mode.

The composite scaling bootstrapping unit tests now also run the StC-first
variant (FULL/EDGE/SPARSE, ITERATIVE, NUM_TOWERS, SERIALIZE), and four
CS-vs-FA precision regression tests were added for this mode. Removed
stale TODO notes that predate PR #1245.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Composite scaling is handled like the FLEXIBLE* modes (the raised
ciphertext is declared to carry the level-specific scaling factor and
the ratios to the nominal 2^p are folded into the encoding/decoding
matrices), with all tower counts scaled by the composite degree: the
modulus of the bottom level and of the output, the levels of the
homomorphic encoding/decoding matrices, the modulus raise (via
ExtendCiphertext), the rescaling steps, and the level reduction in
EvalHomDecoding. SchemeletRLWEMP interprets levels in multiplicative
levels for composite scaling.

Two precision issues that were invisible for single-prime moduli were
fixed along the way:
- The ratio between the bottom modulus and the closest power of two
  (pre) was folded into the matrices although the correction applied
  after the modulus raise already removes it exactly; for composite
  moduli (~2^-10 off a power of two) this scaled the mod-raise
  overflows and cost ~14 bits. It is now applied only in FIXED* modes.
- For UNIFORM_TERNARY the division by K_UNIFORM was applied as a tiny
  scalar (~1/(K*N)) after the modulus raise, whose encoding at the
  scaling factor loses precision unless the scaling factor is close to a
  power of two. The division by K is now folded into the CoeffsToSlots
  matrix for all distributions, which also avoids amplifying the
  CoeffsToSlots key-switching noise by K.

The output noise of composite scaling matches FLEXIBLEAUTO for the same
parameters (within ~0.5 bits at ring dimensions 2^12-2^14). Composite
scaling also enables scaling factors above 64 bits (e.g., 90 bits).

Unit tests: COMPOSITESCALINGAUTO rows 1001-1014 and 1031-1037 (90-bit
scaling factor), COMPOSITESCALINGMANUAL rows 1041-1047, and the new
FBT_NOISE_VS_FLEXIBLE test type (rows 1021-1024, 1047) comparing the
noise with FLEXIBLEAUTO. Documentation updated accordingly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ootstrapping flavors

Sparse secret encapsulation now works with COMPOSITESCALING* in
ModRaise-first bootstrapping, SlotsToCoeffs-first bootstrapping, and
functional bootstrapping.

- The sparse key switching is defined over the bottom basis
  Ql = {q_0, ..., q_{d-1}} (d = composite degree): the ciphertext and the
  keys are extended from Ql to the auxiliary basis P' and scaled back down
  with exact (HPS-style) CRT basis switches over all d limbs (the
  single-limb centered lift is kept for d = 1). The Ql-only tables are
  shared with the composite scaling modulus raise; only the P'-dependent
  tables are new.
- Auxiliary modulus P': ~66 bits for bottom moduli of at most 60 bits
  (two 33-bit primes, or three ~22-bit primes when the register word size
  is at most 33 bits), and ~127 bits (split into primes fitting the
  register word size) for larger bottom moduli of up to 121 bits, where
  the Hamming weight of the sparse secret is also increased from 32 to 64.
  The primes of the composite cases are searched upwards so that enough
  primes exist up to ring dimension 2^17.
- With composite scaling, the sparse-encapsulated case uses the K = 25
  approximation of the modular reduction: the existing coefficient tables
  in functional bootstrapping and a new degree-44 table
  (g_coefficientsSparseAlt) in regular bootstrapping, generated from the
  closed form of the Chebyshev coefficients (Bessel functions).
- The modulus raise of the three bootstrapping flavors is factored into
  ModRaiseInPlace. GetFBTDepth/AdjustDepthFBT take an optional composite
  degree to select the same approximation tables.

Unit tests: composite scaling bootstrapping with SPARSE_ENCAPSULATED for
composite degrees 2 and 3 (66- and 127-bit auxiliary moduli), a key
switching test over the composite bottom basis, functional bootstrapping
rows with SPARSE_ENCAPSULATED (including 90-bit scaling factors and
COMPOSITESCALINGMANUAL), and the largest scaling factors: 119 bits with a
120-bit first modulus (register word size 64) and 120 bits with a 121-bit
first modulus (register word size 32). The noise comparison with
FLEXIBLEAUTO in the functional bootstrapping tests uses the maximum over
three runs to be robust to the key-dependent approximation error.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Yuriy Polyakov and others added 2 commits August 28, 2026 15:21
…E_SIZE=128)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The 119/120-bit scaling factor rows (and the deeper 90-bit functional
bootstrapping rows) need modulus chains beyond the fixed 3500-bit width
of the MATHBACKEND 2 multiprecision integers.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@yspolyakov
yspolyakov requested a review from pascoec August 28, 2026 21:27
@pascoec pascoec self-assigned this Aug 29, 2026
@pascoec
pascoec merged commit d0d03be into dev Sep 1, 2026
19 checks passed
@pascoec
pascoec deleted the issue-1267 branch September 1, 2026 03:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

new feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add COMPOSITESCALING* support for StC-First CKKS boostrapping Add FBT and sparse encapsulation support for COMPOSITESCALING* modes

2 participants