in pir_server.cpp [260:348]
inline vector<Ciphertext> PIRServer::expand_query(const Ciphertext &encrypted, uint32_t m,
uint32_t client_id) {
#ifdef DEBUG
uint64_t plainMod = params_.plain_modulus().value();
cout << "PIRServer side plain modulus = " << plainMod << endl;
#endif
GaloisKeys &galkey = galoisKeys_[client_id];
// Assume that m is a power of 2. If not, round it to the next power of 2.
uint32_t logm = ceil(log2(m));
Plaintext two("2");
vector<int> galois_elts;
auto n = params_.poly_modulus_degree();
if (logm > ceil(log2(n))){
throw logic_error("m > n is not allowed.");
}
for (int i = 0; i < ceil(log2(n)); i++) {
galois_elts.push_back((n + exponentiate_uint64(2, i)) / exponentiate_uint64(2, i));
}
vector<Ciphertext> temp;
temp.push_back(encrypted);
Ciphertext tempctxt;
Ciphertext tempctxt_rotated;
Ciphertext tempctxt_shifted;
Ciphertext tempctxt_rotatedshifted;
for (uint32_t i = 0; i < logm - 1; i++) {
vector<Ciphertext> newtemp(temp.size() << 1);
// temp[a] = (j0 = a (mod 2**i) ? ) : Enc(x^{j0 - a}) else Enc(0). With
// some scaling....
int index_raw = (n << 1) - (1 << i);
int index = (index_raw * galois_elts[i]) % (n << 1);
for (uint32_t a = 0; a < temp.size(); a++) {
evaluator_->apply_galois(temp[a], galois_elts[i], galkey, tempctxt_rotated);
//cout << "rotate " << client.decryptor_->invariant_noise_budget(tempctxt_rotated) << ", ";
evaluator_->add(temp[a], tempctxt_rotated, newtemp[a]);
multiply_power_of_X(temp[a], tempctxt_shifted, index_raw);
//cout << "mul by x^pow: " << client.decryptor_->invariant_noise_budget(tempctxt_shifted) << ", ";
multiply_power_of_X(tempctxt_rotated, tempctxt_rotatedshifted, index);
// cout << "mul by x^pow: " << client.decryptor_->invariant_noise_budget(tempctxt_rotatedshifted) << ", ";
// Enc(2^i x^j) if j = 0 (mod 2**i).
evaluator_->add(tempctxt_shifted, tempctxt_rotatedshifted, newtemp[a + temp.size()]);
}
temp = newtemp;
/*
cout << "end: ";
for (int h = 0; h < temp.size();h++){
cout << client.decryptor_->invariant_noise_budget(temp[h]) << ", ";
}
cout << endl;
*/
}
// Last step of the loop
vector<Ciphertext> newtemp(temp.size() << 1);
int index_raw = (n << 1) - (1 << (logm - 1));
int index = (index_raw * galois_elts[logm - 1]) % (n << 1);
for (uint32_t a = 0; a < temp.size(); a++) {
if (a >= (m - (1 << (logm - 1)))) { // corner case.
evaluator_->multiply_plain(temp[a], two, newtemp[a]); // plain multiplication by 2.
// cout << client.decryptor_->invariant_noise_budget(newtemp[a]) << ", ";
} else {
evaluator_->apply_galois(temp[a], galois_elts[logm - 1], galkey, tempctxt_rotated);
evaluator_->add(temp[a], tempctxt_rotated, newtemp[a]);
multiply_power_of_X(temp[a], tempctxt_shifted, index_raw);
multiply_power_of_X(tempctxt_rotated, tempctxt_rotatedshifted, index);
evaluator_->add(tempctxt_shifted, tempctxt_rotatedshifted, newtemp[a + temp.size()]);
}
}
vector<Ciphertext>::const_iterator first = newtemp.begin();
vector<Ciphertext>::const_iterator last = newtemp.begin() + m;
vector<Ciphertext> newVec(first, last);
return newVec;
}