Example of evaluating arbitrary smooth functions with the Chebyshev approximation using CKKS.
*/
#include "openfhe.h"
#include "math/chebyshev.h"
using namespace lbcrypto;
void EvalLogisticExample();
void EvalFunctionExample();
int main(int argc, char* argv[]) {
EvalLogisticExample();
EvalFunctionExample();
return 0;
}
void EvalLogisticExample() {
std::cout << "--------------------------------- EVAL LOGISTIC FUNCTION ---------------------------------"
<< std::endl;
CCParams<CryptoContextCKKSRNS> parameters;
parameters.SetSecurityLevel(HEStd_NotSet);
parameters.SetRingDim(1 << 10);
#if NATIVEINT == 128
usint scalingModSize = 78;
usint firstModSize = 89;
#else
usint scalingModSize = 50;
usint firstModSize = 60;
#endif
parameters.SetScalingModSize(scalingModSize);
parameters.SetFirstModSize(firstModSize);
uint32_t polyDegree = 16;
uint32_t multDepth = 6;
parameters.SetMultiplicativeDepth(multDepth);
CryptoContext<DCRTPoly> cc = GenCryptoContext(parameters);
cc->Enable(PKE);
cc->Enable(KEYSWITCH);
cc->Enable(LEVELEDSHE);
cc->Enable(ADVANCEDSHE);
auto keyPair = cc->KeyGen();
cc->EvalMultKeyGen(keyPair.secretKey);
std::vector<std::complex<double>> input{-4.0, -3.0, -2.0, -1.0, 0.0, 1.0, 2.0, 3.0, 4.0};
size_t encodedLength = input.size();
Plaintext plaintext = cc->MakeCKKSPackedPlaintext(input);
auto ciphertext = cc->Encrypt(keyPair.publicKey, plaintext);
double lowerBound = -5;
double upperBound = 5;
auto result = cc->EvalLogistic(ciphertext, lowerBound, upperBound, polyDegree);
Plaintext plaintextDec;
cc->Decrypt(keyPair.secretKey, result, &plaintextDec);
plaintextDec->SetLength(encodedLength);
std::vector<std::complex<double>> expectedOutput(
{0.0179885, 0.0474289, 0.119205, 0.268936, 0.5, 0.731064, 0.880795, 0.952571, 0.982011});
std::cout << "Expected output\n\t" << expectedOutput << std::endl;
std::vector<std::complex<double>> finalResult = plaintextDec->GetCKKSPackedValue();
std::cout << "Actual output\n\t" << finalResult << std::endl << std::endl;
}
void EvalFunctionExample() {
std::cout << "--------------------------------- EVAL SQUARE ROOT FUNCTION ---------------------------------"
<< std::endl;
CCParams<CryptoContextCKKSRNS> parameters;
parameters.SetSecurityLevel(HEStd_NotSet);
parameters.SetRingDim(1 << 10);
#if NATIVEINT == 128
usint scalingModSize = 78;
usint firstModSize = 89;
#else
usint scalingModSize = 50;
usint firstModSize = 60;
#endif
parameters.SetScalingModSize(scalingModSize);
parameters.SetFirstModSize(firstModSize);
uint32_t polyDegree = 50;
uint32_t multDepth = 7;
parameters.SetMultiplicativeDepth(multDepth);
CryptoContext<DCRTPoly> cc = GenCryptoContext(parameters);
cc->Enable(PKE);
cc->Enable(KEYSWITCH);
cc->Enable(LEVELEDSHE);
cc->Enable(ADVANCEDSHE);
auto keyPair = cc->KeyGen();
cc->EvalMultKeyGen(keyPair.secretKey);
std::vector<std::complex<double>> input{1, 2, 3, 4, 5, 6, 7, 8, 9};
size_t encodedLength = input.size();
Plaintext plaintext = cc->MakeCKKSPackedPlaintext(input);
auto ciphertext = cc->Encrypt(keyPair.publicKey, plaintext);
double lowerBound = 0;
double upperBound = 10;
auto result = cc->EvalChebyshevFunction([](double x) -> double { return std::sqrt(x); }, ciphertext, lowerBound,
upperBound, polyDegree);
Plaintext plaintextDec;
cc->Decrypt(keyPair.secretKey, result, &plaintextDec);
plaintextDec->SetLength(encodedLength);
std::vector<std::complex<double>> expectedOutput(
{1, 1.414213, 1.732050, 2, 2.236067, 2.449489, 2.645751, 2.828427, 3});
std::cout << "Expected output\n\t" << expectedOutput << std::endl;
std::vector<double> inputDouble{1, 2, 3, 4, 5, 6, 7, 8, 9};
auto ptxtApprox = EvalChebyshevFunctionPtxt(
[](double x) -> double { return std::sqrt(x); },
inputDouble, lowerBound, upperBound, polyDegree);
std::cout << "Cleartext output\n\t" << ptxtApprox << std::endl;
std::vector<std::complex<double>> finalResult = plaintextDec->GetCKKSPackedValue();
std::cout << "Actual output\n\t" << finalResult << std::endl << std::endl;
}