std::cout << “\n-----ArgminViaSchemeSwitching-----\n” << std::endl;
std::cout << “Output precision is only wrt the operations in CKKS after switching back\n” << std::endl;
// Step 1: Setup CryptoContext for CKKS
uint32_t scaleModSize = 50;
uint32_t firstModSize = 60;
uint32_t ringDim = 8192;
SecurityLevel sl = HEStd_NotSet;
BINFHE_PARAMSET slBin = TOY;
uint32_t logQ_ccLWE = 25;
bool arbFunc = false;
bool oneHot = true; // Change to false if the output should not be one-hot encoded
uint32_t slots = 16; // sparsely-packed
uint32_t batchSize = slots;
uint32_t numValues = 16;
ScalingTechnique scTech = FIXEDMANUAL;
uint32_t multDepth =
9 + 3 + 1 + static_cast<int>(std::log2(numValues))+5; // 13 for FHEW to CKKS, log2(numValues) for argmin
if (scTech == FLEXIBLEAUTOEXT)
multDepth += 1;
CCParams<CryptoContextCKKSRNS> parameters;
parameters.SetMultiplicativeDepth(multDepth);
parameters.SetScalingModSize(scaleModSize);
parameters.SetFirstModSize(firstModSize);
parameters.SetScalingTechnique(scTech);
parameters.SetSecurityLevel(sl);
parameters.SetRingDim(ringDim);
parameters.SetBatchSize(batchSize);
CryptoContext<DCRTPoly> cc = GenCryptoContext(parameters);
// Enable the features that you wish to use
cc->Enable(PKE);
cc->Enable(KEYSWITCH);
cc->Enable(LEVELEDSHE);
cc->Enable(ADVANCEDSHE);
cc->Enable(SCHEMESWITCH);
cc->Enable(PRE);
std::cout << "CKKS scheme is using ring dimension " << cc->GetRingDimension();
std::cout << ", and number of slots " << slots << ", and supports a depth of " << multDepth << std::endl
<< std::endl;
// Generate encryption keys
KeyPair<DCRTPoly> keyPaiRserver;
keyPaiRserver=cc->KeyGen();
//auto keys = cc->KeyGen();
// Step 2: Prepare the FHEW cryptocontext and keys for FHEW and scheme switching
auto FHEWparams = cc->EvalSchemeSwitchingSetup(sl, slBin, arbFunc, logQ_ccLWE, false, slots);
auto ccLWE = FHEWparams.first;
auto privateKeyFHEW = FHEWparams.second;
cc->EvalSchemeSwitchingKeyGen(keyPaiRserver, privateKeyFHEW, numValues, oneHot);
std::cout << "FHEW scheme is using lattice parameter " << ccLWE.GetParams()->GetLWEParams()->Getn();
std::cout << ", logQ " << logQ_ccLWE;
std::cout << ", and modulus q " << ccLWE.GetParams()->GetLWEParams()->Getq() << std::endl << std::endl;
// Scale the inputs to ensure their difference is correctly represented after switching to FHEW
double scaleSign = 512.0;
auto modulus_LWE = 1 << logQ_ccLWE;
auto beta = ccLWE.GetBeta().ConvertToInt();
auto pLWE = modulus_LWE / (2 * beta); // Large precision
uint32_t init_level = 0;
const auto cryptoParams = std::dynamic_pointer_cast<CryptoParametersCKKSRNS>(cc->GetCryptoParameters());
if (cryptoParams->GetScalingTechnique() == FLEXIBLEAUTOEXT)
init_level = 1;
// This formulation is for clarity
cc->EvalCompareSwitchPrecompute(pLWE, init_level, scaleSign);
KeyPair<DCRTPoly> keyPair1;
keyPair1 = cc->KeyGen();
cc->EvalSumKeyGen(keyPaiRserver.secretKey, keyPaiRserver.publicKey);
cc->EvalMultKeyGen(keyPaiRserver.secretKey);
std::vector x1 = {91, 140, 204, 50, 70, 129, 98, 57, 91, 140, 204, 50, 70, 129,52,52};
Plaintext ptxt1 = cc->MakeCKKSPackedPlaintext(x1);
auto c1 = cc->Encrypt(keyPair1.publicKey, ptxt1);
auto reencrypt1= cc->ReKeyGen(keyPair1.secretKey, keyPaiRserver.publicKey);
auto ct1 = cc->ReEncrypt(c1, reencrypt1);
auto result = cc->EvalMinSchemeSwitching(ct1, keyPaiRserver.publicKey, numValues, slots, oneHot);
cout<<“111”<<endl;
Plaintext ptxtMin;
cc->Decrypt(keyPaiRserver.secretKey, result[0], &ptxtMin);
ptxtMin->SetLength(1);
std::cout << "Minimum value: " << ptxtMin << std::endl;
cc->Decrypt(keyPaiRserver.secretKey, result[1], &ptxtMin);
if (oneHot) {
ptxtMin->SetLength(numValues);
std::cout << "Argmin indicator vector: " << ptxtMin << std::endl;
}
else {
ptxtMin->SetLength(1);
std::cout << "Argmin: " << ptxtMin << std::endl;
}
result = cc->EvalMaxSchemeSwitching(ct1, keyPaiRserver.publicKey, numValues, slots, oneHot);
Plaintext ptxtMax;
cc->Decrypt(keyPaiRserver.secretKey, result[0], &ptxtMax);
ptxtMax->SetLength(1);
std::cout << "Maximum value: " << ptxtMax << std::endl;
cc->Decrypt(keyPaiRserver.secretKey, result[1], &ptxtMax);
if (oneHot) {
ptxtMax->SetLength(numValues);
std::cout << "Argmax indicator vector: " << ptxtMax << std::endl;
}
else {
ptxtMax->SetLength(1);
std::cout << "Argmax: " << ptxtMax << std::endl;
}
the output is
Minimum value: (204, … ); Estimated precision: 32 bits
Argmin indicator vector: (-1.06807e-12, 2.23187e-13, 5.89118e-07, 2.49577e-12, 8.6444e-12, 1.96647e-12, 2.60188e-12, 1.81553e-12, 3.45485e-12, -1.43813e-12, 0.999998, 5.92664e-07, 7.93075e-10, 3.41856e-12, 5.84236e-07, -7.74684e-13, … ); Estimated precision: 37 bits
Maximum value: (203.999, … ); Estimated precision: 30 bits
Argmax indicator vector: (2.34909e-06, 5.89018e-07, 0.999994, 7.53067e-13, 1.18023e-11, 2.34536e-12, 2.354e-06, 2.9124e-12, 9.45044e-13, -2.82486e-13, 5.89115e-07, -7.60647e-13, -8.32041e-13, -1.97771e-13, -5.45767e-13, 8.5003e-13, … ); Estimated precision: 39 bits