Hello,
I am trying to implement matrix multiplication using the Baby-Step Giant-Step (BSGS) method in CKKS.
To reduce the number of encryptions, I would like to reuse rotated Plaintexts (not Ciphertexts).
So I attempted to implement a Plaintext version of EvalRotate using AutomorphismTransform.
My implementation is based on the same logic used in EvalRotate for Ciphertext.
cryptocontext.cpp
template<>
Plaintext CryptoContextImpl<DCRTPoly>::EvalRotate(
const Plaintext &pt, int32_t index) const
{
auto derived = std::dynamic_pointer_cast<CKKSPackedEncoding>(pt);
if (!derived) {
OPENFHE_THROW("Plaintext is not CKKSPackedEncoding");
}
Plaintext result =
std::make_shared<CKKSPackedEncoding>(*derived);
uint32_t N = pt->GetElementRingDimension();
usint M = N * 2;
uint32_t autoIndex =
FindAutomorphismIndex2nComplex(index, M);
std::vector<usint> vec(N);
PrecomputeAutoMap(N, autoIndex, &vec);
auto& res = result->GetElement<DCRTPoly>();
res = res.AutomorphismTransform(autoIndex, vec);
return result;
}
main.cpp
#include "openfhe.h"
#include <vector>
using namespace lbcrypto;
CryptoContext<DCRTPoly> generate_params(){
CCParams<CryptoContextCKKSRNS> parameters;
SecretKeyDist secretKeyDist = UNIFORM_TERNARY;
usint firstMod = 60;
parameters.SetSecretKeyDist(secretKeyDist);
parameters.SetSecurityLevel(HEStd_NotSet);
parameters.SetMultiplicativeDepth(0);
parameters.SetScalingModSize(40);
parameters.SetFirstModSize(firstMod);
parameters.SetRingDim(8);
parameters.SetKeySwitchTechnique(HYBRID);
CryptoContext<DCRTPoly> cc = GenCryptoContext(parameters);
return cc;
}
int main() {
CryptoContext<DCRTPoly> cc = generate_params();
cc->Enable(PKE);
cc->Enable(KEYSWITCH);
cc->Enable(LEVELEDSHE);
std::vector<double> input({0.1, 0.2, 0.3, 0.4});
size_t encodedLength = input.size();
Plaintext plaintext = cc->MakeCKKSPackedPlaintext(input);
Plaintext plaintextDec = cc->EvalRotate(plaintext, -1);
plaintextDec->SetLength(encodedLength);
std::cout << std::setprecision(15) << std::endl;
std::cout << plaintextDec << std::endl;
return 0;
}
result
before automorphism transform
0: EVAL: [1013651595554295762 690123443558830424 130323650780292307 1048276539879503589 513039758539482255 355282787011445632 842997710840536249 18133468774611369] modulus: 1152921504606846577
1: EVAL: [350064 365575 273736 59331 511933 378289 456374 226463] modulus: 524353
start automorphism transform
after automorphism transform
0: EVAL: [1048276539879503589 130323650780292307 1013651595554295762 690123443558830424 842997710840536249 18133468774611369 355282787011445632 513039758539482255] modulus: 1152921504606846577
1: EVAL: [59331 273736 350064 365575 456374 226463 378289 511933] modulus: 524353
(0.1, 0.2, 0.3, 0.4, ... ); Estimated precision: 40 bits
When I print the DCRTPoly (EVALUATION representation) before and after AutomorphismTransform,
I clearly see that the NTT values are permuted.
However, when printing the resulting Plaintext (CKKSPackedEncoding),
the slot values appear unchanged.
Is applying AutomorphismTransform directly on the underlying DCRTPoly
sufficient to achieve CKKS slot rotation for Plaintext?
Thank you.