# Order of Automorphism and Key-Switching in OpenFHE’s EvalAutomorphism (C++)

**URL:** <https://openfhe.discourse.group/t/order-of-automorphism-and-key-switching-in-openfhe-s-evalautomorphism-c/2123>\
**Category:** Library Questions\
**Created:** [August 2, 2025, 11:52am UTC](https://openfhe.discourse.group/t/order-of-automorphism-and-key-switching-in-openfhe-s-evalautomorphism-c/2123 "2025-08-02T11:52:43Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![oksuman](https://avatars.discourse-cdn.com/v4/letter/o/6de8d8/32.png) [@oksuman](https://openfhe.discourse.group/u/oksuman)\
**Post date:** [August 2, 2025, 11:52am UTC](https://openfhe.discourse.group/t/order-of-automorphism-and-key-switching-in-openfhe-s-evalautomorphism-c/2123/1 "2025-08-02T11:52:43Z")

</div>

Hello,

I have a question about the implementation of rotation in OpenFHE.

While inspecting the code, I noticed that when calling the high-level API `EvalRotate`, it internally calls `EvalAutomorphism`. The implementation of `EvalAutomorphism` looks as follows:

```c
template <class Element>
Ciphertext<Element> LeveledSHEBase<Element>::EvalAutomorphism(ConstCiphertext<Element> ciphertext, usint i, const std::map<usint, EvalKey<Element>>& evalKeyMap, CALLER_INFO_ARGS_CPP) const {
    // this operation can be performed on 2-element ciphertexts only
    if (ciphertext->NumberCiphertextElements() != 2) {
        OPENFHE_THROW("Ciphertext should be relinearized before.");
    }

    // verify if the key i exists in the evalKeyMap
    auto evalKeyIterator = evalKeyMap.find(i);
    if (evalKeyIterator == evalKeyMap.end()) {
        OPENFHE_THROW("EvalKey for index [" + std::to_string(i) + "] is not found." + CALLER_INFO);
    }
    const std::vector<Element>& cv = ciphertext->GetElements();

    usint N = cv[0].GetRingDimension();

    std::vector<usint> vec(N);
    PrecomputeAutoMap(N, i, &vec);

    auto algo = ciphertext->GetCryptoContext()->GetScheme();

    Ciphertext<Element> result = ciphertext->Clone();

    algo->KeySwitchInPlace(result, evalKeyIterator->second);

    std::vector<Element>& rcv = result->GetElements();

    rcv[0] = rcv[0].AutomorphismTransform(i, vec);
    rcv[1] = rcv[1].AutomorphismTransform(i, vec);

    return result;
}

```

From my understanding, an automorphism-based rotation typically involves applying an automorphism first, followed by key switching. This is conceptually similar to how multiplication involves tensoring followed by relinearization.

However, in the above code, **key switching is performed before the automorphism** , which seems counterintuitive. I tried reversing the order as follows:

```auto
    std::vector<usint> vec(N);
    PrecomputeAutoMap(N, i, &vec);

    auto algo = ciphertext->GetCryptoContext()->GetScheme();

    Ciphertext<Element> result = ciphertext->Clone();

    std::vector<Element>& rcv = result->GetElements();
    rcv[0] = rcv[0].AutomorphismTransform(i, vec);
    rcv[1] = rcv[1].AutomorphismTransform(i, vec);

    result->SetElements(rcv);
    algo->KeySwitchInPlace(result, evalKeyIterator->second);

    return result;

```

But this version doesn’t work as. Could you clarify why OpenFHE applies key switching before automorphism? Is there an architectural or correctness reason for this order? And if possible, is there a way to safely revise the code to apply automorphism first and then perform key switching?

Thank you very much!

---

<div class="post-metadata">

**Author:** ![ypolyakov](https://yyz1.discourse-cdn.com/flex031/user_avatar/openfhe.discourse.group/ypolyakov/32/47_2.png) [@ypolyakov](https://openfhe.discourse.group/u/ypolyakov)\
**Post date:** [August 3, 2025, 1:31am UTC](https://openfhe.discourse.group/t/order-of-automorphism-and-key-switching-in-openfhe-s-evalautomorphism-c/2123/2 "2025-08-03T01:31:09Z")

</div>

See the solutions for [CKKS-RNS Automorphism before key-switching leads to excessive noise and decryption failure](https://openfhe.discourse.group/t/ckks-rns-automorphism-before-key-switching-leads-to-excessive-noise-and-decryption-failure/1524) and [EvalAutomorphismKeyGen ModInverse index](https://openfhe.discourse.group/t/evalautomorphismkeygen-modinverse-index/1801)
