intel / pailliercryptolib

Intel Paillier Cryptosystem Library is an open-source library which provides accelerated performance of a partial homomorphic encryption (HE), named Paillier cryptosystem, by utilizing Intel® IPP-Crypto on AVX512IFMA instructions. Intel Paillier Cryptosystem Library is certified for ISO compliance.
Apache License 2.0
73 stars 18 forks source link

Fail to encrypt using OpenMP, and a possible solution #71

Closed zfscgy closed 1 year ago

zfscgy commented 1 year ago

When using encrypt inside a omp parallel for loop, the error ippMontExp: set Mont input error. is very likely to occur, especially when the plaintext is large, e.g., close to N. Here is the simplest code to reproduce the problem.

int main()
{
    ipcl::KeyPair keyPair = ipcl::generateKeypair(2048);
    std::cout << "N=" << *keyPair.pub_key.getN() << std::endl;
    std::cout << "N^2=" << *keyPair.pub_key.getNSQ() << std::endl;
    std::vector<BigNumber> bignums;
    for (size_t i = 0; i < 100; i++)
    {
        bignums.push_back(BigNumber(uint32_t(i + 1)));
    }

    for (size_t t = 0; t < 100; t++)
    {
        std::cout << "Start to encrypt 100 BigNumbers ==== time " << t << std::endl;
        BigNumber N = *keyPair.pub_key.getN();
        BigNumber moded = N - bignums[t];
#pragma omp parallel for
        for (size_t i = 0; i < 100; i++)
        {
            keyPair.pub_key.encrypt(ipcl::PlainText(moded));
        }
        std::cout << "Encrypted 100 BigNumbers" << std::endl;
    }
}

The error seems to be caused by the ippsMod_BN function, which somehow modifies the data of modulus (the m_nquare field) during its computation. Hence it is not thread-safe. However, I notice that copying m_square in raw_encrypt probably fixes the problem.

std::vector<BigNumber> PublicKey::raw_encrypt(const std::vector<BigNumber>& pt,
                                              bool make_secure) const {
  std::size_t pt_size = pt.size();
  BigNumber nsq = *m_nsquare; // This code copies the data of m_nsquare
  std::vector<BigNumber> ct(pt_size);

  for (std::size_t i = 0; i < pt_size; i++)
    // ct[i] = (*m_n * pt[i] + 1) % (*m_nsquare);
    ct[i] = (*m_n * pt[i] + 1) % nsq;

  if (make_secure) applyObfuscator(ct);

  return ct;
}
justalittlenoob commented 1 year ago

Hi @zfscgy
Thank you very much for raising this issue and pointing out improvement plans. This issue has been fixed in this PR #72
You can update the development branch to try it out. If you find any other issue, please feel free to raise them.

zfscgy commented 1 year ago

Thanks!