Hello,
I am currently discovering scheme switching, and I am getting some wrong results after performing AND in fhew…
I added just extra vector, x3 and encoded and encrypted – ptxt3 and c3 – to the example scheme-switching code.
// Inputs
std::vector<double> x1 = {0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0};
std::vector<double> x3 = {1.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 2.0, 3.0, 4.0, 5.0, 1.0};
std::vector<double> x2 = {0.0, 271.0, 30000.0, static_cast<double>(pLWE2) - 2};
uint32_t encodedLength1 = x1.size();
uint32_t encodedLength2 = x2.size();
// Encoding as plaintexts
Plaintext ptxt1 = cc->MakeCKKSPackedPlaintext(x1, 1, 0, nullptr);
Plaintext ptxt3 = cc->MakeCKKSPackedPlaintext(x3, 1, 0, nullptr);
Plaintext ptxt2 = cc->MakeCKKSPackedPlaintext(x2, 1, 0, nullptr);
// Encrypt the encoded vectors
auto c1 = cc->Encrypt(keys.publicKey, ptxt1);
auto c3 = cc->Encrypt(keys.publicKey, ptxt3);
auto c2 = cc->Encrypt(keys.publicKey, ptxt2);
// Step 4: Scheme switching from CKKS to FHEW
// A: First scheme switching case
// Transform the ciphertext from CKKS to FHEW
auto cTemp = cc->EvalCKKStoFHEW(c1, encodedLength1);
auto cTemp3 = cc->EvalCKKStoFHEW(c3, encodedLength1);
std::cout << "\n---Decrypting switched ciphertext with small precision (plaintext modulus " << NativeInteger(pLWE1)
<< ")---\n"
<< std::endl;
std::vector<int32_t> x1Int(encodedLength1);
std::transform(x1.begin(), x1.end(), x1Int.begin(), [&](const double& elem) {
return static_cast<int32_t>(static_cast<int32_t>(std::round(elem)) % pLWE1);
});
std::vector<int32_t> x3Int(encodedLength1);
std::transform(x3.begin(), x3.end(), x3Int.begin(), [&](const double& elem) {
return static_cast<int32_t>(static_cast<int32_t>(std::round(elem)) % pLWE1);
});
ptxt1->SetLength(encodedLength1);
ptxt3->SetLength(encodedLength1);
std::cout << "Input x1: " << ptxt1->GetRealPackedValue() << "; which rounds to: " << x1Int << std::endl;
std::cout << "FHEW decryption: ";
LWEPlaintext result;
for (uint32_t i = 0; i < cTemp.size(); ++i) {
ccLWE.Decrypt(privateKeyFHEW, cTemp[i], &result, pLWE1);
std::cout << result << " ";
}
std::cout << std::endl;
std::cout << "Input x3: " << ptxt3->GetRealPackedValue() << "; which rounds to: " << x3Int << std::endl;
std::cout << "FHEW decryption: ";
LWEPlaintext result3;
for (uint32_t i = 0; i < cTemp.size(); ++i) {
ccLWE.Decrypt(privateKeyFHEW, cTemp3[i], &result3, pLWE1);
std::cout << result3 << " ";
}
std::cout << "\n" << std::endl;
std::cout << "AND OP RESULT" << std::endl;
for (uint32_t i = 0; i < cTemp.size(); ++i) {
cTemp[i] = ccLWE.EvalBinGate(AND, cTemp[i],cTemp3[i]);
ccLWE.Decrypt(privateKeyFHEW, cTemp[i], &result, 2);
std::cout << result << " ";
}
std::cout << "\n" << std::endl;
And I got this following result
---Decrypting switched ciphertext with small precision (plaintext modulus 16)---
Input x1: [ 0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1 2 3 4 5 6 ]; which rounds to: [ 0 0 0 0 0 1 1 1 1 1 1 2 3 4 5 6 ]
FHEW decryption: 0 0 0 0 0 1 1 1 1 1 1 2 3 4 5 6
Input x3: [ 1 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1 2 3 4 5 1 ]; which rounds to: [ 1 0 0 0 0 1 1 1 1 1 1 2 3 4 5 1 ]
FHEW decryption: 1 0 0 0 0 1 1 1 1 1 1 2 3 4 5 1
AND OP RESULT
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
And when I change ccLWE.Decrypt(privateKeyFHEW, cTemp[i], &result, pLWE1);
from ccLWE.Decrypt(privateKeyFHEW, cTemp[i], &result, 2);
---Decrypting switched ciphertext with small precision (plaintext modulus 16)---
Input x1: [ 0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1 2 3 4 5 6 ]; which rounds to: [ 0 0 0 0 0 1 1 1 1 1 1 2 3 4 5 6 ]
FHEW decryption: 0 0 0 0 0 1 1 1 1 1 1 2 3 4 5 6
Input x3: [ 1 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1 2 3 4 5 1 ]; which rounds to: [ 1 0 0 0 0 1 1 1 1 1 1 2 3 4 5 1 ]
FHEW decryption: 1 0 0 0 0 0 1 1 1 1 1 2 3 4 5 1
AND OP RESULT
4 4 4 4 4 0 4 0 4 0 0 4 4 0 4 4
Also wrong output…
I am unsure how I should decrypt to get the correct value after performing gate level operations in fhew.
Could you please guide me?