# How does function AdjustCiphertext work?

**URL:** <https://openfhe.discourse.group/t/how-does-function-adjustciphertext-work/1695>\
**Category:** FHE Questions\
**Created:** [November 6, 2024, 1:44pm UTC](https://openfhe.discourse.group/t/how-does-function-adjustciphertext-work/1695 "2024-11-06T13:44:01Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![yhh](https://avatars.discourse-cdn.com/v4/letter/y/c57346/32.png) [@yhh](https://openfhe.discourse.group/u/yhh)\
**Post date:** [November 6, 2024, 1:44pm UTC](https://openfhe.discourse.group/t/how-does-function-adjustciphertext-work/1695/1 "2024-11-06T13:44:01Z")

</div>

Hi,

I am trying to learn the bootstrapping procedure, and would like to learn what does `AdjustCiphertext` in bootstrapping procedure do, especially the adjustmentFactor = (targetSF / sourceSF) \* (modToDrop / sourceSF) \* std::pow(2, -correction);  
I understand there is an scaling ( std::pow(2, -correction) before the bs starts and after it ends, but what does the `(targetSF / sourceSF) * (modToDrop / sourceSF)` do?

Great thanks for your help!

---

<div class="post-metadata">

**Author:** ![seyda](https://yyz1.discourse-cdn.com/flex031/user_avatar/openfhe.discourse.group/seyda/32/397_2.png) [@seyda](https://openfhe.discourse.group/u/seyda)\
**Post date:** [November 6, 2024, 3:36pm UTC](https://openfhe.discourse.group/t/how-does-function-adjustciphertext-work/1695/2 "2024-11-06T15:36:48Z")

</div>

I suggest checking the paper “[Approximate Homomorphic Encryption with Reduced Approximation Error](https://eprint.iacr.org/2020/1118)” by Kim et al. It proposes that to avoid the approximate rescaling error in CKKS, we can keep a scale factor (SF) table that holds the SF of each different level corresponding to its RNS modulus. AdjustCiphertext is a method to match the SFs when the input to the Add or Mult operation are two ciphertexts having different levels. When that happens, the one with more #levels is reduced to the SF of the smaller one. Section 4.1 of the paper provides more details.  
modToDrop stems from the method proposed in the same paper to increase the precision by increasing the first-level ct modulus q0. You can check Section 3.2 of the same paper.

---

<div class="post-metadata">

**Author:** ![yhh](https://avatars.discourse-cdn.com/v4/letter/y/c57346/32.png) [@yhh](https://openfhe.discourse.group/u/yhh)\
**Post date:** [November 7, 2024, 4:22pm UTC](https://openfhe.discourse.group/t/how-does-function-adjustciphertext-work/1695/3 "2024-11-07T16:22:33Z")

</div>

Thanks for your reply. And i am still a little confused.

I still dont understand why the sourceFactor is divided by twice, and in normal case do i need to multiply modTodrop every times?

Say the current level is 1, and the noisedeg is 1 as well. If i want to drop three limbs of the ciphertext, and keep the noisedeg=1, how should i set the factors(i.e. what adjustment factor should i multiply to)? Is it correct if i do the operation in sequence {mult(adjustment\_factor), level reduce(#To\_drop -1), and mod reduce?

---

<div class="post-metadata">

**Author:** ![seyda](https://yyz1.discourse-cdn.com/flex031/user_avatar/openfhe.discourse.group/seyda/32/397_2.png) [@seyda](https://openfhe.discourse.group/u/seyda)\
**Post date:** [November 8, 2024, 4:01pm UTC](https://openfhe.discourse.group/t/how-does-function-adjustciphertext-work/1695/4 "2024-11-08T16:01:03Z")

</div>

We do each step of scaling with 2 scales, so at the first adjustment we scale by (target/source) and in the second we scale by (modToDrop/source). These steps are explained in the first paragraph of [page 18](https://eprint.iacr.org/2020/1118.pdf). If you print out the values, you will get results like this:

Added the following print statements to Adjust Ciphertext:

```auto
        std::cout << std::fixed << std::setprecision(0);
        std::cout << "targetSF: " << targetSF << std::endl;
        std::cout << "sourceSF: " << sourceSF << std::endl;
        std::cout << "modToDrop: " << modToDrop << std::endl;
        std::cout << std::fixed << std::setprecision(20);
        std::cout << "targetSF/sourceSF: " << (double)(targetSF/sourceSF) << std::endl;
        std::cout << "modToDrop/sourceSF: " <<(double) (modToDrop/sourceSF) << std::endl;

```

Output of running [bootstrapping example](https://github.com/openfheorg/openfhe-development/blob/7b8346f4eac27121543e36c17237b919e03ec058/src/pke/examples/advanced-ckks-bootstrapping.cpp):

```auto
targetSF: 576460752303439872
sourceSF: 576460752297730048
modToDrop: 576460752297492480
targetSF/sourceSF: 1.00000000000990496574
modToDrop/sourceSF: 0.99999999999958788521

```

For your second question, do you mean, with a level of 1, you will run EvalBootstrap() first and then reduce 3 limbs? Otherwise, you cannot consume 3 levels with a level budget of 1. In EvalBootstrap, the adjustment factor depends on several parameters you set in your script. Have you tried looking at those and their impact on the adjustment factor?

---

<div class="post-metadata">

**Author:** ![yhh](https://avatars.discourse-cdn.com/v4/letter/y/c57346/32.png) [@yhh](https://openfhe.discourse.group/u/yhh)\
**Post date:** [November 9, 2024, 5:50pm UTC](https://openfhe.discourse.group/t/how-does-function-adjustciphertext-work/1695/5 "2024-11-09T17:50:46Z")

</div>

I understand! Great thanks for your help!

---

<div class="post-metadata">

**Author:** ![Haow\_P](https://avatars.discourse-cdn.com/v4/letter/h/da6949/32.png) [@Haow\_P](https://openfhe.discourse.group/u/Haow_P)\
**Post date:** [April 24, 2025, 5:14am UTC](https://openfhe.discourse.group/t/how-does-function-adjustciphertext-work/1695/6 "2025-04-24T05:14:42Z")

</div>

Hi, i see the function Adjust(ct\_1,l\_2) in page 18 of [KPP21]. Is the _(targetSF / sourceSF) \* (modToDrop / sourceSF)_ in _AdjustCiphertext_ refer to the constant _Δ\_{l2} · q\_{l2+1}/Δ\_{l1}_? I understand that targetSF = Δ\_{l2}, sourceSF = Δ\_{l1}, and modToDrop = q\_{l2+1}, but the _(targetSF / sourceSF) \* (modToDrop / sourceSF)_ seems equal to _Δ\_{l2} · q\_{l2+1}/Δ\_{l1} · Δ\_{l1}_. Why there is an extra Δ\_{l1} term in the denominator, am i miss something？
