You have to extract each piece of 2^{11}, then add and rotate it 2^{15}/2^{11} times.
// Step 1: Setup CryptoContext
uint32_t multDepth = 2;
uint32_t scaleModSize = 50;
uint32_t batchSizeIn = 16;
uint32_t batchSizeOut = 4;
uint32_t ringDim = 2*batchSizeIn;
CCParams<CryptoContextCKKSRNS> parameters;
parameters.SetMultiplicativeDepth(multDepth);
parameters.SetScalingModSize(scaleModSize);
parameters.SetBatchSize(batchSizeIn);
parameters.SetRingDim(ringDim);
parameters.SetSecurityLevel(HEStd_NotSet);
CryptoContext<DCRTPoly> cc = GenCryptoContext(parameters);
cc->Enable(PKE);
cc->Enable(KEYSWITCH);
cc->Enable(LEVELEDSHE);
// Step 2: Key Generation
auto keys = cc->KeyGen();
cc->EvalMultKeyGen(keys.secretKey);
int32_t index1 = batchSizeOut;
int32_t index2 = 2*batchSizeOut;
int32_t index3 = 3*batchSizeOut;
cc->EvalRotateKeyGen(keys.secretKey, {index1, index2, index3});
// Step 3: Encoding and encryption of inputs
// Input
std::vector<double> x1 = {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0};
// Encoding as plaintexts
Plaintext ptxt1 = cc->MakeCKKSPackedPlaintext(x1);
std::cout << "Input x: " << ptxt1 << std::endl;
// Encrypt the encoded vector
auto c1 = cc->Encrypt(keys.publicKey, ptxt1);
// Create a multiplicative mask to extract the smaller vectors
std::vector<double> mask(batchSizeIn);
std::transform(mask.begin(), mask.begin()+batchSizeOut, mask.begin(), [&](const double& elem) { return 1.0; });
Plaintext ptxtMask = cc->MakeCKKSPackedPlaintext(mask, 1, 0, nullptr, batchSizeIn);
// Construct four sparsely-packed ciphertexts
auto c1M = cc->EvalMult(c1, ptxtMask);
auto c2M = cc->EvalMult(cc->EvalRotate(c1, index1), ptxtMask);
auto c3M = cc->EvalMult(cc->EvalRotate(c1, index2), ptxtMask);
auto c4M = cc->EvalMult(cc->EvalRotate(c1, index3), ptxtMask);
for (uint32_t j = 1; j < batchSizeIn / batchSizeOut; j <<= 1) {
auto temp = cc->EvalAtIndex(c1M, j * batchSizeOut);
cc->EvalAddInPlace(c1M, temp);
temp = cc->EvalAtIndex(c2M, j * batchSizeOut);
cc->EvalAddInPlace(c2M, temp);
temp = cc->EvalAtIndex(c3M, j * batchSizeOut);
cc->EvalAddInPlace(c3M, temp);
temp = cc->EvalAtIndex(c4M, j * batchSizeOut);
cc->EvalAddInPlace(c4M, temp);
}
c1M->SetSlots(batchSizeOut);
c2M->SetSlots(batchSizeOut);
c3M->SetSlots(batchSizeOut);
c4M->SetSlots(batchSizeOut);
Plaintext result;
cc->Decrypt(keys.secretKey, c1M, &result);
std::cout << "First quarter = " << result << std::endl;
cc->Decrypt(keys.secretKey, c2M, &result);
std::cout << "Second quarter = " << result << std::endl;
cc->Decrypt(keys.secretKey, c3M, &result);
std::cout << "Third quarter = " << result << std::endl;
cc->Decrypt(keys.secretKey, c4M, &result);
std::cout << "Fourth quarter = " << result << std::endl;
return 0;