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.979 43.738 30.636 2.442 1.840
Small 4 66.189 27.845 19.376 1.620 1.203
Small 5 65.031 26.751 18.488 1.495 1.086
Medium 3 30.482 12.709 9.777 0.722 0.458
Medium 4 25.075 10.285 7.782 0.583 0.380
Medium 5 24.033 9.659 7.141 0.549 0.361
Large 3 27.592 11.929 9.503 0.699 0.442
Large 4 24.273 10.190 8.088 0.617 0.390
Large 5 21.949 8.920 6.856 0.534 0.346

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.083 41.808 29.179 3.031 2.400
Small 4 62.997 26.939 18.850 1.967 1.543
Small 5 61.404 26.086 18.224 1.869 1.425
Medium 3 29.168 12.484 9.741 0.842 0.577
Medium 4 24.295 10.288 7.997 0.724 0.507
Medium 5 22.049 9.523 7.245 0.701 0.497
Large 3 26.965 11.969 9.784 0.829 0.559
Large 4 24.112 10.623 8.523 0.767 0.521
Large 5 21.865 9.339 7.275 0.687 0.481

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.183 53.607 38.155 2.676 2.018
Medium 3 37.630 15.690 12.093 0.785 0.514
Large 3 34.144 14.629 11.701 0.770 0.490

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 96.607 41.396 28.807 2.476 1.816
Medium 3 28.657 12.085 9.265 0.710 0.448
Large 3 26.619 11.211 9.028 0.691 0.435

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 154.487 66.145 47.710 2.863 2.166
Medium 3 45.767 19.565 15.121 0.883 0.570
Large 3 41.453 18.107 14.564 0.859 0.537

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 123.560 51.713 36.836 2.958 2.309
Medium 3 35.435 15.392 11.872 0.801 0.527
Large 3 32.605 14.441 11.603 0.795 0.505

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 40.905 15.711 11.017 0.716 0.471
32 Small 2 31.569 12.334 8.700 0.567 0.388
32 Medium 1 26.583 10.970 7.938 0.520 0.348
32 Medium 2 25.555 10.033 7.247 0.480 0.328
32 Large 1 26.316 10.882 8.037 0.536 0.352
1024 Small 2 67.003 26.019 17.875 1.159 0.771
1024 Small 3 45.925 18.041 12.680 0.863 0.572
1024 Small 4 43.357 16.900 11.819 0.818 0.553
1024 Medium 2 28.677 12.027 8.968 0.635 0.407
1024 Medium 3 25.641 10.282 7.550 0.539 0.353
1024 Medium 4 24.283 9.554 7.059 0.511 0.341
1024 Large 2 27.722 11.487 8.879 0.614 0.399
1024 Large 3 24.191 10.106 7.606 0.533 0.353

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 79.813 33.948 24.553 2.156 1.632
Small 4 54.211 22.786 16.024 1.456 1.075
Small 5 55.901 22.823 16.044 1.334 0.967
Medium 3 24.104 10.161 7.703 0.587 0.373
Medium 4 20.707 8.424 6.376 0.486 0.313
Medium 5 20.400 8.176 6.029 0.463 0.299
Large 3 22.606 9.456 7.542 0.578 0.363
Large 4 19.736 8.394 6.639 0.516 0.321
Large 5 18.562 7.552 5.812 0.458 0.288

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.574 31.509 22.732 2.030 1.552
Small 4 48.290 20.416 14.509 1.311 0.995
Small 5 49.929 20.603 14.565 1.204 0.893
Medium 3 18.410 7.727 5.941 0.459 0.290
Medium 4 14.922 6.131 4.718 0.359 0.233
Medium 5 14.926 5.998 4.483 0.337 0.222
Large 3 16.110 7.112 5.755 0.448 0.280
Large 4 14.107 6.157 4.990 0.377 0.240
Large 5 12.922 5.422 4.241 0.324 0.210

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.693 34.070 23.847 2.160 1.634
Small 4 54.426 22.689 15.998 1.446 1.073
Small 5 54.867 22.738 16.032 1.332 0.968
Medium 3 24.044 10.112 7.708 0.598 0.374
Medium 4 20.681 8.448 6.387 0.488 0.313
Medium 5 20.310 8.151 6.025 0.467 0.299
Large 3 22.449 9.415 7.551 0.594 0.364
Large 4 20.038 8.380 6.639 0.507 0.321
Large 5 18.174 7.610 5.816 0.449 0.288

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.303 35.038 22.616 2.018 1.550
Small 4 48.873 20.401 14.493 1.315 0.996
Small 5 50.591 20.610 14.576 1.198 0.893
Medium 3 18.353 7.758 5.942 0.458 0.290
Medium 4 14.662 6.194 4.724 0.358 0.233
Medium 5 14.703 6.004 4.468 0.341 0.222
Large 3 16.460 7.082 5.753 0.453 0.280
Large 4 14.282 6.192 4.975 0.379 0.240
Large 5 12.935 5.444 4.247 0.328 0.210

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)}")