If not, does anyone can give an example here?
Here is a sample code (and its output) of how to use EvalSum, EvalSumRows, and EvalSumCols.
The code assumes you are using CKKS. Note that this code is for illustrative purposes only and does not use standard security parameters.
int main() {
uint32_t multDepth = 1;
uint32_t scaleModSize = 50;
uint32_t N = 16;
uint32_t batchSize = N/2;
CCParams<CryptoContextCKKSRNS> parameters;
parameters.SetMultiplicativeDepth(multDepth);
parameters.SetScalingModSize(scaleModSize);
parameters.SetBatchSize(batchSize);
parameters.SetSecurityLevel(HEStd_NotSet);
parameters.SetRingDim(N);
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);
auto keys = cc->KeyGen();
// Encoding and encryption of inputs
// Inputs
std::vector<double> x1 = {1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.5};
std::vector<double> mat1 = {1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0};
std::vector<double> mat2 = {1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0};
uint32_t rowSize = 4;
// Encoding as plaintexts
Plaintext ptxt1 = cc->MakeCKKSPackedPlaintext(x1);
Plaintext ptxtMat1 = cc->MakeCKKSPackedPlaintext(mat1);
Plaintext ptxtMat2 = cc->MakeCKKSPackedPlaintext(mat2);
std::cout << "Input x1: " << ptxt1 << std::endl;
std::cout << "Input mat1: " << ptxtMat1 << std::endl;
std::cout << "Input mat2: " << ptxtMat2 << std::endl;
// Encrypt the encoded vectors
std::cout << "Encryption\n";
auto c1 = cc->Encrypt(keys.publicKey, ptxt1);
auto ctMat1 = cc->Encrypt(keys.publicKey, ptxtMat1);
auto ctMat2 = cc->Encrypt(keys.publicKey, ptxtMat2);
std::cout << "Generating EvalSum* keys\n";
cc->EvalSumKeyGen(keys.secretKey, keys.publicKey);
auto evalSumRowKeys = cc->EvalSumRowsKeyGen(keys.secretKey, nullptr, rowSize);
auto evalSumColKeys = cc->EvalSumColsKeyGen(keys.secretKey);
// Evaluation
std::cout << "EvalSum\n";
auto ctSum = cc->EvalSum(c1, batchSize);
std::cout << "EvalSumRows\n";
auto ctRowsSum = cc->EvalSumRows(ctMat1, rowSize, *evalSumRowKeys);
std::cout << "EvalSumCols\n";
auto ctColsSum = cc->EvalSumCols(ctMat2, rowSize, *evalSumColKeys);
// Decryption and output
std::cout << "Decryption\n";
Plaintext result;
std::cout.precision(8);
std::cout << std::endl << "Results of homomorphic evaluations: " << std::endl;
// Decrypt
cc->Decrypt(keys.secretKey, c1, &result);
result->SetLength(batchSize);
std::cout << "x1 = " << result;
std::cout << "Estimated precision in bits: " << result->GetLogPrecision() << std::endl;
cc->Decrypt(keys.secretKey, ctSum, &result);
result->SetLength(batchSize);
std::cout << "sum = " << result;
cc->Decrypt(keys.secretKey, ctRowsSum, &result);
result->SetLength(batchSize);
std::cout << "sum Rows: " << result;
cc->Decrypt(keys.secretKey, ctColsSum, &result);
result->SetLength(batchSize);
std::cout << "sum Cols: " << result;
return 0;
}
Output
Input x1: (1, 1, 1, 1, 1, 1, 1, 1.5, ... ); Estimated precision: 50 bits
Input mat1: (1, 1, 1, 1, 2, 2, 2, 2, ... ); Estimated precision: 50 bits
Input mat2: (1, 1, 1, 1, 2, 2, 2, 2, ... ); Estimated precision: 50 bits
Encryption
Generating EvalSum* keys
EvalSum
EvalSumRows
EvalSumCols
Decryption
Results of homomorphic evaluations:
x1 = (1, 1, 1, 1, 1, 1, 1, 1.5, ... ); Estimated precision: 44 bits
Estimated precision in bits: 44
sum = (8.5, 8.5, 8.5, 8.5, 8.5, 8.5, 8.5, 8.5, ... ); Estimated precision: 43 bits
sum Rows: (3, 3, 3, 3, 3, 3, 3, 3, ... ); Estimated precision: 44 bits
sum Cols: (4, 4, 4, 4, 8, 8, 8, 8, ... ); Estimated precision: 44 bits
Thank you very much.
Does the batch size of EvalSum has some limitations?
In above case, when I change N=64, and give x1 18 elements as follows:
std::vector x1 = {1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.5, 1, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.5, 1};
Then change the batch size parameter of EvalSum to 9, the result is not correct.
auto ctSum = cc->EvalSum(c1, 9);
Result:
sum = (16.5, 17, 17, 16, 15, 14, 13, 12, 10.5, 9.5, 8.5, 7.5, 6.5, 5.5, 4.5, 3.5, 2.5, 2, 2, 3, 4, 5, 6, 7, 8.5, 9.5, 10.5, 11.5, 12.5, 13.5, 14.5, 15.5, … ); Estimated precision: 46 bits
Could you tell me why? Thanks.
Besides, when I use “EvalSumColsKeyGen” with “rowSize” as 256(batch size is 2048), I get “The number of slots cannot be smaller than value vector size” error messages.
I have no idea about this since I’m sure the slots of the cipher text is equal to the batch size. Could you help with this? thanks.
The batch size should be a power of two (the data should be padded to a power of two).
In CKKS, the maximum number of slots is ring dimension / 2. The ring dimension in the example is 16.
When performing the EvalSumRow or EvalSumColumn operations, is there any level consumption on the ciphertext? I am curious about the internal operations that occur when calling the EvalSumRow (or Column) function, such as rotations and masking.
EvalSumRows
does not consume any levels (it includes only additions and rotations)EvalSumCols
consumes one level (multiplies by a binary mask internally)
Thank you very much!