Palisade utils
文章目录
- Palisade utils
- \core\include\utils\inttypes.h
- \core\include\utils\palisadebase64.h
- \core\include\utils\exception.h
- \core\include\utils\parallel.h
- \core\include\utils\serializable.h
- \core\include\utils\serial.h
- \core\include\utils\serialize-binary.h
- \core\include\utils\serialize-json.h
- \core\include\utils\sertype.h
- \core\include\utils\testcasegen.h
- \core\include\utils\utilities.h
- \core\include\utils\parmfactory.h
- \core\include\utils\memory.h
- \core\include\utils\hashutil.h
- \core\include\utils\define.h
- \core\include\utils\debug.h
- \core\include\utils\caller_info.h
\core\include\utils\inttypes.h
stdint.h 中定义了 uint8_t , uint16_t , uint32_t , uint64_t 等类型,其实它们只是 char , short 等类型的别名。
/**
* @brief Type used for representing unsigned 8-bit integers.
*/
typedef uint8_t uschar;
/**
* @brief Type used for representing unsigned 16-bit short integers.
*/
typedef uint16_t usshort;
/**
* @brief Type used for representing unsigned 32-bit integers.
*/
typedef uint32_t usint;
typedef uint64_t PlaintextModulus;
PlaintextModulus 是在这里被定义的!
定义了一个枚举,代表多项式是计算表示还是系数表示,计算表示是经过 FFT/NTT(Canondial embedding) 后的结果。
/**
* @brief Represents whether the polynomial ring is in EVALUATION or COEFFICIENT
* representation.
*/
enum Format { EVALUATION = 0, COEFFICIENT = 1 };
inline std::ostream &operator<<(std::ostream &s, Format f) {
switch (f) {
case EVALUATION:
s << "EVALUATION";
break;
case COEFFICIENT:
s << "COEFFICIENT";
break;
default:
s << "UKNOWN";
break;
}
return s;
}
接下来定义了 enable() 函数可以接受的参数
/**
* @brief Lists all features supported by public key encryption schemes
*/
enum PKESchemeFeature {
ENCRYPTION = 0x01,
PRE = 0x02,
SHE = 0x04,
FHE = 0x08,
LEVELEDSHE = 0x10,
MULTIPARTY = 0x20,
ADVANCEDSHE = 0x40
};
inline std::ostream &operator<<(std::ostream &s, PKESchemeFeature f) {
switch (f) {
case ENCRYPTION:
s << "ENCRYPTION";
break;
case PRE:
s << "PRE";
break;
case SHE:
s << "SHE";
break;
case FHE:
s << "FHE";
break;
case LEVELEDSHE:
s << "LEVELEDSHE";
break;
case MULTIPARTY:
s << "MULTIPARTY";
break;
case ADVANCEDSHE:
s << "ADVANCEDSHE";
break;
default:
s << "UKNOWN";
break;
}
return s;
}
接下来定义的 optimization mode,是方案初始化时需要传输的参数。
/**
* @brief Lists all modes for RLWE schemes, such as BGV and BFV
*/
enum MODE { RLWE = 0, OPTIMIZED = 1, SPARSE = 2 };
inline std::ostream &operator<<(std::ostream &s, MODE m) {
switch (m) {
case RLWE:
s << "RLWE";
break;
case OPTIMIZED:
s << "OPTIMIZED";
break;
case SPARSE:
s << "SPARSE";
break;
default:
s << "UKNOWN";
break;
}
return s;
}
\core\include\utils\palisadebase64.h
以64为基,6个比特一组。
#ifndef SRC_CORE_LIB_UTILS_PALISADEBASE64_H_
#define SRC_CORE_LIB_UTILS_PALISADEBASE64_H_
#include <utils/exception.h>
#include <cctype>
#include <cstdint>
namespace lbcrypto {
extern const char to_base64_char[];
inline unsigned char value_to_base64(int c) { return to_base64_char[c]; }
A 到 Z为 0-25,a 到 z 为 26-51,0 到 9为 52-61,+加号为 62,剩余所有都是 63.
inline unsigned char base64_to_value(unsigned char b64) {
if (isupper(b64))
return b64 - 'A';
else if (islower(b64))
return b64 - 'a' + 26;
else if (isdigit(b64))
return b64 - '0' + 52;
else if (b64 == '+')
return 62;
else
return 63;
}
高位index大,低位index小,smallmask从0开始,依次为0位,1位,2位,3位,4位,5位,6位;
从index开始向低位截取6个比特。
inline unsigned char get_6bits_atoffset(uint64_t m_value, uint32_t index) {
static unsigned char smallmask[] = {0, 0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f};
if (index == 0) {
PALISADE_THROW(math_error, "Zero index in GetBitAtIndex");
}
if (index <= 6) {
return m_value & smallmask[index];
}
return (m_value >> (index - 6)) & 0x3f;
}
} /* namespace lbcrypto */
#endif /* SRC_CORE_LIB_UTILS_PALISADEBASE64_H_ */
\core\lib\utils\palisadebase64.cpp
#include "utils/palisadebase64.h"
namespace lbcrypto {
const char to_base64_char[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
} /* namespace lbcrypto */
\core\include\utils\exception.h
处理所有可能出现的异常
#ifndef SRC_CORE_LIB_UTILS_EXCEPTION_H_
#define SRC_CORE_LIB_UTILS_EXCEPTION_H_
#include <exception>
#include <iostream>
#include <mutex>
#include <stdexcept>
#include <string>
namespace lbcrypto {
// Exceptions thrown inside of a critical region, or inside of an omp thread,
// must be caught in the same thread where thrown, or Bad Things Happen
//
// This class is used to catch and rethrow exceptions from threads/critical
// regions (thank you stack overflow)
class ThreadException {
std::exception_ptr Ptr;
std::mutex Lock;
public:
ThreadException() : Ptr(nullptr) {}
~ThreadException() {}
void Rethrow() {
if (this->Ptr) std::rethrow_exception(this->Ptr);
}
void CaptureException() {
std::unique_lock<std::mutex> guard(this->Lock);
this->Ptr = std::current_exception();
}
template <typename Function, typename... Parameters>
void Run(Function f, Parameters... params) {
try {
f(params...);
} catch (...) {
CaptureException();
}
}
};
// how to use ThreadException
// To use this, declare an instance of the object before the critical
// region/thread, catch exceptions in thread with CaptureException, then after
// the region call object.Rethrow()
// #pragma omp parallel for
// for (unsigned i = 0; i < rv.size(); i++) try {
// rv.polys[i] = (polys[i].*f)();
// } catch (...) {
// e.CaptureException();
// }
// e.Rethrow();
//
// // use of Run looks like:
// ThreadException e;
// #pragma omp parallel for
// for (int i = 0; i < n; i++) {
// e.Run([=] {
// // code that might throw
// // ...
// });
// }
// e.Rethrow();
class palisade_error : public std::runtime_error {
std::string filename;
int linenum;
std::string message;
public:
palisade_error(const std::string& file, int line, const std::string& what)
: std::runtime_error(what), filename(file), linenum(line) {
message = filename + ":" + std::to_string(linenum) + " " + what;
}
const char* what() const throw() { return message.c_str(); }
const std::string& GetFilename() const { return filename; }
int GetLinenum() const { return linenum; }
};
class config_error : public palisade_error {
public:
config_error(const std::string& file, int line, const std::string& what)
: palisade_error(file, line, what) {}
};
class math_error : public palisade_error {
public:
math_error(const std::string& file, int line, const std::string& what)
: palisade_error(file, line, what) {}
};
class not_implemented_error : public palisade_error {
public:
not_implemented_error(const std::string& file, int line,
const std::string& what)
: palisade_error(file, line, what) {}
};
class not_available_error : public palisade_error {
public:
not_available_error(const std::string& file, int line,
const std::string& what)
: palisade_error(file, line, what) {}
};
class type_error : public palisade_error {
public:
type_error(const std::string& file, int line, const std::string& what)
: palisade_error(file, line, what) {}
};
// use this error when serializing palisade objects
class serialize_error : public palisade_error {
public:
serialize_error(const std::string& file, int line, const std::string& what)
: palisade_error(file, line, what) {}
};
// use this error when deserializing palisade objects
class deserialize_error : public palisade_error {
public:
deserialize_error(const std::string& file, int line, const std::string& what)
: palisade_error(file, line, what) {}
};
#define PALISADE_THROW(exc, expr) throw exc(__FILE__, __LINE__, (expr))
} // namespace lbcrypto
#endif /* SRC_CORE_LIB_UTILS_EXCEPTION_H_ */
\core\include\utils\parallel.h
里面的函数都是根据 PARALLEL 是否被定义来判断的。
#ifdef PARALLEL
#include <omp.h>
#endif
namespace lbcrypto {
class ParallelControls {
int machineThreads;
public:
// @Brief CTOR, enables parallel operations as default
// Cache the number of machine threads the system reports (can be
// overridden by environment variables)
// enable on startup by default
ParallelControls() {
#ifdef PARALLEL
machineThreads = omp_get_max_threads();
Enable();
#else
machineThreads = 1;
#endif
}
// @Brief Enable() enables parallel operation
void Enable() {
#ifdef PARALLEL
omp_set_num_threads(machineThreads);
#endif
}
// @Brief Disable() disables parallel operation
void Disable() {
#ifdef PARALLEL
omp_set_num_threads(0);
#endif
}
int GetMachineThreads() const { return machineThreads; }
static int GetNumProcs() {
#ifdef PARALLEL
return omp_get_num_procs();
#else
return 1;
#endif
}
// @Brief returns current number of threads that are usable
// @return int # threads
int GetNumThreads() {
#ifdef PARALLEL
int nthreads = 1;
int tid = 1;
// Fork a team of threads giving them their own copies of variables
// so we can see how many threads we have to work with
#pragma omp parallel private(tid)
{
/* Obtain thread number */
tid = omp_get_thread_num();
/* Only master thread does this */
if (tid == 0) {
nthreads = omp_get_num_threads();
}
}
// std::cout << "\nNumber of threads = " << nthreads << std::endl;
return nthreads;
#else
return machineThreads;
#endif
}
// @Brief sets number of threads to use (limited by system value)
void SetNumThreads(int nthreads) {
#ifdef PARALLEL
// set number of thread, but limit it to the system set
// number of machine threads...
if (nthreads > machineThreads) {
nthreads = machineThreads;
}
omp_set_num_threads(nthreads);
#endif
}
};
extern ParallelControls PalisadeParallelControls;
} // namespace lbcrypto
\core\lib\utils\parallel.cpp
#include "utils/parallel.h"
namespace lbcrypto {
ParallelControls PalisadeParallelControls;
}
\core\include\utils\serializable.h
所有需要序列化的类都需要继承这个类
#ifndef LBCRYPTO_SERIALIZABLE_H
#define LBCRYPTO_SERIALIZABLE_H
// TODO (dsuponit): purge the headers below and combine #pragma for GNU and clang
#include <iostream>
#include <string>
#ifndef CEREAL_RAPIDJSON_HAS_STDSTRING
#define CEREAL_RAPIDJSON_HAS_STDSTRING 1
#endif
#ifndef CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS
#define CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS 1
#endif
#define CEREAL_RAPIDJSON_HAS_CXX11_NOEXCEPT 0
#ifdef __GNUC__
#if __GNUC__ >= 8
#pragma GCC diagnostic ignored "-Wclass-memaccess"
#endif
#endif
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-private-field"
#endif
#include "cereal/cereal.hpp"
#include "cereal/types/polymorphic.hpp"
#ifdef __GNUC__
#if __GNUC__ >= 8
#pragma GCC diagnostic pop
#endif
#endif
#ifdef __clang__
#pragma clang diagnostic pop
#endif
namespace lbcrypto {
using Serialized = void*;
/**
* \class Serializable
*
* \brief Base class for PALISADE serialization
*
* This class is inherited by every class that needs to be serialized.
* The class contains some deprecated(弃用的) methods from the older mechanisms
* for serialization
*/
class Serializable {
public:
virtual ~Serializable() {}
virtual std::string SerializedObjectName() const = 0;
};
// helper template to stream vector contents provided T has an stream operator<<
template <typename T>
std::ostream& operator<<(std::ostream& os, const std::vector<T>& v) {
os << "[";
for (auto i = v.begin(); i != v.end(); ++i) {
os << " " << *i;
}
os << " ]";
return os;
}
} // namespace lbcrypto
#endif
\core\include\utils\serial.h
调用C++序列化库cereal来进行序列化。
#ifndef LBCRYPTO_SERIAL_H
#define LBCRYPTO_SERIAL_H
// TODO (dsuponit): purge the headers below and combine #pragma for GNU and clang
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#ifndef CEREAL_RAPIDJSON_HAS_STDSTRING
#define CEREAL_RAPIDJSON_HAS_STDSTRING 1
#endif
#ifndef CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS
#define CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS 1
#endif
#define CEREAL_RAPIDJSON_HAS_CXX11_NOEXCEPT 0
#ifdef __GNUC__
#if __GNUC__ >= 8
#pragma GCC diagnostic ignored "-Wclass-memaccess"
#endif
#endif
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-private-field"
#endif
#include "utils/sertype.h"
#include "cereal/archives/portable_binary.hpp"
#include "cereal/archives/json.hpp"
#include "cereal/cereal.hpp"
#include "cereal/types/map.hpp"
#include "cereal/types/memory.hpp"
#include "cereal/types/polymorphic.hpp"
#include "cereal/types/string.hpp"
#include "cereal/types/vector.hpp"
#ifdef __GNUC__
#if __GNUC__ >= 8
#pragma GCC diagnostic pop
#endif
#endif
#ifdef __clang__
#pragma clang diagnostic pop
#endif
namespace lbcrypto {
namespace Serial {
//========================== BINARY serialization ==========================
/**
* Serialize an object
* @param obj - object to serialize
* @param stream - Stream to serialize to
* @param sertype - type of serialization; default is BINARY
*/
template <typename T>
void Serialize(const T& obj, std::ostream& stream, const SerType::SERBINARY& st) {
cereal::PortableBinaryOutputArchive archive(stream);
archive(obj);
}
/**
* Deserialize an object
* @param obj - object to deserialize into
* @param stream - Stream to deserialize from
* @param sertype - type of de-serialization; default is BINARY
*/
template <typename T>
void Deserialize(T& obj, std::istream& stream, const SerType::SERBINARY& st) {
cereal::PortableBinaryInputArchive archive(stream);
archive(obj);
}
template <typename T>
bool SerializeToFile(const std::string& filename, const T& obj, const SerType::SERBINARY& sertype) {
std::ofstream file(filename, std::ios::out | std::ios::binary);
if (file.is_open()) {
Serial::Serialize(obj, file, sertype);
file.close();
return true;
}
return false;
}
template <typename T>
bool DeserializeFromFile(const std::string& filename, T& obj, const SerType::SERBINARY& sertype) {
std::ifstream file(filename, std::ios::in | std::ios::binary);
if (file.is_open()) {
Serial::Deserialize(obj, file, sertype);
file.close();
return true;
}
return false;
}
//========================== JSON serialization ==========================
/**
* Serialize an object
* @param obj - object to serialize
* @param stream - Stream to serialize to
* @param sertype - type of serialization; default is BINARY
*/
template <typename T>
void Serialize(const T& obj, std::ostream& stream, const SerType::SERJSON& ser) {
cereal::JSONOutputArchive archive(stream);
archive(obj);
}
/**
* Deserialize an object
* @param obj - object to deserialize into
* @param stream - Stream to deserialize from
* @param sertype - type of serialization; default is BINARY
*/
template <typename T>
void Deserialize(T& obj, std::istream& stream, const SerType::SERJSON& ser) {
cereal::JSONInputArchive archive(stream);
archive(obj);
}
template <typename T>
bool SerializeToFile(const std::string& filename, const T& obj, const SerType::SERJSON& sertype) {
std::ofstream file(filename, std::ios::out | std::ios::binary);
if (file.is_open()) {
Serial::Serialize(obj, file, sertype);
file.close();
return true;
}
return false;
}
template <typename T>
bool DeserializeFromFile(const std::string& filename, T& obj, const SerType::SERJSON& sertype) {
std::ifstream file(filename, std::ios::in | std::ios::binary);
if (file.is_open()) {
Serial::Deserialize(obj, file, sertype);
file.close();
return true;
}
return false;
}
/**
* SerializeToString - serialize the object to a JSON string and return the
* string
* @param t - any serializable object
* @return JSON string
*/
template <typename T>
std::string SerializeToString(const T& t) {
std::stringstream s;
Serialize(t, s, SerType::JSON);
return s.str();
}
} // namespace Serial
} // namespace lbcrypto
#endif
\core\include\utils\serialize-binary.h
弃用了,现在使用 serial.h
#include "serial.h"
#pragma message "utils/serialize-binary.h is deprecated and will be removed in the 3rd quarter of 2021. serial.h should be used instead"
\core\include\utils\serialize-json.h
同样弃用了。
#include "serial.h"
#pragma message "utils/serialize-json.h is deprecated and will be removed in the 3rd quarter of 2021. serial.h should be used instead"
\core\include\utils\sertype.h
Definition of serialization type.
#ifndef LBCRYPTO_SERTYPE_H
#define LBCRYPTO_SERTYPE_H
namespace lbcrypto {
namespace SerType {
class SERJSON { };
const static SERJSON JSON; // should be const static to avoid compilation failure
class SERBINARY { };
const static SERBINARY BINARY; // should be const static to avoid compilation failure
} // namespace SerType
} // namespace lbcrypto
#endif
\core\include\utils\testcasegen.h
Helper methods for serialization.
#ifndef SRC_CORE_LIB_UTILS_TESTCASEGEN_H_
#define SRC_CORE_LIB_UTILS_TESTCASEGEN_H_
#define GENERATE_PKE_TEST_CASE(TOPNAME, FUNC, ELEMENT, SCHEME, ORD, PTM) \
TEST_F(TOPNAME, FUNC##_##ELEMENT##_##SCHEME) { \
CryptoContext<ELEMENT> cc; \
try { \
cc = GenTestCryptoContext<ELEMENT>(#SCHEME, ORD, PTM); \
} catch (const not_implemented_error&) { \
return; \
} catch (const not_available_error&) { \
return; \
} catch (const std::exception& ex) { \
std::cerr << "Exception occurred: " << ex.what() << std::endl; \
} catch (...) { \
std::cerr << "Unknown failure occurred." << std::endl; \
} \
FUNC<ELEMENT>(cc, #SCHEME); \
}
#define GENERATE_PKE_TEST_CASE_BITS(TOPNAME, FUNC, ELEMENT, SCHEME, ORD, PTM, \
BITS) \
TEST_F(TOPNAME, FUNC##_##ELEMENT##_##SCHEME) { \
CryptoContext<ELEMENT> cc; \
try { \
cc = GenTestCryptoContext<ELEMENT>(#SCHEME, ORD, PTM, BITS); \
} catch (const not_implemented_error&) { \
return; \
} catch (const not_available_error&) { \
return; \
} catch (const std::exception& ex) { \
std::cerr << "Exception occurred: " << ex.what() << std::endl; \
} catch (...) { \
std::cerr << "Unknown failure occurred." << std::endl; \
} \
FUNC<ELEMENT>(cc, #SCHEME); \
}
#define GENERATE_BGVrns_TEST_CASE(TOPNAME, FUNC, ELEMENT, SCHEME, ORD, PTM, \
SIZEMODULI, NUMPRIME, RELIN, KEYSWITCH, \
BATCH, RESCALEALG, MODSWITCHMETHOD) \
TEST_F(TOPNAME, \
FUNC##_##ELEMENT##_##SCHEME##_##KEYSWITCH##_##MODSWITCHMETHOD) { \
CryptoContext<ELEMENT> cc; \
try { \
cc = GenTestCryptoContext<ELEMENT>(#SCHEME, ORD, PTM, SIZEMODULI, \
NUMPRIME, RELIN, BATCH, KEYSWITCH, \
RESCALEALG, MODSWITCHMETHOD); \
} catch (const not_implemented_error&) { \
return; \
} catch (const not_available_error&) { \
return; \
} catch (const std::exception& ex) { \
std::cerr << "Exception occurred: " << ex.what() << std::endl; \
} catch (...) { \
std::cerr << "Unknown failure occurred." << std::endl; \
} \
FUNC<ELEMENT>(cc, #SCHEME); \
}
#define GENERATE_CKKS_TEST_CASE(TOPNAME, FUNC, ELEMENT, SCHEME, ORD, SCALE, \
NUMPRIME, RELIN, BATCH, KEYSWITCH, RESCALEALG) \
TEST_F(TOPNAME, FUNC##_##ELEMENT##_##SCHEME##_##KEYSWITCH##_##RESCALEALG) { \
CryptoContext<ELEMENT> cc; \
try { \
cc = GenTestCryptoContext<ELEMENT>(#SCHEME, ORD, SCALE, SCALE, NUMPRIME, \
RELIN, BATCH, KEYSWITCH, RESCALEALG); \
} catch (const not_implemented_error&) { \
return; \
} catch (const not_available_error&) { \
return; \
} catch (const std::exception& ex) { \
std::cerr << "Exception occurred: " << ex.what() << std::endl; \
} catch (...) { \
std::cerr << "Unknown failure occurred." << std::endl; \
} \
FUNC<ELEMENT>(cc, #SCHEME); \
}
#endif /* SRC_CORE_LIB_UTILS_TESTCASEGEN_H_ */
\core\include\utils\utilities.h
This file contains the utility function functionality.
#include <string>
#include <iomanip>
#include "math/backend.h"
#include "math/distributiongenerator.h"
#include "math/nbtheory.h"
依旧是定义在 namespace lbcrypto 中。
zero padding:
/**
* Zero Padding of Elements.
* Adds zeros to form a polynomial of length 2n (corresponding to cyclotomic
* order m = 2n). It is used by the forward transform of
* ChineseRemainderTransform (a modified version of ZeroPadd will be used for
* the non-power-of-2 case).
*
* @param &InputPoly is the element to perform the transform on.
* @param target_order is the intended target ordering.
* @return is the output of the zero padding.
*/
template <typename V>
V ZeroPadForward(const V &InputPoly, usint target_order);
/**
* Zero Pad Inverse of Elements.
* Adds alternating zeroes to form a polynomial of length of length 2n
* (corresponding to cyclotomic order m = 2n). It is used by the inverse
* transform of ChineseRemainderTransform (a modified version of ZeroPadInverse
* will be used for the non-power-of-2 case).
*
* @param &InputPoly is the element to perform the transform on.
* @param target_order is the intended target ordering.
* @return is the output of the zero padding.
*/
template <typename V>
V ZeroPadInverse(const V &InputPoly, usint target_order);
判断一个数是不是2的幂
/**
* Determines if a number is a power of 2.
*
* @param Input to test if it is a power of 2.
* @return is true if the unsigned int is a power of 2.
*/
inline bool IsPowerOfTwo(usint Input) {
return Input && !(Input & (Input - 1));
}
Auxiliary function to replace a specific character “in” with another character “out”
/**
* Auxiliary function to replace a specific character "in" with another
* character "out"
*
* @param str string where in which characters are replaced
* @param in character being replaced
* @param out character to be replaced with
* @return the modified string.
*/
// auxiliary function to replace a specific character "in" with another
// character "out"
std::string replaceChar(std::string str, char in, char out);
// Lazy Reduction functions: 64-bit multiplier and 128-bit Barrett reducer
// Originally proposed for BFVrnsB
/**
* check if adding two 64-bit number can cause overflow
* @param a: operand 1
* @param b: operand 2
* @return 1 if overflow occurs, 0 otherwise
*/
inline uint32_t IsAdditionOverflow(uint64_t a, uint64_t b) {
a += b;
if (a < b)
return 1;
else
return 0;
}
/**
* add two 64-bit number with carry out, c = a + b
* @param a: operand 1
* @param b: operand 2
* @param c: c = a + b
* @return 1 if overflow occurs, 0 otherwise
*/
inline uint32_t AdditionWithCarryOut(uint64_t a, uint64_t b, uint64_t &c) {
a += b;
c = a;
if (a < b)
return 1;
else
return 0;
}
#if defined(HAVE_INT128)
/**
* 64-bit uint multiplier, result is 128-bit
* @param a: operand 1
* @param b: operand 2
* @return result: 128-bit result = a * b
*/
inline DoubleNativeInt Mul128(uint64_t a, uint64_t b) {
return DoubleNativeInt(a) * DoubleNativeInt(b);
}
/**
* Barrett reduction of 128-bit integer modulo 64-bit integer. Source: Menezes,
* Alfred; Oorschot, Paul; Vanstone, Scott. Handbook of Applied Cryptography,
* Section 14.3.3.
* @param a: operand (128-bit)
* @param m: modulus (64-bit)
* @param mu: 2^128/modulus (128-bit)
* @return result: 64-bit result = a mod m
*/
inline uint64_t BarrettUint128ModUint64(const DoubleNativeInt &a,
uint64_t modulus,
const DoubleNativeInt &mu) {
// (a * mu)/2^128 // we need the upper 128-bit of (256-bit product)
uint64_t result = 0, a_lo = 0, a_hi = 0, mu_lo = 0, mu_hi = 0, left_hi = 0,
middle_lo = 0, middle_hi = 0, tmp1 = 0, tmp2 = 0, carry = 0;
DoubleNativeInt middle = 0;
a_lo = (uint64_t)a;
a_hi = a >> 64;
mu_lo = (uint64_t)mu;
mu_hi = mu >> 64;
left_hi = (Mul128(a_lo, mu_lo)) >> 64; // mul left parts, discard lower word
middle = Mul128(a_lo, mu_hi); // mul middle first
middle_lo = (uint64_t)middle;
middle_hi = middle >> 64;
// accumulate and check carry
carry = AdditionWithCarryOut(middle_lo, left_hi, tmp1);
tmp2 = middle_hi + carry; // accumulate
middle = Mul128(a_hi, mu_lo); // mul middle second
middle_lo = (uint64_t)middle;
middle_hi = middle >> 64;
carry = IsAdditionOverflow(middle_lo, tmp1); // check carry
left_hi = middle_hi + carry; // accumulate
// now we have the lower word of (a * mu)/2^128, no need for higher word
tmp1 = a_hi * mu_hi + tmp2 + left_hi;
// subtract lower words only, higher words should be the same
result = a_lo - tmp1 * modulus;
while (result >= modulus) result -= modulus;
return result;
}
#endif
/**
* Generates a random 128-bit hash
*/
inline std::string GenerateUniqueKeyID() {
const size_t intsInID = 128 / (sizeof(uint32_t) * 8);
std::uniform_int_distribution<uint32_t> distribution(
0, std::numeric_limits<uint32_t>::max());
std::stringstream s;
s.fill('0');
s << std::hex;
for (size_t i = 0; i < intsInID; i++)
s << std::setw(8) << distribution(PseudoRandomNumberGenerator::GetPRNG());
return s.str();
}
\core\lib\utils\utilities.cpp
#include "utils/utilities.h"
namespace lbcrypto {
// Zero-Padd adds extra zeros to the Input polynomial
// if Input polynomial has a length n less than CycloOrder,
// then it adds CycloOrder-n zeros in the Input Polynomial
template <typename V>
V ZeroPadForward(const V &InputPoly, usint target_order) { // 在最后补 0
if (InputPoly.GetLength() < target_order) {
V ans(target_order);
for (usint i = 0; i < InputPoly.GetLength(); i++)
ans.at(i) = InputPoly.at(i);
for (usint i = InputPoly.GetLength(); i < target_order; i++)
ans.at(i) = typename V::Integer(0); // 告诉编译器这是类型不是变量
ans.SetModulus(InputPoly.GetModulus());
return ans;
} else {
return V(InputPoly);
}
}
// Adds 0 between each BigInteger to support conversion from Inverse FFT to
// Inverse CRT
template <typename V>
V ZeroPadInverse(const V &InputPoly, usint target_order) {
if (InputPoly.GetLength() < target_order) { // 偶数位补 0
V ans(target_order);
for (usint i = 0; i < InputPoly.GetLength(); i++) {
ans.at(2 * i) = typename V::Integer("0");
ans.at(2 * i + 1) = InputPoly.at(i);
}
ans.SetModulus(InputPoly.GetModulus());
return ans;
} else {
return V(InputPoly);
}
}
// auxiliary function to replace a specific character "in" with another
// character "out"
std::string replaceChar(std::string str, char in, char out) {
// set our locator equal to the first appearance of any character in replace
size_t found = str.find_first_of(in);
// While our position in the string is in range.
while (found != std::string::npos) {
str[found] = out; // Change the character at position.
found = str.find_first_of(in, found + 1); // Relocate again.
}
return str; // return our new string.
}
} // namespace lbcrypto
\core\include\utils\parmfactory.h
parameter factory. 暂时没看懂。
#ifndef SRC_CORE_LIB_UTILS_PARMFACTORY_H_
#define SRC_CORE_LIB_UTILS_PARMFACTORY_H_
// useful for testing
#include <memory>
#include <vector>
#include "lattice/dcrtpoly.h"
#include "math/backend.h"
#include "math/distrgen.h"
#include "utils/inttypes.h"
#include "lattice/elemparams.h"
#include "lattice/ildcrtparams.h"
#include "lattice/ilelement.h"
#include "lattice/ilparams.h"
#include "lattice/poly.h"
using namespace lbcrypto;
/**
* Generate an ILDCRTParams with a given number of parms, with cyphertext moduli
* of at least a given size
* @param m - order
* @param numOfTower - # of polynomials
* @param pbits - number of bits in the prime, to start with
* @return
*/
template <typename I>
inline shared_ptr<ILDCRTParams<I>> GenerateDCRTParams(usint m, usint numOfTower,
usint pbits) {
DEBUG_FLAG(false);
DEBUG("in GenerateDCRTParams");
DEBUGEXP(m);
DEBUGEXP(numOfTower);
DEBUGEXP(pbits);
if (numOfTower == 0) {
PALISADE_THROW(math_error, "Can't make parms with numOfTower == 0");
}
std::vector<NativeInteger> moduli(numOfTower);
std::vector<NativeInteger> rootsOfUnity(numOfTower);
NativeInteger q = FirstPrime<NativeInteger>(pbits, m);
I modulus(1);
usint j = 0;
DEBUGEXP(q);
for (;;) {
moduli[j] = q;
rootsOfUnity[j] = RootOfUnity(m, q);
modulus = modulus * I(q.ConvertToInt());
DEBUG("j " << j << " modulus " << q << " rou " << rootsOfUnity[j]);
if (++j == numOfTower) break;
q = NextPrime(q, m);
}
auto params = std::make_shared<ILDCRTParams<I>>(m, moduli, rootsOfUnity);
return params;
}
#endif /* SRC_CORE_LIB_UTILS_PARMFACTORY_H_ */
\core\include\utils\memory.h
_MSC_VER 为微软C编译器版本
https://blog.csdn.net/a135138/article/details/114325057
#ifndef LBCRYPTO_UTILS_MEMORY_H
#define LBCRYPTO_UTILS_MEMORY_H
#include <algorithm>
#include <iterator>
#include <memory>
#include <utility>
#include <vector>
using std::unique_ptr;
using std::vector;
namespace lbcrypto {
// make_unique was left out of c++11, these are the accepted implementation
#if _MSC_VER == 1700
// MSVC11 does not support variadic templates
#define _MAKE_UNIQUE(TEMPLATE_LIST, PADDING_LIST, LIST, COMMA, X1, X2, X3, X4) \
\
template <class T COMMA LIST(_CLASS_TYPE)> \
inline std::unique_ptr<T> make_unique(LIST(_TYPE_REFREF_ARG)) { \
return std::unique_ptr<T>(new T(LIST(_FORWARD_ARG))); \
}
_VARIADIC_EXPAND_0X(_MAKE_UNIQUE, , , , )
#undef _MAKE_UNIQUE
#else
// *nix implementation
template <typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args) {
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
#endif
template <class X>
void MoveAppend(std::vector<X>& dst, std::vector<X>& src) {
if (dst.empty()) {
dst = std::move(src);
} else {
dst.reserve(dst.size() + src.size());
std::move(std::begin(src), std::end(src), std::back_inserter(dst));
src.clear();
}
}
} // namespace lbcrypto
#endif // LBCRYPTO_UTILS_MEMORY_H
\core\include\utils\hashutil.h
#ifndef _SRC_LIB_UTILS_HASHUTIL_H
#define _SRC_LIB_UTILS_HASHUTIL_H
#include <utils/exception.h>
#include <iostream>
#include <string>
#include <vector>
using std::string;
using std::vector;
namespace lbcrypto {
enum HashAlgorithm { SHA_256 = 0, SHA_512 = 1 };
class HashUtil {
public:
static void Hash(string message, HashAlgorithm algo,
vector<int64_t>& digest) {
switch (algo) {
case SHA_256:
SHA256(message, digest);
return;
case SHA_512:
// TODO SHA512 disabled, returning SHA256 instead
SHA256(message, digest);
return;
default:
PALISADE_THROW(not_available_error, "ERROR: Unknown Hash Algorithm");
}
}
static std::string HashString(std::string message);
private:
static void SHA256(string message, vector<int64_t>& digest);
static void SHA512(string message, vector<int64_t>& digest);
static const uint32_t k_256[64];
static const uint64_t k_512[80];
};
} // namespace lbcrypto
#endif
\core\include\utils\define.h
config.h – Declarations of global configuration parameters
#ifndef SRC_CORE_INCLUDE_UTILS_DEFINES_H
#define SRC_CORE_INCLUDE_UTILS_DEFINES_H
// Avoid unused variable warnings
#define PALISADE_UNUSED(x) (void)(x)
#endif // SRC_CORE_INCLUDE_UTILS_DEFINES_H
\core\include\utils\debug.h
This file contains macros and associated helper functions for quick cerr oriented debugging that can be quickly enabled and disabled. It also contains functions for timing code.
这个文件包含宏和相关的辅助函数,用于快速的面向cerr的调试,可以快速地启用和禁用这些调试。它还包含用于计时代码的函数。
#ifndef __dbg_h__
#define __dbg_h__
// include <iostream>
// include <cstdlib.h>
/* defining NDEBUG in the compile line turns everything off.
unless PROFILE is defined in the file before all includes,'
in which case TIC/TOC will still work and PROFILELOG() can be
used for logging results to std::cout, and DEBUG() will remain
silent. dbg_flag does not get used by PROFILELOG()
*/
#include <time.h>
#include <chrono> // for timing
#include <utility>
#include "utils/inttypes.h"
#if !defined(NDEBUG)
// note that for the following dbg_flag needs to be defined in some scope using
// DEBUG_FLAG
#define DEBUG_FLAG(x) bool dbg_flag = x;
// debugging macro prints value of x on cerr
#define DEBUG(x) \
do { \
if (dbg_flag) { \
std::cerr << x << std::endl; \
} \
} while (0)
// debugging macro prints typography of x and value of x on cerr
#define DEBUGEXP(x) \
do { \
if (dbg_flag) { \
std::cerr << #x << ":" << x << std::endl; \
} \
} while (0)
// debugging macro prints value of x and location in codex on cerr
#define DEBUGWHERE(x) \
do { \
if (dbg_flag) { \
std::cerr << __FILE__ << ":" << __LINE__ << ": " \
<< #x << ":" << x << std::endl; \
} \
} while (0)
#if defined(PROFILE) // Profiler works
#define PROFILELOG(x) \
do { \
if (true) { \
std::cout << x << std::endl; \
} \
} while (0)
// debugging macro prints typography of x and value of x on cerr
#define PROFILELOGEXP(x) \
do { \
if (true) { \
std::cout << #x << ":" << x << std::endl; \
} \
} while (0)
// debugging macro prints value of x and location in codex on cerr
#define PROFILELOGWHERE(x) \
do { \
if (true) { \
std::cout << #x << ":" << x << " at " << __FILE__ << " line " \
<< __LINE__ << std::endl; \
} \
} while (0)
#else // #if!defined(PROFILE) // profiling a noop
#define PROFILELOG(x)
#define PROFILELOGEXP(x)
#define PROFILELOGWHERE(x)
#endif // PROFILE
#define TIC(t) t = timeNow()
#define TOC(t) duration(timeNow() - t)
#define TOC_NS(t) duration_ns(timeNow() - t)
#define TOC_US(t) duration_us(timeNow() - t)
#define TOC_MS(t) duration_ms(timeNow() - t)
#else // NDEBUG
// #define debug(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n", __FILE__,
// __LINE__, ##__VA_ARGS__)
#if !defined(PROFILE)
// these are turned off functions
#define DEBUG_FLAG(x)
#define DEBUG(x)
#define DEBUGEXP(x)
#define DEBUGWHERE(x)
#define PROFILELOG(x)
#define PROFILELOGEXP(x)
#define PROFILELOGWHERE(x)
#define TIC(t) t = timeNow()
#define TOC(t) std::chrono::steady_clock::duration::zero().count()
#define TOC_NS(t) std::chrono::steady_clock::duration::zero().count()
#define TOC_US(t) std::chrono::steady_clock::duration::zero().count()
#define TOC_MS(t) std::chrono::steady_clock::duration::zero().count()
#else // PROFILE
// if PROFILE is turned on, then TIC TOC still work and
#define DEBUG_FLAG(x)
#define DEBUG(x)
#define DEBUGEXP(x)
#define DEBUGWHERE(x)
#define PROFILELOG(x) \
do { \
if (true) { \
std::cerr << x << std::endl; \
} \
} while (0)
// debugging macro prints typography of x and value of x on cerr
#define PROFILELOGEXP(x) \
do { \
if (true) { \
std::cout << #x << ":" << x << std::endl; \
} \
} while (0)
// debugging macro prints value of x and location in codex on cerr
#define PROFILELOGWHERE(x) \
do { \
if (true) { \
std::cout << #x << ":" << x << " at " << __FILE__ << " line " \
<< __LINE__ LL std::endl; \
} \
} while (0)
#define TIC(t) t = timeNow()
#define TOC(t) duration(timeNow() - t)
#define TOC_NS(t) duration_ns(timeNow() - t)
#define TOC_US(t) duration_us(timeNow() - t)
#define TOC_MS(t) duration_ms(timeNow() - t)
#endif // PROFILE
#endif // NDEBUG
typedef std::chrono::high_resolution_clock::time_point TimeVar;
#define duration(a) \
std::chrono::duration_cast<std::chrono::milliseconds>(a).count()
#define duration_ns(a) \
std::chrono::duration_cast<std::chrono::nanoseconds>(a).count()
#define duration_us(a) \
std::chrono::duration_cast<std::chrono::microseconds>(a).count()
#define duration_ms(a) \
std::chrono::duration_cast<std::chrono::milliseconds>(a).count()
#define timeNow() std::chrono::high_resolution_clock::now()
double currentDateTime();
template <typename F, typename... Args>
double funcTime(F func, Args&&... args) {
TimeVar t1 = timeNow();
func(std::forward<Args>(args)...);
return duration(timeNow() - t1);
}
#endif // #__dbg_h__
\core\include\utils\caller_info.h
This file contains macros to help access caller function information
#ifndef _CALLER_INFO_H_
#define _CALLER_INFO_H_
#include <string>
/*
* ATTN: the caller information is accessible if BUILTIN_INFO_AVAILABLE is defined in CMakeLists.txt.
* Currently, USE_BUILTIN_INFO is defined for GCC only.
* Instructions how to use the macros defined below:
* if you want to access the caller information from within a function
* you should add CALLER_INFO_ARGS_HDR as the last argument to your function
* in the header file where the function is declared and add
* CALLER_INFO_ARGS_CPP as the last argument to your function in the source
* file where it is implemented. if you have the function definition only then
* CALLER_INFO_ARGS_HDR should be added. After that you can use the string
* CALLER_INFO inside the function.
*
* Example:
* before adding caller information
* *.h:
* void foo(int x);
* *.cpp:
* void foo(int x) {
* std::cout << "foo() input: " << x << std::endl;
* }
*
* after adding caller information
* *.h:
* void foo(int x, CALLER_INFO_ARGS_HDR);
* *.cpp:
* void foo(int x, CALLER_INFO_ARGS_CPP) {
* std::cout << "foo() input: " << x << CALLER_INFO << std::endl;
* }
*/
#ifdef BUILTIN_INFO_AVAILABLE
#define CALLER_INFO_ARGS_HDR \
const char* callerFile = __builtin_FILE(), \
const char* callerFunc = __builtin_FUNCTION(), \
size_t callerLine = __builtin_LINE()
#define CALLER_INFO std::string(" [called from: ") + callerFile + ":" + \
callerFunc + "():l." + std::to_string(callerLine) + "]"
#else
#define CALLER_INFO_ARGS_HDR \
const char* callerFile = "", \
const char* callerFunc = "", \
size_t callerLine = 0
#define CALLER_INFO std::string("")
#endif // BUILTIN_INFO_AVAILABLE
#define CALLER_INFO_ARGS_CPP \
const char* callerFile, \
const char* callerFunc, \
size_t callerLine
#endif // _CALLER_INFO_H_