PALISADE Lattice Crypto Library  1.11.9
A lattice crypto library for software engineers by software engineers.
distributiongenerator.h
1 // @file distributiongenerator.h This code provides basic structure for
2 // distribution generators. This should be inherited by all other distribution
3 // generators.
4 // @author TPOC: contact@palisade-crypto.org
5 //
6 // @copyright Copyright (c) 2019, New Jersey Institute of Technology (NJIT)
7 // All rights reserved.
8 // Redistribution and use in source and binary forms, with or without
9 // modification, are permitted provided that the following conditions are met:
10 // 1. Redistributions of source code must retain the above copyright notice,
11 // this list of conditions and the following disclaimer.
12 // 2. Redistributions in binary form must reproduce the above copyright notice,
13 // this list of conditions and the following disclaimer in the documentation
14 // and/or other materials provided with the distribution. THIS SOFTWARE IS
15 // PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
16 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
17 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
18 // EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
19 // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 
26 #ifndef LBCRYPTO_MATH_DISTRIBUTIONGENERATOR_H_
27 #define LBCRYPTO_MATH_DISTRIBUTIONGENERATOR_H_
28 
29 #include <chrono>
30 #include <memory>
31 #include <mutex>
32 #include <random>
33 #include <thread>
34 #include "math/backend.h"
35 #include "utils/prng/blake2engine.h"
36 
37 // #define FIXED_SEED // if defined, then uses a fixed seed number for
38 // reproducible results during debug. Use only one OMP thread to ensure
39 // reproducibility
40 
41 namespace lbcrypto {
42 
43 // Defines the PRNG implementation used by PALISADE.
44 // The cryptographically secure PRNG used by PALISADE is based on BLAKE2 hash
45 // functions. A user can replace it with a different PRNG if desired by defining
46 // the same methods as for the Blake2Engine class.
47 typedef Blake2Engine PRNG;
48 
57  public:
62  static void InitPRNG() {
63  int threads = PalisadeParallelControls.GetNumThreads();
64  if (threads == 0) {
65  threads = 1;
66  }
67 #pragma omp parallel for num_threads(threads)
68  for (int i = 0; i < threads; ++i) {
69  GetPRNG();
70  }
71  }
72 
73  static PRNG &GetPRNG() {
74  // initialization of PRNGs
75  if (m_prng == nullptr) {
76 #pragma omp critical
77  {
78 #if defined(FIXED_SEED)
79  // Only used for debugging in the single-threaded mode.
80  std::cerr << "**FOR DEBUGGING ONLY!!!! Using fixed initializer for "
81  "PRNG. Use a single thread only, e.g., OMP_NUM_THREADS=1!"
82  << std::endl;
83 
84  std::array<uint32_t, 16> seed{};
85  seed[0] = 1;
86  m_prng = std::make_shared<PRNG>(seed);
87 
88 #else
89  // A 512-bit seed is generated for each thread (this roughly corresponds
90  // to 256 bits of security). The seed is the sum of a random sample
91  // generated using std::random_device (typically works correctly in
92  // Linux, MacOS X, and MinGW starting with GCC 9.2) and a BLAKE2 sample
93  // seeded from current time stamp, a hash of the current thread, and a
94  // memory location of a heap variable. The BLAKE2 sample is added in
95  // case random_device is deterministic (happens on MinGW with GCC
96  // below 9.2). All future calls to PRNG use the seed generated here.
97 
98  // The code below derives randomness from time, thread id, and a memory
99  // location of a heap variable. This seed is relevant only if the
100  // implementation of random_device is deterministic (as in older
101  // versions of GCC in MinGW)
102  std::array<uint32_t, 16> initKey{};
103  // high-resolution clock typically has a nanosecond tick period
104  // Arguably this may give up to 32 bits of entropy as the clock gets
105  // recycled every 4.3 seconds
106  initKey[0] = std::chrono::high_resolution_clock::now()
107  .time_since_epoch()
108  .count();
109  // A thread id is often close to being random (on most systems)
110  initKey[1] = std::hash<std::thread::id>{}(std::this_thread::get_id());
111  // On a 64-bit machine, the thread id is 64 bits long
112  // skip on 32-bit arm architectures
113 #if !defined(__arm__) && !defined(__EMSCRIPTEN__)
114  if (sizeof(size_t) == 8)
115  initKey[2] =
116  (std::hash<std::thread::id>{}(std::this_thread::get_id()) >> 32);
117 #endif
118 
119  // heap variable; we are going to use the least 32 bits of its memory
120  // location as the counter for BLAKE2 This will increase the entropy of
121  // the BLAKE2 sample
122  void *mem = malloc(1);
123  uint32_t counter = reinterpret_cast<long long>(mem);
124  free(mem);
125 
126  PRNG gen(initKey, counter);
127 
128  std::uniform_int_distribution<uint32_t> distribution(0);
129  std::array<uint32_t, 16> seed{};
130  for (uint32_t i = 0; i < 16; i++) {
131  seed[i] = distribution(gen);
132  }
133 
134  std::array<uint32_t, 16> rdseed{};
135  size_t attempts = 3;
136  bool rdGenPassed = false;
137  size_t idx = 0;
138  while (!rdGenPassed && idx < attempts) {
139  try {
140  std::random_device genR;
141  for (uint32_t i = 0; i < 16; i++) {
142  // we use the fact that there is no overflow for unsigned integers
143  // (from C++ standard) i.e., arithmetic mod 2^32 is performed. For
144  // the seed to be random, it is sufficient for one of the two
145  // samples below to be random. In almost all practical cases,
146  // distribution(genR) is random. We add distribution(gen) just in
147  // case there is an implementation issue with random_device (as in
148  // older MinGW systems).
149  rdseed[i] = distribution(genR);
150  }
151  rdGenPassed = true;
152  } catch (std::exception &e) {
153  }
154  idx++;
155  }
156 
157  for (uint32_t i = 0; i < 16; i++) {
158  seed[i] += rdseed[i];
159  }
160 
161  m_prng = std::make_shared<PRNG>(seed);
162 #endif
163  }
164  }
165  return *m_prng;
166  }
167 
168  private:
169  // shared pointer to a thread-specific PRNG engine
170  static std::shared_ptr<PRNG> m_prng;
171 
172 #if !defined(FIXED_SEED)
173  // avoid contention on m_prng
174  // local copies of m_prng are created for each thread
175 #pragma omp threadprivate(m_prng)
176 #endif
177 };
178 
187 template <typename VecType>
189  public:
191  virtual ~DistributionGenerator() {}
192 };
193 
194 } // namespace lbcrypto
195 
196 #endif // LBCRYPTO_MATH_DISTRIBUTIONGENERATOR_H_
static void InitPRNG()
Returns a reference to the PRNG engine.
Definition: distributiongenerator.h:62
The class providing the PRNG capability to all random distribution generators in PALISADE. THe security of Ring Learning With Errors (used for all crypto capabilities in PALISADE) depends on the randomness of uniform, ternary, and Gaussian distributions, which derive their randomness from the PRNG.
Definition: distributiongenerator.h:56
Abstract class describing generator requirements.
Definition: distributiongenerator.h:188
Definition: binfhecontext.h:36