Skip to content

CKKS Bootstrapping

When a ciphertext is created, it has a fixed multiplication count called a level. When two cipehrtexts are multiplied, the resulting ciphertext will have the level reduced by one compared to the input ciphertexts. A ciphertext with level 0 can no longer be multiplied. It is possible to reset this level to a higher value by the bootstrapping operation.

Regular Bootstrap

The Bootstrapping operation requires the bootstrap key. The bootstrap key incorporates every single fixed rotation key that is needed by the bootstrap operation. Because of this, the bootstrap key is quite large (about 12.3GB).

from desilofhe import Engine

engine = Engine(use_bootstrap=True)
secret_key = engine.create_secret_key()
public_key = engine.create_public_key(secret_key)
relinearization_key = engine.create_relinearization_key(secret_key)
conjugation_key = engine.create_conjugation_key(secret_key)
bootstrap_key = engine.create_bootstrap_key(secret_key, stage_count=3)

message = [-1, 0, 1]
ciphertext = engine.encrypt(message, public_key, level=0)
bootstrapped = engine.bootstrap(
    ciphertext, relinearization_key, conjugation_key, bootstrap_key
)

Small Bootstrap Key

Alternatively, the bootstrapping operation can be performed using the rotation key and the small bootstrap key instead of the bootstrapping key. This approach reduces memory usage to around 3.8GB but makes the operation slower.

from desilofhe import Engine

engine = Engine(use_bootstrap=True)
secret_key = engine.create_secret_key()
public_key = engine.create_public_key(secret_key)
relinearization_key = engine.create_relinearization_key(secret_key)
conjugation_key = engine.create_conjugation_key(secret_key)
rotation_key = engine.create_rotation_key(secret_key)
small_bootstrap_key = engine.create_small_bootstrap_key(secret_key)

message = [-1, 0, 1]
ciphertext = engine.encrypt(message, public_key, level=0)
bootstrapped = engine.bootstrap(
    ciphertext,
    relinearization_key,
    conjugation_key,
    rotation_key,
    small_bootstrap_key,
)

bootstrapped_stage_count_5 = engine.bootstrap(
    ciphertext,
    relinearization_key,
    conjugation_key,
    rotation_key,
    small_bootstrap_key,
    stage_count=5,
)

Benchmark

Here are the benchmarks of the bootstrapping operation. The experiments were performed on an Intel(R) Core(TM) i7-10700K CPU @ 3.80GHz for the CPU measurements and an NVIDIA GeForce RTX 5090 for the GPU measurements. These values are the averages of 10 runs.

Key
Size
Stage
Count
Runtime (s)
1 Thread

4 Threads

16 Threads
Sync
GPU
Async
GPU
Small 3 102.904 41.259 30.103 1.664 1.131
Small 4 66.153 26.261 18.669 1.079 0.684
Small 5 66.345 25.235 17.789 0.937 0.530
Medium 3 30.690 12.203 9.529 0.373 0.118
Medium 4 25.035 9.850 7.582 0.307 0.097
Medium 5 24.212 9.231 6.920 0.284 0.090
Large 3 28.222 11.526 9.324 0.375 0.116
Large 4 24.408 9.887 7.932 0.333 0.101
Large 5 22.100 8.611 6.705 0.275 0.087

Compact Representation

Here are the benchmarks of the bootstrapping operation using the compact representation. The experiments were performed on an Intel(R) Core(TM) i7-10700K CPU @ 3.80GHz for the CPU measurements and an NVIDIA GeForce RTX 5090 for the GPU measurements. These values are the averages of 10 runs.

Key
Size
Stage
Count
Runtime (s)
1 Thread

4 Threads

16 Threads
Sync
GPU
Async
GPU
Small 3 98.476 40.204 28.274 1.776 1.183
Small 4 63.749 25.542 18.292 1.107 0.711
Small 5 62.320 24.919 17.625 0.946 0.556
Medium 3 28.779 12.111 9.533 0.396 0.128
Medium 4 24.342 9.973 7.795 0.327 0.108
Medium 5 22.483 9.169 7.057 0.306 0.103
Large 3 27.312 11.737 9.600 0.394 0.127
Large 4 23.831 10.349 8.382 0.352 0.115
Large 5 21.858 8.999 7.086 0.318 0.101

Bootstrap To 14 Levels

The original parameter set for bootstrapping leaves 10 levels after 3 stages. To overcome this, a new parameter set has been introduced to have 14 levels after the bootstrapping operation. Due to the limitations of the new parameter set, the only supported stage count is 3.

from desilofhe import Engine

engine = Engine(use_bootstrap_to_14_levels=True)
secret_key = engine.create_secret_key()
public_key = engine.create_public_key(secret_key)
relinearization_key = engine.create_relinearization_key(secret_key)
conjugation_key = engine.create_conjugation_key(secret_key)
bootstrap_key = engine.create_bootstrap_key(secret_key)

message = [-1, 0, 1]
ciphertext = engine.encrypt(message, public_key, level=0)
bootstrapped = engine.bootstrap(
    ciphertext, relinearization_key, conjugation_key, bootstrap_key
)

Small Bootstrap Key

The small boostrap key can also be used for this parameter set.

from desilofhe import Engine

engine = Engine(use_bootstrap_to_14_levels=True)
secret_key = engine.create_secret_key()
public_key = engine.create_public_key(secret_key)
relinearization_key = engine.create_relinearization_key(secret_key)
conjugation_key = engine.create_conjugation_key(secret_key)
rotation_key = engine.create_rotation_key(secret_key)
small_bootstrap_key = engine.create_small_bootstrap_key(secret_key)

message = [-1, 0, 1]
ciphertext = engine.encrypt(message, public_key, level=0)
bootstrapped = engine.bootstrap(
    ciphertext,
    relinearization_key,
    conjugation_key,
    rotation_key,
    small_bootstrap_key,
)

Benchmark

Here are the benchmarks of the bootstrapping operation to 14 levels. The experiments were performed on an Intel(R) Core(TM) i7-10700K CPU @ 3.80GHz for the CPU measurements and an NVIDIA GeForce RTX 5090 for the GPU measurements. These values are the averages of 10 runs.

Key
Size
Stage
Count
Runtime (s)
1 Thread

4 Threads

16 Threads
Sync
GPU
Async
GPU
Small 3 127.532 50.154 35.938 1.793 1.200
Medium 3 37.972 14.874 11.705 0.417 0.144
Large 3 34.329 14.059 11.428 0.415 0.141

Compact Representation

Here are the benchmarks of the bootstrapping operation to 14 levels using the compact representation. The experiments were performed on an Intel(R) Core(TM) i7-10700K CPU @ 3.80GHz for the CPU measurements and an NVIDIA GeForce RTX 5090 for the GPU measurements. These values are the averages of 10 runs.

Key
Size
Stage
Count
Runtime (s)
1 Thread

4 Threads

16 Threads
Sync
GPU
Async
GPU
Small 3 103.517 41.115 29.097 1.729 1.165
Medium 3 30.020 12.164 9.532 0.419 0.123
Large 3 27.745 11.443 9.478 0.408 0.121

Bootstrap To 17 Levels

A new parameter set has been introduced to have 17 levels after the bootstrapping operation. Due to the limitations of the new parameter set, the only supported stage count is 3.

from desilofhe import Engine

engine = Engine(use_bootstrap_to_17_levels=True)
secret_key = engine.create_secret_key()
public_key = engine.create_public_key(secret_key)
relinearization_key = engine.create_relinearization_key(secret_key)
conjugation_key = engine.create_conjugation_key(secret_key)
bootstrap_key = engine.create_bootstrap_key(secret_key)

message = [-1, 0, 1]
ciphertext = engine.encrypt(message, public_key, level=0)
bootstrapped = engine.bootstrap(
    ciphertext, relinearization_key, conjugation_key, bootstrap_key
)

Small Bootstrap Key

The small bootstrap key can also be used for this parameter set.

from desilofhe import Engine

engine = Engine(use_bootstrap_to_17_levels=True)
secret_key = engine.create_secret_key()
public_key = engine.create_public_key(secret_key)
relinearization_key = engine.create_relinearization_key(secret_key)
conjugation_key = engine.create_conjugation_key(secret_key)
rotation_key = engine.create_rotation_key(secret_key)
small_bootstrap_key = engine.create_small_bootstrap_key(secret_key)

message = [-1, 0, 1]
ciphertext = engine.encrypt(message, public_key, level=0)
bootstrapped = engine.bootstrap(
    ciphertext,
    relinearization_key,
    conjugation_key,
    rotation_key,
    small_bootstrap_key,
)

Benchmark

Here are the benchmarks of the bootstrapping operation to 17 levels. The experiments were performed on an Intel(R) Core(TM) i7-10700K CPU @ 3.80GHz for the CPU measurements and an NVIDIA GeForce RTX 5090 for the GPU measurements. These values are the averages of 10 runs.

Key
Size
Stage
Count
Runtime (s)
1 Thread

4 Threads

16 Threads
Sync
GPU
Async
GPU
Small 3 155.058 60.656 44.093 1.929 1.263
Medium 3 46.211 18.292 14.372 0.470 0.169
Large 3 41.048 17.089 13.993 0.479 0.164

Compact Representation

Here are the benchmarks of the bootstrapping operation to 17 levels using the compact representation. The experiments were performed on an Intel(R) Core(TM) i7-10700K CPU @ 3.80GHz for the CPU measurements and an NVIDIA GeForce RTX 5090 for the GPU measurements. These values are the averages of 10 runs.

Key
Size
Stage
Count
Runtime (s)
1 Thread

4 Threads

16 Threads
Sync
GPU
Async
GPU
Small 3 124.160 49.284 35.525 1.844 1.220
Medium 3 36.097 14.576 11.480 0.435 0.142
Large 3 33.296 13.888 11.348 0.425 0.140

Sparse Bootstrap

The bootstrapping operation is faster with a reduced slot_count. The sparse bootstrapping operation can be done with either a bootstrap key or a small bootstrap key.

Bootstrap Key

from desilofhe import Engine

engine = Engine(slot_count=1024, use_bootstrap=True)
secret_key = engine.create_secret_key()
public_key = engine.create_public_key(secret_key)
relinearization_key = engine.create_relinearization_key(secret_key)
conjugation_key = engine.create_conjugation_key(secret_key)
bootstrap_key = engine.create_bootstrap_key(secret_key, stage_count=3)

message = [-1, 0, 1, 0] * 256
ciphertext = engine.encrypt(message, public_key, level=0)
bootstrapped = engine.bootstrap(
    ciphertext, relinearization_key, conjugation_key, bootstrap_key
)

Small Bootstrap Key

from desilofhe import Engine

engine = Engine(slot_count=1024, use_bootstrap=True)
secret_key = engine.create_secret_key()
public_key = engine.create_public_key(secret_key)
relinearization_key = engine.create_relinearization_key(secret_key)
conjugation_key = engine.create_conjugation_key(secret_key)
rotation_key = engine.create_rotation_key(secret_key)
small_bootstrap_key = engine.create_small_bootstrap_key(secret_key)

message = [-1, 0, 1, 0] * 256
ciphertext = engine.encrypt(message, public_key, level=0)
bootstrapped = engine.bootstrap(
    ciphertext,
    relinearization_key,
    conjugation_key,
    rotation_key,
    small_bootstrap_key,
    stage_count=1,
)

Benchmark

Here are the benchmarks of the sparse bootstrapping operation. The experiments were performed on an Intel(R) Core(TM) i7-10700K CPU @ 3.80GHz for the CPU measurements and an NVIDIA GeForce RTX 5090 for the GPU measurements. These values are the averages of 10 runs.

Slot
Count
Key
Size
Stage
Count
Runtime (s)
1 Thread

4 Threads

16 Threads
Sync
GPU
Async
GPU
32 Small 1 41.705 14.626 10.563 0.375 0.139
32 Small 2 31.067 11.609 8.328 0.289 0.108
32 Medium 1 26.632 10.325 7.650 0.261 0.094
32 Medium 2 25.631 9.504 6.969 0.236 0.087
32 Large 1 26.711 10.351 7.775 0.268 0.096
1024 Small 2 66.192 24.287 17.154 0.651 0.242
1024 Small 3 46.943 16.965 12.135 0.440 0.169
1024 Small 4 43.536 15.827 11.320 0.416 0.157
1024 Medium 2 29.304 11.423 8.720 0.330 0.108
1024 Medium 3 25.584 9.798 7.326 0.272 0.091
1024 Medium 4 24.445 9.171 6.801 0.252 0.087
1024 Large 2 27.636 11.060 8.661 0.319 0.107
1024 Large 3 24.302 9.590 7.405 0.279 0.093

Lossy Bootstap

The lossy bootstrap operation is faster while sacrificing some precision. The resulting significant figures below the decimal is about halved. In general, the regular bootstrapping is the recommended method, but depending on the precision requirements this method could also be useful. The lossy bootstrapping operation can be done with either a lossy bootstrap key or a small bootstrap key. The lossy bootstrapping operation is not supported for the bootstrap to 14 levels or bootstrap to 17 levels parameter sets.

Lossy Bootstrap Key

from desilofhe import Engine

engine = Engine(use_bootstrap=True)
secret_key = engine.create_secret_key()
public_key = engine.create_public_key(secret_key)
relinearization_key = engine.create_relinearization_key(secret_key)
conjugation_key = engine.create_conjugation_key(secret_key)
lossy_bootstrap_key = engine.create_lossy_bootstrap_key(
    secret_key, stage_count=3
)

message = [-1, 0, 1]
ciphertext = engine.encrypt(message, public_key, level=3)
bootstrapped = engine.lossy_bootstrap(
    ciphertext, relinearization_key, conjugation_key, lossy_bootstrap_key
)

Small Bootstrap Key

from desilofhe import Engine

engine = Engine(use_bootstrap=True)
secret_key = engine.create_secret_key()
public_key = engine.create_public_key(secret_key)
relinearization_key = engine.create_relinearization_key(secret_key)
conjugation_key = engine.create_conjugation_key(secret_key)
rotation_key = engine.create_rotation_key(secret_key)
small_bootstrap_key = engine.create_small_bootstrap_key(secret_key)

message = [-1, 0, 1]
ciphertext_level_3 = engine.encrypt(message, public_key, level=3)
bootstrapped = engine.lossy_bootstrap(
    ciphertext_level_3,
    relinearization_key,
    conjugation_key,
    rotation_key,
    small_bootstrap_key,
)

ciphertext_level_5 = engine.encrypt(message, public_key, level=5)
bootstrapped_stage_count_5 = engine.lossy_bootstrap(
    ciphertext_level_5,
    relinearization_key,
    conjugation_key,
    rotation_key,
    small_bootstrap_key,
    stage_count=5,
)

Benchmark

Here are the benchmarks of the lossy bootstrapping operation. The experiments were performed on an Intel(R) Core(TM) i7-10700K CPU @ 3.80GHz for the CPU measurements and an NVIDIA GeForce RTX 5090 for the GPU measurements. These values are the averages of 10 runs.

Key
Size
Stage
Count
Runtime (s)
1 Thread

4 Threads

16 Threads
Sync
GPU
Async
GPU
Small 3 80.181 31.917 22.980 1.544 1.074
Small 4 54.390 21.291 15.389 0.980 0.643
Small 5 55.148 21.555 15.371 0.858 0.499
Medium 3 24.591 9.692 7.459 0.306 0.096
Medium 4 20.403 8.047 6.170 0.264 0.080
Medium 5 20.513 7.773 5.808 0.234 0.075
Large 3 22.263 9.197 7.349 0.313 0.095
Large 4 19.808 8.141 6.479 0.273 0.084
Large 5 18.335 7.247 5.618 0.235 0.073

Lossy bootstrapping is optimized for ciphertexts that contain only real values.

Key
Size
Stage
Count
Runtime (s)
1 Thread

4 Threads

16 Threads
Sync
GPU
Async
GPU
Small 3 73.859 32.329 21.735 1.488 1.055
Small 4 48.945 19.163 13.971 0.916 0.629
Small 5 50.433 19.589 14.007 0.779 0.483
Medium 3 18.415 7.347 5.780 0.245 0.075
Medium 4 14.895 5.918 4.591 0.196 0.060
Medium 5 14.999 5.692 4.332 0.173 0.056
Large 3 16.392 6.859 5.650 0.247 0.074
Large 4 14.107 5.956 4.890 0.210 0.065
Large 5 13.179 5.196 4.134 0.172 0.055

Sign Bootstrap

The sign bootstrapping operation is a variant of the lossy bootstrap that enables bootstrapping of sign values, i.e., -1 and 1, with higher precision. Although this is applicable only to sign values, the resulting ciphertext achieves roughly three times more significant digits. By efficiently reducing the noise of sign values, this operation facilitates fast and high-precision comparison functions such as min and max. The sign bootstrapping can be performed with either a small bootstrap key or a lossy bootstrap key. The sign bootstrapping operation is not supported for the bootstrap to 14 levels or bootstrap to 17 levels parameter sets.

Sign Bootstrap with Lossy Bootstrap Key

from desilofhe import Engine

engine = Engine(use_bootstrap=True)
secret_key = engine.create_secret_key()
public_key = engine.create_public_key(secret_key)
relinearization_key = engine.create_relinearization_key(secret_key)
conjugation_key = engine.create_conjugation_key(secret_key)
lossy_bootstrap_key = engine.create_lossy_bootstrap_key(
    secret_key, stage_count=3
)

message = [-1, 1]
ciphertext = engine.encrypt(message, public_key, level=3)
bootstrapped = engine.sign_bootstrap(
    ciphertext, relinearization_key, conjugation_key, lossy_bootstrap_key
)

Small Bootstrap Key

from desilofhe import Engine

engine = Engine(use_bootstrap=True)
secret_key = engine.create_secret_key()
public_key = engine.create_public_key(secret_key)
relinearization_key = engine.create_relinearization_key(secret_key)
conjugation_key = engine.create_conjugation_key(secret_key)
rotation_key = engine.create_rotation_key(secret_key)
small_bootstrap_key = engine.create_small_bootstrap_key(secret_key)

message = [-1, 1]
ciphertext_level_3 = engine.encrypt(message, public_key, level=3)
bootstrapped = engine.sign_bootstrap(
    ciphertext_level_3,
    relinearization_key,
    conjugation_key,
    rotation_key,
    small_bootstrap_key,
)

ciphertext_level_5 = engine.encrypt(message, public_key, level=5)
bootstrapped_stage_count_5 = engine.sign_bootstrap(
    ciphertext_level_5,
    relinearization_key,
    conjugation_key,
    rotation_key,
    small_bootstrap_key,
    stage_count=5,
)

Benchmark

Here are the benchmarks of the sign bootstrapping operation. The experiments were performed on an Intel(R) Core(TM) i7-10700K CPU @ 3.80GHz for the CPU measurements and an NVIDIA GeForce RTX 5090 for the GPU measurements. These values are the averages of 10 runs.

Key
Size
Stage
Count
Runtime (s)
1 Thread

4 Threads

16 Threads
Sync
GPU
Async
GPU
Small 3 79.947 31.870 23.184 1.530 1.071
Small 4 54.298 21.360 15.341 0.998 0.647
Small 5 56.108 21.584 15.342 0.836 0.497
Medium 3 24.177 9.720 7.465 0.326 0.096
Medium 4 20.565 8.119 6.184 0.255 0.080
Medium 5 20.325 7.780 5.807 0.235 0.075
Large 3 22.490 9.221 7.351 0.324 0.094
Large 4 20.182 8.166 6.496 0.288 0.084
Large 5 18.584 7.276 5.640 0.243 0.073

Sign bootstrapping is optimized for ciphertexts that contain only real values.

Key
Size
Stage
Count
Runtime (s)
1 Thread

4 Threads

16 Threads
Sync
GPU
Async
GPU
Small 3 72.616 29.674 21.773 1.468 1.053
Small 4 49.053 19.208 13.971 0.926 0.630
Small 5 50.633 19.477 14.039 0.778 0.483
Medium 3 18.504 7.344 5.761 0.249 0.075
Medium 4 15.020 5.936 4.607 0.193 0.060
Medium 5 15.073 5.748 4.329 0.173 0.056
Large 3 16.357 6.869 5.647 0.250 0.074
Large 4 14.308 5.910 4.880 0.207 0.064
Large 5 12.928 5.227 4.141 0.177 0.054

Comparison of Bootstrapping Error for Sign Messages

The following shows the average error observed when bootstrapping sign messages (i.e., -1 and 1) using the regular, lossy, and sign bootstrapping methods, respectively.

Regular
Bootstrap
Lossy
Bootstrap
Sign
Bootstrap
Average error 8.03008e-4 1.60562e-3 1.98124e-08
Precision 10.3 bits 9.3 bits 25.6 bits

Precision of Bootstrapping

The following represents the precision of the bootstrapping operation. It is the average of the bootstrapping error measured over messages uniformly distributed in the interval [-1, 1]. When evaluating the precision of the sign bootstrapping, we use only the sign values (i.e., -1 and 1).

Average error Precision Compact
Average error
Compact
Precision
Bootstrap 6.72878e-07 20.5 bits 6.67666e-07 20.5 bits
Bootstrap to 14 Levels 7.29874e-06 17.1 bits 2.67900e-05 15.2 bits
Bootstrap to 17 Levels 1.08748e-06 19.8 bits 7.02514e-07 20.4 bits
Sparse Bootstrap 2.59681e-07 21.9 bits 2.53088e-07 21.9 bits
Lossy Bootstrap 4.01552e-4 11.3 bits 3.80117e-4 11.4 bits
Sign Bootstrap 1.98124e-08 25.6 bits 2.20190e-08 25.4 bits

The errors were measured with the following code.

Bootstrap
import numpy as np
from desilofhe import Engine

engine = Engine(use_bootstrap=True)

secret_key = engine.create_secret_key()
relinearization_key = engine.create_relinearization_key(secret_key)
conjugation_key = engine.create_conjugation_key(secret_key)
bootstrap_key = engine.create_bootstrap_key(secret_key)

message = np.linspace(-1, 1, engine.slot_count)

ciphertext = engine.encrypt(message, secret_key)
bootstrapped = engine.bootstrap(
    ciphertext, relinearization_key, conjugation_key, bootstrap_key
)
decrypted = engine.decrypt(bootstrapped, secret_key)

average_noise = np.mean(abs(message - decrypted))
print(f"Bootstrap Average Noise :{average_noise}")
print(f"Bootstrap Average Noise (Bits) :{np.log2(average_noise)}")
Bootstrap to 14 Levels
import numpy as np
from desilofhe import Engine

engine = Engine(use_bootstrap_to_14_levels=True)

secret_key = engine.create_secret_key()
relinearization_key = engine.create_relinearization_key(secret_key)
conjugation_key = engine.create_conjugation_key(secret_key)
bootstrap_key = engine.create_bootstrap_key(secret_key)

message = np.linspace(-1, 1, engine.slot_count)

ciphertext = engine.encrypt(message, secret_key)
bootstrapped = engine.bootstrap(
    ciphertext, relinearization_key, conjugation_key, bootstrap_key
)
decrypted = engine.decrypt(bootstrapped, secret_key)

average_noise = np.mean(abs(message - decrypted))
print(f"BootstrapTo14Levels Average Noise :{average_noise}")
print(f"BootstrapTo14Levels Average Noise (Bits) :{np.log2(average_noise)}")
Bootstrap to 17 Levels
import numpy as np
from desilofhe import Engine

engine = Engine(use_bootstrap_to_17_levels=True)

secret_key = engine.create_secret_key()
relinearization_key = engine.create_relinearization_key(secret_key)
conjugation_key = engine.create_conjugation_key(secret_key)
bootstrap_key = engine.create_bootstrap_key(secret_key)

message = np.linspace(-1, 1, engine.slot_count)

ciphertext = engine.encrypt(message, secret_key)
bootstrapped = engine.bootstrap(
    ciphertext, relinearization_key, conjugation_key, bootstrap_key
)
decrypted = engine.decrypt(bootstrapped, secret_key)

average_noise = np.mean(abs(message - decrypted))
print(f"BootstrapTo17Levels Average Noise :{average_noise}")
print(f"BootstrapTo17Levels Average Noise (Bits) :{np.log2(average_noise)}")
Sparse Bootstrap
import numpy as np
from desilofhe import Engine

engine = Engine(slot_count=1024, use_bootstrap=True)

secret_key = engine.create_secret_key()
relinearization_key = engine.create_relinearization_key(secret_key)
conjugation_key = engine.create_conjugation_key(secret_key)
bootstrap_key = engine.create_bootstrap_key(secret_key)

message = np.linspace(-1, 1, engine.slot_count)

ciphertext = engine.encrypt(message, secret_key)
bootstrapped = engine.bootstrap(
    ciphertext, relinearization_key, conjugation_key, bootstrap_key
)
decrypted = engine.decrypt(bootstrapped, secret_key)

average_noise = np.mean(abs(message - decrypted))
print(f"SparseBootstrap Average Noise :{average_noise}")
print(f"SparseBootstrap Average Noise (Bits) :{np.log2(average_noise)}")
Lossy Bootstrap
import numpy as np
from desilofhe import Engine

engine = Engine(use_bootstrap=True)

secret_key = engine.create_secret_key()
relinearization_key = engine.create_relinearization_key(secret_key)
conjugation_key = engine.create_conjugation_key(secret_key)
lossy_bootstrap_key = engine.create_lossy_bootstrap_key(secret_key)

message = np.linspace(-1, 1, engine.slot_count)

ciphertext = engine.encrypt(message, secret_key)
bootstrapped = engine.lossy_bootstrap(
    ciphertext, relinearization_key, conjugation_key, lossy_bootstrap_key
)
decrypted = engine.decrypt(bootstrapped, secret_key)

average_noise = np.mean(abs(message - decrypted))
print(f"Lossy Bootstrap Average Noise :{average_noise}")
print(f"Lossy Bootstrap Average Noise (Bits) :{np.log2(average_noise)}")
Sign Bootstrap
import numpy as np
from desilofhe import Engine

engine = Engine(use_bootstrap=True)

secret_key = engine.create_secret_key()
relinearization_key = engine.create_relinearization_key(secret_key)
conjugation_key = engine.create_conjugation_key(secret_key)
lossy_bootstrap_key = engine.create_lossy_bootstrap_key(secret_key)

message = [-1, 1] * (engine.slot_count // 2)

ciphertext = engine.encrypt(message, secret_key)
bootstrapped = engine.sign_bootstrap(
    ciphertext, relinearization_key, conjugation_key, lossy_bootstrap_key
)
decrypted = engine.decrypt(bootstrapped, secret_key)

average_noise = np.mean(abs(message - decrypted))
print(f"Sign Bootstrap Average Noise :{average_noise}")
print(f"Sign Bootstrap Average Noise (Bits) :{np.log2(average_noise)}")