diff --git a/CMakeLists.txt b/CMakeLists.txt index 4bdaf00..92aab59 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -115,6 +115,23 @@ else() endif() endif() +# check whether cpu support rdseed or rdrand instruction +set(CPU_RDSEED_FLAG "rdseed") +execute_process(COMMAND lscpu COMMAND grep ${CPU_RDSEED_FLAG} OUTPUT_VARIABLE CPU_ENABLE_RDSEED) +if("${CPU_ENABLE_RDSEED}" STREQUAL "") + set(CPU_RDRAND_FLAG "rdrand") + execute_process(COMMAND lscpu COMMAND grep ${CPU_RDRAND_FLAG} OUTPUT_VARIABLE CPU_ENABLE_RDRAND) + if("${CPU_ENABLE_RDRAND}" STREQUAL "") + message(WARNING "CPU doesn't support RDSEED and RDRAND instruction, using random generator will cause errors.") + else () + message(STATUS "Support RDRAND instruction: True") + add_compile_definitions(IPCL_RNG_INSTR_RDRAND) + endif() +else() + message(STATUS "Support RDSEED instruction: True") + add_compile_definitions(IPCL_RNG_INSTR_RDSEED) +endif() + # find package for OpenSSL and Threads set(OPENSSL_USE_STATIC_LIBS TRUE) find_package(Threads REQUIRED) diff --git a/README.md b/README.md index 9ef5c92..114d654 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Intel Paillier Cryptosystem Library -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Ā® [Integrated Performance Primitives Cryptography](https://github.com/intel/ipp-crypto) technologies on Intel CPUs supporting the AVX512IFMA instructions. The library is written in modern standard C++ and provides the essential API for the Paillier cryptosystem scheme. Intel Paillier Cryptosystem Library is certified for ISO compliance. +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Ā® [Integrated Performance Primitives Cryptography](https://github.com/intel/ipp-crypto) technologies on Intel CPUs supporting the AVX512IFMA instructions. The library is written in modern standard C++ and provides the essential API for the Paillier cryptosystem scheme. Intel Paillier Cryptosystem Library is certified for ISO compliance. ## Contents - [Intel Paillier Cryptosystem Library](#intel-paillier-cryptosystem-library) diff --git a/ipcl/CMakeLists.txt b/ipcl/CMakeLists.txt index ef76656..b1388b2 100644 --- a/ipcl/CMakeLists.txt +++ b/ipcl/CMakeLists.txt @@ -10,6 +10,7 @@ set(IPCL_SRCS pri_key.cpp plaintext.cpp ciphertext.cpp util.cpp + common.cpp ) diff --git a/ipcl/common.cpp b/ipcl/common.cpp new file mode 100644 index 0000000..90209eb --- /dev/null +++ b/ipcl/common.cpp @@ -0,0 +1,56 @@ +// Copyright (C) 2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#include "ipcl/common.hpp" + +#include + +#include "ipcl/util.hpp" + +namespace ipcl { + +IppStatus ippGenRandom(Ipp32u* rand, int bits, void* ctx) { +#ifdef IPCL_RNG_INSTR_RDSEED + return ippsTRNGenRDSEED(rand, bits, ctx); +#elif defined(IPCL_RNG_INSTR_RDRAND) + return ippsPRNGenRDRAND(rand, bits, ctx); +#else + return ippsPRNGen(rand, bits, ctx); +#endif +} + +IppStatus ippGenRandomBN(IppsBigNumState* rand, int bits, void* ctx) { +#ifdef IPCL_RNG_INSTR_RDSEED + return ippsTRNGenRDSEED_BN(rand, bits, ctx); +#elif defined(IPCL_RNG_INSTR_RDRAND) + return ippsPRNGenRDRAND_BN(rand, bits, ctx); +#else + return ippsPRNGen_BN(rand, bits, ctx); +#endif +} + +BigNumber getRandomBN(int bits) { + IppStatus stat; + int bn_buf_size; + + int bn_len = BITSIZE_WORD(bits); + stat = ippsBigNumGetSize(bn_len, &bn_buf_size); + ERROR_CHECK(stat == ippStsNoErr, + "getRandomBN: get IppsBigNumState context error."); + + IppsBigNumState* pBN = + reinterpret_cast(alloca(bn_buf_size)); + ERROR_CHECK(pBN != nullptr, "getRandomBN: big number alloca error"); + + stat = ippsBigNumInit(bn_len, pBN); + ERROR_CHECK(stat == ippStsNoErr, + "getRandomBN: init big number context error."); + + stat = ippGenRandomBN(pBN, bits, NULL); + ERROR_CHECK(stat == ippStsNoErr, + "getRandomBN: generate random big number error."); + + return BigNumber{pBN}; +} + +} // namespace ipcl diff --git a/ipcl/include/ipcl/common.hpp b/ipcl/include/ipcl/common.hpp index f954026..e15d44e 100644 --- a/ipcl/include/ipcl/common.hpp +++ b/ipcl/include/ipcl/common.hpp @@ -4,9 +4,38 @@ #ifndef IPCL_INCLUDE_IPCL_COMMON_HPP_ #define IPCL_INCLUDE_IPCL_COMMON_HPP_ +#include "ipcl/bignum.h" + namespace ipcl { constexpr int IPCL_CRYPTO_MB_SIZE = 8; +/** + * Random generator wrapper.Generates a random unsigned Big Number of the + * specified bit length + * @param[in] rand Pointer to the output unsigned integer big number + * @param[in] bits The number of generated bits + * @param[in] ctx Pointer to the IppsPRNGState context. + * @return Error code + */ +IppStatus ippGenRandom(Ipp32u* rand, int bits, void* ctx); + +/** + * Random generator wrapper.Generates a random positive Big Number of the + * specified bit length + * @param[in] rand Pointer to the output Big Number + * @param[in] bits The number of generated bits + * @param[in] ctx Pointer to the IppsPRNGState context. + * @return Error code + */ +IppStatus ippGenRandomBN(IppsBigNumState* rand, int bits, void* ctx); + +/** + * Get random value + * @param[in] bits The number of Big Number bits + * @return The random value of type Big Number + */ +BigNumber getRandomBN(int bits); + } // namespace ipcl #endif // IPCL_INCLUDE_IPCL_COMMON_HPP_ diff --git a/ipcl/include/ipcl/pub_key.hpp b/ipcl/include/ipcl/pub_key.hpp index 6938e40..1b28d19 100644 --- a/ipcl/include/ipcl/pub_key.hpp +++ b/ipcl/include/ipcl/pub_key.hpp @@ -128,13 +128,6 @@ class PublicKey { std::vector m_r; bool m_testv; - /** - * Get random value - * @param[in] size size of random - * @return addr of random of type Ipp32u vector - */ - std::vector randIpp32u(int size) const; - /** * Big number vector multi buffer encryption * @param[in] pt plaintext of BigNumber vector type @@ -144,13 +137,6 @@ class PublicKey { std::vector raw_encrypt(const std::vector& pt, bool make_secure = true) const; - /** - * Get random value - * @param[in] length bit length - * @return the random value of type BigNumber - */ - BigNumber getRandom(int length) const; - void applyDjnObfuscator(std::vector& obfuscator) const; void applyNormalObfuscator(std::vector& obfuscator) const; diff --git a/ipcl/keygen.cpp b/ipcl/keygen.cpp index efbf1d6..290e502 100644 --- a/ipcl/keygen.cpp +++ b/ipcl/keygen.cpp @@ -3,8 +3,6 @@ #include "ipcl/keygen.hpp" -#include -#include #include #include "ipcl/util.hpp" @@ -12,45 +10,31 @@ namespace ipcl { constexpr int N_BIT_SIZE_MAX = 2048; -constexpr int N_BIT_SIZE_MIN = 16; - -static void rand32u(std::vector& addr) { - std::random_device dev; - std::mt19937 rng(dev()); - std::uniform_int_distribution dist(0, UINT_MAX); - for (auto& x : addr) x = (dist(rng) << 16) + dist(rng); -} - -BigNumber getPrimeBN(int maxBitSize) { - int PrimeSize; - ippsPrimeGetSize(maxBitSize, &PrimeSize); - auto primeGen = std::vector(PrimeSize); - ippsPrimeInit(maxBitSize, reinterpret_cast(primeGen.data())); - - // define Pseudo Random Generator (default settings) - constexpr int seedBitSize = 160; - constexpr int seedSize = BITSIZE_WORD(seedBitSize); - - ippsPRNGGetSize(&PrimeSize); - auto rand = std::vector(PrimeSize); - ippsPRNGInit(seedBitSize, reinterpret_cast(rand.data())); - - auto seed = std::vector(seedSize); - rand32u(seed); - BigNumber bseed(seed.data(), seedSize, IppsBigNumPOS); - - ippsPRNGSetSeed(BN(bseed), reinterpret_cast(rand.data())); - - // generate maxBit prime - BigNumber pBN(0, maxBitSize / 8); +constexpr int N_BIT_SIZE_MIN = 200; + +BigNumber getPrimeBN(int max_bits) { + int prime_size; + ippsPrimeGetSize(max_bits, &prime_size); + auto prime_ctx = std::vector(prime_size); + ippsPrimeInit(max_bits, reinterpret_cast(prime_ctx.data())); + +#if defined(IPCL_RNG_INSTR_RDSEED) || defined(IPCL_RNG_INSTR_RDRAND) + bool rand_param = NULL; +#else + auto buff = std::vector(prime_size); + auto rand_param = buff.data(); + ippsPRNGInit(160, reinterpret_cast(rand_param)); +#endif + + BigNumber prime_bn(0, max_bits / 8); while (ippStsNoErr != - ippsPrimeGen_BN(pBN, maxBitSize, 10, - reinterpret_cast(primeGen.data()), - ippsPRNGen, - reinterpret_cast(rand.data()))) { + ippsPrimeGen_BN(prime_bn, max_bits, 10, + reinterpret_cast(prime_ctx.data()), + ippGenRandom, + reinterpret_cast(rand_param))) { } - return pBN; + return prime_bn; } static BigNumber getPrimeDistance(int64_t key_size) { @@ -111,7 +95,7 @@ keyPair generateKeypair(int64_t n_length, bool enable_DJN) { "generateKeyPair: modulus size in bits should belong to either 1Kb, 2Kb, " "3Kb or 4Kb range only, key size exceed the range!!!"); ERROR_CHECK((n_length >= N_BIT_SIZE_MIN) && (n_length % 4 == 0), - "generateKeyPair: key size should >=16, and divisible by 4"); + "generateKeyPair: key size should >=200, and divisible by 4"); BigNumber ref_dist = getPrimeDistance(n_length); diff --git a/ipcl/pub_key.cpp b/ipcl/pub_key.cpp index d19c915..0968691 100644 --- a/ipcl/pub_key.cpp +++ b/ipcl/pub_key.cpp @@ -35,44 +35,12 @@ PublicKey::PublicKey(const BigNumber& n, int bits, bool enableDJN_) if (enableDJN_) this->enableDJN(); // sets m_enable_DJN } -// array of 32-bit random, using rand() from stdlib -std::vector PublicKey::randIpp32u(int size) const { - std::vector addr(size); - // TODO(skmono): check if copy of m_init_seed is needed for const - unsigned int init_seed = m_init_seed; - for (auto& a : addr) a = (rand_r(&init_seed) << 16) + rand_r(&init_seed); - return addr; -} - -// length is arbitrary -BigNumber PublicKey::getRandom(int bit_len) const { - IppStatus stat; - int bn_buf_size; - - // define length Big Numbers - int bn_len = BITSIZE_WORD(bit_len); - stat = ippsBigNumGetSize(bn_len, &bn_buf_size); - ERROR_CHECK(stat == ippStsNoErr, - "getRandom: get IppsBigNumState context error."); - - IppsBigNumState* pBN = - reinterpret_cast(alloca(bn_buf_size)); - ERROR_CHECK(pBN != nullptr, "getRandom: big number alloca error"); - - stat = ippsBigNumInit(bn_len, pBN); - ERROR_CHECK(stat == ippStsNoErr, "getRandom: init big number context error."); - - ippsPRNGenRDRAND_BN(pBN, bit_len, NULL); - - return BigNumber{pBN}; -} - void PublicKey::enableDJN() { BigNumber gcd; BigNumber rmod; do { int rand_bit = m_n.BitSize(); - BigNumber rand = getRandom(rand_bit + 128); + BigNumber rand = getRandomBN(rand_bit + 128); rmod = rand % m_n; gcd = rand.gcd(m_n); } while (gcd.compare(1)); @@ -96,7 +64,7 @@ void PublicKey::applyDjnObfuscator(std::vector& obfuscator) const { r = m_r; } else { for (auto& r_ : r) { - r_ = getRandom(m_randbits); + r_ = getRandomBN(m_randbits); } } obfuscator = ipcl::ippModExp(base, r, sq); @@ -113,7 +81,7 @@ void PublicKey::applyNormalObfuscator( r = m_r; } else { for (int i = 0; i < obf_size; i++) { - r[i] = getRandom(m_bits); + r[i] = getRandomBN(m_bits); r[i] = r[i] % (m_n - 1) + 1; } }